aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@www.linux.org.uk>2005-06-06 16:36:06 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-06-06 17:42:26 -0400
commite13b210f6f7bdc44dfee0a9bbd633a32db0d6333 (patch)
treef957ec2fc24f8a9eb84dcffe76341262c1acedf0 /fs
parent463ffb2e9d39c2a3fd8c3c1d4a34e01f2078f972 (diff)
[PATCH] namei fixes (10/19)
In open_namei(), __follow_down() loop turned into __follow_mount(). Instead of if we are on a mountpoint dentry if O_NOFOLLOW checks fail drop path.dentry drop nd return do equivalent of follow_mount(&path.mnt, &path.dentry) nd->mnt = path.mnt we do if __follow_mount(path) had, indeed, traversed mountpoint /* now both nd->mnt and path.mnt are pinned down */ if O_NOFOLLOW checks fail drop path.dentry drop path.mnt drop nd return mntput(nd->mnt) nd->mnt = path.mnt Now __follow_down() can be folded into follow_down() - no other callers left. We need to reorder dput()/mntput() there - same problem as in follow_mount(). Equivalent transformation + fix for a bug in O_NOFOLLOW handling - we used to get -ELOOP if we had the same fs mounted on /foo and /bar, had something bound on /bar/baz and tried to open /foo/baz with O_NOFOLLOW. And fix of too-early-mntput() race in follow_down() 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.c20
1 files changed, 9 insertions, 11 deletions
diff --git a/fs/namei.c b/fs/namei.c
index 23a1ad467976..935b08d8dcd8 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -612,26 +612,21 @@ static int follow_mount(struct vfsmount **mnt, struct dentry **dentry)
612/* no need for dcache_lock, as serialization is taken care in 612/* no need for dcache_lock, as serialization is taken care in
613 * namespace.c 613 * namespace.c
614 */ 614 */
615static inline int __follow_down(struct vfsmount **mnt, struct dentry **dentry) 615int follow_down(struct vfsmount **mnt, struct dentry **dentry)
616{ 616{
617 struct vfsmount *mounted; 617 struct vfsmount *mounted;
618 618
619 mounted = lookup_mnt(*mnt, *dentry); 619 mounted = lookup_mnt(*mnt, *dentry);
620 if (mounted) { 620 if (mounted) {
621 dput(*dentry);
621 mntput(*mnt); 622 mntput(*mnt);
622 *mnt = mounted; 623 *mnt = mounted;
623 dput(*dentry);
624 *dentry = dget(mounted->mnt_root); 624 *dentry = dget(mounted->mnt_root);
625 return 1; 625 return 1;
626 } 626 }
627 return 0; 627 return 0;
628} 628}
629 629
630int follow_down(struct vfsmount **mnt, struct dentry **dentry)
631{
632 return __follow_down(mnt,dentry);
633}
634
635static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) 630static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
636{ 631{
637 while(1) { 632 while(1) {
@@ -1498,11 +1493,14 @@ do_last:
1498 if (flag & O_EXCL) 1493 if (flag & O_EXCL)
1499 goto exit_dput; 1494 goto exit_dput;
1500 1495
1501 if (d_mountpoint(path.dentry)) { 1496 if (__follow_mount(&path)) {
1502 error = -ELOOP; 1497 error = -ELOOP;
1503 if (flag & O_NOFOLLOW) 1498 if (flag & O_NOFOLLOW) {
1504 goto exit_dput; 1499 dput(path.dentry);
1505 while (__follow_down(&path.mnt,&path.dentry) && d_mountpoint(path.dentry)); 1500 mntput(path.mnt);
1501 goto exit;
1502 }
1503 mntput(nd->mnt);
1506 nd->mnt = path.mnt; 1504 nd->mnt = path.mnt;
1507 } 1505 }
1508 error = -ENOENT; 1506 error = -ENOENT;