Re: [PATCH 3/3] ovl: introduce a dedicated cache pool for ovl_entry

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

 



On Tue, Apr 17, 2018 at 5:42 AM, Chengguang Xu <cgxu519@xxxxxxx> wrote:
> Introduce a dedicated cache pool for ovl_entry to optimize
> memory allocation adn deallocation.
>
> Signed-off-by: Chengguang Xu <cgxu519@xxxxxxx>
> ---
>  fs/overlayfs/export.c    | 11 +++++++----
>  fs/overlayfs/namei.c     |  7 +++++--
>  fs/overlayfs/overlayfs.h |  4 ++++
>  fs/overlayfs/ovl_entry.h |  9 +++++----
>  fs/overlayfs/super.c     | 38 +++++++++++++++++++++++++++++---------
>  fs/overlayfs/util.c      | 28 ++++++++++++++++++++++++----
>  6 files changed, 74 insertions(+), 23 deletions(-)
>
> diff --git a/fs/overlayfs/export.c b/fs/overlayfs/export.c
> index f2ba5fb..b1047ae 100644
> --- a/fs/overlayfs/export.c
> +++ b/fs/overlayfs/export.c
> @@ -321,8 +321,8 @@ static struct dentry *ovl_obtain_alias(struct super_block *sb,
>                         goto nomem;
>
>                 if (lower) {
> -                       oe->lowerstack->dentry = dget(lower);
> -                       oe->lowerstack->layer = lowerpath->layer;
> +                       oe->lowerstack.dentry = dget(lower);
> +                       oe->lowerstack.layer = lowerpath->layer;
>                 }
>                 dentry->d_fsdata = oe;
>                 if (upper_alias)
> @@ -346,9 +346,12 @@ static struct dentry *ovl_dentry_real_at(struct dentry *dentry, int idx)
>         if (!idx)
>                 return ovl_dentry_upper(dentry);
>
> +       if (oe->numlower == 1 && oe->lowerstack.layer->idx == idx)
> +               return oe->lowerstack.dentry;
> +
>         for (i = 0; i < oe->numlower; i++) {
> -               if (oe->lowerstack[i].layer->idx == idx)
> -                       return oe->lowerstack[i].dentry;
> +               if (oe->lowerstacks[i].layer->idx == idx)
> +                       return oe->lowerstacks[i].dentry;
>         }
>
>         return NULL;
> diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c
> index eb3ec6c..51fd914 100644
> --- a/fs/overlayfs/namei.c
> +++ b/fs/overlayfs/namei.c
> @@ -994,7 +994,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>         if (!oe)
>                 goto out_put;
>
> -       memcpy(oe->lowerstack, stack, sizeof(struct ovl_path) * ctr);
> +       if (oe->numlower == 1)
> +               memcpy(&oe->lowerstack, stack, sizeof(struct ovl_path));
> +       else
> +               memcpy(oe->lowerstacks, stack, sizeof(struct ovl_path) * ctr);
>         dentry->d_fsdata = oe;
>
>         if (upperopaque)
> @@ -1028,7 +1031,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
>
>  out_free_oe:
>         dentry->d_fsdata = NULL;
> -       kfree(oe);
> +       ovl_free_entry(oe);
>  out_put:
>         dput(index);
>         for (i = 0; i < ctr; i++)
> diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
> index 8039602..a104e02 100644
> --- a/fs/overlayfs/overlayfs.h
> +++ b/fs/overlayfs/overlayfs.h
> @@ -207,6 +207,7 @@ static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode)
>  bool ovl_index_all(struct super_block *sb);
>  bool ovl_verify_lower(struct super_block *sb);
>  struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
> +void ovl_free_entry(struct ovl_entry *oe);
>  bool ovl_dentry_remote(struct dentry *dentry);
>  bool ovl_dentry_weird(struct dentry *dentry);
>  enum ovl_path_type ovl_path_type(struct dentry *dentry);
> @@ -378,3 +379,6 @@ int ovl_set_origin(struct dentry *dentry, struct dentry *lower,
>
>  /* export.c */
>  extern const struct export_operations ovl_export_operations;
> +
> +/* super.c */
> +extern struct kmem_cache *ovl_entry_cachep;
> diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
> index 41655a7..3ed8ab4 100644
> --- a/fs/overlayfs/ovl_entry.h
> +++ b/fs/overlayfs/ovl_entry.h
> @@ -71,13 +71,14 @@ struct ovl_fs {
>  /* private information held for every overlayfs dentry */
>  struct ovl_entry {
>         union {
> -               struct {
> -                       unsigned long flags;
> -               };
> +               unsigned long flags;
>                 struct rcu_head rcu;
>         };
>         unsigned numlower;
> -       struct ovl_path lowerstack[];
> +       union {
> +               struct ovl_path lowerstack;
> +               struct ovl_path *lowerstacks;
> +       };

1. The names are not representative to what they stand for
'stack' is something containing many items already, so you
want 'lowerpath' (numlower == 1) and 'lowerstack' (numlower > 1).

2. I suggested a different approach, not sure if it is better.
I will repeat it in case you did not understand me:

       struct ovl_path lowerstack[1];

this approach requires no union and most of the code that does
if (numlower == 1) can be removed.
Only need special casing alloc and free (see below).

>  };
>
>  struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 38c1dd1..6327497 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -60,8 +60,11 @@ static void ovl_entry_stack_free(struct ovl_entry *oe)
>  {
>         unsigned int i;
>
> -       for (i = 0; i < oe->numlower; i++)
> -               dput(oe->lowerstack[i].dentry);
> +       if (oe->numlower == 1)
> +               dput(oe->lowerstack.dentry);
> +       else
> +               for (i = 0; i < oe->numlower; i++)
> +                       dput(oe->lowerstacks[i].dentry);

No special casing here.

>  }
>
>  static void ovl_dentry_release(struct dentry *dentry)
> @@ -191,6 +194,7 @@ static int ovl_dentry_weak_revalidate(struct dentry *dentry, unsigned int flags)
>  };
>
>  static struct kmem_cache *ovl_inode_cachep;
> +struct kmem_cache *ovl_entry_cachep;
>
>  static struct inode *ovl_alloc_inode(struct super_block *sb)
>  {
> @@ -1332,9 +1336,14 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
>         if (!oe)
>                 goto out_err;
>
> -       for (i = 0; i < numlower; i++) {
> -               oe->lowerstack[i].dentry = dget(stack[i].dentry);
> -               oe->lowerstack[i].layer = &ofs->lower_layers[i];
> +       if (numlower == 1) {
> +               oe->lowerstack.dentry = stack[0].dentry;
> +               oe->lowerstack.layer = &ofs->lower_layers[0];
> +       } else {
> +               for (i = 0; i < numlower; i++) {
> +                       oe->lowerstacks[i].dentry = dget(stack[i].dentry);
> +                       oe->lowerstacks[i].layer = &ofs->lower_layers[i];
> +               }

No special casing here.

>         }
>
>         if (remote)
> @@ -1515,20 +1524,31 @@ static void ovl_inode_init_once(void *foo)
>
>  static int __init ovl_init(void)
>  {
> -       int err;
> +       int err = -ENOMEM;
>
>         ovl_inode_cachep = kmem_cache_create("ovl_inode",
>                                              sizeof(struct ovl_inode), 0,
>                                              (SLAB_RECLAIM_ACCOUNT|
>                                               SLAB_MEM_SPREAD|SLAB_ACCOUNT),
>                                              ovl_inode_init_once);
> -       if (ovl_inode_cachep == NULL)
> -               return -ENOMEM;
> +       if (!ovl_inode_cachep)
> +               return err;
> +
> +       ovl_entry_cachep = KMEM_CACHE(ovl_entry,
> +                               SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
> +       if (!ovl_entry_cachep)
> +               goto bad_entry_cachep;
>
>         err = register_filesystem(&ovl_fs_type);
>         if (err)
> -               kmem_cache_destroy(ovl_inode_cachep);
> +               goto err_out;
>
> +       return 0;
> +
> +err_out:
> +       kmem_cache_destroy(ovl_entry_cachep);
> +bad_entry_cachep:
> +       kmem_cache_destroy(ovl_inode_cachep);
>         return err;
>  }
>
> diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c
> index a3459e6..7d4ff3e 100644
> --- a/fs/overlayfs/util.c
> +++ b/fs/overlayfs/util.c
> @@ -95,13 +95,30 @@ bool ovl_verify_lower(struct super_block *sb)
>         return ofs->config.nfs_export && ofs->config.index;
>  }
>
> +void ovl_free_entry(struct ovl_entry *oe)
> +{
> +       if (oe->numlower > 1)
> +               kfree(oe->lowerstacks);
> +

      if (oe->numlower > 1)
              kfree(oe);
      else

> +       kmem_cache_free(ovl_entry_cachep, oe);
> +}
> +
>  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);
> +       size_t size = sizeof(struct ovl_path) * numlower;
> +       struct ovl_entry *oe;
>
> -       if (oe)
> +       oe = kmem_cache_zalloc(ovl_entry_cachep, GFP_KERNEL);

    if (numlower > 1) {
       size = offsetof(struct ovl_entry, lowerstack[numlower]);
       oe = kzalloc(size, GFP_KERNEL);
   } else {
       oe = kmem_cache_zalloc(ovl_entry_cachep, GFP_KERNEL);
   }

> +       if (oe) {
>                 oe->numlower = numlower;
> +               if (numlower > 1) {
> +                       oe->lowerstacks = kzalloc(size, GFP_KERNEL);
> +                       if (!oe->lowerstacks) {
> +                               kmem_cache_free(ovl_entry_cachep, oe);
> +                               oe = NULL;
> +                       }
> +               }
> +       }
>
>         return oe;
>  }
> @@ -186,7 +203,10 @@ struct ovl_path *__ovl_path_lower(struct ovl_entry *oe, int layer)
>         if (layer > oe->numlower)
>                 return NULL;
>
> -       return &oe->lowerstack[layer - 1];
> +       if (layer == 1 && oe->numlower == 1)
> +               return &oe->lowerstack;
> +       else
> +               return &oe->lowerstacks[layer - 1];
>  }
>

No special casing here.

Thanks,
Amir.
--
To unsubscribe from this list: send the line "unsubscribe linux-unionfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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