forked from Minki/linux
affs_lookup(): close a race with affs_remove_link()
we unlock the directory hash too early - if we are looking at secondary link and primary (in another directory) gets removed just as we unlock, we could have the old primary moved in place of the secondary, leaving us to look into freed entry (and leaving our dentry with ->d_fsdata pointing to a freed entry). Cc: stable@vger.kernel.org # 2.4.4+ Acked-by: David Sterba <dsterba@suse.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
parent
b127125d9d
commit
30da870ce4
@ -206,9 +206,10 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
|||||||
|
|
||||||
affs_lock_dir(dir);
|
affs_lock_dir(dir);
|
||||||
bh = affs_find_entry(dir, dentry);
|
bh = affs_find_entry(dir, dentry);
|
||||||
affs_unlock_dir(dir);
|
if (IS_ERR(bh)) {
|
||||||
if (IS_ERR(bh))
|
affs_unlock_dir(dir);
|
||||||
return ERR_CAST(bh);
|
return ERR_CAST(bh);
|
||||||
|
}
|
||||||
if (bh) {
|
if (bh) {
|
||||||
u32 ino = bh->b_blocknr;
|
u32 ino = bh->b_blocknr;
|
||||||
|
|
||||||
@ -222,10 +223,13 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
|||||||
}
|
}
|
||||||
affs_brelse(bh);
|
affs_brelse(bh);
|
||||||
inode = affs_iget(sb, ino);
|
inode = affs_iget(sb, ino);
|
||||||
if (IS_ERR(inode))
|
if (IS_ERR(inode)) {
|
||||||
|
affs_unlock_dir(dir);
|
||||||
return ERR_CAST(inode);
|
return ERR_CAST(inode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
d_add(dentry, inode);
|
d_add(dentry, inode);
|
||||||
|
affs_unlock_dir(dir);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user