[Virtio-fs] [PATCH-v2 2/2] virtiofs: FUSE_REMOVEMAPPING support multiple removing multiple entries

Peng Tao tao.peng at linux.alibaba.com
Mon May 13 14:41:09 UTC 2019


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

Signed-off-by: Peng Tao <tao.peng at 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




More information about the Virtio-fs mailing list