mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
[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:
parent
39ca6d4975
commit
58c465eba4
1 changed files with 16 additions and 19 deletions
35
fs/namei.c
35
fs/namei.c
|
@ -596,20 +596,17 @@ static int __follow_mount(struct path *path)
|
|||
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)) {
|
||||
struct vfsmount *mounted = lookup_mnt(*mnt, *dentry);
|
||||
if (!mounted)
|
||||
break;
|
||||
dput(*dentry);
|
||||
mntput(*mnt);
|
||||
*mnt = mounted;
|
||||
dput(*dentry);
|
||||
*dentry = dget(mounted->mnt_root);
|
||||
res = 1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
static inline void follow_dotdot(struct vfsmount **mnt, struct dentry **dentry)
|
||||
static inline void follow_dotdot(struct nameidata *nd)
|
||||
{
|
||||
while(1) {
|
||||
struct vfsmount *parent;
|
||||
struct dentry *old = *dentry;
|
||||
struct dentry *old = nd->dentry;
|
||||
|
||||
read_lock(¤t->fs->lock);
|
||||
if (*dentry == current->fs->root &&
|
||||
*mnt == current->fs->rootmnt) {
|
||||
if (nd->dentry == current->fs->root &&
|
||||
nd->mnt == current->fs->rootmnt) {
|
||||
read_unlock(¤t->fs->lock);
|
||||
break;
|
||||
}
|
||||
read_unlock(¤t->fs->lock);
|
||||
spin_lock(&dcache_lock);
|
||||
if (*dentry != (*mnt)->mnt_root) {
|
||||
*dentry = dget((*dentry)->d_parent);
|
||||
if (nd->dentry != nd->mnt->mnt_root) {
|
||||
nd->dentry = dget(nd->dentry->d_parent);
|
||||
spin_unlock(&dcache_lock);
|
||||
dput(old);
|
||||
break;
|
||||
}
|
||||
spin_unlock(&dcache_lock);
|
||||
spin_lock(&vfsmount_lock);
|
||||
parent = (*mnt)->mnt_parent;
|
||||
if (parent == *mnt) {
|
||||
parent = nd->mnt->mnt_parent;
|
||||
if (parent == nd->mnt) {
|
||||
spin_unlock(&vfsmount_lock);
|
||||
break;
|
||||
}
|
||||
mntget(parent);
|
||||
*dentry = dget((*mnt)->mnt_mountpoint);
|
||||
nd->dentry = dget(nd->mnt->mnt_mountpoint);
|
||||
spin_unlock(&vfsmount_lock);
|
||||
dput(old);
|
||||
mntput(*mnt);
|
||||
*mnt = parent;
|
||||
mntput(nd->mnt);
|
||||
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:
|
||||
if (this.name[1] != '.')
|
||||
break;
|
||||
follow_dotdot(&nd->mnt, &nd->dentry);
|
||||
follow_dotdot(nd);
|
||||
inode = nd->dentry->d_inode;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
|
@ -839,7 +836,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
|
|||
case 2:
|
||||
if (this.name[1] != '.')
|
||||
break;
|
||||
follow_dotdot(&nd->mnt, &nd->dentry);
|
||||
follow_dotdot(nd);
|
||||
inode = nd->dentry->d_inode;
|
||||
/* fallthrough */
|
||||
case 1:
|
||||
|
|
Loading…
Reference in a new issue