Re: [PATCH v2] ovl: improving copy-up efficiency for big sparse file

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 ---- 在 星期三, 2019-10-30 23:50:13 Amir Goldstein <amir73il@xxxxxxxxx> 撰写 ----
 > On Wed, Oct 30, 2019 at 2:45 PM Chengguang Xu <cgxu519@xxxxxxxxxxxx> wrote:
 > >
 > > Current copy-up is not efficient for big sparse file,
 > > It's not only slow but also wasting more disk space
 > > when the target lower file has huge hole inside.
 > > This patch tries to recognize file hole and skip it
 > > during copy-up.
 > >
 > > In detail, this optimization checks the hole according
 > > to copy-up chunk size so it may not recognize all kind
 > > of holes in the file. However, it is easy to implement
 > > and will be enough for most of the use case.
 > >
 > > Additionally, this optimization relies on lseek(2)
 > > SEEK_DATA implementation, so for some specific
 > > filesystems which do not support this feature
 > > will behave as before on copy-up.
 > >
 > > Signed-off-by: Chengguang Xu <cgxu519@xxxxxxxxxxxx>
 > > ---
 > >
 > > Hi Miklos, Amir
 > >
 > > This is v2 version of hole copy-up improvement which
 > > addressed amir's concerns in previous email.
 > >
 > > Could you have a look at this patch?
 > >
 > > There is a checkpatch warning but that is
 > > false-positive warning, so you can ignore it.
 > >
 > > I've tested the patch with the cases under overlay dir
 > > (include overlay/066) in fstest for xfs/ext4 fstype,
 > > and passed most of the cases except below.
 > >
 > > overlay/045     [not run] fsck.overlay utility required, skipped this test
 > > overlay/046     [not run] fsck.overlay utility required, skipped this test
 > > overlay/056     [not run] fsck.overlay utility required, skipped this test
 > 
 > Those are not failures.
 > You need to install fsck.overlay from
 > https://github.com/hisilicon/overlayfs-progs
 > for these tests to run.

