Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszer...
[deliverable/linux.git] / fs / overlayfs / super.c
index ed53ae0fe86881ea3578320e880cc561b113b459..ce02f46029da7c3aa7c69be9291d62c81baeb642 100644 (file)
@@ -42,6 +42,8 @@ struct ovl_fs {
        long lower_namelen;
        /* pathnames of lower and upper dirs, for show_options */
        struct ovl_config config;
+       /* creds of process who forced instantiation of super block */
+       const struct cred *creator_cred;
 };
 
 struct ovl_dir_cache;
@@ -265,6 +267,13 @@ bool ovl_is_whiteout(struct dentry *dentry)
        return inode && IS_WHITEOUT(inode);
 }
 
+const struct cred *ovl_override_creds(struct super_block *sb)
+{
+       struct ovl_fs *ofs = sb->s_fs_info;
+
+       return override_creds(ofs->creator_cred);
+}
+
 static bool ovl_is_opaquedir(struct dentry *dentry)
 {
        int res;
@@ -603,6 +612,7 @@ static void ovl_put_super(struct super_block *sb)
        kfree(ufs->config.lowerdir);
        kfree(ufs->config.upperdir);
        kfree(ufs->config.workdir);
+       put_cred(ufs->creator_cred);
        kfree(ufs);
 }
 
@@ -1064,16 +1074,19 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
                /*
                 * Upper should support d_type, else whiteouts are visible.
                 * Given workdir and upper are on same fs, we can do
-                * iterate_dir() on workdir.
+                * iterate_dir() on workdir. This check requires successful
+                * creation of workdir in previous step.
                 */
-               err = ovl_check_d_type_supported(&workpath);
-               if (err < 0)
-                       goto out_put_workdir;
+               if (ufs->workdir) {
+                       err = ovl_check_d_type_supported(&workpath);
+                       if (err < 0)
+                               goto out_put_workdir;
 
-               if (!err) {
-                       pr_err("overlayfs: upper fs needs to support d_type.\n");
-                       err = -EINVAL;
-                       goto out_put_workdir;
+                       if (!err) {
+                               pr_err("overlayfs: upper fs needs to support d_type.\n");
+                               err = -EINVAL;
+                               goto out_put_workdir;
+                       }
                }
        }
 
@@ -1108,10 +1121,14 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
        else
                sb->s_d_op = &ovl_dentry_operations;
 
+       ufs->creator_cred = prepare_creds();
+       if (!ufs->creator_cred)
+               goto out_put_lower_mnt;
+
        err = -ENOMEM;
        oe = ovl_alloc_entry(numlower);
        if (!oe)
-               goto out_put_lower_mnt;
+               goto out_put_cred;
 
        root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe));
        if (!root_dentry)
@@ -1144,6 +1161,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
 
 out_free_oe:
        kfree(oe);
+out_put_cred:
+       put_cred(ufs->creator_cred);
 out_put_lower_mnt:
        for (i = 0; i < ufs->numlower; i++)
                mntput(ufs->lower_mnt[i]);
This page took 0.056107 seconds and 5 git commands to generate.