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:
Linus Torvalds 2010-05-15 09:03:15 -07:00
commit 3f8bf8f0fd
8 changed files with 49 additions and 26 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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;
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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;

View file

@ -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;