Re: [PATCH V2] ovl: Allocate anonymous devs for lowerdirs

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

 



On Fri, Jun 23, 2017 at 1:01 PM, Chandan Rajendra
<chandan@xxxxxxxxxxxxxxxxxx> wrote:
> For stat(2) on lowerdir non-dir entries in non-samefs case, this commit
> provides unique values for st_dev. The unique values are obtained by
> allocating anonymous bdevs for each of the lowerdirs in the overlayfs
> instance.
>
> Signed-off-by: Chandan Rajendra <chandan@xxxxxxxxxxxxxxxxxx>
> ---
> Changelog:
> v1->v2: Drop code that provided unique st_dev across copy up.
>
>  fs/overlayfs/inode.c     | 20 ++++++++++++++++++++
>  fs/overlayfs/ovl_entry.h |  8 +++++++-
>  fs/overlayfs/super.c     | 33 +++++++++++++++++++++++++--------
>  3 files changed, 52 insertions(+), 9 deletions(-)
>
> diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
> index d613e2c..e30bdca 100644
> --- a/fs/overlayfs/inode.c
> +++ b/fs/overlayfs/inode.c
> @@ -8,11 +8,29 @@
>   */
>
>  #include <linux/fs.h>
> +#include <linux/mount.h>
>  #include <linux/slab.h>
>  #include <linux/cred.h>
>  #include <linux/xattr.h>
>  #include <linux/posix_acl.h>
>  #include "overlayfs.h"
> +#include "ovl_entry.h"
> +
> +static dev_t ovl_get_pseudo_dev(struct dentry *dentry, dev_t dev)
> +{
> +       struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
> +       int i;
> +
> +       if (ofs->upper_mnt && ofs->upper_mnt->mnt_sb->s_dev == dev)
> +               return dev;
> +
> +       for (i = 0; i < ofs->numlower; i++) {
> +               if (ofs->lower_mnt[i].real_dev == dev)
> +                       return ofs->lower_mnt[i].pseudo_dev;
> +       }
> +
> +       return dev;
> +}

This is a good way to test out the functionality.  But there's a
trivial way to optimize away the O(num of layers) from this function:
instead of using struct path for lower stack, use

struct ovl_lower {
        struct ovl_lower_mnt *layer;
        struct dentry *dentry;
};

That means one more dereference to get the vfsmount, but I don't think
we need to care about that.

>
>  int ovl_setattr(struct dentry *dentry, struct iattr *attr)
>  {
> @@ -116,6 +134,8 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
>                  */
>                 stat->dev = dentry->d_sb->s_dev;
>                 stat->ino = dentry->d_inode->i_ino;
> +       } else {
> +               stat->dev = ovl_get_pseudo_dev(dentry, stat->dev);
>         }
>
>         /*
> diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
> index 34bc4a9..92aebe9 100644
> --- a/fs/overlayfs/ovl_entry.h
> +++ b/fs/overlayfs/ovl_entry.h
> @@ -16,11 +16,17 @@ struct ovl_config {
>         bool redirect_dir;
>  };
>
> +struct ovl_lower_mnt {
> +       struct vfsmount *mnt;
> +       dev_t real_dev;

Why store the real_dev?  It's stored in mnt->mnt_sb->s_dev, right?

> +       dev_t pseudo_dev;
> +};
> +
>  /* private information held for overlayfs's superblock */
>  struct ovl_fs {
>         struct vfsmount *upper_mnt;
>         unsigned numlower;
> -       struct vfsmount **lower_mnt;
> +       struct ovl_lower_mnt *lower_mnt;
>         struct dentry *workdir;
>         long namelen;
>         /* pathnames of lower and upper dirs, for show_options */
> diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
> index 4882ffb..c922a92 100644
> --- a/fs/overlayfs/super.c
> +++ b/fs/overlayfs/super.c
> @@ -172,8 +172,10 @@ static void ovl_put_super(struct super_block *sb)
>
>         dput(ufs->workdir);
>         mntput(ufs->upper_mnt);
> -       for (i = 0; i < ufs->numlower; i++)
> -               mntput(ufs->lower_mnt[i]);
> +       for (i = 0; i < ufs->numlower; i++) {
> +               mntput(ufs->lower_mnt[i].mnt);
> +               free_anon_bdev(ufs->lower_mnt[i].pseudo_dev);
> +       }
>         kfree(ufs->lower_mnt);
>
>         kfree(ufs->config.lowerdir);
> @@ -908,15 +910,25 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
>         }
>
>         err = -ENOMEM;
> -       ufs->lower_mnt = kcalloc(numlower, sizeof(struct vfsmount *), GFP_KERNEL);
> +       ufs->lower_mnt = kcalloc(numlower, sizeof(struct ovl_lower_mnt),
> +                               GFP_KERNEL);
>         if (ufs->lower_mnt == NULL)
>                 goto out_put_workdir;
>         for (i = 0; i < numlower; i++) {
> -               struct vfsmount *mnt = clone_private_mount(&stack[i]);
> +               struct vfsmount *mnt;
> +               dev_t dev;
>
> +               err = get_anon_bdev(&dev);
> +               if (err) {
> +                       pr_err("overlayfs: failed to get anonymous bdev for lowerpath\n");
> +                       goto out_put_lower_mnt;
> +               }
> +
> +               mnt = clone_private_mount(&stack[i]);
>                 err = PTR_ERR(mnt);
>                 if (IS_ERR(mnt)) {
>                         pr_err("overlayfs: failed to clone lowerpath\n");
> +                       free_anon_bdev(dev);
>                         goto out_put_lower_mnt;
>                 }
>                 /*
> @@ -925,7 +937,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
>                  */
>                 mnt->mnt_flags |= MNT_READONLY | MNT_NOATIME;
>
> -               ufs->lower_mnt[ufs->numlower] = mnt;
> +               ufs->lower_mnt[ufs->numlower].mnt = mnt;
> +               ufs->lower_mnt[ufs->numlower].real_dev = mnt->mnt_sb->s_dev;
> +               ufs->lower_mnt[ufs->numlower].pseudo_dev = dev;
>                 ufs->numlower++;
>
>                 /* Check if all lower layers are on same sb */
> @@ -980,7 +994,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
>         }
>         for (i = 0; i < numlower; i++) {
>                 oe->lowerstack[i].dentry = stack[i].dentry;
> -               oe->lowerstack[i].mnt = ufs->lower_mnt[i];
> +               oe->lowerstack[i].mnt = ufs->lower_mnt[i].mnt;
>         }
>         kfree(stack);
>
> @@ -999,8 +1013,11 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
>  out_put_cred:
>         put_cred(ufs->creator_cred);
>  out_put_lower_mnt:
> -       for (i = 0; i < ufs->numlower; i++)
> -               mntput(ufs->lower_mnt[i]);
> +       for (i = 0; i < ufs->numlower; i++) {
> +               if (ufs->lower_mnt[i].mnt)
> +                       free_anon_bdev(ufs->lower_mnt[i].pseudo_dev);
> +               mntput(ufs->lower_mnt[i].mnt);
> +       }
>         kfree(ufs->lower_mnt);
>  out_put_workdir:
>         dput(ufs->workdir);
> --
> 2.9.4
>
--
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