aboutsummaryrefslogtreecommitdiffstats
path: root/fs/autofs4
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2008-07-24 00:30:19 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:32 -0400
commita1362fe92f1bde687b3a9e93d6b8d105d0a84f74 (patch)
treeb176c2494ea23b1842a8b408247f02058533dda5 /fs/autofs4
parent5a11d4d0ee1ff284271f7265929d07ea4a1168a6 (diff)
autofs4: fix pending mount race
Close a race between a pending mount that is about to finish and a new lookup for the same directory. Process P1 triggers a mount of directory foo. It sets DCACHE_AUTOFS_PENDING in the ->lookup routine, creates a waitq entry for 'foo', and calls out to the daemon to perform the mount. The autofs daemon will then create the directory 'foo', using a new dentry that will be hashed in the dcache. Before the mount completes, another process, P2, tries to walk into the 'foo' directory. The vfs path walking code finds an entry for 'foo' and calls the revalidate method. Revalidate finds that the entry is not PENDING (because PENDING was never set on the dentry created by the mkdir), but it does find the directory is empty. Revalidate calls try_to_fill_dentry, which sets the PENDING flag and then calls into the autofs4 wait code to trigger or wait for a mount of 'foo'. The wait code finds the entry for 'foo' and goes to sleep waiting for the completion of the mount. Yet another process, P3, tries to walk into the 'foo' directory. This process again finds a dentry in the dcache for 'foo', and calls into the autofs revalidate code. The revalidate code finds that the PENDING flag is set, and so calls try_to_fill_dentry. a) try_to_fill_dentry sets the PENDING flag redundantly for this dentry, then calls into the autofs4 wait code. b) the autofs4 wait code takes the waitq mutex and searches for an entry for 'foo' Between a and b, P1 is woken up because the mount completed. P1 takes the wait queue mutex, clears the PENDING flag from the dentry, and removes the waitqueue entry for 'foo' from the list. When it releases the waitq mutex, P3 (eventually) acquires it. At this time, it looks for an existing waitq for 'foo', finds none, and so creates a new one and calls out to the daemon to mount the 'foo' directory. Now, the reason that three processes are required to trigger this race is that, because the PENDING flag is not set on the dentry created by mkdir, the window for the race would be way to slim for it to ever occur. Basically, between the testing of d_mountpoint(dentry) and the taking of the waitq mutex, the mount would have to complete and the daemon would have to be woken up, and that in turn would have to wake up P1. This is simply impossible. Add the third process, though, and it becomes slightly more likely. Signed-off-by: Jeff Moyer <jmoyer@redhat.com> Signed-off-by: Ian Kent <raven@themaw.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/autofs4')
-rw-r--r--fs/autofs4/waitq.c135
1 files changed, 97 insertions, 38 deletions
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index 55aac10cf328..cd3b2a671696 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -215,19 +215,106 @@ autofs4_find_wait(struct autofs_sb_info *sbi, struct qstr *qstr)
215 return wq; 215 return wq;
216} 216}
217 217
218/*
219 * Check if we have a valid request.
220 * Returns
221 * 1 if the request should continue.
222 * In this case we can return an autofs_wait_queue entry if one is
223 * found or NULL to idicate a new wait needs to be created.
224 * 0 or a negative errno if the request shouldn't continue.
225 */
226static int validate_request(struct autofs_wait_queue **wait,
227 struct autofs_sb_info *sbi,
228 struct qstr *qstr,
229 struct dentry*dentry, enum autofs_notify notify)
230{
231 struct autofs_wait_queue *wq;
232 struct autofs_info *ino;
233
234 /* Wait in progress, continue; */
235 wq = autofs4_find_wait(sbi, qstr);
236 if (wq) {
237 *wait = wq;
238 return 1;
239 }
240
241 *wait = NULL;
242
243 /* If we don't yet have any info this is a new request */
244 ino = autofs4_dentry_ino(dentry);
245 if (!ino)
246 return 1;
247
248 /*
249 * If we've been asked to wait on an existing expire (NFY_NONE)
250 * but there is no wait in the queue ...
251 */
252 if (notify == NFY_NONE) {
253 /*
254 * Either we've betean the pending expire to post it's
255 * wait or it finished while we waited on the mutex.
256 * So we need to wait till either, the wait appears
257 * or the expire finishes.
258 */
259
260 while (ino->flags & AUTOFS_INF_EXPIRING) {
261 mutex_unlock(&sbi->wq_mutex);
262 schedule_timeout_interruptible(HZ/10);
263 if (mutex_lock_interruptible(&sbi->wq_mutex))
264 return -EINTR;
265
266 wq = autofs4_find_wait(sbi, qstr);
267 if (wq) {
268 *wait = wq;
269 return 1;
270 }
271 }
272
273 /*
274 * Not ideal but the status has already gone. Of the two
275 * cases where we wait on NFY_NONE neither depend on the
276 * return status of the wait.
277 */
278 return 0;
279 }
280
281 /*
282 * If we've been asked to trigger a mount and the request
283 * completed while we waited on the mutex ...
284 */
285 if (notify == NFY_MOUNT) {
286 /*
287 * If the dentry isn't hashed just go ahead and try the
288 * mount again with a new wait (not much else we can do).
289 */
290 if (!d_unhashed(dentry)) {
291 /*
292 * But if the dentry is hashed, that means that we
293 * got here through the revalidate path. Thus, we
294 * need to check if the dentry has been mounted
295 * while we waited on the wq_mutex. If it has,
296 * simply return success.
297 */
298 if (d_mountpoint(dentry))
299 return 0;
300 }
301 }
302
303 return 1;
304}
305
218int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, 306int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
219 enum autofs_notify notify) 307 enum autofs_notify notify)
220{ 308{
221 struct autofs_info *ino;
222 struct autofs_wait_queue *wq; 309 struct autofs_wait_queue *wq;
223 struct qstr qstr; 310 struct qstr qstr;
224 char *name; 311 char *name;
225 int status, type; 312 int status, ret, type;
226 313
227 /* In catatonic mode, we don't wait for nobody */ 314 /* In catatonic mode, we don't wait for nobody */
228 if (sbi->catatonic) 315 if (sbi->catatonic)
229 return -ENOENT; 316 return -ENOENT;
230 317
231 name = kmalloc(NAME_MAX + 1, GFP_KERNEL); 318 name = kmalloc(NAME_MAX + 1, GFP_KERNEL);
232 if (!name) 319 if (!name)
233 return -ENOMEM; 320 return -ENOMEM;
@@ -245,43 +332,15 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
245 qstr.name = name; 332 qstr.name = name;
246 qstr.hash = full_name_hash(name, qstr.len); 333 qstr.hash = full_name_hash(name, qstr.len);
247 334
248 if (mutex_lock_interruptible(&sbi->wq_mutex)) { 335 if (mutex_lock_interruptible(&sbi->wq_mutex))
249 kfree(qstr.name);
250 return -EINTR; 336 return -EINTR;
251 }
252
253 wq = autofs4_find_wait(sbi, &qstr);
254 ino = autofs4_dentry_ino(dentry);
255 if (!wq && ino && notify == NFY_NONE) {
256 /*
257 * Either we've betean the pending expire to post it's
258 * wait or it finished while we waited on the mutex.
259 * So we need to wait till either, the wait appears
260 * or the expire finishes.
261 */
262 337
263 while (ino->flags & AUTOFS_INF_EXPIRING) { 338 ret = validate_request(&wq, sbi, &qstr, dentry, notify);
264 mutex_unlock(&sbi->wq_mutex); 339 if (ret <= 0) {
265 schedule_timeout_interruptible(HZ/10); 340 if (ret == 0)
266 if (mutex_lock_interruptible(&sbi->wq_mutex)) {
267 kfree(qstr.name);
268 return -EINTR;
269 }
270 wq = autofs4_find_wait(sbi, &qstr);
271 if (wq)
272 break;
273 }
274
275 /*
276 * Not ideal but the status has already gone. Of the two
277 * cases where we wait on NFY_NONE neither depend on the
278 * return status of the wait.
279 */
280 if (!wq) {
281 kfree(qstr.name);
282 mutex_unlock(&sbi->wq_mutex); 341 mutex_unlock(&sbi->wq_mutex);
283 return 0; 342 kfree(qstr.name);
284 } 343 return ret;
285 } 344 }
286 345
287 if (!wq) { 346 if (!wq) {
@@ -392,9 +451,9 @@ int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_tok
392 } 451 }
393 452
394 *wql = wq->next; /* Unlink from chain */ 453 *wql = wq->next; /* Unlink from chain */
395 mutex_unlock(&sbi->wq_mutex);
396 kfree(wq->name.name); 454 kfree(wq->name.name);
397 wq->name.name = NULL; /* Do not wait on this queue */ 455 wq->name.name = NULL; /* Do not wait on this queue */
456 mutex_unlock(&sbi->wq_mutex);
398 457
399 wq->status = status; 458 wq->status = status;
400 459