[Devel] [PATCH 1/2] fuse: add a new async operation to unmap regions

Konstantin Khorenko khorenko at virtuozzo.com
Tue Feb 6 23:49:30 MSK 2018


Andrey, this seems to be a feature and it should be tested.

Please post here a jira id with the feature description, QA task, etc.

And whom to review?

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

On 02/06/2018 03:25 AM, Andrei Vagin wrote:
> 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               | 63 ++++++++++++++++++++++++++++++++++++++------
>  fs/fuse/fuse_i.h             |  3 +++
>  include/uapi/linux/aio_abi.h |  1 +
>  4 files changed, 60 insertions(+), 8 deletions(-)
>
> diff --git a/fs/aio.c b/fs/aio.c
> index 3a6a9b0..cdc7558 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -1492,6 +1492,7 @@ rw_common:
>  		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 877c41f..83ea9da 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 +
> @@ -1322,6 +1335,33 @@ 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;
> +	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)
>  {
> @@ -3455,7 +3495,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++;
> @@ -3465,14 +3505,21 @@ 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 2da4520..b2edcf9 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 22ce4bd..ea2c346 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