diff options
Diffstat (limited to 'fs')
| -rw-r--r-- | fs/overlayfs/dir.c | 20 | ||||
| -rw-r--r-- | fs/overlayfs/namei.c | 61 | ||||
| -rw-r--r-- | fs/overlayfs/overlayfs.h | 22 | ||||
| -rw-r--r-- | fs/overlayfs/ovl_entry.h | 2 | ||||
| -rw-r--r-- | fs/overlayfs/params.c | 91 | ||||
| -rw-r--r-- | fs/overlayfs/params.h | 2 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 52 | ||||
| -rw-r--r-- | fs/overlayfs/util.c | 12 |
8 files changed, 210 insertions, 52 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index e0a164e22d67..8fec18dc5fc7 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c @@ -368,7 +368,7 @@ static bool ovl_type_origin(struct dentry *dentry) } static int ovl_create_upper(struct dentry *dentry, struct inode *inode, - struct ovl_cattr *attr) + struct ovl_cattr *attr, bool origin) { struct ovl_fs *ofs = OVL_FS(dentry->d_sb); struct dentry *upperdir = ovl_dentry_upper(dentry->d_parent); @@ -393,7 +393,7 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode, ovl_set_opaque(dentry, newdentry); } - ovl_dir_modified(dentry->d_parent, false); + ovl_dir_modified(dentry->d_parent, origin); err = ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink, NULL); if (err) goto out_cleanup; @@ -491,7 +491,7 @@ static int ovl_set_upper_acl(struct ovl_fs *ofs, struct dentry *upperdentry, } static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, - struct ovl_cattr *cattr) + struct ovl_cattr *cattr, bool origin) { struct ovl_fs *ofs = OVL_FS(dentry->d_sb); struct dentry *workdir = ovl_workdir(dentry); @@ -582,7 +582,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, if (err) goto out_cleanup_unlocked; } - ovl_dir_modified(dentry->d_parent, false); + ovl_dir_modified(dentry->d_parent, origin); err = ovl_instantiate(dentry, inode, newdentry, hardlink, NULL); if (err) { ovl_cleanup(ofs, upperdir, newdentry); @@ -647,12 +647,12 @@ DEFINE_CLASS(ovl_override_creator_creds, static int ovl_create_handle_whiteouts(struct dentry *dentry, struct inode *inode, - struct ovl_cattr *attr) + struct ovl_cattr *attr, bool origin) { if (!ovl_dentry_is_whiteout(dentry)) - return ovl_create_upper(dentry, inode, attr); + return ovl_create_upper(dentry, inode, attr, origin); - return ovl_create_over_whiteout(dentry, inode, attr); + return ovl_create_over_whiteout(dentry, inode, attr, origin); } static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, @@ -687,12 +687,14 @@ static int ovl_create_or_link(struct dentry *dentry, struct inode *inode, */ if (attr->hardlink) - return ovl_create_handle_whiteouts(dentry, inode, attr); + return ovl_create_handle_whiteouts(dentry, inode, attr, + origin); scoped_class(ovl_override_creator_creds, cred, original_creds, dentry, inode, attr->mode) { if (IS_ERR(cred)) return PTR_ERR(cred); - return ovl_create_handle_whiteouts(dentry, inode, attr); + return ovl_create_handle_whiteouts(dentry, inode, attr, + origin); } } return err; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 64d63b260709..ddf60254888a 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -27,6 +27,7 @@ struct ovl_lookup_data { bool last; char *redirect; char *upperredirect; + char *lowerdata_redirect; int metacopy; /* Referring to last redirect xattr */ bool absolute_redirect; @@ -39,13 +40,12 @@ static int ovl_check_redirect(const struct path *path, struct ovl_lookup_data *d char *buf; struct ovl_fs *ofs = OVL_FS(d->sb); - d->absolute_redirect = false; buf = ovl_get_redirect_xattr(ofs, path, prelen + strlen(post)); if (IS_ERR_OR_NULL(buf)) return PTR_ERR(buf); - if (buf[0] == '/') { - d->absolute_redirect = true; + d->absolute_redirect = buf[0] == '/'; + if (d->absolute_redirect) { /* * One of the ancestor path elements in an absolute path * lookup in ovl_lookup_layer() could have been opaque and @@ -1047,6 +1047,14 @@ out: out_err: pr_warn_ratelimited("lazy lowerdata lookup failed (%pd2, err=%i)\n", dentry, err); + /* + * The data of a metacopy file is missing or is not a regular file in + * the data-only layers: the layers are corrupted. Do not return the + * error of the lookup (e.g. ENOENT) to the caller, it would make the + * file look like it does not exist. + */ + if (err != -ENOMEM) + err = -EIO; goto out; } @@ -1079,7 +1087,8 @@ static bool ovl_check_follow_redirect(struct ovl_lookup_data *d) pr_warn_ratelimited("refusing to follow metacopy origin for (%pd2)\n", d->dentry); return false; } - if ((d->redirect || d->upperredirect) && !ovl_redirect_follow(ofs)) { + /* Check follow to lower layer, redirects to lowerdata are not checked here */ + if ((d->redirect || d->upperredirect) && !ovl_redirect_follow_lower(ofs)) { pr_warn_ratelimited("refusing to follow redirect for (%pd2)\n", d->dentry); return false; } @@ -1097,13 +1106,26 @@ struct ovl_lookup_ctx { unsigned int ctr; }; +/* + * Without metacopy=on, the absolute redirect of a lower metacopy file is + * followed only into the data-only layers. + */ +static bool ovl_is_lowerdata_redirect(struct ovl_lookup_ctx *ctx, + struct ovl_lookup_data *d) +{ + struct ovl_fs *ofs = OVL_FS(d->sb); + + return ofs->numdatalayer && !ofs->config.metacopy && ctx->ctr && + d->metacopy && d->absolute_redirect; +} + static int ovl_lookup_layers(struct ovl_lookup_ctx *ctx, struct ovl_lookup_data *d) { struct dentry *dentry = ctx->dentry; struct ovl_fs *ofs = OVL_FS(dentry->d_sb); struct ovl_entry *poe = OVL_E(dentry->d_parent); struct ovl_entry *roe = OVL_E(dentry->d_sb->s_root); - bool check_redirect = (ovl_redirect_follow(ofs) || ofs->numdatalayer); + bool check_redirect = ovl_redirect_follow(ofs); struct dentry *upperdir; struct dentry *this; struct dentry *origin = NULL; @@ -1234,6 +1256,10 @@ static int ovl_lookup_layers(struct ovl_lookup_ctx *ctx, struct ovl_lookup_data ctx->ctr++; } + /* Lookup of lowerdata in the data-only layers only */ + if (ovl_is_lowerdata_redirect(ctx, d)) + d->stop = true; + if (d->stop) break; @@ -1251,6 +1277,8 @@ static int ovl_lookup_layers(struct ovl_lookup_ctx *ctx, struct ovl_lookup_data if (d->metacopy && ctx->ctr && ofs->numdatalayer && d->absolute_redirect) { d->metacopy = 0; ctx->ctr++; + d->lowerdata_redirect = d->redirect; + d->redirect = NULL; } else if (!ovl_check_follow_redirect(d)) { err = -EPERM; return err; @@ -1367,24 +1395,32 @@ static int ovl_lookup_layers(struct ovl_lookup_ctx *ctx, struct ovl_lookup_data }; /* Store lowerdata redirect for lazy lookup */ - if (ctx->ctr > 1 && !d->is_dir && !ctx->stack[ctx->ctr - 1].dentry) { - oip.lowerdata_redirect = d->redirect; - d->redirect = NULL; - } + if (d->lowerdata_redirect) + oip.lowerdata_redirect = d->lowerdata_redirect; inode = ovl_get_inode(dentry->d_sb, &oip); if (IS_ERR(inode)) return PTR_ERR(inode); + d->lowerdata_redirect = NULL; + ctx->inode = inode; if (ctx->upperdentry && !uppermetacopy) ovl_set_flag(OVL_UPPERDATA, ctx->inode); if (metacopy_size > OVL_METACOPY_MIN_SIZE) ovl_set_flag(OVL_HAS_DIGEST, ctx->inode); - } - ovl_dentry_init_reval(dentry, ctx->upperdentry, OVL_I_E(ctx->inode)); + /* + * ovl_get_inode() puts ctx->upperdentry if it finds a cached + * inode, e.g. for another hard link, so use the upper dentry + * of the inode. + */ + ovl_dentry_init_reval(dentry, ovl_i_dentry_upper(inode), + OVL_I_E(inode)); + } else { + ovl_dentry_init_reval(dentry, NULL, NULL); + } return 0; } @@ -1394,7 +1430,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, { struct ovl_fs *ofs = OVL_FS(dentry->d_sb); struct ovl_entry *poe = OVL_E(dentry->d_parent); - bool check_redirect = (ovl_redirect_follow(ofs) || ofs->numdatalayer); + bool check_redirect = ovl_redirect_follow(ofs); int err; struct ovl_lookup_ctx ctx = { .dentry = dentry, @@ -1419,6 +1455,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, dput(ctx.index); ovl_stack_free(ctx.stack, ctx.ctr); kfree(d.redirect); + kfree(d.lowerdata_redirect); if (err) { ovl_free_entry(ctx.oe); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index e42543d4c108..646f8ffc40ae 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -76,9 +76,15 @@ enum ovl_entry_flag { }; enum { - OVL_REDIRECT_OFF, /* "off" mode is never used. In effect */ - OVL_REDIRECT_FOLLOW, /* ...it translates to either "follow" */ - OVL_REDIRECT_NOFOLLOW, /* ...or "nofollow". */ + /* + * "off" mode is never used after mount options are verified. + * In effect it translates to either "follow", "nofollow" or + * "followdata" (with data-only layers). + */ + OVL_REDIRECT_OFF, + OVL_REDIRECT_FOLLOW, + OVL_REDIRECT_FOLLOWDATA, + OVL_REDIRECT_NOFOLLOW, OVL_REDIRECT_ON, }; @@ -582,6 +588,7 @@ static inline int ovl_set_impure_dir(struct dentry *dentry) bool ovl_inuse_trylock(struct dentry *dentry); void ovl_inuse_unlock(struct dentry *dentry); bool ovl_is_inuse(struct dentry *dentry); +void ovl_inuse_unlock_all(struct ovl_fs *ofs); bool ovl_need_index(struct dentry *dentry); int ovl_nlink_start(struct dentry *dentry); void ovl_nlink_end(struct dentry *dentry); @@ -632,11 +639,20 @@ static inline char ovl_get_opaquedir_val(struct ovl_fs *ofs, return ovl_get_dir_xattr_val(ofs, path, OVL_XATTR_OPAQUE); } +/* Are redirects followed into lower layers? */ +static inline bool ovl_redirect_follow_lower(struct ovl_fs *ofs) +{ + return ofs->config.redirect_mode == OVL_REDIRECT_FOLLOW || + ofs->config.redirect_mode == OVL_REDIRECT_ON; +} + +/* Are redirects followed into lower or lowerdata layers? */ static inline bool ovl_redirect_follow(struct ovl_fs *ofs) { return ofs->config.redirect_mode != OVL_REDIRECT_NOFOLLOW; } +/* Are redirects created in upper dir? */ static inline bool ovl_redirect_dir(struct ovl_fs *ofs) { return ofs->config.redirect_mode == OVL_REDIRECT_ON; diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index ac07e8769f9b..5b2f1b930daa 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -24,6 +24,8 @@ struct ovl_config { struct ovl_sb { struct super_block *sb; dev_t pseudo_dev; + /* Idmap of the first lower layer on this fs */ + const struct mnt_idmap *lower_idmap; /* Unusable (conflicting) uuid */ bool bad_uuid; /* Used as a lower layer (but maybe also as upper) */ 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. diff --git a/fs/overlayfs/params.h b/fs/overlayfs/params.h index ffd53cdd8482..3a514a21b14c 100644 --- a/fs/overlayfs/params.h +++ b/fs/overlayfs/params.h @@ -42,3 +42,5 @@ int ovl_fs_params_verify(const struct ovl_fs_context *ctx, struct ovl_config *config); int ovl_show_options(struct seq_file *m, struct dentry *dentry); const char *ovl_xino_mode(struct ovl_config *config); +const char *ovl_redirect_mode(struct ovl_config *config); +int ovl_redirect_follow_mode(bool follow_lower, size_t nr_data); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 8bc970748b96..e61aab1999d3 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -701,7 +701,7 @@ static int ovl_create_volatile_dirty(struct ovl_fs *ofs) } static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, - const struct path *workpath) + const struct path *workpath, size_t nr_data) { struct vfsmount *mnt = ovl_upper_mnt(ofs); struct dentry *workdir; @@ -765,9 +765,11 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs, if (err) { pr_warn("failed to set xattr on upper\n"); ofs->noxattr = true; - if (ovl_redirect_follow(ofs)) { - ofs->config.redirect_mode = OVL_REDIRECT_NOFOLLOW; - pr_warn("...falling back to redirect_dir=nofollow.\n"); + if (ovl_redirect_follow_lower(ofs)) { + ofs->config.redirect_mode = + ovl_redirect_follow_mode(false, nr_data); + pr_warn("...falling back to redirect_dir=%s.\n", + ovl_redirect_mode(&ofs->config)); } if (ofs->config.metacopy) { ofs->config.metacopy = false; @@ -844,7 +846,7 @@ out: static int ovl_get_workdir(struct super_block *sb, struct ovl_fs *ofs, const struct path *upperpath, - const struct path *workpath) + const struct path *workpath, size_t nr_data) { int err; @@ -873,7 +875,7 @@ static int ovl_get_workdir(struct super_block *sb, struct ovl_fs *ofs, if (err) return err; - return ovl_make_workdir(sb, ofs, workpath); + return ovl_make_workdir(sb, ofs, workpath, nr_data); } static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs, @@ -1142,6 +1144,29 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs, } /* + * Lower file handles identify the lower fs, but not the layer, + * so with different idmaps on the same lower fs, index and + * nfs_export may decode a file handle through a layer with the + * wrong idmap. Following copy up origin without index is only + * used for st_ino, which does not depend on the idmap. + */ + if (i < nr_merged_lower && + (ofs->config.index || ofs->config.nfs_export)) { + const struct mnt_idmap *idmap = mnt_idmap(mnt); + struct ovl_sb *fs = &ofs->fs[fsid]; + + if (!fs->lower_idmap) { + fs->lower_idmap = idmap; + } else if (fs->lower_idmap != idmap) { + pr_err("lower layer '%pd2' conflicts with idmap of another lower layer on the same fs, mount with '-o index=off,nfs_export=off' to override.\n", + l->path.dentry); + iput(trap); + kern_unmount(mnt); + return -EINVAL; + } + } + + /* * Make lower layers R/O. That way fchmod/fchown on lower file * will fail instead of modifying lower fs. */ @@ -1485,7 +1510,8 @@ static int ovl_fill_super_creds(struct fs_context *fc, struct super_block *sb) } } - err = ovl_get_workdir(sb, ofs, &ctx->upper, &ctx->work); + err = ovl_get_workdir(sb, ofs, &ctx->upper, &ctx->work, + ctx->nr_data); if (err) return err; @@ -1619,13 +1645,23 @@ out_err: return err; } +static void ovl_kill_sb(struct super_block *sb) +{ + struct ovl_fs *ofs = OVL_FS(sb); + + /* Nothing can modify them now, do not hold them across the sync */ + if (ofs) + ovl_inuse_unlock_all(ofs); + kill_anon_super(sb); +} + struct file_system_type ovl_fs_type = { .owner = THIS_MODULE, .name = "overlay", .init_fs_context = ovl_init_fs_context, .parameters = ovl_parameter_spec, .fs_flags = FS_USERNS_MOUNT | FS_ALLOW_IDMAP, - .kill_sb = kill_anon_super, + .kill_sb = ovl_kill_sb, }; MODULE_ALIAS_FS("overlay"); diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 788c6870d67d..fd4b1fcf57ad 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1059,6 +1059,18 @@ bool ovl_is_inuse(struct dentry *dentry) return inuse; } +void ovl_inuse_unlock_all(struct ovl_fs *ofs) +{ + if (ofs->workdir_locked) { + ovl_inuse_unlock(ofs->workbasedir); + ofs->workdir_locked = false; + } + if (ofs->upperdir_locked) { + ovl_inuse_unlock(ovl_upper_mnt(ofs)->mnt_root); + ofs->upperdir_locked = false; + } +} + /* * Does this overlay dentry need to be indexed on copy up? */ |
