Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: JFS: Free sbi memory in error path fs/sysv: dereferencing ERR_PTR() Fix double-free in logfs Fix the regression created by "set S_DEAD on unlink()..." commit
This commit is contained in:
commit
3f8bf8f0fd
8 changed files with 49 additions and 26 deletions
|
@ -380,6 +380,7 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
mutex_lock(&inode->i_mutex);
|
||||
dentry_unhash(dentry);
|
||||
if (usbfs_empty(dentry)) {
|
||||
dont_mount(dentry);
|
||||
drop_nlink(dentry->d_inode);
|
||||
drop_nlink(dentry->d_inode);
|
||||
dput(dentry);
|
||||
|
|
|
@ -645,6 +645,7 @@ static void detach_groups(struct config_group *group)
|
|||
|
||||
configfs_detach_group(sd->s_element);
|
||||
child->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(child);
|
||||
|
||||
mutex_unlock(&child->d_inode->i_mutex);
|
||||
|
||||
|
@ -840,6 +841,7 @@ static int configfs_attach_item(struct config_item *parent_item,
|
|||
mutex_lock(&dentry->d_inode->i_mutex);
|
||||
configfs_remove_dir(item);
|
||||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
d_delete(dentry);
|
||||
}
|
||||
|
@ -882,6 +884,7 @@ static int configfs_attach_group(struct config_item *parent_item,
|
|||
if (ret) {
|
||||
configfs_detach_item(item);
|
||||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
}
|
||||
configfs_adjust_dir_dirent_depth_after_populate(sd);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
|
@ -1725,6 +1728,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
|
|||
mutex_unlock(&configfs_symlink_mutex);
|
||||
configfs_detach_group(&group->cg_item);
|
||||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
|
||||
d_delete(dentry);
|
||||
|
|
|
@ -446,10 +446,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
/* initialize the mount flag and determine the default error handler */
|
||||
flag = JFS_ERR_REMOUNT_RO;
|
||||
|
||||
if (!parse_options((char *) data, sb, &newLVSize, &flag)) {
|
||||
kfree(sbi);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!parse_options((char *) data, sb, &newLVSize, &flag))
|
||||
goto out_kfree;
|
||||
sbi->flag = flag;
|
||||
|
||||
#ifdef CONFIG_JFS_POSIX_ACL
|
||||
|
@ -458,7 +456,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
|
||||
if (newLVSize) {
|
||||
printk(KERN_ERR "resize option for remount only\n");
|
||||
return -EINVAL;
|
||||
goto out_kfree;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -478,7 +476,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
inode = new_inode(sb);
|
||||
if (inode == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out_kfree;
|
||||
goto out_unload;
|
||||
}
|
||||
inode->i_ino = 0;
|
||||
inode->i_nlink = 1;
|
||||
|
@ -550,9 +548,10 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
make_bad_inode(sbi->direct_inode);
|
||||
iput(sbi->direct_inode);
|
||||
sbi->direct_inode = NULL;
|
||||
out_kfree:
|
||||
out_unload:
|
||||
if (sbi->nls_tab)
|
||||
unload_nls(sbi->nls_tab);
|
||||
out_kfree:
|
||||
kfree(sbi);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -333,27 +333,27 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt)
|
|||
goto fail;
|
||||
|
||||
sb->s_root = d_alloc_root(rootdir);
|
||||
if (!sb->s_root)
|
||||
goto fail2;
|
||||
if (!sb->s_root) {
|
||||
iput(rootdir);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
super->s_erase_page = alloc_pages(GFP_KERNEL, 0);
|
||||
if (!super->s_erase_page)
|
||||
goto fail2;
|
||||
goto fail;
|
||||
memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE);
|
||||
|
||||
/* FIXME: check for read-only mounts */
|
||||
err = logfs_make_writeable(sb);
|
||||
if (err)
|
||||
goto fail3;
|
||||
goto fail1;
|
||||
|
||||
log_super("LogFS: Finished mounting\n");
|
||||
simple_set_mnt(mnt, sb);
|
||||
return 0;
|
||||
|
||||
fail3:
|
||||
fail1:
|
||||
__free_page(super->s_erase_page);
|
||||
fail2:
|
||||
iput(rootdir);
|
||||
fail:
|
||||
iput(logfs_super(sb)->s_master_inode);
|
||||
return -EIO;
|
||||
|
|
21
fs/namei.c
21
fs/namei.c
|
@ -2176,8 +2176,10 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
error = security_inode_rmdir(dir, dentry);
|
||||
if (!error) {
|
||||
error = dir->i_op->rmdir(dir, dentry);
|
||||
if (!error)
|
||||
if (!error) {
|
||||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
}
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
|
@ -2261,7 +2263,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
|
|||
if (!error) {
|
||||
error = dir->i_op->unlink(dir, dentry);
|
||||
if (!error)
|
||||
dentry->d_inode->i_flags |= S_DEAD;
|
||||
dont_mount(dentry);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&dentry->d_inode->i_mutex);
|
||||
|
@ -2572,17 +2574,20 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
|
|||
return error;
|
||||
|
||||
target = new_dentry->d_inode;
|
||||
if (target) {
|
||||
if (target)
|
||||
mutex_lock(&target->i_mutex);
|
||||
dentry_unhash(new_dentry);
|
||||
}
|
||||
if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
|
||||
error = -EBUSY;
|
||||
else
|
||||
else {
|
||||
if (target)
|
||||
dentry_unhash(new_dentry);
|
||||
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||
}
|
||||
if (target) {
|
||||
if (!error)
|
||||
if (!error) {
|
||||
target->i_flags |= S_DEAD;
|
||||
dont_mount(new_dentry);
|
||||
}
|
||||
mutex_unlock(&target->i_mutex);
|
||||
if (d_unhashed(new_dentry))
|
||||
d_rehash(new_dentry);
|
||||
|
@ -2614,7 +2619,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
|
|||
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
|
||||
if (!error) {
|
||||
if (target)
|
||||
target->i_flags |= S_DEAD;
|
||||
dont_mount(new_dentry);
|
||||
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
|
||||
d_move(old_dentry, new_dentry);
|
||||
}
|
||||
|
|
|
@ -1432,7 +1432,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
|
|||
|
||||
err = -ENOENT;
|
||||
mutex_lock(&path->dentry->d_inode->i_mutex);
|
||||
if (IS_DEADDIR(path->dentry->d_inode))
|
||||
if (cant_mount(path->dentry))
|
||||
goto out_unlock;
|
||||
|
||||
err = security_sb_check_sb(mnt, path);
|
||||
|
@ -1623,7 +1623,7 @@ static int do_move_mount(struct path *path, char *old_name)
|
|||
|
||||
err = -ENOENT;
|
||||
mutex_lock(&path->dentry->d_inode->i_mutex);
|
||||
if (IS_DEADDIR(path->dentry->d_inode))
|
||||
if (cant_mount(path->dentry))
|
||||
goto out1;
|
||||
|
||||
if (d_unlinked(path->dentry))
|
||||
|
@ -2234,7 +2234,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
|
|||
if (!check_mnt(root.mnt))
|
||||
goto out2;
|
||||
error = -ENOENT;
|
||||
if (IS_DEADDIR(new.dentry->d_inode))
|
||||
if (cant_mount(old.dentry))
|
||||
goto out2;
|
||||
if (d_unlinked(new.dentry))
|
||||
goto out2;
|
||||
|
|
|
@ -164,8 +164,8 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_
|
|||
name, de->name))
|
||||
goto found;
|
||||
}
|
||||
dir_put_page(page);
|
||||
}
|
||||
dir_put_page(page);
|
||||
|
||||
if (++n >= npages)
|
||||
n = 0;
|
||||
|
|
|
@ -186,6 +186,8 @@ d_iput: no no no yes
|
|||
|
||||
#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 /* Parent inode is watched by some fsnotify listener */
|
||||
|
||||
#define DCACHE_CANT_MOUNT 0x0100
|
||||
|
||||
extern spinlock_t dcache_lock;
|
||||
extern seqlock_t rename_lock;
|
||||
|
||||
|
@ -358,6 +360,18 @@ static inline int d_unlinked(struct dentry *dentry)
|
|||
return d_unhashed(dentry) && !IS_ROOT(dentry);
|
||||
}
|
||||
|
||||
static inline int cant_mount(struct dentry *dentry)
|
||||
{
|
||||
return (dentry->d_flags & DCACHE_CANT_MOUNT);
|
||||
}
|
||||
|
||||
static inline void dont_mount(struct dentry *dentry)
|
||||
{
|
||||
spin_lock(&dentry->d_lock);
|
||||
dentry->d_flags |= DCACHE_CANT_MOUNT;
|
||||
spin_unlock(&dentry->d_lock);
|
||||
}
|
||||
|
||||
static inline struct dentry *dget_parent(struct dentry *dentry)
|
||||
{
|
||||
struct dentry *ret;
|
||||
|
|
Loading…
Reference in a new issue