aboutsummaryrefslogtreecommitdiffstats
path: root/fs/autofs4/expire.c
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2008-07-24 00:30:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:32 -0400
commit97e7449a7ad883bf9f516fc970778d75999c7843 (patch)
tree903f6de243847eb12d1a372b271b15046ecdc774 /fs/autofs4/expire.c
parent26e81b3142f1ba497d4cd0365c13661684b784ce (diff)
autofs4: fix indirect mount pending expire race
The selection of a dentry for expiration and the setting of the AUTOFS_INF_EXPIRING flag isn't done atomically which can lead to lookups walking into an expiring mount. What happens is that an expire is initiated by the daemon and a dentry is selected for expire but, since there is no lock held between the selection and setting of the expiring flag, a process may find the flag clear and continue walking into the mount tree at the same time the daemon attempts the expire it. Signed-off-by: Ian Kent <raven@themaw.net> Reviewed-by: Jeff Moyer <jmoyer@redhat.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/autofs4/expire.c')
-rw-r--r--fs/autofs4/expire.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 894fee54d4d8..19f5bea2704f 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -292,6 +292,8 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
292 struct list_head *next; 292 struct list_head *next;
293 int do_now = how & AUTOFS_EXP_IMMEDIATE; 293 int do_now = how & AUTOFS_EXP_IMMEDIATE;
294 int exp_leaves = how & AUTOFS_EXP_LEAVES; 294 int exp_leaves = how & AUTOFS_EXP_LEAVES;
295 struct autofs_info *ino;
296 unsigned int ino_count;
295 297
296 if (!root) 298 if (!root)
297 return NULL; 299 return NULL;
@@ -316,6 +318,9 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
316 dentry = dget(dentry); 318 dentry = dget(dentry);
317 spin_unlock(&dcache_lock); 319 spin_unlock(&dcache_lock);
318 320
321 spin_lock(&sbi->fs_lock);
322 ino = autofs4_dentry_ino(dentry);
323
319 /* 324 /*
320 * Case 1: (i) indirect mount or top level pseudo direct mount 325 * Case 1: (i) indirect mount or top level pseudo direct mount
321 * (autofs-4.1). 326 * (autofs-4.1).
@@ -326,6 +331,11 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
326 DPRINTK("checking mountpoint %p %.*s", 331 DPRINTK("checking mountpoint %p %.*s",
327 dentry, (int)dentry->d_name.len, dentry->d_name.name); 332 dentry, (int)dentry->d_name.len, dentry->d_name.name);
328 333
334 /* Path walk currently on this dentry? */
335 ino_count = atomic_read(&ino->count) + 2;
336 if (atomic_read(&dentry->d_count) > ino_count)
337 goto next;
338
329 /* Can we umount this guy */ 339 /* Can we umount this guy */
330 if (autofs4_mount_busy(mnt, dentry)) 340 if (autofs4_mount_busy(mnt, dentry))
331 goto next; 341 goto next;
@@ -343,23 +353,25 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
343 353
344 /* Case 2: tree mount, expire iff entire tree is not busy */ 354 /* Case 2: tree mount, expire iff entire tree is not busy */
345 if (!exp_leaves) { 355 if (!exp_leaves) {
346 /* Lock the tree as we must expire as a whole */ 356 /* Path walk currently on this dentry? */
347 spin_lock(&sbi->fs_lock); 357 ino_count = atomic_read(&ino->count) + 1;
348 if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) { 358 if (atomic_read(&dentry->d_count) > ino_count)
349 struct autofs_info *inf = autofs4_dentry_ino(dentry); 359 goto next;
350 360
351 /* Set this flag early to catch sys_chdir and the like */ 361 if (!autofs4_tree_busy(mnt, dentry, timeout, do_now)) {
352 inf->flags |= AUTOFS_INF_EXPIRING;
353 spin_unlock(&sbi->fs_lock);
354 expired = dentry; 362 expired = dentry;
355 goto found; 363 goto found;
356 } 364 }
357 spin_unlock(&sbi->fs_lock);
358 /* 365 /*
359 * Case 3: pseudo direct mount, expire individual leaves 366 * Case 3: pseudo direct mount, expire individual leaves
360 * (autofs-4.1). 367 * (autofs-4.1).
361 */ 368 */
362 } else { 369 } else {
370 /* Path walk currently on this dentry? */
371 ino_count = atomic_read(&ino->count) + 1;
372 if (atomic_read(&dentry->d_count) > ino_count)
373 goto next;
374
363 expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); 375 expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
364 if (expired) { 376 if (expired) {
365 dput(dentry); 377 dput(dentry);
@@ -367,6 +379,7 @@ static struct dentry *autofs4_expire_indirect(struct super_block *sb,
367 } 379 }
368 } 380 }
369next: 381next:
382 spin_unlock(&sbi->fs_lock);
370 dput(dentry); 383 dput(dentry);
371 spin_lock(&dcache_lock); 384 spin_lock(&dcache_lock);
372 next = next->next; 385 next = next->next;
@@ -377,6 +390,9 @@ next:
377found: 390found:
378 DPRINTK("returning %p %.*s", 391 DPRINTK("returning %p %.*s",
379 expired, (int)expired->d_name.len, expired->d_name.name); 392 expired, (int)expired->d_name.len, expired->d_name.name);
393 ino = autofs4_dentry_ino(expired);
394 ino->flags |= AUTOFS_INF_EXPIRING;
395 spin_unlock(&sbi->fs_lock);
380 spin_lock(&dcache_lock); 396 spin_lock(&dcache_lock);
381 list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); 397 list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
382 spin_unlock(&dcache_lock); 398 spin_unlock(&dcache_lock);
@@ -390,7 +406,9 @@ int autofs4_expire_run(struct super_block *sb,
390 struct autofs_packet_expire __user *pkt_p) 406 struct autofs_packet_expire __user *pkt_p)
391{ 407{
392 struct autofs_packet_expire pkt; 408 struct autofs_packet_expire pkt;
409 struct autofs_info *ino;
393 struct dentry *dentry; 410 struct dentry *dentry;
411 int ret = 0;
394 412
395 memset(&pkt,0,sizeof pkt); 413 memset(&pkt,0,sizeof pkt);
396 414
@@ -406,9 +424,14 @@ int autofs4_expire_run(struct super_block *sb,
406 dput(dentry); 424 dput(dentry);
407 425
408 if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) ) 426 if ( copy_to_user(pkt_p, &pkt, sizeof(struct autofs_packet_expire)) )
409 return -EFAULT; 427 ret = -EFAULT;
410 428
411 return 0; 429 spin_lock(&sbi->fs_lock);
430 ino = autofs4_dentry_ino(dentry);
431 ino->flags &= ~AUTOFS_INF_EXPIRING;
432 spin_unlock(&sbi->fs_lock);
433
434 return ret;
412} 435}
413 436
414/* Call repeatedly until it returns -EAGAIN, meaning there's nothing 437/* Call repeatedly until it returns -EAGAIN, meaning there's nothing
@@ -433,9 +456,10 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt,
433 456
434 /* This is synchronous because it makes the daemon a 457 /* This is synchronous because it makes the daemon a
435 little easier */ 458 little easier */
436 ino->flags |= AUTOFS_INF_EXPIRING;
437 ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); 459 ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
460 spin_lock(&sbi->fs_lock);
438 ino->flags &= ~AUTOFS_INF_EXPIRING; 461 ino->flags &= ~AUTOFS_INF_EXPIRING;
462 spin_unlock(&sbi->fs_lock);
439 dput(dentry); 463 dput(dentry);
440 } 464 }
441 465