diff options
Diffstat (limited to 'fs/overlayfs/super.c')
-rw-r--r-- | fs/overlayfs/super.c | 122 |
1 files changed, 72 insertions, 50 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 6d02ca31bb90..6c8703112b8f 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -895,6 +895,75 @@ out: return err; } +static int ovl_get_lowerstack(struct super_block *sb, struct ovl_fs *ufs, + struct path **stackp, unsigned int *stacklenp) +{ + int err; + char *lowertmp, *lower; + struct path *stack; + unsigned int stacklen, numlower, i; + bool remote = false; + + err = -ENOMEM; + lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL); + if (!lowertmp) + goto out; + + err = -EINVAL; + stacklen = ovl_split_lowerdirs(lowertmp); + if (stacklen > OVL_MAX_STACK) { + pr_err("overlayfs: too many lower directories, limit is %d\n", + OVL_MAX_STACK); + goto out; + } else if (!ufs->config.upperdir && stacklen == 1) { + pr_err("overlayfs: at least 2 lowerdir are needed while upperdir nonexistent\n"); + goto out; + } + + err = -ENOMEM; + stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL); + if (!stack) + goto out; + + err = -EINVAL; + lower = lowertmp; + for (numlower = 0; numlower < stacklen; numlower++) { + err = ovl_lower_dir(lower, &stack[numlower], ufs, + &sb->s_stack_depth, &remote); + if (err) + goto out_free_stack; + + lower = strchr(lower, '\0') + 1; + } + + err = -EINVAL; + sb->s_stack_depth++; + if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { + pr_err("overlayfs: maximum fs stacking depth exceeded\n"); + goto out_free_stack; + } + + *stackp = stack; + *stacklenp = numlower; + + if (remote) + sb->s_d_op = &ovl_reval_dentry_operations; + else + sb->s_d_op = &ovl_dentry_operations; + + err = 0; + +out: + kfree(lowertmp); + return err; + +out_free_stack: + for (i = 0; i < numlower; i++) + path_put(&stack[i]); + kfree(stack); + goto out; +} + static int ovl_fill_super(struct super_block *sb, void *data, int silent) { struct path upperpath = { }; @@ -903,12 +972,8 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) struct ovl_entry *oe; struct ovl_fs *ufs; struct path *stack = NULL; - char *lowertmp; - char *lower; - unsigned int numlower; - unsigned int stacklen = 0; + unsigned int numlower = 0; unsigned int i; - bool remote = false; struct cred *cred; int err; @@ -948,45 +1013,10 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth; } - err = -ENOMEM; - lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL); - if (!lowertmp) + err = ovl_get_lowerstack(sb, ufs, &stack, &numlower); + if (err) goto out_unlock_workdentry; - err = -EINVAL; - stacklen = ovl_split_lowerdirs(lowertmp); - if (stacklen > OVL_MAX_STACK) { - pr_err("overlayfs: too many lower directories, limit is %d\n", - OVL_MAX_STACK); - goto out_free_lowertmp; - } else if (!ufs->config.upperdir && stacklen == 1) { - pr_err("overlayfs: at least 2 lowerdir are needed while upperdir nonexistent\n"); - goto out_free_lowertmp; - } - - err = -ENOMEM; - stack = kcalloc(stacklen, sizeof(struct path), GFP_KERNEL); - if (!stack) - goto out_free_lowertmp; - - err = -EINVAL; - lower = lowertmp; - for (numlower = 0; numlower < stacklen; numlower++) { - err = ovl_lower_dir(lower, &stack[numlower], ufs, - &sb->s_stack_depth, &remote); - if (err) - goto out_put_lowerpath; - - lower = strchr(lower, '\0') + 1; - } - - err = -EINVAL; - sb->s_stack_depth++; - if (sb->s_stack_depth > FILESYSTEM_MAX_STACK_DEPTH) { - pr_err("overlayfs: maximum fs stacking depth exceeded\n"); - goto out_put_lowerpath; - } - if (ufs->config.upperdir) { ufs->upper_mnt = clone_private_mount(&upperpath); err = PTR_ERR(ufs->upper_mnt); @@ -1145,11 +1175,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) if (!ufs->indexdir) ufs->config.index = false; - if (remote) - sb->s_d_op = &ovl_reval_dentry_operations; - else - sb->s_d_op = &ovl_dentry_operations; - err = -ENOMEM; ufs->creator_cred = cred = prepare_creds(); if (!cred) @@ -1173,7 +1198,6 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) mntput(stack[i].mnt); kfree(stack); mntput(workpath.mnt); - kfree(lowertmp); if (upperpath.dentry) { oe->has_upper = true; @@ -1212,8 +1236,6 @@ out_put_lowerpath: for (i = 0; i < numlower; i++) path_put(&stack[i]); kfree(stack); -out_free_lowertmp: - kfree(lowertmp); out_unlock_workdentry: if (ufs->workdir_locked) ovl_inuse_unlock(workpath.dentry); |