Re: [PATCH] ovl: fix some bug exist in ovl_get_inode

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

 



On Fri, May 29, 2020 at 10:01 PM Vivek Goyal <vgoyal@xxxxxxxxxx> wrote:
>
> On Fri, May 29, 2020 at 06:46:43PM +0300, Amir Goldstein wrote:
> > > > > @@ -1023,7 +1020,7 @@ struct dentry *ovl_lookup(struct inode *
> > > > >          *
> > > > >          * Always lookup index of non-dir non-metacopy and non-upper.
> > > > >          */
> > > > > -       if (ctr && (!upperdentry || (!d.is_dir && !metacopy)))
> > > > > +       if (ctr && (!upperdentry || (!d.is_dir && !uppermetacopy)))
> > > > >                 origin = stack[0].dentry;
> > > > >
> > > >
> > > > I think this should be:
> > > >
> > > >           * Always lookup index of non-dir and non-upper.
> > > >           */
> > > >           if (!origin && ctr && (!upperdentry || !d.is_dir))
> > > >                  origin = stack[0].dentry;
> > > >
> > > > uppermetacopy is guaranteed to either have origin already set or
> > > > exit with an an error for ovl_verify_origin().
> > >
> > > Only if index is enabled and upper had origin xattr.
> > >
> > > (!d.is_dir && ofs->config.index && origin_path)
> > >
> > > So if index is disabled or uppermetacopy did not have "origin" xattr,
> > > we will not have origin set by the time we come out of the loop.
> > >
> >
> > True. But if index is disabled, setting origin is moot. origin is only
> > ever used here to lookup the index.
>
> Well, while looking up for index, we are checking for presence of
> index dir (and not checking whether index is currently enabled or
> not). So if somebody mounts overlayfs with index=on and later remounts
> with index=off, we can still start looking up the index even if it
> is not enabled. Is it intentional? If not, to simplify it, should
> we lookup index only if it is enabled.
>
>         if (origin && ofs->config.index &&
>             (!d.is_dir || ovl_index_all(dentry->d_sb))) {
>                 index = ovl_lookup_index(ofs, upperdentry, origin, true);
>

What do you mean by remount? actual -o remount cannot
change any overlay config variables.
For umount/mount,  ofs->indexdir doesn't mean that there is an
index dir, it means that index dir is in use because index is enabled.
See:

        if (!(ovl_force_readonly(ofs)) && ofs->config.index) {
...
                err = ovl_get_indexdir(sb, ofs, oe, &upperpath);
...
        if (!ofs->indexdir) {
                ofs->config.index = false;

Most of the code checks for ofs->indexdir.
The test for ofs->config.index is also correct, but inconsistent, although
I see that we also use ofs->config.index in other places in ovl_lookup().

>
> >
> > About "origin" xattr. If it is not set in upper that lower fs probably does
> > not have file handle support. In that case, index cannot be enabled
> > anyway.
>
> What about the case of multiple lower layers. IIUC, we will only
> ensure that top most lower layer has file handle support and not
> worry about rest of the layers. This will break the case of setting
> origin for !upperdentry. This will lookup index and fail if lower
> layer does not support file handle.
>
> So may be while enabling index, we should make sure all lower
> layers support file handles otherwise fail?
>

Enabling index requires that all layers support file handles:

                pr_warn("fs on '%s' does not support file handles,
falling back to index=off,nfs_export=off.\n",
                        name);
        }

> >
> > > I see for non-metacopy regular files, if upper did not have origin
> > > xattr, that means origin_path will by NULL. That means ctr will be
> > > 0 and that means we will not set "origin" for non-metacopy regular
> > > files in such case. So question is, should we set "origin" for
> > > metacopy upper files in such a case.
> > >
> > > We did not have origin xattr, but we looked up lower layers for
> > > upper metacopy. In theory, stack[0].dentry is origin for upper
> > > metacopy files. Should we use it? Current logic does not and that's
> > > why this additiona check (!d.is_dir && !uppermetacopy).
> > >
> >
> > I agree with your analysis, but this is a very theoretical discussion.
> > Unless I am missing something, I think we have written a very complex
> > condition for a corner case that doesn't seem to be valid or interesting.
>
> I agree. I want to simplify it too. Just trying to make sure that
> I don't end up breaking some valid configuration.
>
> >
> > Basically, for non-dir, if there is no "origin" xattr, then there should be no
> > index, because the metacopy feature was added way long after we
> > started storing "origin" on copy up. That's not the case for directories.
> >
> > There is one corner case where it may be relevant -
> > overlay layers with metacopy that were created on fs with no file handle
> > support (or no uuid) that are migrated to a filesystem with file handle
> > support (and metacopy xattr are preserved in migration).
> > In that case, index may be enabled while upper metacopy exists
> > without "origin".
> >
> > What happens if we do not set origin and do not lookup index in that case?
> > We can get two overlay inodes, both from different metacopy upper inodes
> > redirected to the same lower inode, that have the same st_ino, but differnt
> > metadata.
>
> We do not set origin on upper for broken hardlinks. So we will report
> inode number from upper. I tried. it.

Good point. I figured we had to have some protection in place.

>
> I tried following.
>
> - touch foo.txt
> - ln foo.txt foo-link.txt
> - mount with metacopy=on
> - chwon test:test foo.txt
> - umount
> - Goto upper/ and remove origin xattr from foo.txt. But there should not
>   be one because we do not create ORIGIN for broken hardlinks if index is
>   not enabled.
> - mount overlay with index=on
> - Do stat on foo.txt and foo-link.txt. foo.txt reports inode number from
>   upper and foo-link.txt reports inode number from lower.
> - chown test:test foo-link.txt
> - stat foo-link.txt still reports inode number from lower.
>
> Anyway, at this point of time, how about following.
>
> - For non-upper dentry, always set origin.
> - For upperdentry, there are 3 cases.
>         - directories
>         - regular files
>         - regular metacopy files
>
>   For directories and regular metacopy files only use verified origin.
>   That means upper has origin xattr and it matches patch based looked
>   up dentry. If we did not verify because either ORIGIN xattr is not
>   there, or because index is not enabled or because ovl_verify_lower()
>   is not set, then don't use path based looked up dentry as origin.
>
>   For the case of regular file upper dentry, use unverified origin.
>   It implies that ORGIN xattr is there. As there is no path based
>   lookup origin for upper regular files.
>
> I am attaching a simple patch. Please let me know what do you think
> of it.
>
> >
> > > >
> > > > HOWEVER, if we set origin to lower, which turns out to be a lower
> > > > metacopy, we then skip this layer to the next one, but origin remains
> > > > set on the skipped layer dentry, which we had already dput().
> > > > Ay ay ay!
> > >
> > > We only skip the intermediate metacopy entries in lower. So top most
> > > lower metacopy will still be retained. For example, if there are 3
> > > lower layers where top two are metacopy and one data, then we will
> > > only skip middle one. And middle one should not be origin for upper.
> > >
> > >                 /*
> > >                  * Do not store intermediate metacopy dentries in chain,
> > >                  * except top most lower metacopy dentry
> > >                  */
> > >                 if (d.metacopy && ctr) {
> > >                         dput(this);
> > >                         continue;
> > >                 }
> > >
> > > For the first lower, ctr will be 0 and we will always store it in
> > > stack. So if it is metacopy dentry, it will still be stored at
> > > stack[0].
> > >
> > > Do you still see the problem?
> >
> > No. it's fine. My eyes missed the ctr condition.
> > I still think since you are changing this code.
> > It will be much easier to follow if both simple continue statement
> > are at the top of the loop.
>
> Ok, will do.
>
> Here is the patch to simplify the condition or origin. I will add some
> changelog and comments in code in v2 of patch if you like the patch.
>
> Thanks
> Vivek
>
>
> ---
>  fs/overlayfs/namei.c |    5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> Index: redhat-linux/fs/overlayfs/namei.c
> ===================================================================
> --- redhat-linux.orig/fs/overlayfs/namei.c      2020-05-29 14:24:45.997113946 -0400
> +++ redhat-linux/fs/overlayfs/namei.c   2020-05-29 14:46:46.692113946 -0400
> @@ -1005,6 +1005,7 @@ struct dentry *ovl_lookup(struct inode *
>                 }
>                 stack = origin_path;
>                 ctr = 1;
> +               origin = origin_path->dentry;
>                 origin_path = NULL;
>         }
>
> @@ -1021,9 +1022,9 @@ struct dentry *ovl_lookup(struct inode *
>          * index. This case should be handled in same way as a non-dir upper
>          * without ORIGIN is handled.
>          *
> -        * Always lookup index of non-dir non-metacopy and non-upper.
> +        * Always lookup index of non-upper.
>          */
> -       if (ctr && (!upperdentry || (!d.is_dir && !metacopy)))
> +       if (!origin && ctr && !upperdentry)
>                 origin = stack[0].dentry;
>

As I wrote in review, the condition could be further simplified to
(!upperdentry).

Thanks for digging up the truth,
Amir.



[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