[Devel] [PATCH RHEL7 COMMIT] fuse: add a new async operation to unmap regions

Konstantin Khorenko khorenko at virtuozzo.com
Thu Feb 15 17:34:47 MSK 2018


The commit is pushed to "branch-rh7-3.10.0-693.17.1.vz7.43.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.17.1.vz7.43.5
------>
commit f61077b33db4675d2c21a8571baa123f50e7d816
Author: Andrei Vagin <avagin at openvz.org>
Date:   Thu Feb 15 17:34:46 2018 +0300

    fuse: add a new async operation to unmap regions
    
    The fuse interface allows to run any operation asynchronously, because
    the kernel redirect all operations to an user daemon and then waits an
    answer.
    
    In ploop, we want to handle discard requests via fallocate and
    a simplest way to do this is to run fallocate(FALLOC_FL_PUNCH_HOLE)
    asynchronously like the write command.
    
    This patch adds a new async command IOCB_CMD_UNMAP_ITER, which sends
    fallocate(FALLOC_FL_PUNCH_HOLE) to a fuse user daemon.
    
    Signed-off-by: Andrei Vagin <avagin at openvz.org>
---
 fs/aio.c                     |  1 +
 fs/fuse/file.c               | 66 ++++++++++++++++++++++++++++++++++++++------
 fs/fuse/fuse_i.h             |  3 ++
 include/uapi/linux/aio_abi.h |  1 +
 4 files changed, 62 insertions(+), 9 deletions(-)

diff --git a/fs/aio.c b/fs/aio.c
index 3a6a9b01dc2e..cdc7558c7e27 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -1492,6 +1492,7 @@ static ssize_t aio_run_iocb(struct kiocb *req, bool compat)
 		ret = aio_read_iter(req);
 		break;
 
+	case IOCB_CMD_UNMAP_ITER:
 	case IOCB_CMD_WRITE_ITER:
 		ret = aio_write_iter(req);
 		break;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index de0187c910a0..ab1e6a7d33c6 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -920,6 +920,19 @@ static void fuse_aio_complete_req(struct fuse_conn *fc, struct fuse_req *req)
 	if (!req->bvec)
 		fuse_release_user_pages(req, !io->write);
 
+	if (req->in.h.opcode == FUSE_FALLOCATE) {
+		if (req->out.h.error)
+			printk("fuse_aio_complete_req: request (fallocate fh=0x%llx "
+			       "offset=%lld length=%lld mode=%x) completed with err=%d\n",
+			       req->misc.fallocate.in.fh,
+			       req->misc.fallocate.in.offset,
+			       req->misc.fallocate.in.length,
+			       req->misc.fallocate.in.mode,
+			       req->out.h.error);
+		fuse_aio_complete(io, req->out.h.error, -1);
+		return;
+	}
+
 	if (io->write) {
 		if (req->misc.write.in.size != req->misc.write.out.size)
 			pos = req->misc.write.in.offset - io->offset +
@@ -1317,6 +1330,35 @@ static void fuse_write_fill(struct fuse_req *req, struct fuse_file *ff,
 	req->out.args[0].value = outarg;
 }
 
+static size_t fuse_send_unmap(struct fuse_req *req, struct fuse_io_priv *io,
+		loff_t pos, size_t count, fl_owner_t owner)
+{
+	struct file *file = io->file;
+	struct fuse_file *ff = file->private_data;
+	struct fuse_conn *fc = ff->fc;
+	struct fuse_fallocate_in *inarg = &req->misc.fallocate.in;
+
+	inarg->fh = ff->fh;
+	inarg->offset = pos;
+	inarg->length = count;
+	inarg->mode = FALLOC_FL_KEEP_SIZE |
+		      FALLOC_FL_PUNCH_HOLE |
+		      FALLOC_FL_ZERO_RANGE;
+	req->in.h.opcode = FUSE_FALLOCATE;
+	req->in.h.nodeid = ff->nodeid;
+	req->in.numargs = 1;
+	req->in.args[0].size = sizeof(struct fuse_fallocate_in);
+	req->in.args[0].value = inarg;
+
+	fuse_account_request(fc, count);
+
+	if (io->async)
+		return fuse_async_req_send(fc, req, count, io);
+
+	fuse_request_send(fc, req);
+	return count;
+}
+
 static size_t fuse_send_write(struct fuse_req *req, struct fuse_io_priv *io,
 			      loff_t pos, size_t count, fl_owner_t owner)
 {
@@ -3450,7 +3492,7 @@ static ssize_t fuse_direct_IO_bvec(int rw, struct kiocb *iocb,
 			req->bvec = bvec;
 		}
 
-		if (filled + bvec->bv_len <= nmax) {
+		if (bvec_len && filled + bvec->bv_len <= nmax) {
 			filled += bvec->bv_len;
 			req->num_bvecs++;
 			bvec++;
@@ -3460,14 +3502,20 @@ static ssize_t fuse_direct_IO_bvec(int rw, struct kiocb *iocb,
 				continue;
 		}
 
-		BUG_ON(!filled);
-
-		if (rw == WRITE)
-			nres = fuse_send_write(req, io, pos,
-					filled, NULL);
-		else
-			nres = fuse_send_read(req, io, pos,
-					filled, NULL);
+		if (iocb->ki_opcode == IOCB_CMD_UNMAP_ITER) {
+			req->in.argbvec = 0;
+			nres = fuse_send_unmap(req, io, pos,
+					iocb->ki_nbytes, NULL);
+			filled = nres;
+		} else {
+			BUG_ON(!filled);
+			if (rw == WRITE)
+				nres = fuse_send_write(req, io, pos,
+						filled, NULL);
+			else
+				nres = fuse_send_read(req, io, pos,
+						filled, NULL);
+		}
 
 		BUG_ON(nres != filled);
 		fuse_put_request(fc, req);
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 2da45201474a..b2edcf9a1f8e 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -364,6 +364,9 @@ struct fuse_req {
 			struct fuse_write_in in;
 			struct fuse_write_out out;
 		} write;
+		struct {
+			struct fuse_fallocate_in in;
+		} fallocate;
 		struct fuse_notify_retrieve_in retrieve_in;
 		struct fuse_lk_in lk_in;
 	} misc;
diff --git a/include/uapi/linux/aio_abi.h b/include/uapi/linux/aio_abi.h
index 22ce4bd25013..ea2c346a2d9f 100644
--- a/include/uapi/linux/aio_abi.h
+++ b/include/uapi/linux/aio_abi.h
@@ -46,6 +46,7 @@ enum {
 	IOCB_CMD_PWRITEV = 8,
 	IOCB_CMD_READ_ITER = 9,
 	IOCB_CMD_WRITE_ITER = 10,
+	IOCB_CMD_UNMAP_ITER = 11,
 };
 
 /*


More information about the Devel mailing list