All of lore.kernel.org
 help / color / mirror / Atom feed
* [Virtio-fs] [PATCH-v2 0/2] fuse: remove dmap when truncating inode
@ 2019-05-13 14:41 Peng Tao
  2019-05-13 14:41 ` [Virtio-fs] [PATCH-v2 1/2] " Peng Tao
  0 siblings, 1 reply; 3+ messages in thread
From: Peng Tao @ 2019-05-13 14:41 UTC (permalink / raw)
  To: virtio-fs; +Cc: Peng Tao

Hi Vivek,

The two patches try to remove dmap during truncation. virtiofs fuse
protocol is also modified to support removing multiple entries in
a single request. The host side virtiofsd patch will be sent separately.

Cheers,
Tao


Peng Tao (2):
  fuse: remove dmap when truncating inode
  virtiofs: FUSE_REMOVEMAPPING support multiple removing multiple
    entries

 fs/fuse/dir.c             |   5 ++
 fs/fuse/file.c            | 134 ++++++++++++++++++++++++++++++++------
 fs/fuse/fuse_i.h          |   2 +
 include/uapi/linux/fuse.h |   9 ++-
 4 files changed, 129 insertions(+), 21 deletions(-)

-- 
2.17.1


^ permalink raw reply	[flat|nested] 3+ messages in thread

* [Virtio-fs] [PATCH-v2 1/2] fuse: remove dmap when truncating inode
  2019-05-13 14:41 [Virtio-fs] [PATCH-v2 0/2] fuse: remove dmap when truncating inode Peng Tao
@ 2019-05-13 14:41 ` Peng Tao
  2019-05-13 14:41   ` [Virtio-fs] [PATCH-v2 2/2] virtiofs: FUSE_REMOVEMAPPING support multiple removing multiple entries Peng Tao
  0 siblings, 1 reply; 3+ messages in thread
From: Peng Tao @ 2019-05-13 14:41 UTC (permalink / raw)
  To: virtio-fs; +Cc: Peng Tao

The obseleted dmap entries can be put back to global free list
immediately and we don't have to rely on reclaim code to free them.

Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
---
 fs/fuse/dir.c    |  5 +++++
 fs/fuse/file.c   | 55 ++++++++++++++++++++++++++++++++++++++----------
 fs/fuse/fuse_i.h |  2 ++
 3 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 3f923fe7841a..233c3ed391f1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1751,6 +1751,11 @@ int fuse_do_setattr(struct dentry *dentry, struct iattr *attr,
 		down_write(&fi->i_mmap_sem);
 		truncate_pagecache(inode, outarg.attr.size);
 		invalidate_inode_pages2(inode->i_mapping);
+		// Free dmap beyond i_size
+		if (IS_DAX(inode) && oldsize > outarg.attr.size)
+			fuse_dax_free_mappings_range(fc, inode,
+						     outarg.attr.size, -1);
+
 		up_write(&fi->i_mmap_sem);
 	}
 
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 7362aab3ee74..b9f6688c4062 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3848,7 +3848,6 @@ int fuse_dax_reclaim_dmap_locked(struct fuse_conn *fc, struct inode *inode,
 		return ret;
 	}
 
-	/* Remove dax mapping from inode interval tree now */
 	fuse_dax_interval_tree_remove(dmap, &fi->dmap_tree);
 	fi->nr_dmaps--;
 	return 0;
@@ -3927,6 +3926,49 @@ static struct fuse_dax_mapping *alloc_dax_mapping_reclaim(struct fuse_conn *fc,
 	}
 }
 
+/* Cleanup dmap entry and add back to free list */
+static void fuse_dax_do_free_mapping_locked(struct fuse_conn *fc, struct fuse_dax_mapping *dmap)
+{
+	pr_debug("fuse: freed memory range start=0x%llx end=0x%llx "
+		"window_offset=0x%llx length=0x%llx\n", dmap->start,
+		dmap->end, dmap->window_offset, dmap->length);
+	spin_lock(&fc->lock);
+	__dmap_remove_busy_list(fc, dmap);
+	dmap->inode = NULL;
+	dmap->start = dmap->end = 0;
+	__free_dax_mapping(fc, dmap);
+	spin_unlock(&fc->lock);
+}
+
+/*
+ * Free inode dmap entries whose range falls entirely inside [start, end].
+ * Called with inode->i_rwsem and fuse_inode->i_mmap_sem held.
+ */
+void fuse_dax_free_mappings_range(struct fuse_conn *fc, struct inode *inode, loff_t start, loff_t end)
+{
+	struct fuse_inode *fi = get_fuse_inode(inode);
+	struct fuse_dax_mapping *dmap;
+
+	WARN_ON(!inode_is_locked(inode));
+	WARN_ON(!rwsem_is_locked(&fi->i_mmap_sem));
+
+	/* interval tree search matches intersecting entries.
+	 * Adjust the range to avoid dropping partial valid entries. */
+	start = ALIGN(start, FUSE_DAX_MEM_RANGE_SZ);
+	end = ALIGN_DOWN(end, FUSE_DAX_MEM_RANGE_SZ);
+
+	pr_debug("fuse: fuse_dax_free_mappings_range start=0x%llx, end=0x%llx\n", start, end);
+	/* Lock ordering follows fuse_dax_free_one_mapping() */
+	down_write(&fi->i_dmap_sem);
+	while ((dmap = fuse_dax_interval_tree_iter_first(&fi->dmap_tree, start, end))) {
+		fuse_dax_interval_tree_remove(dmap, &fi->dmap_tree);
+		fi->nr_dmaps--;
+		fuse_dax_do_free_mapping_locked(fc, dmap);
+		fuse_removemapping_one(inode, dmap);
+	}
+	up_write(&fi->i_dmap_sem);
+}
+
 int fuse_dax_free_one_mapping_locked(struct fuse_conn *fc, struct inode *inode,
 				u64 dmap_start)
 {
@@ -3948,17 +3990,8 @@ int fuse_dax_free_one_mapping_locked(struct fuse_conn *fc, struct inode *inode,
 	if (ret < 0)
 		return ret;
 
-	/* Cleanup dmap entry and add back to free list */
-	spin_lock(&fc->lock);
-	__dmap_remove_busy_list(fc, dmap);
-	dmap->inode = NULL;
-	dmap->start = dmap->end = 0;
-	__free_dax_mapping(fc, dmap);
-	spin_unlock(&fc->lock);
+	fuse_dax_do_free_mapping_locked(fc, dmap);
 
-	pr_debug("fuse: freed memory range window_offset=0x%llx,"
-				" length=0x%llx\n", dmap->window_offset,
-				dmap->length);
 	return ret;
 }
 
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 20a8bfd63b80..894fc5e78589 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1206,5 +1206,7 @@ void fuse_dax_free_mem_worker(struct work_struct *work);
 void fuse_removemapping(struct inode *inode);
 void fuse_end_pending_request(struct fuse_conn *fc, struct fuse_pqueue *fpq,
 			      u64 unique, int err);
+void fuse_dax_free_mappings_range(struct fuse_conn *fc, struct inode *inode,
+			loff_t start, loff_t end);
 
 #endif /* _FS_FUSE_I_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [Virtio-fs] [PATCH-v2 2/2] virtiofs: FUSE_REMOVEMAPPING support multiple removing multiple entries
  2019-05-13 14:41 ` [Virtio-fs] [PATCH-v2 1/2] " Peng Tao
