Re: [PATCH RFC 2/2] ovl: invalidate dentry if lower was renamed

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

 



On Mon, Jul 13, 2020 at 11:05 PM Vivek Goyal <vgoyal@xxxxxxxxxx> wrote:
>
> On Mon, Jul 13, 2020 at 01:57:32PM +0300, Amir Goldstein wrote:
> > Changes to lower layer while overlay in mounted result in undefined
> > behavior.  Therefore, we can change the behavior to invalidate the
> > overlay dentry on dcache lookup if one of the dentries in the lowerstack
> > was renamed since the lowerstack was composed.
> >
> > To be absolute certain that lower dentry was not renamed we would need to
> > know the redirect path that lead to it, but that is not necessary.
> > Instead, we just store the hash of the parent/name from when we composed
> > the stack, which gives a good enough probablity to detect a lower rename
> > and is much less complexity.
> >
> > We do not provide this protection for upper dentries, because that would
> > require updating the hash on overlay initiated renames and that is harder
> > to implement with lockless lookup.
> >
> > This doesn't make live changes to underlying layers valid, because
> > invalid dentry stacks may still be referenced by open files, but it
> > reduces the window for possible bugs caused by lower rename, because
> > lookup cannot return those invalid dentry stacks.
> >
> > Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>
> > ---
> >  fs/overlayfs/export.c    |  1 +
> >  fs/overlayfs/namei.c     |  4 +++-
> >  fs/overlayfs/ovl_entry.h |  2 ++
> >  fs/overlayfs/super.c     | 17 ++++++++++-------
> >  4 files changed, 16 insertions(+), 8 deletions(-)
> >
> > diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
> > index 0e696f72cf65..7221b6226e26 100644
> > --- a/fs/overlayfs/export.c
> > +++ b/fs/overlayfs/export.c
> > @@ -319,6 +319,7 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
> >       if (lower) {
> >               oe->lowerstack->dentry = dget(lower);
> >               oe->lowerstack->layer = lowerpath->layer;
> > +             oe->lowerstack->hash = lower->d_name.hash_len;
> >       }
> >       dentry->d_fsdata = oe;
> >       if (upper_alias)
> > diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> > index 3566282a9199..ae1c1216a038 100644
> > --- a/fs/overlayfs/namei.c
> > +++ b/fs/overlayfs/namei.c
> > @@ -375,7 +375,8 @@ int ovl_check_origin_fh(struct ovl_fs *ofs, struct ovl_fh *fh, bool connected,
> >       }
> >       **stackp = (struct ovl_path){
> >               .dentry = origin,
> > -             .layer = &ofs->layers[i]
> > +             .layer = &ofs->layers[i],
> > +             .hash = origin->d_name.hash_len,
> >       };
> >
> >       return 0;
> > @@ -968,6 +969,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
> >               } else {
> >                       stack[ctr].dentry = this;
> >                       stack[ctr].layer = lower.layer;
> > +                     stack[ctr].hash = this->d_name.hash_len;
> >                       ctr++;
> >               }
> >
> > diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
> > index b429c80879ee..557f1782f53b 100644
> > --- a/fs/overlayfs/ovl_entry.h
> > +++ b/fs/overlayfs/ovl_entry.h
> > @@ -42,6 +42,8 @@ struct ovl_layer {
> >  struct ovl_path {
> >       const struct ovl_layer *layer;
> >       struct dentry *dentry;
> > +     /* Hash of the lower parent/name when we found it */
> > +     u64 hash;
> >  };
> >
> >  /* private information held for overlayfs's superblock */
> > diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> > index f2c74387e05b..4b7cb2d98203 100644
> > --- a/fs/overlayfs/super.c
> > +++ b/fs/overlayfs/super.c
> > @@ -119,13 +119,13 @@ static bool ovl_dentry_is_dead(struct dentry *d)
> >  }
> >
> >  static int ovl_revalidate_real(struct dentry *d, unsigned int flags, bool weak,
> > -                            bool is_upper)
> > +                            bool is_upper, u64 hash)
> >  {
> >       bool strict = !weak;
> >       int ret = 1;
> >
> > -     /* Invalidate dentry if real was deleted since we found it */
> > -     if (ovl_dentry_is_dead(d)) {
> > +     /* Invalidate dentry if real was deleted/renamed since we found it */
> > +     if (ovl_dentry_is_dead(d) || (hash && hash != d->d_name.hash_len)) {
>
> So if lower hash_len changes, on local filesystem we will return -ESTALE?
> I am assuming we did that for remote filesystems and now we will do
> that for local filesystems as well?
>

That is correct.
Although I am personally in favor of the non 'strict' behavior.

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