diff options
Diffstat (limited to 'fs/overlayfs/params.c')
| -rw-r--r-- | fs/overlayfs/params.c | 91 |
1 files changed, 71 insertions, 20 deletions
diff --git a/fs/overlayfs/params.c b/fs/overlayfs/params.c index 5a15e5478a6b..d1ca4a9094f2 100644 --- a/fs/overlayfs/params.c +++ b/fs/overlayfs/params.c @@ -107,21 +107,40 @@ static int ovl_xino_def(void) const struct constant_table ovl_parameter_redirect_dir[] = { { "off", OVL_REDIRECT_OFF }, { "follow", OVL_REDIRECT_FOLLOW }, + { "followdata", OVL_REDIRECT_FOLLOWDATA }, { "nofollow", OVL_REDIRECT_NOFOLLOW }, { "on", OVL_REDIRECT_ON }, {} }; -static const char *ovl_redirect_mode(struct ovl_config *config) +static const char *ovl_redirect_mode_name(int redirect_mode) { - return ovl_parameter_redirect_dir[config->redirect_mode].name; + return ovl_parameter_redirect_dir[redirect_mode].name; } +const char *ovl_redirect_mode(struct ovl_config *config) +{ + return ovl_redirect_mode_name(config->redirect_mode); +} + +int ovl_redirect_follow_mode(bool follow_lower, size_t nr_data) +{ + if (ovl_redirect_always_follow && follow_lower) + return OVL_REDIRECT_FOLLOW; + + /* Data-only layers cannot be used without following redirects to them */ + return nr_data ? OVL_REDIRECT_FOLLOWDATA : OVL_REDIRECT_NOFOLLOW; +} + +/* + * The default for show_options() is resolved as if there are no data-only layers, + * so that redirect_dir=followdata, which is auto selected with data-only layers, + * is displayed in mount options. + */ static int ovl_redirect_mode_def(void) { - return ovl_redirect_dir_def ? OVL_REDIRECT_ON : - ovl_redirect_always_follow ? OVL_REDIRECT_FOLLOW : - OVL_REDIRECT_NOFOLLOW; + return ovl_redirect_dir_def ? OVL_REDIRECT_ON : + ovl_redirect_follow_mode(true, 0); } static const struct constant_table ovl_parameter_verity[] = { @@ -659,11 +678,6 @@ static int ovl_parse_param(struct fs_context *fc, struct fs_parameter *param) break; case Opt_redirect_dir: config->redirect_mode = result.uint_32; - if (config->redirect_mode == OVL_REDIRECT_OFF) { - config->redirect_mode = ovl_redirect_always_follow ? - OVL_REDIRECT_FOLLOW : - OVL_REDIRECT_NOFOLLOW; - } ctx->set.redirect = true; break; case Opt_index: @@ -819,7 +833,13 @@ int ovl_init_fs_context(struct fs_context *fc) if (!ofs) goto out_err; - ofs->config.redirect_mode = ovl_redirect_mode_def(); + /* + * The module default determines only if new redirects are created in + * upper dir. If they are not, the redirect follow mode will be + * determined after parsing mount options. + */ + ofs->config.redirect_mode = ovl_redirect_dir_def ? + OVL_REDIRECT_ON : OVL_REDIRECT_OFF; ofs->config.index = ovl_index_def; ofs->config.uuid = ovl_uuid_def(); ofs->config.nfs_export = ovl_nfs_export_def; @@ -845,15 +865,12 @@ void ovl_free_fs(struct ovl_fs *ofs) struct vfsmount **mounts; unsigned i; + ovl_inuse_unlock_all(ofs); iput(ofs->workbasedir_trap); iput(ofs->workdir_trap); dput(ofs->whiteout); dput(ofs->workdir); - if (ofs->workdir_locked) - ovl_inuse_unlock(ofs->workbasedir); dput(ofs->workbasedir); - if (ofs->upperdir_locked) - ovl_inuse_unlock(ovl_upper_mnt(ofs)->mnt_root); /* Reuse ofs->config.lowerdirs as a vfsmount array before freeing it */ mounts = (struct vfsmount **) ofs->config.lowerdirs; @@ -880,6 +897,11 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, struct ovl_config *config) { struct ovl_opt_set set = ctx->set; + /* The requested redirect_dir=, for reporting conflicts with it */ + int redirect_opt = config->redirect_mode; + /* The redirect follow mode for redirect_dir=off and for the default */ + int follow_mode = ovl_redirect_follow_mode(!config->userxattr, + ctx->nr_data); /* Workdir/index are useless in non-upper mount */ if (!config->upperdir) { @@ -907,6 +929,13 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, } /* + * Resolve redirect_dir=off to the default redirect follow mode. + * With userxattr, redirects are not followed to lower by default. + */ + if (config->redirect_mode == OVL_REDIRECT_OFF) + config->redirect_mode = follow_mode; + + /* * This is to make the logic below simpler. It doesn't make any other * difference, since redirect_dir=on is only used for upper. */ @@ -917,7 +946,7 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, if (config->metacopy && config->redirect_mode != OVL_REDIRECT_ON) { if (set.metacopy && set.redirect) { pr_err("conflicting options: metacopy=on,redirect_dir=%s\n", - ovl_redirect_mode(config)); + ovl_redirect_mode_name(redirect_opt)); return -EINVAL; } if (set.redirect) { @@ -926,7 +955,7 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, * in this conflict. */ pr_info("disabling metacopy due to redirect_dir=%s\n", - ovl_redirect_mode(config)); + ovl_redirect_mode_name(redirect_opt)); config->metacopy = false; } else { /* Automatically enable redirect otherwise. */ @@ -934,6 +963,16 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, } } + /* Resolve nfs_export -> !data-only layers dependency */ + if (config->nfs_export && ctx->nr_data) { + if (set.nfs_export) { + pr_err("NFS export is not supported with data-only layers\n"); + return -EINVAL; + } + pr_info("disabling nfs_export due to data-only layers\n"); + config->nfs_export = false; + } + /* Resolve nfs_export -> index dependency */ if (config->nfs_export && !config->index) { if (!config->upperdir && @@ -991,9 +1030,10 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, /* Resolve userxattr -> !redirect && !metacopy dependency */ if (config->userxattr) { if (set.redirect && - config->redirect_mode != OVL_REDIRECT_NOFOLLOW) { + config->redirect_mode != OVL_REDIRECT_NOFOLLOW && + config->redirect_mode != OVL_REDIRECT_FOLLOWDATA) { pr_err("conflicting options: userxattr,redirect_dir=%s\n", - ovl_redirect_mode(config)); + ovl_redirect_mode_name(redirect_opt)); return -EINVAL; } if (config->metacopy && set.metacopy) { @@ -1006,10 +1046,21 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, * options must be explicitly enabled if used together with * userxattr. */ - config->redirect_mode = OVL_REDIRECT_NOFOLLOW; + if (!set.redirect) + config->redirect_mode = follow_mode; config->metacopy = false; } + /* Data-only layers are reached through redirects */ + if (ctx->nr_data && config->redirect_mode == OVL_REDIRECT_NOFOLLOW) { + pr_err("redirect_dir=nofollow is not supported with data-only layers\n"); + return -EINVAL; + } + if (!ctx->nr_data && config->redirect_mode == OVL_REDIRECT_FOLLOWDATA) { + pr_err("redirect_dir=followdata requires data-only layers\n"); + return -EINVAL; + } + /* * Fail if we don't have trusted xattr capability and a feature was * explicitly requested that requires them. |