I'll do.

 > 
 > >
 > > Above three cases are fsck related cases,
 > > I think they are not important for copy-up.
 > >
 > > overlay/061     - output mismatch (see /home/cgxu/git/xfstests-dev/results//overlay/061.out.bad)
 > >     --- tests/overlay/061.out   2019-05-28 09:54:42.320874925 +0800
 > >     +++ /home/cgxu/git/xfstests-dev/results//overlay/061.out.bad        2019-10-30 16:11:50.490848367 +0800
 > >     @@ -1,4 +1,4 @@
 > >      QA output created by 061
 > >     -00000000:  61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61  aaaaaaaaaaaaaaaa
 > >     +00000000:  54 68 69 73 20 69 73 20 6f 6c 64 20 6e 65 77 73  This.is.old.news
 > >      After mount cycle:
 > >      00000000:  61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61  aaaaaaaaaaaaaaaa
 > >     ...
 > >     (Run 'diff -u /home/cgxu/git/xfstests-dev/tests/overlay/061.out /home/cgxu/git/xfstests-dev/results//overlay/061.out.bad'  to see the entire diff)
 > >
 > > overlay/061 was failed with/without my patch and test results
 > > were just same. have something already broken for the test?
 > 
 > Yes, overlayfs does not comply with this "posix"' test.
 > This is why it was removed from the auto and quick groups.

So I'm curious what is the purpose for the test?

 > 
 > >
 > >
 > > v1->v2:
 > > - Set file size when the hole is in the end of the file.
 > > - Add a code comment for hole copy-up improvement.
 > > - Check SEEK_DATA support before doing hole skip.
 > > - Back to original copy-up when seek data fails(in error case).
 > >
 > >  fs/overlayfs/copy_up.c | 78 ++++++++++++++++++++++++++++++++++--------
 > >  1 file changed, 64 insertions(+), 14 deletions(-)
 > >
 > > diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
 > > index b801c6353100..7d8a34c480f4 100644
 > > --- a/fs/overlayfs/copy_up.c
 > > +++ b/fs/overlayfs/copy_up.c
 > > @@ -116,13 +116,30 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
 > >         return error;
 > >  }
 > >
 > > -static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
 > > +static int ovl_set_size(struct dentry *upperdentry, struct kstat *stat)
 > > +{
 > > +       struct iattr attr = {
 > > +               .ia_valid = ATTR_SIZE,
 > > +               .ia_size = stat->size,
 > > +       };
 > > +
 > > +       return notify_change(upperdentry, &attr, NULL);
 > > +}
 > > +
 > > +static int ovl_copy_up_data(struct path *old, struct path *new,
 > > +                           struct kstat *stat)
 > >  {
 > >         struct file *old_file;
 > >         struct file *new_file;
 > > +       loff_t len = stat->size;
 > >         loff_t old_pos = 0;
 > >         loff_t new_pos = 0;
 > >         loff_t cloned;
 > > +       loff_t old_next_data_pos;
 > > +       loff_t hole_len;
 > > +       bool seek_support = false;
 > > +       bool skip_hole = true;
 > > +       bool set_size = false;
 > >         int error = 0;
 > >
 > >         if (len == 0)
 > > @@ -144,7 +161,12 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
 > >                 goto out;
 > >         /* Couldn't clone, so now we try to copy the data */
 > >
 > > -       /* FIXME: copy up sparse files efficiently */
 > > +       /* Check if lower fs supports seek operation */
 > > +       if (old_file->f_mode & FMODE_LSEEK &&
 > > +           old_file->f_op->llseek) {
 > > +               seek_support = true;
 > > +       }
 > > +
 > >         while (len) {
 > >                 size_t this_len = OVL_COPY_UP_CHUNK_SIZE;
 > >                 long bytes;
 > > @@ -157,6 +179,38 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
 > >                         break;
 > >                 }
 > >
 > > +               /*
 > > +                * Fill zero for hole will cost unnecessary disk space
 > > +                * and meanwhile slow down the copy-up speed, so we do
 > > +                * an optimization for hole during copy-up, it relies
 > > +                * on SEEK_DATA implementation and the hole check is
 > > +                * aligned to OVL_COPY_UP_CHUNK_SIZE. In other word,
 > > +                * we do not try to recognize all kind of holes here,
 > > +                * we just skip big enough hole for simplicity to
 > > +                * implement. If lower fs does not support SEEK_DATA
 > > +                * operation, the copy-up will behave as before.
 > > +                */
 > > +
 > > +               if (seek_support && skip_hole) {
 > > +                       old_next_data_pos = vfs_llseek(old_file,
 > > +                                               old_pos, SEEK_DATA);
 > > +                       if (old_next_data_pos >= old_pos +
 > > +                                               OVL_COPY_UP_CHUNK_SIZE) {
 > > +                               hole_len = (old_next_data_pos - old_pos) /
 > > +                                               OVL_COPY_UP_CHUNK_SIZE *
 > > +                                               OVL_COPY_UP_CHUNK_SIZE;
 > 
 > Use round_down() helper

I'll change the logic of hole detection a bit, so that it could work
more effectively for big continuous hole.


 > 
 > > +                               old_pos += hole_len;
 > > +                               new_pos += hole_len;
 > > +                               len -= hole_len;
 > > +                               continue;
 > > +                       } else if (old_next_data_pos == -ENXIO) {
 > > +                               set_size = true;
 > > +                               break;
 > > +                       } else if (old_next_data_pos < 0) {
 > > +                               skip_hole = false;
 > 
 > Why do you need to use 2 booleans?
 > You can initialize skip_hole = true only in case of lower
 > has seek support.
 > 
 > >
 > > +                       }
 > > +               }
 > > +
 > >                 bytes = do_splice_direct(old_file, &old_pos,
 > >                                          new_file, &new_pos,
 > >                                          this_len, SPLICE_F_MOVE);
 > > @@ -168,6 +222,12 @@ static int ovl_copy_up_data(struct path *old, struct path *new, loff_t len)
 > >
 > >                 len -= bytes;
 > >         }
 > > +
 > > +       if (!error && set_size) {
 > > +               inode_lock(new->dentry->d_inode);
 > > +               error = ovl_set_size(new->dentry, stat);
 > > +               inode_unlock(new->dentry->d_inode);
 > > +       }
 > 
 > I see no reason to repeat this code here.
 > Two options:
 > 1. always set_size at the end of ovl_copy_up_inode()
 >     what's the harm in that?

I think at least it's not suitable for directory.


 > 2. set boolean c->set_size here and check it at the end
 >     of ovl_copy_up_inode() instead of checking c->metacopy
 > 

I don't understand why 'c->set_size' can replace 'c->metacopy',

Thanks,
Chengguang.






[Index of Archives]     [Linux Filesystems Devel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux