ovl: proper cleanup of workdir
Subsystems (2)
PATCH 1/1 ovl: proper cleanup of workdir
From: Miklos Szeredi <[email protected]>
When mounting overlayfs it needs a clean "work" directory under the supplied workdir.
Previously the mount code removed this directory if it already existed and created a new one. If the removal failed (e.g. directory was not empty) then it fell back to a read-only mount not using the workdir.
While this has never been reported, it is possible to get a non-empty "work" dir from a previous mount of overlayfs in case of crash in the middle of an operation using the work directory.
In this case the left over state should be discarded and the overlay filesystem will be consistent, guaranteed by the atomicity of operations on moving to/from the workdir to the upper layer.
This patch implements cleaning out any files left in workdir. It is implemented using real recursion for simplicity, but the depth is limited to 2, because the worst case is that of a directory containing whiteouts under "work".
--- fs/overlayfs/copy_up.c | 26 +- fs/overlayfs/dir.c | 67 +-- fs/overlayfs/overlayfs.h | 3 + fs/overlayfs/readdir.c | 77 ++- fs/overlayfs/super.c | 20 +- include/linux/scif.h | 1339 ---------------------------------------------- 6 files changed, 92 insertions(+), 1440 deletions(-)
fs/overlayfs/copy_up.c +1 -25
@@ -317,7 +317,6 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,struct dentry *upperdir;struct dentry *upperdentry;const struct cred *old_cred; -struct cred *override_cred;char *link =NULL ;if (WARN_ON (!workdir))
@@ -336,28 +335,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,return PTR_ERR (link); } - err = -ENOMEM ; - override_cred =prepare_creds (); -if (!override_cred) - goto out_free_link; - - override_cred->fsuid = stat->uid; - override_cred->fsgid = stat->gid; -/* -* CAP_SYS_ADMIN for copying up extended attributes -* CAP_DAC_OVERRIDE for create -* CAP_FOWNER for chmod, timestamp update -* CAP_FSETID for chmod -* CAP_CHOWN for chown -* CAP_MKNOD for mknod -*/ -cap_raise (override_cred->cap_effective,CAP_SYS_ADMIN ); -cap_raise (override_cred->cap_effective,CAP_DAC_OVERRIDE ); -cap_raise (override_cred->cap_effective,CAP_FOWNER ); -cap_raise (override_cred->cap_effective,CAP_FSETID ); -cap_raise (override_cred->cap_effective,CAP_CHOWN ); -cap_raise (override_cred->cap_effective,CAP_MKNOD ); - old_cred =override_creds (override_cred); + old_cred =ovl_override_creds (dentry->d_sb); err = -EIO ;if (lock_rename (workdir, upperdir) !=NULL ) {
@@ -380,9 +358,7 @@ int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, out_unlock:unlock_rename (workdir, upperdir);revert_creds (old_cred); -put_cred (override_cred); -out_free_link:if (link)free_page ((unsigned long ) link);
fs/overlayfs/dir.c +5 -62
108 lines not on this page · raw message
fs/overlayfs/overlayfs.h +3 -0
@@ -150,6 +150,7 @@ void ovl_drop_write(struct dentry *dentry);bool ovl_dentry_is_opaque (struct dentry *dentry);void ovl_dentry_set_opaque (struct dentry *dentry,bool opaque);bool ovl_is_whiteout (struct dentry *dentry); +const struct cred *ovl_override_creds (struct super_block *sb);void ovl_dentry_update (struct dentry *dentry,struct dentry *upperdentry);struct dentry *ovl_lookup (struct inode *dir,struct dentry *dentry,unsigned int flags);
@@ -163,6 +164,8 @@ extern const struct file_operations ovl_dir_operations;int ovl_check_empty_dir (struct dentry *dentry,struct list_head *list);void ovl_cleanup_whiteouts (struct dentry *upper,struct list_head *list);void ovl_cache_free (struct list_head *list); +void ovl_workdir_cleanup (struct inode *dir,struct vfsmount *mnt, +struct dentry *dentry,int level);/* inode.c */ int ovl_setattr (struct dentry *dentry,struct iattr *attr);
fs/overlayfs/readdir.c +65 -12
111 lines not on this page · raw message
fs/overlayfs/super.c +18 -2
@@ -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 ;
@@ -246,6 +248,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;
@@ -587,6 +596,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); }
@@ -774,7 +784,7 @@ retry: goto out_dput; retried = true; -ovl_cleanup (dir, work); +ovl_workdir_cleanup (dir, mnt, work,0 );dput (work); goto retry; }
@@ -1087,10 +1097,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)
@@ -1123,6 +1137,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]);
include/linux/scif.h +0 -1339
1,339 lines not on this page · raw message
Signature · 1 line
2.11.0