diff options
Diffstat (limited to 'fs/overlayfs/super.c')
-rw-r--r-- | fs/overlayfs/super.c | 38 |
1 files changed, 27 insertions, 11 deletions
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 76440feb79f6..e3d5fb651f9a 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -211,6 +211,7 @@ static void ovl_destroy_inode(struct inode *inode) struct ovl_inode *oi = OVL_I(inode); dput(oi->__upperdentry); + iput(oi->lower); kfree(oi->redirect); ovl_dir_cache_free(inode); mutex_destroy(&oi->lock); @@ -520,10 +521,6 @@ static struct dentry *ovl_workdir_create(struct ovl_fs *ofs, bool retried = false; bool locked = false; - err = mnt_want_write(mnt); - if (err) - goto out_err; - inode_lock_nested(dir, I_MUTEX_PARENT); locked = true; @@ -588,7 +585,6 @@ retry: goto out_err; } out_unlock: - mnt_drop_write(mnt); if (locked) inode_unlock(dir); @@ -703,7 +699,8 @@ static int ovl_lower_dir(const char *name, struct path *path, * The inodes index feature needs to encode and decode file * handles, so it requires that all layers support them. */ - if (ofs->config.index && !ovl_can_decode_fh(path->dentry->d_sb)) { + if (ofs->config.index && ofs->config.upperdir && + !ovl_can_decode_fh(path->dentry->d_sb)) { ofs->config.index = false; pr_warn("overlayfs: fs on '%s' does not support file handles, falling back to index=off.\n", name); } @@ -929,12 +926,17 @@ out: static int ovl_make_workdir(struct ovl_fs *ofs, struct path *workpath) { + struct vfsmount *mnt = ofs->upper_mnt; struct dentry *temp; int err; + err = mnt_want_write(mnt); + if (err) + return err; + ofs->workdir = ovl_workdir_create(ofs, OVL_WORKDIR_NAME, false); if (!ofs->workdir) - return 0; + goto out; /* * Upper should support d_type, else whiteouts are visible. Given @@ -944,7 +946,7 @@ static int ovl_make_workdir(struct ovl_fs *ofs, struct path *workpath) */ err = ovl_check_d_type_supported(workpath); if (err < 0) - return err; + goto out; /* * We allowed this configuration and don't want to break users over @@ -968,6 +970,7 @@ static int ovl_make_workdir(struct ovl_fs *ofs, struct path *workpath) if (err) { ofs->noxattr = true; pr_warn("overlayfs: upper fs does not support xattr.\n"); + err = 0; } else { vfs_removexattr(ofs->workdir, OVL_XATTR_OPAQUE); } @@ -979,7 +982,9 @@ static int ovl_make_workdir(struct ovl_fs *ofs, struct path *workpath) pr_warn("overlayfs: upper fs does not support file handles, falling back to index=off.\n"); } - return 0; +out: + mnt_drop_write(mnt); + return err; } static int ovl_get_workdir(struct ovl_fs *ofs, struct path *upperpath) @@ -1026,8 +1031,13 @@ out: static int ovl_get_indexdir(struct ovl_fs *ofs, struct ovl_entry *oe, struct path *upperpath) { + struct vfsmount *mnt = ofs->upper_mnt; int err; + err = mnt_want_write(mnt); + if (err) + return err; + /* Verify lower root is upper root origin */ err = ovl_verify_origin(upperpath->dentry, oe->lowerstack[0].dentry, false, true); @@ -1055,6 +1065,7 @@ static int ovl_get_indexdir(struct ovl_fs *ofs, struct ovl_entry *oe, pr_warn("overlayfs: try deleting index dir or mounting with '-o index=off' to disable inodes index.\n"); out: + mnt_drop_write(mnt); return err; } @@ -1257,11 +1268,16 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent) if (err) goto out_free_oe; - if (!ofs->indexdir) + /* Force r/o mount with no index dir */ + if (!ofs->indexdir) { + dput(ofs->workdir); + ofs->workdir = NULL; sb->s_flags |= SB_RDONLY; + } + } - /* Show index=off/on in /proc/mounts for any of the reasons above */ + /* Show index=off in /proc/mounts for forced r/o mount */ if (!ofs->indexdir) ofs->config.index = false; |