@ 2019-05-13 14:41   ` Peng Tao
  0 siblings, 0 replies; 3+ messages in thread
From: Peng Tao @ 2019-05-13 14:41 UTC (permalink / raw)
  To: virtio-fs; +Cc: Peng Tao

Change FUSE_REMOVEMAPPING wire protocol so that we can remove
multiple mappings in one call.

Signed-off-by: Peng Tao <tao.peng@linux.alibaba.com>
---
 fs/fuse/file.c            | 85 +++++++++++++++++++++++++++++++++------
 include/uapi/linux/fuse.h |  9 ++++-
 2 files changed, 81 insertions(+), 13 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b9f6688c4062..41ec7fdb780e 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -350,25 +350,80 @@ static int fuse_mkwrite_one_mapping(struct inode *inode, struct file *file,
 	return __fuse_setup_one_mapping(inode, file, offset, flags, dmap, true);
 }
 
-static int fuse_removemapping_one(struct inode *inode,
-					struct fuse_dax_mapping *dmap)
+static int fuse_send_removemapping_request(struct inode *inode,
+		struct fuse_removemapping_in_header *header,
+		struct fuse_removemapping_in *inargp)
 {
 	struct fuse_inode *fi = get_fuse_inode(inode);
 	struct fuse_conn *fc = get_fuse_conn(inode);
-	struct fuse_removemapping_in inarg;
 	FUSE_ARGS(args);
 
-	memset(&inarg, 0, sizeof(inarg));
-	inarg.moffset = dmap->window_offset;
-	inarg.len = dmap->length;
 	args.in.h.opcode = FUSE_REMOVEMAPPING;
 	args.in.h.nodeid = fi->nodeid;
-	args.in.numargs = 1;
-	args.in.args[0].size = sizeof(inarg);
-	args.in.args[0].value = &inarg;
+	args.in.numargs = 2;
+	args.in.args[0].size = sizeof(*header);
+	args.in.args[0].value = header;
+	args.in.args[1].size = header->num * sizeof(*inargp);
+	args.in.args[1].value = inargp;
 	return fuse_simple_request(fc, &args);
 }
 
+static int fuse_removemappings(struct inode *inode, unsigned num,
+				struct list_head *to_remove)
+{
+	struct fuse_removemapping_in *inargp, *ptr;
+	struct fuse_removemapping_in_header header;
+	struct fuse_dax_mapping *dmap;
+	int ret, i = 0;
+
+	if (num <= FUSE_REMOVEMAPPING_MAX_ENTRY) {
+		inargp = kmalloc_array(num, sizeof(*inargp), GFP_NOIO);
+	} else {
+		inargp = kmalloc_array(FUSE_REMOVEMAPPING_MAX_ENTRY,
+					sizeof(*inargp), GFP_NOIO);
+	}
+	if (inargp == NULL)
+		return -ENOMEM;
+
+	ptr = inargp;
+	list_for_each_entry(dmap, to_remove, list) {
+		ptr->moffset = dmap->window_offset;
+		ptr->len = dmap->length;
+		ptr++;
+		i++;
+		num--;
+		if (i >= FUSE_REMOVEMAPPING_MAX_ENTRY || num == 0) {
+			memset(&header, 0, sizeof(header));
+			header.num = i;
+			ret = fuse_send_removemapping_request(inode, &header, inargp);
+			if (ret)
+				goto out;
+			ptr = inargp;
+			i = 0;
+		}
+	}
+
+out:
+	kfree(inargp);
+	return ret;
+}
+
+static int fuse_removemapping_one(struct inode *inode,
+					struct fuse_dax_mapping *dmap)
+{
+	struct fuse_removemapping_in inarg;
+	struct fuse_removemapping_in_header header;
+
+	memset(&header, 0, sizeof(header));
+	/* TODO: fill in header.fh when available */
+	header.num = 1;
+	memset(&inarg, 0, sizeof(inarg));
+	inarg.moffset = dmap->window_offset;
+	inarg.len = dmap->length;
+
+	return fuse_send_removemapping_request(inode, &header, &inarg);
+}
+
 /*
  * It is called from evict_inode() and by that time inode is going away. So
  * this function does not take any locks like fi->i_dmap_sem for traversing
@@ -3947,7 +4002,9 @@ static void fuse_dax_do_free_mapping_locked(struct fuse_conn *fc, struct fuse_da
 void fuse_dax_free_mappings_range(struct fuse_conn *fc, struct inode *inode, loff_t start, loff_t end)
 {
 	struct fuse_inode *fi = get_fuse_inode(inode);
-	struct fuse_dax_mapping *dmap;
+	struct fuse_dax_mapping *dmap, *n;
+	int num = 0;
+	LIST_HEAD(to_remove);
 
 	WARN_ON(!inode_is_locked(inode));
 	WARN_ON(!rwsem_is_locked(&fi->i_mmap_sem));
@@ -3962,9 +4019,13 @@ void fuse_dax_free_mappings_range(struct fuse_conn *fc, struct inode *inode, lof
 	down_write(&fi->i_dmap_sem);
 	while ((dmap = fuse_dax_interval_tree_iter_first(&fi->dmap_tree, start, end))) {
 		fuse_dax_interval_tree_remove(dmap, &fi->dmap_tree);
-		fi->nr_dmaps--;
+		num++;
+		list_add(&dmap->list, &to_remove);
+	}
+	fi->nr_dmaps -= num;
+	fuse_removemappings(inode, num, &to_remove);
+	list_for_each_entry_safe(dmap, n, &to_remove, list) {
 		fuse_dax_do_free_mapping_locked(fc, dmap);
-		fuse_removemapping_one(inode, dmap);
 	}
 	up_write(&fi->i_dmap_sem);
 }
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index dbc5013ad747..04a4204e7f98 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -817,13 +817,20 @@ struct fuse_setupmapping_out {
         uint64_t	len[FUSE_SETUPMAPPING_ENTRIES];
 };
 
-struct fuse_removemapping_in {
+struct fuse_removemapping_in_header {
         /* An already open handle */
         uint64_t	fh;
+	/* number of fuse_removemapping_in follows */
+	unsigned	num;
+};
+
+struct fuse_removemapping_in {
 	/* Offset into the dax window start the unmapping */
 	uint64_t        moffset;
         /* Length of mapping required */
         uint64_t	len;
 };
+#define FUSE_REMOVEMAPPING_MAX_ENTRY	\
+		(PAGE_SIZE / sizeof(struct fuse_removemapping_in))
 
 #endif /* _LINUX_FUSE_H */
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2019-05-13 14:41 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-13 14:41 [Virtio-fs] [PATCH-v2 0/2] fuse: remove dmap when truncating inode Peng Tao
2019-05-13 14:41 ` [Virtio-fs] [PATCH-v2 1/2] " Peng Tao
2019-05-13 14:41   ` [Virtio-fs] [PATCH-v2 2/2] virtiofs: FUSE_REMOVEMAPPING support multiple removing multiple entries Peng Tao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.