Re: [PATCH 6/7] ovl: deduplicate lowerpath and lowerstack[0]

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

 



On Sat, 2023-04-08 at 19:43 +0300, Amir Goldstein wrote:
> For the common case of single lower layer, embed ovl_entry with a
> single lower path in ovl_inode, so no stack allocation is needed.
> 
> For directory with more than single lower layer and for regular file
> with lowerdata, the lower stack is stored in an external allocation.
> 
> Use accessor ovl_lowerstack() to get the embedded or external stack.
> 
> Signed-off-by: Amir Goldstein <amir73il@xxxxxxxxx>

Reviewed-by: Alexander Larsson <alexl@xxxxxxxxxx>

> ---
>  fs/overlayfs/dir.c       |  2 ++
>  fs/overlayfs/export.c    | 18 +++++----------
>  fs/overlayfs/inode.c     | 12 ++++------
>  fs/overlayfs/namei.c     | 15 +++++--------
>  fs/overlayfs/overlayfs.h | 10 +++++----
>  fs/overlayfs/ovl_entry.h | 14 +++++++-----
>  fs/overlayfs/super.c     | 41 +++++++++++++---------------------
>  fs/overlayfs/util.c      | 48 +++++++++++++++++++++++++++++---------
> --
>  8 files changed, 81 insertions(+), 79 deletions(-)
> 
> diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
> index 92bdcedfaaec..aa0465c61064 100644
> --- a/fs/overlayfs/dir.c
> +++ b/fs/overlayfs/dir.c
> @@ -262,9 +262,11 @@ static int ovl_set_opaque(struct dentry *dentry,
> struct dentry *upperdentry)
>  static int ovl_instantiate(struct dentry *dentry, struct inode
> *inode,
>                            struct dentry *newdentry, bool hardlink)
>  {
> +       struct ovl_entry oe = {};
>         struct ovl_inode_params oip = {
>                 .upperdentry = newdentry,
>                 .newinode = inode,
> +               .oe = &oe,
>         };
>  
>         ovl_dir_modified(dentry->d_parent, false);
> diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
> index d4caf57c8e17..9951c504fb8d 100644
> --- a/fs/overlayfs/export.c
> +++ b/fs/overlayfs/export.c
> @@ -287,30 +287,22 @@ static struct dentry *ovl_obtain_alias(struct
> super_block *sb,
>         struct dentry *upper = upper_alias ?: index;
>         struct dentry *dentry;
>         struct inode *inode = NULL;
> -       struct ovl_entry *oe;
> +       struct ovl_entry oe;
>         struct ovl_inode_params oip = {
> -               .lowerpath = lowerpath,
> +               .oe = &oe,
>                 .index = index,
> -               .numlower = !!lower
>         };
>  
>         /* We get overlay directory dentries with ovl_lookup_real()
> */
>         if (d_is_dir(upper ?: lower))
>                 return ERR_PTR(-EIO);
>  
> -       oe = ovl_alloc_entry(!!lower);
> -       if (!oe)
> -               goto nomem;
> -

Ah, I see that the goto nomem goes away here, so I guess ignore my
comment on previous patch.


>         oip.upperdentry = dget(upper);
> -       if (lower) {
> -               ovl_lowerstack(oe)->dentry = dget(lower);
> -               ovl_lowerstack(oe)->layer = lowerpath->layer;
> -       }
> -       oip.oe = oe;
> +       /* Should not fail because does not allocate lowerstack */
> +       ovl_init_entry(&oe, lowerpath, !!lower);
>         inode = ovl_get_inode(sb, &oip);
>         if (IS_ERR(inode)) {
> -               ovl_free_entry(oe);
> +               ovl_destroy_entry(&oe);
>                 dput(upper);
>                 return ERR_CAST(inode);
>         }
> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> index c296bd656858..9f29fc3e9fa5 100644
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -1004,12 +1004,8 @@ void ovl_inode_init(struct inode *inode,
> struct ovl_inode_params *oip,
>         struct ovl_inode *oi = OVL_I(inode);
>  
>         oi->__upperdentry = oip->upperdentry;
> -       oi->oe = oip->oe;
> +       oi->oe = *oip->oe;
>         oi->redirect = oip->redirect;
> -       if (oip->lowerpath && oip->lowerpath->dentry) {
> -               oi->lowerpath.dentry = dget(oip->lowerpath->dentry);
> -               oi->lowerpath.layer = oip->lowerpath->layer;
> -       }
>         if (oip->lowerdata)
>                 oi->lowerdata = igrab(d_inode(oip->lowerdata));
>  
> @@ -1326,7 +1322,7 @@ struct inode *ovl_get_inode(struct super_block
> *sb,
>  {
>         struct ovl_fs *ofs = OVL_FS(sb);
>         struct dentry *upperdentry = oip->upperdentry;
> -       struct ovl_path *lowerpath = oip->lowerpath;
> +       struct ovl_path *lowerpath = ovl_lowerstack(oip->oe);
>         struct inode *realinode = upperdentry ? d_inode(upperdentry)
> : NULL;
>         struct inode *inode;
>         struct dentry *lowerdentry = lowerpath ? lowerpath->dentry :
> NULL;
> @@ -1370,7 +1366,7 @@ struct inode *ovl_get_inode(struct super_block
> *sb,
>                         }
>  
>                         dput(upperdentry);
> -                       ovl_free_entry(oip->oe);
> +                       ovl_destroy_entry(oip->oe);
>                         kfree(oip->redirect);
>                         goto out;
>                 }
> @@ -1405,7 +1401,7 @@ struct inode *ovl_get_inode(struct super_block
> *sb,
>  
>         /* Check for non-merge dir that may have whiteouts */
>         if (is_dir) {
> -               if (((upperdentry && lowerdentry) || oip->numlower >
> 1) ||
> +               if (((upperdentry && lowerdentry) ||
> ovl_numlower(oip->oe) > 1) ||
>                     ovl_path_check_origin_xattr(ofs, &realpath)) {
>                         ovl_set_flag(OVL_WHITEOUTS, inode);
>                 }
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index a0a1c498dbd1..cdcb2ac5d95c 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -831,7 +831,7 @@ static int ovl_fix_origin(struct ovl_fs *ofs,
> struct dentry *dentry,
>  struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>                           unsigned int flags)
>  {
> -       struct ovl_entry *oe;
> +       struct ovl_entry oe;
>         const struct cred *old_cred;
>         struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
>         struct ovl_entry *poe = OVL_E(dentry->d_parent);
> @@ -1067,13 +1067,10 @@ struct dentry *ovl_lookup(struct inode *dir,
> struct dentry *dentry,
>                 }
>         }
>  
> -       oe = ovl_alloc_entry(ctr);
> -       err = -ENOMEM;
> -       if (!oe)
> +       err = ovl_init_entry(&oe, stack, ctr);
> +       if (err)
>                 goto out_put;
>  
> -       ovl_stack_cpy(ovl_lowerstack(oe), stack, ctr);
> -
>         if (upperopaque)
>                 ovl_dentry_set_opaque(dentry);
>  
> @@ -1105,10 +1102,8 @@ struct dentry *ovl_lookup(struct inode *dir,
> struct dentry *dentry,
>         if (upperdentry || ctr) {
>                 struct ovl_inode_params oip = {
>                         .upperdentry = upperdentry,
> -                       .lowerpath = stack,
> -                       .oe = oe,
> +                       .oe = &oe,
>                         .index = index,
> -                       .numlower = ctr,
>                         .redirect = upperredirect,
>                         .lowerdata = (ctr > 1 && !d.is_dir) ?
>                                       stack[ctr - 1].dentry : NULL,
> @@ -1135,7 +1130,7 @@ struct dentry *ovl_lookup(struct inode *dir,
> struct dentry *dentry,
>         return d_splice_alias(inode, dentry);
>  
>  out_free_oe:
> -       ovl_free_entry(oe);
> +       ovl_destroy_entry(&oe);
>  out_put:
>         dput(index);
>         ovl_stack_free(stack, ctr);
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index e14ca0fd1063..32532342e56a 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -377,8 +377,12 @@ struct ovl_path *ovl_stack_alloc(unsigned int
> n);
>  void ovl_stack_cpy(struct ovl_path *dst, struct ovl_path *src,
> unsigned int n);
>  void ovl_stack_put(struct ovl_path *stack, unsigned int n);
>  void ovl_stack_free(struct ovl_path *stack, unsigned int n);
> -struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
> -void ovl_free_entry(struct ovl_entry *oe);
> +struct ovl_path *ovl_alloc_stack(unsigned int n);
> +void ovl_stack_cpy(struct ovl_path *dst, struct ovl_path *src,
> unsigned int n);
> +void ovl_stack_put(struct ovl_path *stack, unsigned int n);
> +int ovl_init_entry(struct ovl_entry *oe, struct ovl_path *stack,
> +                  unsigned int numlower);
> +void ovl_destroy_entry(struct ovl_entry *oe);
>  bool ovl_dentry_remote(struct dentry *dentry);
>  void ovl_dentry_update_reval(struct dentry *dentry, struct dentry
> *realdentry);
>  void ovl_dentry_init_reval(struct dentry *dentry, struct dentry
> *upperdentry,
> @@ -653,10 +657,8 @@ bool ovl_is_private_xattr(struct super_block
> *sb, const char *name);
>  struct ovl_inode_params {
>         struct inode *newinode;
>         struct dentry *upperdentry;
> -       struct ovl_path *lowerpath;
>         struct ovl_entry *oe;
>         bool index;
> -       unsigned int numlower;
>         char *redirect;
>         struct dentry *lowerdata;
>  };
> diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
> index 201de9da45d3..5d95e937f555 100644
> --- a/fs/overlayfs/ovl_entry.h
> +++ b/fs/overlayfs/ovl_entry.h
> @@ -49,7 +49,12 @@ struct ovl_path {
>  
>  struct ovl_entry {
>         unsigned int __numlower;
> -       struct ovl_path __lowerstack[];
> +       union {
> +               /* Embedded path for numlower == 1 */
> +               struct ovl_path __lowerpath;
> +               /* External stack for numlower > 1 */
> +               struct ovl_path *__lowerstack;
> +       };
>  };
>  
>  /* private information held for overlayfs's superblock */
> @@ -117,7 +122,7 @@ static inline unsigned int ovl_numlower(struct
> ovl_entry *oe)
>  
>  static inline struct ovl_path *ovl_lowerstack(struct ovl_entry *oe)
>  {
> -       return oe ? oe->__lowerstack : NULL;
> +       return oe && oe->__numlower > 1 ? oe->__lowerstack : &oe-
> >__lowerpath;
>  }
>  
>  /* private information held for every overlayfs dentry */
> @@ -136,8 +141,7 @@ struct ovl_inode {
>         unsigned long flags;
>         struct inode vfs_inode;
>         struct dentry *__upperdentry;
> -       struct ovl_path lowerpath;
> -       struct ovl_entry *oe;
> +       struct ovl_entry oe;
>  
>         /* synchronize copy up and more */
>         struct mutex lock;
> @@ -150,7 +154,7 @@ static inline struct ovl_inode *OVL_I(struct
> inode *inode)
>  
>  static inline struct ovl_entry *OVL_I_E(struct inode *inode)
>  {
> -       return inode ? OVL_I(inode)->oe : NULL;
> +       return inode ? &OVL_I(inode)->oe : NULL;
>  }
>  
>  static inline struct ovl_entry *OVL_E(struct dentry *dentry)
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index b9e62ccd609f..e01a76de787c 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -171,9 +171,7 @@ static struct inode *ovl_alloc_inode(struct
> super_block *sb)
>         oi->version = 0;
>         oi->flags = 0;
>         oi->__upperdentry = NULL;
> -       oi->oe = NULL;
> -       oi->lowerpath.dentry = NULL;
> -       oi->lowerpath.layer = NULL;
> +       ovl_init_entry(&oi->oe, NULL, 0);
>         oi->lowerdata = NULL;
>         mutex_init(&oi->lock);
>  
> @@ -194,8 +192,7 @@ static void ovl_destroy_inode(struct inode
> *inode)
>         struct ovl_inode *oi = OVL_I(inode);
>  
>         dput(oi->__upperdentry);
> -       dput(oi->lowerpath.dentry);
> -       ovl_free_entry(oi->oe);
> +       ovl_destroy_entry(&oi->oe);
>         if (S_ISDIR(inode->i_mode))
>                 ovl_dir_cache_free(inode);
>         else
> @@ -1702,7 +1699,7 @@ static int ovl_get_layers(struct super_block
> *sb, struct ovl_fs *ofs,
>         return err;
>  }
>  
> -static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
> +static int ovl_get_lowerstack(struct super_block *sb, struct
> ovl_entry *oe,
>                                 const char *lower, unsigned int
> numlower,
>                                 struct ovl_fs *ofs, struct ovl_layer
> *layers)
>  {
> @@ -1710,16 +1707,15 @@ static struct ovl_entry
> *ovl_get_lowerstack(struct super_block *sb,
>         struct path *stack = NULL;
>         struct ovl_path *lowerstack;
>         unsigned int i;
> -       struct ovl_entry *oe;
>  
>         if (!ofs->config.upperdir && numlower == 1) {
>                 pr_err("at least 2 lowerdir are needed while upperdir
> nonexistent\n");
> -               return ERR_PTR(-EINVAL);
> +               return -EINVAL;
>         }
>  
>         stack = kcalloc(numlower, sizeof(struct path), GFP_KERNEL);
>         if (!stack)
> -               return ERR_PTR(-ENOMEM);
> +               return -ENOMEM;
>  
>         err = -EINVAL;
>         for (i = 0; i < numlower; i++) {
> @@ -1741,9 +1737,8 @@ static struct ovl_entry
> *ovl_get_lowerstack(struct super_block *sb,
>         if (err)
>                 goto out_err;
>  
> -       err = -ENOMEM;
> -       oe = ovl_alloc_entry(numlower);
> -       if (!oe)
> +       err = ovl_init_entry(oe, NULL, numlower);
> +       if (err)
>                 goto out_err;
>  
>         lowerstack = ovl_lowerstack(oe);
> @@ -1752,16 +1747,12 @@ static struct ovl_entry
> *ovl_get_lowerstack(struct super_block *sb,
>                 lowerstack[i].layer = &ofs->layers[i+1];
>         }
>  
> -out:
> +out_err:
>         for (i = 0; i < numlower; i++)
>                 path_put(&stack[i]);
>         kfree(stack);
>  
> -       return oe;
> -
> -out_err:
> -       oe = ERR_PTR(err);
> -       goto out;
> +       return err;
>  }
>  
>  /*
> @@ -1847,7 +1838,6 @@ static struct dentry *ovl_get_root(struct
> super_block *sb,
>         int fsid = lowerpath->layer->fsid;
>         struct ovl_inode_params oip = {
>                 .upperdentry = upperdentry,
> -               .lowerpath = lowerpath,
>                 .oe = oe,
>         };
>  
> @@ -1878,7 +1868,7 @@ static int ovl_fill_super(struct super_block
> *sb, void *data, int silent)
>  {
>         struct path upperpath = { };
>         struct dentry *root_dentry;
> -       struct ovl_entry *oe;
> +       struct ovl_entry oe;
>         struct ovl_fs *ofs;
>         struct ovl_layer *layers;
>         struct cred *cred;
> @@ -1991,9 +1981,8 @@ static int ovl_fill_super(struct super_block
> *sb, void *data, int silent)
>                 sb->s_stack_depth = upper_sb->s_stack_depth;
>                 sb->s_time_gran = upper_sb->s_time_gran;
>         }
> -       oe = ovl_get_lowerstack(sb, splitlower, numlower, ofs,
> layers);
> -       err = PTR_ERR(oe);
> -       if (IS_ERR(oe))
> +       err = ovl_get_lowerstack(sb, &oe, splitlower, numlower, ofs,
> layers);
> +       if (err)
>                 goto out_err;
>  
>         /* If the upper fs is nonexistent, we mark overlayfs r/o too
> */
> @@ -2006,7 +1995,7 @@ static int ovl_fill_super(struct super_block
> *sb, void *data, int silent)
>         }
>  
>         if (!ovl_force_readonly(ofs) && ofs->config.index) {
> -               err = ovl_get_indexdir(sb, ofs, oe, &upperpath);
> +               err = ovl_get_indexdir(sb, ofs, &oe, &upperpath);
>                 if (err)
>                         goto out_free_oe;
>  
> @@ -2047,7 +2036,7 @@ static int ovl_fill_super(struct super_block
> *sb, void *data, int silent)
>         sb->s_iflags |= SB_I_SKIP_SYNC;
>  
>         err = -ENOMEM;
> -       root_dentry = ovl_get_root(sb, upperpath.dentry, oe);
> +       root_dentry = ovl_get_root(sb, upperpath.dentry, &oe);
>         if (!root_dentry)
>                 goto out_free_oe;
>  
> @@ -2059,7 +2048,7 @@ static int ovl_fill_super(struct super_block
> *sb, void *data, int silent)
>         return 0;
>  
>  out_free_oe:
> -       ovl_free_entry(oe);
> +       ovl_destroy_entry(&oe);
>  out_err:
>         kfree(splitlower);
>         path_put(&upperpath);
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index f5e2c70a57f8..540819ac9b9c 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -111,21 +111,41 @@ void ovl_stack_free(struct ovl_path *stack,
> unsigned int n)
>         kfree(stack);
>  }
>  
> -struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
> -{
> -       size_t size = offsetof(struct ovl_entry,
> __lowerstack[numlower]);
> -       struct ovl_entry *oe = kzalloc(size, GFP_KERNEL);
> +/* On success, takes references on @stack dentries */
> +int ovl_init_entry(struct ovl_entry *oe, struct ovl_path *stack,
> +                  unsigned int numlower)
> +{
> +       oe->__numlower = numlower;
> +       oe->__lowerpath = (struct ovl_path) {};
> +
> +       /* No allocated stack for numlower <= 1 */
> +       if (numlower <= 1) {
> +               if (numlower && stack)
> +                       oe->__lowerpath = *stack;
> +               dget(oe->__lowerpath.dentry);
> +               return 0;
> +       }
> +
> +       oe->__lowerstack = ovl_stack_alloc(numlower);
> +       if (!oe->__lowerstack)
> +               return -ENOMEM;
> +
> +       if (!stack)
> +               return 0;
>  
> -       if (oe)
> -               oe->__numlower = numlower;
> +       ovl_stack_cpy(oe->__lowerstack, stack, numlower);
>  
> -       return oe;
> +       return 0;
>  }
>  
> -void ovl_free_entry(struct ovl_entry *oe)
> +void ovl_destroy_entry(struct ovl_entry *oe)
>  {
> -       ovl_stack_put(ovl_lowerstack(oe), ovl_numlower(oe));
> -       kfree(oe);
> +       if (oe->__numlower > 1) {
> +               ovl_stack_put(oe->__lowerstack, oe->__numlower);
> +               kfree(oe->__lowerstack);
> +       } else {
> +               dput(oe->__lowerpath.dentry);
> +       }
>  }
>  
>  #define OVL_D_REVALIDATE (DCACHE_OP_REVALIDATE |
> DCACHE_OP_WEAK_REVALIDATE)
> @@ -306,10 +326,12 @@ struct dentry *ovl_i_dentry_upper(struct inode
> *inode)
>  
>  void ovl_i_path_real(struct inode *inode, struct path *path)
>  {
> +       struct ovl_path *lowerstack = ovl_lowerstack(OVL_I_E(inode));
> +
>         path->dentry = ovl_i_dentry_upper(inode);
>         if (!path->dentry) {
> -               path->dentry = OVL_I(inode)->lowerpath.dentry;
> -               path->mnt = OVL_I(inode)->lowerpath.layer->mnt;
> +               path->dentry = lowerstack->dentry;
> +               path->mnt = lowerstack->layer->mnt;
>         } else {
>                 path->mnt = ovl_upper_mnt(OVL_FS(inode->i_sb));
>         }
> @@ -324,7 +346,7 @@ struct inode *ovl_inode_upper(struct inode
> *inode)
>  
>  struct inode *ovl_inode_lower(struct inode *inode)
>  {
> -       struct dentry *lowerdentry = OVL_I(inode)->lowerpath.dentry;
> +       struct dentry *lowerdentry = ovl_lowerstack(OVL_I_E(inode))-
> >dentry;
>  
>         return lowerdentry ? d_inode(lowerdentry) : NULL;
>  }

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=-=-=
 Alexander Larsson                                            Red Hat,
Inc 
       alexl@xxxxxxxxxx            alexander.larsson@xxxxxxxxx 
He's a globe-trotting shark-wrestling vagrant on a search for his
missing 
sister. She's a mistrustful extravagent advertising executive with an
MBA 
from Harvard. They fight crime! 




[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