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

Andrei Vagin avagin at virtuozzo.com
Wed Feb 7 00:34:35 MSK 2018


On Tue, Feb 06, 2018 at 11:49:30PM +0300, Konstantin Khorenko wrote:
> 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.

1. Feature

Add support of discard requests via punch-holes for plain ploops
https://pmc.acronis.com/browse/VSTOR-6962

2. Description

When ploop receives a discard request, it calls fallocate() to make a
punch hole in a ploop image file. It allows to drop useless data from a
storage.

4. Testing

[root at localhost ploop]# cat test/ploop-fdiscard.sh
set -e -x

path=$1
mkdir -p $path
ploop init $path/root -s 1G -f raw --sparse -t none
out=$(ploop mount $path/DiskDescriptor.xml)
echo $out
dev=$(echo $out | sed "s/.*dev=\(\S*\).*/\1/")
echo $dev
filefrag -sv $path/root
dd if=/dev/urandom of=$dev bs=1M count=1
dd if=/dev/urandom of=$dev bs=1M count=1 seek=512
fout1="$(filefrag -sv $path/root | wc -l)"
filefrag -sv $path/root
blkdiscard -l 1M -o 512M $dev
filefrag -sv $path/root
fout2="$(filefrag -sv $path/root | wc -l)"
if [ "$fout1" -le "$fout2" ]; then
	echo FAIL
	exit 1
fi
blkdiscard $dev
filefrag -sv $path/root
fout3="$(filefrag -sv $path/root | wc -l)"
if [ "$fout2" -le "$fout3" ]; then
	echo FAIL
	exit 1
fi
ploop umount -d $dev
rm -rf $path

5. Known issues

Works only for raw images on a fuse file system (vstorage)

7. Feature owner
Andrei Vagin (avagin@)


> 
> And whom to review?

Dima, could you review this patch set?

> 
> --
> 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