aboutsummaryrefslogtreecommitdiffstats
path: root/fs/autofs4
diff options
context:
space:
mode:
authorIan Kent <raven@themaw.net>2011-01-14 13:46:03 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2011-01-15 20:07:38 -0500
commitb5b801779d59165c4ecf1009009109545bd1f642 (patch)
tree3a1c8b2e65e72977993ba96c1398edba4c63cbf5 /fs/autofs4
parent10584211e48036182212b598cc53331776406d60 (diff)
autofs4: Add d_manage() dentry operation
This patch required a previous patch to add the ->d_automount() dentry operation. Add a function to use the newly defined ->d_manage() dentry operation for blocking during mount and expire. Whether the VFS calls the dentry operations d_automount() and d_manage() is controled by the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags. autofs uses the d_automount() operation to callback to user space to request mount operations and the d_manage() operation to block walks into mounts that are under construction or destruction. In order to prevent these functions from being called unnecessarily the DMANAGED_* flags are cleared for cases which would cause this. In the common case the DMANAGED_AUTOMOUNT and DMANAGED_TRANSIT flags are both set for dentrys waiting to be mounted. The DMANAGED_TRANSIT flag is cleared upon successful mount request completion and set during expire runs, both during the dentry expire check, and if selected for expire, is left set until a subsequent successful mount request completes. The exception to this is the so-called rootless multi-mount which has no actual mount at its base. In this case the DMANAGED_AUTOMOUNT flag is cleared upon successful mount request completion as well and set again after a successful expire. Signed-off-by: Ian Kent <raven@themaw.net> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/autofs4')
-rw-r--r--fs/autofs4/autofs_i.h50
-rw-r--r--fs/autofs4/expire.c51
-rw-r--r--fs/autofs4/inode.c3
-rw-r--r--fs/autofs4/root.c95
4 files changed, 159 insertions, 40 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 1ebfe53872b5..f0c95e0460cf 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -99,7 +99,6 @@ struct autofs_info {
99}; 99};
100 100
101#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ 101#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
102#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */
103#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ 102#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */
104 103
105struct autofs_wait_queue { 104struct autofs_wait_queue {
@@ -221,6 +220,7 @@ extern const struct file_operations autofs4_root_operations;
221/* Operations methods */ 220/* Operations methods */
222 221
223struct vfsmount *autofs4_d_automount(struct path *); 222struct vfsmount *autofs4_d_automount(struct path *);
223int autofs4_d_manage(struct dentry *, bool);
224 224
225/* VFS automount flags management functions */ 225/* VFS automount flags management functions */
226 226
@@ -248,6 +248,54 @@ static inline void managed_dentry_clear_automount(struct dentry *dentry)
248 spin_unlock(&dentry->d_lock); 248 spin_unlock(&dentry->d_lock);
249} 249}
250 250
251static inline void __managed_dentry_set_transit(struct dentry *dentry)
252{
253 dentry->d_flags |= DCACHE_MANAGE_TRANSIT;
254}
255
256static inline void managed_dentry_set_transit(struct dentry *dentry)
257{
258 spin_lock(&dentry->d_lock);
259 __managed_dentry_set_transit(dentry);
260 spin_unlock(&dentry->d_lock);
261}
262
263static inline void __managed_dentry_clear_transit(struct dentry *dentry)
264{
265 dentry->d_flags &= ~DCACHE_MANAGE_TRANSIT;
266}
267
268static inline void managed_dentry_clear_transit(struct dentry *dentry)
269{
270 spin_lock(&dentry->d_lock);
271 __managed_dentry_clear_transit(dentry);
272 spin_unlock(&dentry->d_lock);
273}
274
275static inline void __managed_dentry_set_managed(struct dentry *dentry)
276{
277 dentry->d_flags |= (DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
278}
279
280static inline void managed_dentry_set_managed(struct dentry *dentry)
281{
282 spin_lock(&dentry->d_lock);
283 __managed_dentry_set_managed(dentry);
284 spin_unlock(&dentry->d_lock);
285}
286
287static inline void __managed_dentry_clear_managed(struct dentry *dentry)
288{
289 dentry->d_flags &= ~(DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT);
290}
291
292static inline void managed_dentry_clear_managed(struct dentry *dentry)
293{
294 spin_lock(&dentry->d_lock);
295 __managed_dentry_clear_managed(dentry);
296 spin_unlock(&dentry->d_lock);
297}
298
251/* Initializing function */ 299/* Initializing function */
252 300
253int autofs4_fill_super(struct super_block *, void *, int); 301int autofs4_fill_super(struct super_block *, void *, int);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 0571ec8352b7..3ed79d76c233 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -26,10 +26,6 @@ static inline int autofs4_can_expire(struct dentry *dentry,
26 if (ino == NULL) 26 if (ino == NULL)
27 return 0; 27 return 0;
28 28
29 /* No point expiring a pending mount */
30 if (ino->flags & AUTOFS_INF_PENDING)
31 return 0;
32
33 if (!do_now) { 29 if (!do_now) {
34 /* Too young to die */ 30 /* Too young to die */
35 if (!timeout || time_after(ino->last_used + timeout, now)) 31 if (!timeout || time_after(ino->last_used + timeout, now))
@@ -283,6 +279,7 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
283 unsigned long timeout; 279 unsigned long timeout;
284 struct dentry *root = dget(sb->s_root); 280 struct dentry *root = dget(sb->s_root);
285 int do_now = how & AUTOFS_EXP_IMMEDIATE; 281 int do_now = how & AUTOFS_EXP_IMMEDIATE;
282 struct autofs_info *ino;
286 283
287 if (!root) 284 if (!root)
288 return NULL; 285 return NULL;
@@ -291,20 +288,21 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
291 timeout = sbi->exp_timeout; 288 timeout = sbi->exp_timeout;
292 289
293 spin_lock(&sbi->fs_lock); 290 spin_lock(&sbi->fs_lock);
291 ino = autofs4_dentry_ino(root);
292 /* No point expiring a pending mount */
293 if (ino->flags & AUTOFS_INF_PENDING) {
294 spin_unlock(&sbi->fs_lock);
295 return NULL;
296 }
297 managed_dentry_set_transit(root);
294 if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { 298 if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
295 struct autofs_info *ino = autofs4_dentry_ino(root); 299 struct autofs_info *ino = autofs4_dentry_ino(root);
296 if (d_mountpoint(root)) {
297 ino->flags |= AUTOFS_INF_MOUNTPOINT;
298 spin_lock(&root->d_lock);
299 root->d_flags &= ~DCACHE_MOUNTED;
300 spin_unlock(&root->d_lock);
301 }
302 ino->flags |= AUTOFS_INF_EXPIRING; 300 ino->flags |= AUTOFS_INF_EXPIRING;
303 managed_dentry_set_automount(root);
304 init_completion(&ino->expire_complete); 301 init_completion(&ino->expire_complete);
305 spin_unlock(&sbi->fs_lock); 302 spin_unlock(&sbi->fs_lock);
306 return root; 303 return root;
307 } 304 }
305 managed_dentry_clear_transit(root);
308 spin_unlock(&sbi->fs_lock); 306 spin_unlock(&sbi->fs_lock);
309 dput(root); 307 dput(root);
310 308
@@ -341,6 +339,10 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
341 while ((dentry = get_next_positive_dentry(dentry, root))) { 339 while ((dentry = get_next_positive_dentry(dentry, root))) {
342 spin_lock(&sbi->fs_lock); 340 spin_lock(&sbi->fs_lock);
343 ino = autofs4_dentry_ino(dentry); 341 ino = autofs4_dentry_ino(dentry);
342 /* No point expiring a pending mount */
343 if (ino->flags & AUTOFS_INF_PENDING)
344 goto cont;
345 managed_dentry_set_transit(dentry);
344 346
345 /* 347 /*
346 * Case 1: (i) indirect mount or top level pseudo direct mount 348 * Case 1: (i) indirect mount or top level pseudo direct mount
@@ -400,6 +402,8 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
400 } 402 }
401 } 403 }
402next: 404next:
405 managed_dentry_clear_transit(dentry);
406cont:
403 spin_unlock(&sbi->fs_lock); 407 spin_unlock(&sbi->fs_lock);
404 } 408 }
405 return NULL; 409 return NULL;
@@ -409,7 +413,6 @@ found:
409 expired, (int)expired->d_name.len, expired->d_name.name); 413 expired, (int)expired->d_name.len, expired->d_name.name);
410 ino = autofs4_dentry_ino(expired); 414 ino = autofs4_dentry_ino(expired);
411 ino->flags |= AUTOFS_INF_EXPIRING; 415 ino->flags |= AUTOFS_INF_EXPIRING;
412 managed_dentry_set_automount(expired);
413 init_completion(&ino->expire_complete); 416 init_completion(&ino->expire_complete);
414 spin_unlock(&sbi->fs_lock); 417 spin_unlock(&sbi->fs_lock);
415 spin_lock(&autofs4_lock); 418 spin_lock(&autofs4_lock);
@@ -482,7 +485,7 @@ int autofs4_expire_run(struct super_block *sb,
482 ino = autofs4_dentry_ino(dentry); 485 ino = autofs4_dentry_ino(dentry);
483 ino->flags &= ~AUTOFS_INF_EXPIRING; 486 ino->flags &= ~AUTOFS_INF_EXPIRING;
484 if (!d_unhashed(dentry)) 487 if (!d_unhashed(dentry))
485 managed_dentry_clear_automount(dentry); 488 managed_dentry_clear_transit(dentry);
486 complete_all(&ino->expire_complete); 489 complete_all(&ino->expire_complete);
487 spin_unlock(&sbi->fs_lock); 490 spin_unlock(&sbi->fs_lock);
488 491
@@ -508,20 +511,18 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
508 ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); 511 ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
509 512
510 spin_lock(&sbi->fs_lock); 513 spin_lock(&sbi->fs_lock);
511 if (ino->flags & AUTOFS_INF_MOUNTPOINT) {
512 spin_lock(&sb->s_root->d_lock);
513 /*
514 * If we haven't been expired away, then reset
515 * mounted status.
516 */
517 if (mnt->mnt_parent != mnt)
518 sb->s_root->d_flags |= DCACHE_MOUNTED;
519 spin_unlock(&sb->s_root->d_lock);
520 ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
521 }
522 ino->flags &= ~AUTOFS_INF_EXPIRING; 514 ino->flags &= ~AUTOFS_INF_EXPIRING;
515 spin_lock(&dentry->d_lock);
523 if (ret) 516 if (ret)
524 managed_dentry_clear_automount(dentry); 517 __managed_dentry_clear_transit(dentry);
518 else {
519 if ((IS_ROOT(dentry) ||
520 (autofs_type_indirect(sbi->type) &&
521 IS_ROOT(dentry->d_parent))) &&
522 !(dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
523 __managed_dentry_set_automount(dentry);
524 }
525 spin_unlock(&dentry->d_lock);
525 complete_all(&ino->expire_complete); 526 complete_all(&ino->expire_complete);
526 spin_unlock(&sbi->fs_lock); 527 spin_unlock(&sbi->fs_lock);
527 dput(dentry); 528 dput(dentry);
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index d0aa38cac302..75c1ed8e2fb9 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -253,6 +253,7 @@ static struct autofs_info *autofs4_mkroot(struct autofs_sb_info *sbi)
253 253
254static const struct dentry_operations autofs4_sb_dentry_operations = { 254static const struct dentry_operations autofs4_sb_dentry_operations = {
255 .d_automount = autofs4_d_automount, 255 .d_automount = autofs4_d_automount,
256 .d_manage = autofs4_d_manage,
256 .d_release = autofs4_dentry_release, 257 .d_release = autofs4_dentry_release,
257}; 258};
258 259
@@ -322,7 +323,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
322 } 323 }
323 324
324 if (autofs_type_trigger(sbi->type)) 325 if (autofs_type_trigger(sbi->type))
325 __managed_dentry_set_automount(root); 326 __managed_dentry_set_managed(root);
326 327
327 root_inode->i_fop = &autofs4_root_operations; 328 root_inode->i_fop = &autofs4_root_operations;
328 root_inode->i_op = autofs_type_trigger(sbi->type) ? 329 root_inode->i_op = autofs_type_trigger(sbi->type) ?
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 27dc53e111fd..f1076b91a0fa 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -424,6 +424,7 @@ static const struct dentry_operations autofs4_root_dentry_operations = {
424/* For other dentries */ 424/* For other dentries */
425static const struct dentry_operations autofs4_dentry_operations = { 425static const struct dentry_operations autofs4_dentry_operations = {
426 .d_automount = autofs4_d_automount, 426 .d_automount = autofs4_d_automount,
427 .d_manage = autofs4_d_manage,
427 .d_release = autofs4_dentry_release, 428 .d_release = autofs4_dentry_release,
428}; 429};
429 430
@@ -604,6 +605,18 @@ struct vfsmount *autofs4_d_automount(struct path *path)
604 DPRINTK("dentry=%p %.*s", 605 DPRINTK("dentry=%p %.*s",
605 dentry, dentry->d_name.len, dentry->d_name.name); 606 dentry, dentry->d_name.len, dentry->d_name.name);
606 607
608 /*
609 * Someone may have manually umounted this or it was a submount
610 * that has gone away.
611 */
612 spin_lock(&dentry->d_lock);
613 if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
614 if (!(dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
615 (dentry->d_flags & DCACHE_NEED_AUTOMOUNT))
616 __managed_dentry_set_transit(path->dentry);
617 }
618 spin_unlock(&dentry->d_lock);
619
607 /* The daemon never triggers a mount. */ 620 /* The daemon never triggers a mount. */
608 if (autofs4_oz_mode(sbi)) 621 if (autofs4_oz_mode(sbi))
609 return NULL; 622 return NULL;
@@ -633,31 +646,63 @@ struct vfsmount *autofs4_d_automount(struct path *path)
633 646
634 /* 647 /*
635 * If the dentry is a symlink it's equivalent to a directory 648 * If the dentry is a symlink it's equivalent to a directory
636 * having d_mounted() true, so there's no need to call back 649 * having d_mountpoint() true, so there's no need to call back
637 * to the daemon. 650 * to the daemon.
638 */ 651 */
639 if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) 652 if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode))
640 goto done; 653 goto done;
641 spin_lock(&dentry->d_lock); 654 if (!d_mountpoint(dentry)) {
642 if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { 655 /*
656 * It's possible that user space hasn't removed directories
657 * after umounting a rootless multi-mount, although it
658 * should. For v5 have_submounts() is sufficient to handle
659 * this because the leaves of the directory tree under the
660 * mount never trigger mounts themselves (they have an autofs
661 * trigger mount mounted on them). But v4 pseudo direct mounts
662 * do need the leaves to to trigger mounts. In this case we
663 * have no choice but to use the list_empty() check and
664 * require user space behave.
665 */
666 if (sbi->version > 4) {
667 if (have_submounts(dentry))
668 goto done;
669 } else {
670 spin_lock(&dentry->d_lock);
671 if (!list_empty(&dentry->d_subdirs)) {
672 spin_unlock(&dentry->d_lock);
673 goto done;
674 }
675 spin_unlock(&dentry->d_lock);
676 }
643 ino->flags |= AUTOFS_INF_PENDING; 677 ino->flags |= AUTOFS_INF_PENDING;
644 spin_unlock(&dentry->d_lock);
645 spin_unlock(&sbi->fs_lock); 678 spin_unlock(&sbi->fs_lock);
646 status = autofs4_mount_wait(dentry); 679 status = autofs4_mount_wait(dentry);
647 if (status) 680 if (status)
648 return ERR_PTR(status); 681 return ERR_PTR(status);
649 spin_lock(&sbi->fs_lock); 682 spin_lock(&sbi->fs_lock);
650 ino->flags &= ~AUTOFS_INF_PENDING; 683 ino->flags &= ~AUTOFS_INF_PENDING;
651 goto done;
652 } 684 }
653 spin_unlock(&dentry->d_lock);
654done: 685done:
655 /* 686 if (!(ino->flags & AUTOFS_INF_EXPIRING)) {
656 * Any needed mounting has been completed and the path updated 687 /*
657 * so turn this into a normal dentry so we don't continually 688 * Any needed mounting has been completed and the path updated
658 * call ->d_automount(). 689 * so turn this into a normal dentry so we don't continually
659 */ 690 * call ->d_automount() and ->d_manage().
660 managed_dentry_clear_automount(dentry); 691 */
692 spin_lock(&dentry->d_lock);
693 __managed_dentry_clear_transit(dentry);
694 /*
695 * Only clear DMANAGED_AUTOMOUNT for rootless multi-mounts and
696 * symlinks as in all other cases the dentry will be covered by
697 * an actual mount so ->d_automount() won't be called during
698 * the follow.
699 */
700 if ((!d_mountpoint(dentry) &&
701 !list_empty(&dentry->d_subdirs)) ||
702 (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)))
703 __managed_dentry_clear_automount(dentry);
704 spin_unlock(&dentry->d_lock);
705 }
661 spin_unlock(&sbi->fs_lock); 706 spin_unlock(&sbi->fs_lock);
662 707
663 /* Mount succeeded, check if we ended up with a new dentry */ 708 /* Mount succeeded, check if we ended up with a new dentry */
@@ -668,6 +713,30 @@ done:
668 return NULL; 713 return NULL;
669} 714}
670 715
716int autofs4_d_manage(struct dentry *dentry, bool mounting_here)
717{
718 struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
719
720 DPRINTK("dentry=%p %.*s",
721 dentry, dentry->d_name.len, dentry->d_name.name);
722
723 /* The daemon never waits. */
724 if (autofs4_oz_mode(sbi) || mounting_here) {
725 if (!d_mountpoint(dentry))
726 return -EISDIR;
727 return 0;
728 }
729
730 /* Wait for pending expires */
731 do_expire_wait(dentry);
732
733 /*
734 * This dentry may be under construction so wait on mount
735 * completion.
736 */
737 return autofs4_mount_wait(dentry);
738}
739
671/* Lookups in the root directory */ 740/* Lookups in the root directory */
672static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) 741static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
673{ 742{
@@ -704,7 +773,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
704 /* Mark entries in the root as mount triggers */ 773 /* Mark entries in the root as mount triggers */
705 if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) { 774 if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) {
706 d_set_d_op(dentry, &autofs4_dentry_operations); 775 d_set_d_op(dentry, &autofs4_dentry_operations);
707 managed_dentry_set_automount(dentry); 776 __managed_dentry_set_managed(dentry);
708 } 777 }
709 778
710 ino = autofs4_init_ino(NULL, sbi, 0555); 779 ino = autofs4_init_ino(NULL, sbi, 0555);