diff options
author | Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 2010-06-30 09:48:50 -0400 |
---|---|---|
committer | Eric Van Hensbergen <ericvh@gmail.com> | 2010-08-02 15:28:35 -0400 |
commit | a534c8d15b1f1d0f861fc2bb9e0529bd8486ec3f (patch) | |
tree | 0451da7a61bd7e3eb5968d65beee3243f7f51b5d /fs/9p/vfs_inode.c | |
parent | ebf46264a004818fe5b23f0ac18ac7336897d807 (diff) |
fs/9p: Prevent parallel rename when doing fid_lookup
During fid lookup we need to make sure that the dentry->d_parent doesn't
change so that we can safely walk the parent dentries. To ensure that
we need to prevent cross directory rename during fid_lookup. Add a
per superblock rename_sem rw_semaphore to prevent parallel fid lookup and
rename.
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Venkateswararao Jujjuri <jvrao@linux.vnet.ibm.com>
Signed-off-by: Eric Van Hensbergen <ericvh@gmail.com>
Diffstat (limited to 'fs/9p/vfs_inode.c')
-rw-r--r-- | fs/9p/vfs_inode.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 39352ef954d..75c261fdc7b 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -948,6 +948,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
948 | 948 | ||
949 | sb = dir->i_sb; | 949 | sb = dir->i_sb; |
950 | v9ses = v9fs_inode2v9ses(dir); | 950 | v9ses = v9fs_inode2v9ses(dir); |
951 | /* We can walk d_parent because we hold the dir->i_mutex */ | ||
951 | dfid = v9fs_fid_lookup(dentry->d_parent); | 952 | dfid = v9fs_fid_lookup(dentry->d_parent); |
952 | if (IS_ERR(dfid)) | 953 | if (IS_ERR(dfid)) |
953 | return ERR_CAST(dfid); | 954 | return ERR_CAST(dfid); |
@@ -1055,27 +1056,33 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
1055 | goto clunk_olddir; | 1056 | goto clunk_olddir; |
1056 | } | 1057 | } |
1057 | 1058 | ||
1059 | down_write(&v9ses->rename_sem); | ||
1058 | if (v9fs_proto_dotl(v9ses)) { | 1060 | if (v9fs_proto_dotl(v9ses)) { |
1059 | retval = p9_client_rename(oldfid, newdirfid, | 1061 | retval = p9_client_rename(oldfid, newdirfid, |
1060 | (char *) new_dentry->d_name.name); | 1062 | (char *) new_dentry->d_name.name); |
1061 | if (retval != -ENOSYS) | 1063 | if (retval != -ENOSYS) |
1062 | goto clunk_newdir; | 1064 | goto clunk_newdir; |
1063 | } | 1065 | } |
1066 | if (old_dentry->d_parent != new_dentry->d_parent) { | ||
1067 | /* | ||
1068 | * 9P .u can only handle file rename in the same directory | ||
1069 | */ | ||
1064 | 1070 | ||
1065 | /* 9P can only handle file rename in the same directory */ | ||
1066 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { | ||
1067 | P9_DPRINTK(P9_DEBUG_ERROR, | 1071 | P9_DPRINTK(P9_DEBUG_ERROR, |
1068 | "old dir and new dir are different\n"); | 1072 | "old dir and new dir are different\n"); |
1069 | retval = -EXDEV; | 1073 | retval = -EXDEV; |
1070 | goto clunk_newdir; | 1074 | goto clunk_newdir; |
1071 | } | 1075 | } |
1072 | |||
1073 | v9fs_blank_wstat(&wstat); | 1076 | v9fs_blank_wstat(&wstat); |
1074 | wstat.muid = v9ses->uname; | 1077 | wstat.muid = v9ses->uname; |
1075 | wstat.name = (char *) new_dentry->d_name.name; | 1078 | wstat.name = (char *) new_dentry->d_name.name; |
1076 | retval = p9_client_wstat(oldfid, &wstat); | 1079 | retval = p9_client_wstat(oldfid, &wstat); |
1077 | 1080 | ||
1078 | clunk_newdir: | 1081 | clunk_newdir: |
1082 | if (!retval) | ||
1083 | /* successful rename */ | ||
1084 | d_move(old_dentry, new_dentry); | ||
1085 | up_write(&v9ses->rename_sem); | ||
1079 | p9_client_clunk(newdirfid); | 1086 | p9_client_clunk(newdirfid); |
1080 | 1087 | ||
1081 | clunk_olddir: | 1088 | clunk_olddir: |