Andrei Vagin <ava...@virtuozzo.com> writes:

> 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@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?
Ack, with minor request.
It is good moment to add stress test for rw-io vs discard
via fio. I can imagine two types of tests:
1) simple stress read/write/trim
2) integrity test via trimwrite, and  read verify after
>
>> 
>> --
>> 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 <ava...@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,
>> >  };
>> > 
>> >  /*
>> > 
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to