aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p/fid.c
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2010-06-30 09:48:50 -0400
committerEric Van Hensbergen <ericvh@gmail.com>2010-08-02 15:28:35 -0400
commita534c8d15b1f1d0f861fc2bb9e0529bd8486ec3f (patch)
tree0451da7a61bd7e3eb5968d65beee3243f7f51b5d /fs/9p/fid.c
parentebf46264a004818fe5b23f0ac18ac7336897d807 (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/fid.c')
-rw-r--r--fs/9p/fid.c114
1 files changed, 78 insertions, 36 deletions
diff --git a/fs/9p/fid.c b/fs/9p/fid.c
index 5d6cfcbf73e7..358563689064 100644
--- a/fs/9p/fid.c
+++ b/fs/9p/fid.c
@@ -97,6 +97,34 @@ static struct p9_fid *v9fs_fid_find(struct dentry *dentry, u32 uid, int any)
97 return ret; 97 return ret;
98} 98}
99 99
100/*
101 * We need to hold v9ses->rename_sem as long as we hold references
102 * to returned path array. Array element contain pointers to
103 * dentry names.
104 */
105static int build_path_from_dentry(struct v9fs_session_info *v9ses,
106 struct dentry *dentry, char ***names)
107{
108 int n = 0, i;
109 char **wnames;
110 struct dentry *ds;
111
112 for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent)
113 n++;
114
115 wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL);
116 if (!wnames)
117 goto err_out;
118
119 for (ds = dentry, i = (n-1); i >= 0; i--, ds = ds->d_parent)
120 wnames[i] = (char *)ds->d_name.name;
121
122 *names = wnames;
123 return n;
124err_out:
125 return -ENOMEM;
126}
127
100/** 128/**
101 * v9fs_fid_lookup - lookup for a fid, try to walk if not found 129 * v9fs_fid_lookup - lookup for a fid, try to walk if not found
102 * @dentry: dentry to look for fid in 130 * @dentry: dentry to look for fid in
@@ -112,7 +140,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
112 int i, n, l, clone, any, access; 140 int i, n, l, clone, any, access;
113 u32 uid; 141 u32 uid;
114 struct p9_fid *fid, *old_fid = NULL; 142 struct p9_fid *fid, *old_fid = NULL;
115 struct dentry *d, *ds; 143 struct dentry *ds;
116 struct v9fs_session_info *v9ses; 144 struct v9fs_session_info *v9ses;
117 char **wnames, *uname; 145 char **wnames, *uname;
118 146
@@ -139,50 +167,62 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
139 fid = v9fs_fid_find(dentry, uid, any); 167 fid = v9fs_fid_find(dentry, uid, any);
140 if (fid) 168 if (fid)
141 return fid; 169 return fid;
142 170 /*
171 * we don't have a matching fid. To do a TWALK we need
172 * parent fid. We need to prevent rename when we want to
173 * look at the parent.
174 */
175 down_read(&v9ses->rename_sem);
143 ds = dentry->d_parent; 176 ds = dentry->d_parent;
144 fid = v9fs_fid_find(ds, uid, any); 177 fid = v9fs_fid_find(ds, uid, any);
145 if (!fid) { /* walk from the root */ 178 if (fid) {
146 n = 0; 179 /* Found the parent fid do a lookup with that */
147 for (ds = dentry; !IS_ROOT(ds); ds = ds->d_parent) 180 fid = p9_client_walk(fid, 1, (char **)&dentry->d_name.name, 1);
148 n++; 181 goto fid_out;
149 182 }
150 fid = v9fs_fid_find(ds, uid, any); 183 up_read(&v9ses->rename_sem);
151 if (!fid) { /* the user is not attached to the fs yet */
152 if (access == V9FS_ACCESS_SINGLE)
153 return ERR_PTR(-EPERM);
154
155 if (v9fs_proto_dotu(v9ses) ||
156 v9fs_proto_dotl(v9ses))
157 uname = NULL;
158 else
159 uname = v9ses->uname;
160 184
161 fid = p9_client_attach(v9ses->clnt, NULL, uname, uid, 185 /* start from the root and try to do a lookup */
162 v9ses->aname); 186 fid = v9fs_fid_find(dentry->d_sb->s_root, uid, any);
187 if (!fid) {
188 /* the user is not attached to the fs yet */
189 if (access == V9FS_ACCESS_SINGLE)
190 return ERR_PTR(-EPERM);
163 191
164 if (IS_ERR(fid)) 192 if (v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses))
165 return fid; 193 uname = NULL;
194 else
195 uname = v9ses->uname;
166 196
167 v9fs_fid_add(ds, fid); 197 fid = p9_client_attach(v9ses->clnt, NULL, uname, uid,
168 } 198 v9ses->aname);
169 } else /* walk from the parent */ 199 if (IS_ERR(fid))
170 n = 1; 200 return fid;
171 201
172 if (ds == dentry) 202 v9fs_fid_add(dentry->d_sb->s_root, fid);
203 }
204 /* If we are root ourself just return that */
205 if (dentry->d_sb->s_root == dentry)
173 return fid; 206 return fid;
174 207 /*
175 wnames = kmalloc(sizeof(char *) * n, GFP_KERNEL); 208 * Do a multipath walk with attached root.
176 if (!wnames) 209 * When walking parent we need to make sure we
177 return ERR_PTR(-ENOMEM); 210 * don't have a parallel rename happening
178 211 */
179 for (d = dentry, i = (n-1); i >= 0; i--, d = d->d_parent) 212 down_read(&v9ses->rename_sem);
180 wnames[i] = (char *) d->d_name.name; 213 n = build_path_from_dentry(v9ses, dentry, &wnames);
181 214 if (n < 0) {
215 fid = ERR_PTR(n);
216 goto err_out;
217 }
182 clone = 1; 218 clone = 1;
183 i = 0; 219 i = 0;
184 while (i < n) { 220 while (i < n) {
185 l = min(n - i, P9_MAXWELEM); 221 l = min(n - i, P9_MAXWELEM);
222 /*
223 * We need to hold rename lock when doing a multipath
224 * walk to ensure none of the patch component change
225 */
186 fid = p9_client_walk(fid, l, &wnames[i], clone); 226 fid = p9_client_walk(fid, l, &wnames[i], clone);
187 if (IS_ERR(fid)) { 227 if (IS_ERR(fid)) {
188 if (old_fid) { 228 if (old_fid) {
@@ -194,15 +234,17 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
194 p9_client_clunk(old_fid); 234 p9_client_clunk(old_fid);
195 } 235 }
196 kfree(wnames); 236 kfree(wnames);
197 return fid; 237 goto err_out;
198 } 238 }
199 old_fid = fid; 239 old_fid = fid;
200 i += l; 240 i += l;
201 clone = 0; 241 clone = 0;
202 } 242 }
203
204 kfree(wnames); 243 kfree(wnames);
244fid_out:
205 v9fs_fid_add(dentry, fid); 245 v9fs_fid_add(dentry, fid);
246err_out:
247 up_read(&v9ses->rename_sem);
206 return fid; 248 return fid;
207} 249}
208 250