diff options
author | Al Viro <viro@www.linux.org.uk> | 2005-06-06 16:36:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-06 17:42:27 -0400 |
commit | 58c465eba4d7ed307c4c7cb3382ba7ee565e8858 (patch) | |
tree | f147af3fee122ec5cc054ac78fa30e1490a8acd0 /fs | |
parent | 39ca6d49759346d4710c759d443eec8048b27213 (diff) |
[PATCH] namei fixes (17/19)
follow_mount() made void, reordered dput()/mntput() in it.
follow_dotdot() switched from struct vfmount ** + struct dentry ** to
struct nameidata *; callers updated.
Equivalent transformation + fix for too-early-mntput() race.
Signed-off-by: Al Viro <viro@parcelfarce.linux.theplanet.co.uk>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/namei.c | 35 |
1 files changed, 16 insertions, 19 deletions
diff --git a/fs/namei.c b/fs/namei.c index 444086d441e1..36925ff307b3 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -596,20 +596,17 @@ static int __follow_mount(struct path *path) | |||
596 | return res; | 596 | return res; |
597 | } | 597 | } |
598 | 598 | ||
599 | static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) | 599 | static void follow_mount(struct vfsmount **mnt, struct dentry **dentry) |
600 | { | 600 | { |
601 | int res = 0; | ||
602 | while (d_mountpoint(*dentry)) { | 601 | while (d_mountpoint(*dentry)) { |
603 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); | 602 | struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); |
604 | if (!mounted) | 603 | if (!mounted) |
605 | break; | 604 | break; |
605 | dput(*dentry); | ||
606 | mntput(*mnt); | 606 | mntput(*mnt); |
607 | *mnt = mounted; | 607 | *mnt = mounted; |
608 | dput(*dentry); | ||
609 | *dentry = dget(mounted->mnt_root); | 608 | *dentry = dget(mounted->mnt_root); |
610 | res = 1; | ||
611 | } | 609 | } |
612 | return res; | ||
613 | } | 610 | } |
614 | 611 | ||
615 | /* no need for dcache_lock, as serialization is taken care in | 612 | /* no need for dcache_lock, as serialization is taken care in |
@@ -630,41 +627,41 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry) | |||
630 | return 0; | 627 | return 0; |
631 | } | 628 | } |
632 | 629 | ||
633 | static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) | 630 | static inline void follow_dotdot(struct nameidata *nd) |
634 | { | 631 | { |
635 | while(1) { | 632 | while(1) { |
636 | struct vfsmount *parent; | 633 | struct vfsmount *parent; |
637 | struct dentry *old = *dentry; | 634 | struct dentry *old = nd->dentry; |
638 | 635 | ||
639 | read_lock(¤t->fs->lock); | 636 | read_lock(¤t->fs->lock); |
640 | if (*dentry == current->fs->root && | 637 | if (nd->dentry == current->fs->root && |
641 | *mnt == current->fs->rootmnt) { | 638 | nd->mnt == current->fs->rootmnt) { |
642 | read_unlock(¤t->fs->lock); | 639 | read_unlock(¤t->fs->lock); |
643 | break; | 640 | break; |
644 | } | 641 | } |
645 | read_unlock(¤t->fs->lock); | 642 | read_unlock(¤t->fs->lock); |
646 | spin_lock(&dcache_lock); | 643 | spin_lock(&dcache_lock); |
647 | if (*dentry != (*mnt)->mnt_root) { | 644 | if (nd->dentry != nd->mnt->mnt_root) { |
648 | *dentry = dget((*dentry)->d_parent); | 645 | nd->dentry = dget(nd->dentry->d_parent); |
649 | spin_unlock(&dcache_lock); | 646 | spin_unlock(&dcache_lock); |
650 | dput(old); | 647 | dput(old); |
651 | break; | 648 | break; |
652 | } | 649 | } |
653 | spin_unlock(&dcache_lock); | 650 | spin_unlock(&dcache_lock); |
654 | spin_lock(&vfsmount_lock); | 651 | spin_lock(&vfsmount_lock); |
655 | parent = (*mnt)->mnt_parent; | 652 | parent = nd->mnt->mnt_parent; |
656 | if (parent == *mnt) { | 653 | if (parent == nd->mnt) { |
657 | spin_unlock(&vfsmount_lock); | 654 | spin_unlock(&vfsmount_lock); |
658 | break; | 655 | break; |
659 | } | 656 | } |
660 | mntget(parent); | 657 | mntget(parent); |
661 | *dentry = dget((*mnt)->mnt_mountpoint); | 658 | nd->dentry = dget(nd->mnt->mnt_mountpoint); |
662 | spin_unlock(&vfsmount_lock); | 659 | spin_unlock(&vfsmount_lock); |
663 | dput(old); | 660 | dput(old); |
664 | mntput(*mnt); | 661 | mntput(nd->mnt); |
665 | *mnt = parent; | 662 | nd->mnt = parent; |
666 | } | 663 | } |
667 | follow_mount(mnt, dentry); | 664 | follow_mount(&nd->mnt, &nd->dentry); |
668 | } | 665 | } |
669 | 666 | ||
670 | /* | 667 | /* |
@@ -772,7 +769,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd) | |||
772 | case 2: | 769 | case 2: |
773 | if (this.name[1] != '.') | 770 | if (this.name[1] != '.') |
774 | break; | 771 | break; |
775 | follow_dotdot(&nd->mnt, &nd->dentry); | 772 | follow_dotdot(nd); |
776 | inode = nd->dentry->d_inode; | 773 | inode = nd->dentry->d_inode; |
777 | /* fallthrough */ | 774 | /* fallthrough */ |
778 | case 1: | 775 | case 1: |
@@ -839,7 +836,7 @@ last_component: | |||
839 | case 2: | 836 | case 2: |
840 | if (this.name[1] != '.') | 837 | if (this.name[1] != '.') |
841 | break; | 838 | break; |
842 | follow_dotdot(&nd->mnt, &nd->dentry); | 839 | follow_dotdot(nd); |
843 | inode = nd->dentry->d_inode; | 840 | inode = nd->dentry->d_inode; |
844 | /* fallthrough */ | 841 | /* fallthrough */ |
845 | case 1: | 842 | case 1: |