diff options
author | Ian Kent <raven@themaw.net> | 2011-01-14 13:45:58 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2011-01-15 20:07:37 -0500 |
commit | 10584211e48036182212b598cc53331776406d60 (patch) | |
tree | b66067b47a1104c3ae3ccd4248c9b41d5b869c5e /fs/autofs4/root.c | |
parent | db3729153e82ba3ada89681f26c4f1b6d6807a80 (diff) |
autofs4: Add d_automount() dentry operation
Add a function to use the newly defined ->d_automount() dentry operation
for triggering mounts instead of doing the user space callback in ->lookup()
and ->d_revalidate().
Note, to be useful the subsequent patch to add the ->d_manage() dentry
operation is also needed so the discussion of functionality is deferred to
that patch.
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/root.c')
-rw-r--r-- | fs/autofs4/root.c | 261 |
1 files changed, 149 insertions, 112 deletions
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 20225636a4e9..27dc53e111fd 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
@@ -35,7 +35,6 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long); | |||
35 | #endif | 35 | #endif |
36 | static int autofs4_dir_open(struct inode *inode, struct file *file); | 36 | static int autofs4_dir_open(struct inode *inode, struct file *file); |
37 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 37 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
38 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); | ||
39 | 38 | ||
40 | #define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) | 39 | #define TRIGGER_FLAGS (LOOKUP_CONTINUE | LOOKUP_DIRECTORY) |
41 | #define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE) | 40 | #define TRIGGER_INTENTS (LOOKUP_OPEN | LOOKUP_CREATE) |
@@ -73,7 +72,6 @@ const struct inode_operations autofs4_direct_root_inode_operations = { | |||
73 | .unlink = autofs4_dir_unlink, | 72 | .unlink = autofs4_dir_unlink, |
74 | .mkdir = autofs4_dir_mkdir, | 73 | .mkdir = autofs4_dir_mkdir, |
75 | .rmdir = autofs4_dir_rmdir, | 74 | .rmdir = autofs4_dir_rmdir, |
76 | .follow_link = autofs4_follow_link, | ||
77 | }; | 75 | }; |
78 | 76 | ||
79 | const struct inode_operations autofs4_dir_inode_operations = { | 77 | const struct inode_operations autofs4_dir_inode_operations = { |
@@ -420,13 +418,12 @@ void autofs4_dentry_release(struct dentry *de) | |||
420 | 418 | ||
421 | /* For dentries of directories in the root dir */ | 419 | /* For dentries of directories in the root dir */ |
422 | static const struct dentry_operations autofs4_root_dentry_operations = { | 420 | static const struct dentry_operations autofs4_root_dentry_operations = { |
423 | .d_revalidate = autofs4_revalidate, | ||
424 | .d_release = autofs4_dentry_release, | 421 | .d_release = autofs4_dentry_release, |
425 | }; | 422 | }; |
426 | 423 | ||
427 | /* For other dentries */ | 424 | /* For other dentries */ |
428 | static const struct dentry_operations autofs4_dentry_operations = { | 425 | static const struct dentry_operations autofs4_dentry_operations = { |
429 | .d_revalidate = autofs4_revalidate, | 426 | .d_automount = autofs4_d_automount, |
430 | .d_release = autofs4_dentry_release, | 427 | .d_release = autofs4_dentry_release, |
431 | }; | 428 | }; |
432 | 429 | ||
@@ -540,50 +537,176 @@ next: | |||
540 | return NULL; | 537 | return NULL; |
541 | } | 538 | } |
542 | 539 | ||
540 | static int autofs4_mount_wait(struct dentry *dentry) | ||
541 | { | ||
542 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
543 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
544 | int status; | ||
545 | |||
546 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
547 | DPRINTK("waiting for mount name=%.*s", | ||
548 | dentry->d_name.len, dentry->d_name.name); | ||
549 | status = autofs4_wait(sbi, dentry, NFY_MOUNT); | ||
550 | DPRINTK("mount wait done status=%d", status); | ||
551 | ino->last_used = jiffies; | ||
552 | return status; | ||
553 | } | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int do_expire_wait(struct dentry *dentry) | ||
558 | { | ||
559 | struct dentry *expiring; | ||
560 | |||
561 | expiring = autofs4_lookup_expiring(dentry); | ||
562 | if (!expiring) | ||
563 | return autofs4_expire_wait(dentry); | ||
564 | else { | ||
565 | /* | ||
566 | * If we are racing with expire the request might not | ||
567 | * be quite complete, but the directory has been removed | ||
568 | * so it must have been successful, just wait for it. | ||
569 | */ | ||
570 | autofs4_expire_wait(expiring); | ||
571 | autofs4_del_expiring(expiring); | ||
572 | dput(expiring); | ||
573 | } | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static struct dentry *autofs4_mountpoint_changed(struct path *path) | ||
578 | { | ||
579 | struct dentry *dentry = path->dentry; | ||
580 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
581 | |||
582 | /* | ||
583 | * If this is an indirect mount the dentry could have gone away | ||
584 | * as a result of an expire and a new one created. | ||
585 | */ | ||
586 | if (autofs_type_indirect(sbi->type) && d_unhashed(dentry)) { | ||
587 | struct dentry *parent = dentry->d_parent; | ||
588 | struct dentry *new = d_lookup(parent, &dentry->d_name); | ||
589 | if (!new) | ||
590 | return NULL; | ||
591 | dput(path->dentry); | ||
592 | path->dentry = new; | ||
593 | } | ||
594 | return path->dentry; | ||
595 | } | ||
596 | |||
597 | struct vfsmount *autofs4_d_automount(struct path *path) | ||
598 | { | ||
599 | struct dentry *dentry = path->dentry; | ||
600 | struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); | ||
601 | struct autofs_info *ino = autofs4_dentry_ino(dentry); | ||
602 | int status; | ||
603 | |||
604 | DPRINTK("dentry=%p %.*s", | ||
605 | dentry, dentry->d_name.len, dentry->d_name.name); | ||
606 | |||
607 | /* The daemon never triggers a mount. */ | ||
608 | if (autofs4_oz_mode(sbi)) | ||
609 | return NULL; | ||
610 | |||
611 | /* | ||
612 | * If an expire request is pending everyone must wait. | ||
613 | * If the expire fails we're still mounted so continue | ||
614 | * the follow and return. A return of -EAGAIN (which only | ||
615 | * happens with indirect mounts) means the expire completed | ||
616 | * and the directory was removed, so just go ahead and try | ||
617 | * the mount. | ||
618 | */ | ||
619 | status = do_expire_wait(dentry); | ||
620 | if (status && status != -EAGAIN) | ||
621 | return NULL; | ||
622 | |||
623 | /* Callback to the daemon to perform the mount or wait */ | ||
624 | spin_lock(&sbi->fs_lock); | ||
625 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
626 | spin_unlock(&sbi->fs_lock); | ||
627 | status = autofs4_mount_wait(dentry); | ||
628 | if (status) | ||
629 | return ERR_PTR(status); | ||
630 | spin_lock(&sbi->fs_lock); | ||
631 | goto done; | ||
632 | } | ||
633 | |||
634 | /* | ||
635 | * 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 | ||
637 | * to the daemon. | ||
638 | */ | ||
639 | if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) | ||
640 | goto done; | ||
641 | spin_lock(&dentry->d_lock); | ||
642 | if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { | ||
643 | ino->flags |= AUTOFS_INF_PENDING; | ||
644 | spin_unlock(&dentry->d_lock); | ||
645 | spin_unlock(&sbi->fs_lock); | ||
646 | status = autofs4_mount_wait(dentry); | ||
647 | if (status) | ||
648 | return ERR_PTR(status); | ||
649 | spin_lock(&sbi->fs_lock); | ||
650 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
651 | goto done; | ||
652 | } | ||
653 | spin_unlock(&dentry->d_lock); | ||
654 | done: | ||
655 | /* | ||
656 | * Any needed mounting has been completed and the path updated | ||
657 | * so turn this into a normal dentry so we don't continually | ||
658 | * call ->d_automount(). | ||
659 | */ | ||
660 | managed_dentry_clear_automount(dentry); | ||
661 | spin_unlock(&sbi->fs_lock); | ||
662 | |||
663 | /* Mount succeeded, check if we ended up with a new dentry */ | ||
664 | dentry = autofs4_mountpoint_changed(path); | ||
665 | if (!dentry) | ||
666 | return ERR_PTR(-ENOENT); | ||
667 | |||
668 | return NULL; | ||
669 | } | ||
670 | |||
543 | /* Lookups in the root directory */ | 671 | /* Lookups in the root directory */ |
544 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 672 | static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
545 | { | 673 | { |
546 | struct autofs_sb_info *sbi; | 674 | struct autofs_sb_info *sbi; |
547 | struct autofs_info *ino; | 675 | struct autofs_info *ino; |
548 | struct dentry *expiring, *active; | 676 | struct dentry *active; |
549 | int oz_mode; | ||
550 | 677 | ||
551 | DPRINTK("name = %.*s", | 678 | DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name); |
552 | dentry->d_name.len, dentry->d_name.name); | ||
553 | 679 | ||
554 | /* File name too long to exist */ | 680 | /* File name too long to exist */ |
555 | if (dentry->d_name.len > NAME_MAX) | 681 | if (dentry->d_name.len > NAME_MAX) |
556 | return ERR_PTR(-ENAMETOOLONG); | 682 | return ERR_PTR(-ENAMETOOLONG); |
557 | 683 | ||
558 | sbi = autofs4_sbi(dir->i_sb); | 684 | sbi = autofs4_sbi(dir->i_sb); |
559 | oz_mode = autofs4_oz_mode(sbi); | ||
560 | 685 | ||
561 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", | 686 | DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", |
562 | current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); | 687 | current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); |
563 | 688 | ||
564 | active = autofs4_lookup_active(dentry); | 689 | active = autofs4_lookup_active(dentry); |
565 | if (active) { | 690 | if (active) { |
566 | dentry = active; | 691 | return active; |
567 | ino = autofs4_dentry_ino(dentry); | ||
568 | } else { | 692 | } else { |
569 | /* | ||
570 | * Mark the dentry incomplete but don't hash it. We do this | ||
571 | * to serialize our inode creation operations (symlink and | ||
572 | * mkdir) which prevents deadlock during the callback to | ||
573 | * the daemon. Subsequent user space lookups for the same | ||
574 | * dentry are placed on the wait queue while the daemon | ||
575 | * itself is allowed passage unresticted so the create | ||
576 | * operation itself can then hash the dentry. Finally, | ||
577 | * we check for the hashed dentry and return the newly | ||
578 | * hashed dentry. | ||
579 | */ | ||
580 | d_set_d_op(dentry, &autofs4_root_dentry_operations); | 693 | d_set_d_op(dentry, &autofs4_root_dentry_operations); |
581 | 694 | ||
582 | /* | 695 | /* |
583 | * And we need to ensure that the same dentry is used for | 696 | * A dentry that is not within the root can never trigger a |
584 | * all following lookup calls until it is hashed so that | 697 | * mount operation, unless the directory already exists, so we |
585 | * the dentry flags are persistent throughout the request. | 698 | * can return fail immediately. The daemon however does need |
699 | * to create directories within the file system. | ||
586 | */ | 700 | */ |
701 | if (!autofs4_oz_mode(sbi) && !IS_ROOT(dentry->d_parent)) | ||
702 | return ERR_PTR(-ENOENT); | ||
703 | |||
704 | /* Mark entries in the root as mount triggers */ | ||
705 | if (autofs_type_indirect(sbi->type) && IS_ROOT(dentry->d_parent)) { | ||
706 | d_set_d_op(dentry, &autofs4_dentry_operations); | ||
707 | managed_dentry_set_automount(dentry); | ||
708 | } | ||
709 | |||
587 | ino = autofs4_init_ino(NULL, sbi, 0555); | 710 | ino = autofs4_init_ino(NULL, sbi, 0555); |
588 | if (!ino) | 711 | if (!ino) |
589 | return ERR_PTR(-ENOMEM); | 712 | return ERR_PTR(-ENOMEM); |
@@ -595,82 +718,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s | |||
595 | 718 | ||
596 | d_instantiate(dentry, NULL); | 719 | d_instantiate(dentry, NULL); |
597 | } | 720 | } |
598 | |||
599 | if (!oz_mode) { | ||
600 | mutex_unlock(&dir->i_mutex); | ||
601 | expiring = autofs4_lookup_expiring(dentry); | ||
602 | if (expiring) { | ||
603 | /* | ||
604 | * If we are racing with expire the request might not | ||
605 | * be quite complete but the directory has been removed | ||
606 | * so it must have been successful, so just wait for it. | ||
607 | */ | ||
608 | autofs4_expire_wait(expiring); | ||
609 | autofs4_del_expiring(expiring); | ||
610 | dput(expiring); | ||
611 | } | ||
612 | |||
613 | spin_lock(&sbi->fs_lock); | ||
614 | ino->flags |= AUTOFS_INF_PENDING; | ||
615 | spin_unlock(&sbi->fs_lock); | ||
616 | if (dentry->d_op && dentry->d_op->d_revalidate) | ||
617 | (dentry->d_op->d_revalidate)(dentry, nd); | ||
618 | mutex_lock(&dir->i_mutex); | ||
619 | } | ||
620 | |||
621 | /* | ||
622 | * If we are still pending, check if we had to handle | ||
623 | * a signal. If so we can force a restart.. | ||
624 | */ | ||
625 | if (ino->flags & AUTOFS_INF_PENDING) { | ||
626 | /* See if we were interrupted */ | ||
627 | if (signal_pending(current)) { | ||
628 | sigset_t *sigset = ¤t->pending.signal; | ||
629 | if (sigismember (sigset, SIGKILL) || | ||
630 | sigismember (sigset, SIGQUIT) || | ||
631 | sigismember (sigset, SIGINT)) { | ||
632 | if (active) | ||
633 | dput(active); | ||
634 | return ERR_PTR(-ERESTARTNOINTR); | ||
635 | } | ||
636 | } | ||
637 | if (!oz_mode) { | ||
638 | spin_lock(&sbi->fs_lock); | ||
639 | ino->flags &= ~AUTOFS_INF_PENDING; | ||
640 | spin_unlock(&sbi->fs_lock); | ||
641 | } | ||
642 | } | ||
643 | |||
644 | /* | ||
645 | * If this dentry is unhashed, then we shouldn't honour this | ||
646 | * lookup. Returning ENOENT here doesn't do the right thing | ||
647 | * for all system calls, but it should be OK for the operations | ||
648 | * we permit from an autofs. | ||
649 | */ | ||
650 | if (!oz_mode && d_unhashed(dentry)) { | ||
651 | /* | ||
652 | * A user space application can (and has done in the past) | ||
653 | * remove and re-create this directory during the callback. | ||
654 | * This can leave us with an unhashed dentry, but a | ||
655 | * successful mount! So we need to perform another | ||
656 | * cached lookup in case the dentry now exists. | ||
657 | */ | ||
658 | struct dentry *parent = dentry->d_parent; | ||
659 | struct dentry *new = d_lookup(parent, &dentry->d_name); | ||
660 | if (new != NULL) | ||
661 | dentry = new; | ||
662 | else | ||
663 | dentry = ERR_PTR(-ENOENT); | ||
664 | |||
665 | if (active) | ||
666 | dput(active); | ||
667 | |||
668 | return dentry; | ||
669 | } | ||
670 | |||
671 | if (active) | ||
672 | return active; | ||
673 | |||
674 | return NULL; | 721 | return NULL; |
675 | } | 722 | } |
676 | 723 | ||
@@ -715,11 +762,6 @@ static int autofs4_dir_symlink(struct inode *dir, | |||
715 | } | 762 | } |
716 | d_add(dentry, inode); | 763 | d_add(dentry, inode); |
717 | 764 | ||
718 | if (dir == dir->i_sb->s_root->d_inode) | ||
719 | d_set_d_op(dentry, &autofs4_root_dentry_operations); | ||
720 | else | ||
721 | d_set_d_op(dentry, &autofs4_dentry_operations); | ||
722 | |||
723 | dentry->d_fsdata = ino; | 765 | dentry->d_fsdata = ino; |
724 | ino->dentry = dget(dentry); | 766 | ino->dentry = dget(dentry); |
725 | atomic_inc(&ino->count); | 767 | atomic_inc(&ino->count); |
@@ -850,11 +892,6 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
850 | } | 892 | } |
851 | d_add(dentry, inode); | 893 | d_add(dentry, inode); |
852 | 894 | ||
853 | if (dir == dir->i_sb->s_root->d_inode) | ||
854 | d_set_d_op(dentry, &autofs4_root_dentry_operations); | ||
855 | else | ||
856 | d_set_d_op(dentry, &autofs4_dentry_operations); | ||
857 | |||
858 | dentry->d_fsdata = ino; | 895 | dentry->d_fsdata = ino; |
859 | ino->dentry = dget(dentry); | 896 | ino->dentry = dget(dentry); |
860 | atomic_inc(&ino->count); | 897 | atomic_inc(&ino->count); |