From f2cdc67f79a780abd0c5b53efaf15c4f003ec89c Mon Sep 17 00:00:00 2001 From: Erez Zadok Date: Thu, 21 May 2009 21:02:31 -0400 Subject: [PATCH] Unionfs: lock base inode mutex around lookup_one_len Signed-off-by: Erez Zadok --- fs/unionfs/commonfops.c | 2 +- fs/unionfs/copyup.c | 4 ++-- fs/unionfs/lookup.c | 4 ++-- fs/unionfs/union.h | 11 +++++++++++ fs/unionfs/whiteout.c | 8 ++++---- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c index e9dc23c5478..f1d66b3ca55 100644 --- a/fs/unionfs/commonfops.c +++ b/fs/unionfs/commonfops.c @@ -62,7 +62,7 @@ retry: pr_debug("unionfs: trying to rename %s to %s\n", dentry->d_name.name, name); - tmp_dentry = lookup_one_len(name, lower_dentry->d_parent, + tmp_dentry = lookup_lck_len(name, lower_dentry->d_parent, nlen); if (IS_ERR(tmp_dentry)) { err = PTR_ERR(tmp_dentry); diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c index 3d0c0ca0bec..c43cc7f133c 100644 --- a/fs/unionfs/copyup.c +++ b/fs/unionfs/copyup.c @@ -778,7 +778,7 @@ begin: if (child_dentry != dentry) { /* lookup child in the underlying file system */ - lower_dentry = lookup_one_len(childname, lower_parent_dentry, + lower_dentry = lookup_lck_len(childname, lower_parent_dentry, childnamelen); if (IS_ERR(lower_dentry)) goto out; @@ -787,7 +787,7 @@ begin: * Is the name a whiteout of the child name ? lookup the * whiteout child in the underlying file system */ - lower_dentry = lookup_one_len(name, lower_parent_dentry, + lower_dentry = lookup_lck_len(name, lower_parent_dentry, strlen(name)); if (IS_ERR(lower_dentry)) goto out; diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c index 9d887ac5ff9..6361541a5ce 100644 --- a/fs/unionfs/lookup.c +++ b/fs/unionfs/lookup.c @@ -50,7 +50,7 @@ struct dentry *__lookup_one(struct dentry *base, struct vfsmount *mnt, * it's safe to call lookup_one_len (which doesn't take a * vfsmount). */ - dentry = lookup_one_len(name, base, strlen(name)); + dentry = lookup_lck_len(name, base, strlen(name)); if (new_mnt) *new_mnt = mntget(lower_nd.path.mnt); break; @@ -469,7 +469,7 @@ struct dentry *unionfs_lookup_full(struct dentry *dentry, if (!S_ISDIR(lower_dir_dentry->d_inode->i_mode)) goto out; /* XXX: should be BUG_ON */ /* XXX: do we need to cross bind mounts here? */ - lower_dentry = lookup_one_len(name, lower_dir_dentry, namelen); + lower_dentry = lookup_lck_len(name, lower_dir_dentry, namelen); if (IS_ERR(lower_dentry)) { err = PTR_ERR(lower_dentry); goto out; diff --git a/fs/unionfs/union.h b/fs/unionfs/union.h index 1b2b86f4acf..1a05f63c5f9 100644 --- a/fs/unionfs/union.h +++ b/fs/unionfs/union.h @@ -553,6 +553,17 @@ static inline void unlock_dir(struct dentry *dir) dput(dir); } +/* lock base inode mutex before calling lookup_one_len */ +static inline struct dentry *lookup_lck_len(const char *name, + struct dentry *base, int len) +{ + struct dentry *d; + mutex_lock(&base->d_inode->i_mutex); + d = lookup_one_len(name, base, len); + mutex_unlock(&base->d_inode->i_mutex); + return d; +} + static inline struct vfsmount *unionfs_mntget(struct dentry *dentry, int bindex) { diff --git a/fs/unionfs/whiteout.c b/fs/unionfs/whiteout.c index a55684d98ae..626006a3735 100644 --- a/fs/unionfs/whiteout.c +++ b/fs/unionfs/whiteout.c @@ -101,7 +101,7 @@ struct dentry *lookup_whiteout(const char *name, struct dentry *lower_parent) } /* check if whiteout exists in this branch: lookup .wh.foo */ - wh_dentry = lookup_one_len(whname, lower_parent, strlen(whname)); + wh_dentry = lookup_lck_len(whname, lower_parent, strlen(whname)); if (IS_ERR(wh_dentry)) { err = PTR_ERR(wh_dentry); goto out; @@ -311,7 +311,7 @@ int create_whiteout(struct dentry *dentry, int start) } lower_wh_dentry = - lookup_one_len(name, lower_dentry->d_parent, + lookup_lck_len(name, lower_dentry->d_parent, dentry->d_name.len + UNIONFS_WHLEN); if (IS_ERR(lower_wh_dentry)) continue; @@ -334,7 +334,7 @@ int create_whiteout(struct dentry *dentry, int start) if (!err) err = vfs_create(lower_dir_dentry->d_inode, lower_wh_dentry, - ~current->fs->umask & S_IRUGO, + current_umask() & S_IRUGO, &nd); unlock_dir(lower_dir_dentry); dput(lower_wh_dentry); @@ -397,7 +397,7 @@ static int do_delete_whiteouts(struct dentry *dentry, int bindex, strlcpy(p, cursor->name, PATH_MAX - UNIONFS_WHLEN); lower_dentry = - lookup_one_len(name, lower_dir_dentry, + lookup_lck_len(name, lower_dir_dentry, cursor->namelen + UNIONFS_WHLEN); if (IS_ERR(lower_dentry)) { -- 2.34.1