[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>
This commit is contained in:
Al Viro 2005-06-06 13:36:13 -07:00 committed by Linus Torvalds
parent 39ca6d4975
commit 58c465eba4
1 changed files with 16 additions and 19 deletions

View File

@ -596,20 +596,17 @@ static int __follow_mount(struct path *path)
return res; return res;
} }
static int follow_mount(struct vfsmount **mnt, struct dentry **dentry) static void follow_mount(struct vfsmount **mnt, struct dentry **dentry)
{ {
int res = 0;
while (d_mountpoint(*dentry)) { while (d_mountpoint(*dentry)) {
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry); struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
if (!mounted) if (!mounted)
break; break;
dput(*dentry);
mntput(*mnt); mntput(*mnt);
*mnt = mounted; *mnt = mounted;
dput(*dentry);
*dentry = dget(mounted->mnt_root); *dentry = dget(mounted->mnt_root);
res = 1;
} }
return res;
} }
/* no need for dcache_lock, as serialization is taken care in /* no need for dcache_lock, as serialization is taken care in
@ -630,41 +627,41 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
return 0; return 0;
} }
static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry) static inline void follow_dotdot(struct nameidata *nd)
{ {
while(1) { while(1) {
struct vfsmount *parent; struct vfsmount *parent;
struct dentry *old = *dentry; struct dentry *old = nd->dentry;
read_lock(&current->fs->lock); read_lock(&current->fs->lock);
if (*dentry == current->fs->root && if (nd->dentry == current->fs->root &&
*mnt == current->fs->rootmnt) { nd->mnt == current->fs->rootmnt) {
read_unlock(&current->fs->lock); read_unlock(&current->fs->lock);
break; break;
} }
read_unlock(&current->fs->lock); read_unlock(&current->fs->lock);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
if (*dentry != (*mnt)->mnt_root) { if (nd->dentry != nd->mnt->mnt_root) {
*dentry = dget((*dentry)->d_parent); nd->dentry = dget(nd->dentry->d_parent);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
dput(old); dput(old);
break; break;
} }
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
parent = (*mnt)->mnt_parent; parent = nd->mnt->mnt_parent;
if (parent == *mnt) { if (parent == nd->mnt) {
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
break; break;
} }
mntget(parent); mntget(parent);
*dentry = dget((*mnt)->mnt_mountpoint); nd->dentry = dget(nd->mnt->mnt_mountpoint);
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
dput(old); dput(old);
mntput(*mnt); mntput(nd->mnt);
*mnt = parent; nd->mnt = parent;
} }
follow_mount(mnt, dentry); follow_mount(&nd->mnt, &nd->dentry);
} }
/* /*
@ -772,7 +769,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
case 2: case 2:
if (this.name[1] != '.') if (this.name[1] != '.')
break; break;
follow_dotdot(&nd->mnt, &nd->dentry); follow_dotdot(nd);
inode = nd->dentry->d_inode; inode = nd->dentry->d_inode;
/* fallthrough */ /* fallthrough */
case 1: case 1:
@ -839,7 +836,7 @@ last_component:
case 2: case 2:
if (this.name[1] != '.') if (this.name[1] != '.')
break; break;
follow_dotdot(&nd->mnt, &nd->dentry); follow_dotdot(nd);
inode = nd->dentry->d_inode; inode = nd->dentry->d_inode;
/* fallthrough */ /* fallthrough */
case 1: case 1: