diff options
Diffstat (limited to 'fs/namei.c')
-rw-r--r-- | fs/namei.c | 19 |
1 files changed, 3 insertions, 16 deletions
diff --git a/fs/namei.c b/fs/namei.c index b20f83d1e065..3df2ed50ab57 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -689,33 +689,20 @@ static __always_inline void follow_dotdot(struct nameidata *nd) | |||
689 | set_root(nd); | 689 | set_root(nd); |
690 | 690 | ||
691 | while(1) { | 691 | while(1) { |
692 | struct vfsmount *parent; | ||
693 | struct dentry *old = nd->path.dentry; | 692 | struct dentry *old = nd->path.dentry; |
694 | 693 | ||
695 | if (nd->path.dentry == nd->root.dentry && | 694 | if (nd->path.dentry == nd->root.dentry && |
696 | nd->path.mnt == nd->root.mnt) { | 695 | nd->path.mnt == nd->root.mnt) { |
697 | break; | 696 | break; |
698 | } | 697 | } |
699 | spin_lock(&dcache_lock); | ||
700 | if (nd->path.dentry != nd->path.mnt->mnt_root) { | 698 | if (nd->path.dentry != nd->path.mnt->mnt_root) { |
701 | nd->path.dentry = dget(nd->path.dentry->d_parent); | 699 | /* rare case of legitimate dget_parent()... */ |
702 | spin_unlock(&dcache_lock); | 700 | nd->path.dentry = dget_parent(nd->path.dentry); |
703 | dput(old); | 701 | dput(old); |
704 | break; | 702 | break; |
705 | } | 703 | } |
706 | spin_unlock(&dcache_lock); | 704 | if (!follow_up(&nd->path)) |
707 | spin_lock(&vfsmount_lock); | ||
708 | parent = nd->path.mnt->mnt_parent; | ||
709 | if (parent == nd->path.mnt) { | ||
710 | spin_unlock(&vfsmount_lock); | ||
711 | break; | 705 | break; |
712 | } | ||
713 | mntget(parent); | ||
714 | nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint); | ||
715 | spin_unlock(&vfsmount_lock); | ||
716 | dput(old); | ||
717 | mntput(nd->path.mnt); | ||
718 | nd->path.mnt = parent; | ||
719 | } | 706 | } |
720 | follow_mount(&nd->path); | 707 | follow_mount(&nd->path); |
721 | } | 708 | } |