Commit 3f8bf8f0 authored by Linus Torvalds's avatar Linus Torvalds

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
parents c28f3f86 684bdc7f
...@@ -380,6 +380,7 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -380,6 +380,7 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
dentry_unhash(dentry); dentry_unhash(dentry);
if (usbfs_empty(dentry)) { if (usbfs_empty(dentry)) {
dont_mount(dentry);
drop_nlink(dentry->d_inode); drop_nlink(dentry->d_inode);
drop_nlink(dentry->d_inode); drop_nlink(dentry->d_inode);
dput(dentry); dput(dentry);
......
...@@ -645,6 +645,7 @@ static void detach_groups(struct config_group *group) ...@@ -645,6 +645,7 @@ static void detach_groups(struct config_group *group)
configfs_detach_group(sd->s_element); configfs_detach_group(sd->s_element);
child->d_inode->i_flags |= S_DEAD; child->d_inode->i_flags |= S_DEAD;
dont_mount(child);
mutex_unlock(&child->d_inode->i_mutex); mutex_unlock(&child->d_inode->i_mutex);
...@@ -840,6 +841,7 @@ static int configfs_attach_item(struct config_item *parent_item, ...@@ -840,6 +841,7 @@ static int configfs_attach_item(struct config_item *parent_item,
mutex_lock(&dentry->d_inode->i_mutex); mutex_lock(&dentry->d_inode->i_mutex);
configfs_remove_dir(item); configfs_remove_dir(item);
dentry->d_inode->i_flags |= S_DEAD; dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry);
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
d_delete(dentry); d_delete(dentry);
} }
...@@ -882,6 +884,7 @@ static int configfs_attach_group(struct config_item *parent_item, ...@@ -882,6 +884,7 @@ static int configfs_attach_group(struct config_item *parent_item,
if (ret) { if (ret) {
configfs_detach_item(item); configfs_detach_item(item);
dentry->d_inode->i_flags |= S_DEAD; dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry);
} }
configfs_adjust_dir_dirent_depth_after_populate(sd); configfs_adjust_dir_dirent_depth_after_populate(sd);
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
...@@ -1725,6 +1728,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) ...@@ -1725,6 +1728,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
mutex_unlock(&configfs_symlink_mutex); mutex_unlock(&configfs_symlink_mutex);
configfs_detach_group(&group->cg_item); configfs_detach_group(&group->cg_item);
dentry->d_inode->i_flags |= S_DEAD; dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry);
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
d_delete(dentry); d_delete(dentry);
......
...@@ -446,10 +446,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -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 */ /* initialize the mount flag and determine the default error handler */
flag = JFS_ERR_REMOUNT_RO; flag = JFS_ERR_REMOUNT_RO;
if (!parse_options((char *) data, sb, &newLVSize, &flag)) { if (!parse_options((char *) data, sb, &newLVSize, &flag))
kfree(sbi); goto out_kfree;
return -EINVAL;
}
sbi->flag = flag; sbi->flag = flag;
#ifdef CONFIG_JFS_POSIX_ACL #ifdef CONFIG_JFS_POSIX_ACL
...@@ -458,7 +456,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) ...@@ -458,7 +456,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
if (newLVSize) { if (newLVSize) {
printk(KERN_ERR "resize option for remount only\n"); 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) ...@@ -478,7 +476,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
inode = new_inode(sb); inode = new_inode(sb);
if (inode == NULL) { if (inode == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto out_kfree; goto out_unload;
} }
inode->i_ino = 0; inode->i_ino = 0;
inode->i_nlink = 1; inode->i_nlink = 1;
...@@ -550,9 +548,10 @@ out_mount_failed: ...@@ -550,9 +548,10 @@ out_mount_failed:
make_bad_inode(sbi->direct_inode); make_bad_inode(sbi->direct_inode);
iput(sbi->direct_inode); iput(sbi->direct_inode);
sbi->direct_inode = NULL; sbi->direct_inode = NULL;
out_kfree: out_unload:
if (sbi->nls_tab) if (sbi->nls_tab)
unload_nls(sbi->nls_tab); unload_nls(sbi->nls_tab);
out_kfree:
kfree(sbi); kfree(sbi);
return ret; return ret;
} }
......
...@@ -333,27 +333,27 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) ...@@ -333,27 +333,27 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt)
goto fail; goto fail;
sb->s_root = d_alloc_root(rootdir); sb->s_root = d_alloc_root(rootdir);
if (!sb->s_root) if (!sb->s_root) {
goto fail2; iput(rootdir);
goto fail;
}
super->s_erase_page = alloc_pages(GFP_KERNEL, 0); super->s_erase_page = alloc_pages(GFP_KERNEL, 0);
if (!super->s_erase_page) if (!super->s_erase_page)
goto fail2; goto fail;
memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE); memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE);
/* FIXME: check for read-only mounts */ /* FIXME: check for read-only mounts */
err = logfs_make_writeable(sb); err = logfs_make_writeable(sb);
if (err) if (err)
goto fail3; goto fail1;
log_super("LogFS: Finished mounting\n"); log_super("LogFS: Finished mounting\n");
simple_set_mnt(mnt, sb); simple_set_mnt(mnt, sb);
return 0; return 0;
fail3: fail1:
__free_page(super->s_erase_page); __free_page(super->s_erase_page);
fail2:
iput(rootdir);
fail: fail:
iput(logfs_super(sb)->s_master_inode); iput(logfs_super(sb)->s_master_inode);
return -EIO; return -EIO;
......
...@@ -2176,8 +2176,10 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -2176,8 +2176,10 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
error = security_inode_rmdir(dir, dentry); error = security_inode_rmdir(dir, dentry);
if (!error) { if (!error) {
error = dir->i_op->rmdir(dir, dentry); error = dir->i_op->rmdir(dir, dentry);
if (!error) if (!error) {
dentry->d_inode->i_flags |= S_DEAD; dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry);
}
} }
} }
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
...@@ -2261,7 +2263,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -2261,7 +2263,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
if (!error) { if (!error) {
error = dir->i_op->unlink(dir, dentry); error = dir->i_op->unlink(dir, dentry);
if (!error) if (!error)
dentry->d_inode->i_flags |= S_DEAD; dont_mount(dentry);
} }
} }
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
...@@ -2572,17 +2574,20 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry, ...@@ -2572,17 +2574,20 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
return error; return error;
target = new_dentry->d_inode; target = new_dentry->d_inode;
if (target) { if (target)
mutex_lock(&target->i_mutex); mutex_lock(&target->i_mutex);
dentry_unhash(new_dentry);
}
if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
error = -EBUSY; error = -EBUSY;
else else {
if (target)
dentry_unhash(new_dentry);
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
}
if (target) { if (target) {
if (!error) if (!error) {
target->i_flags |= S_DEAD; target->i_flags |= S_DEAD;
dont_mount(new_dentry);
}
mutex_unlock(&target->i_mutex); mutex_unlock(&target->i_mutex);
if (d_unhashed(new_dentry)) if (d_unhashed(new_dentry))
d_rehash(new_dentry); d_rehash(new_dentry);
...@@ -2614,7 +2619,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_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); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (!error) { if (!error) {
if (target) 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)) if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
d_move(old_dentry, new_dentry); d_move(old_dentry, new_dentry);
} }
......
...@@ -1432,7 +1432,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) ...@@ -1432,7 +1432,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
err = -ENOENT; err = -ENOENT;
mutex_lock(&path->dentry->d_inode->i_mutex); mutex_lock(&path->dentry->d_inode->i_mutex);
if (IS_DEADDIR(path->dentry->d_inode)) if (cant_mount(path->dentry))
goto out_unlock; goto out_unlock;
err = security_sb_check_sb(mnt, path); err = security_sb_check_sb(mnt, path);
...@@ -1623,7 +1623,7 @@ static int do_move_mount(struct path *path, char *old_name) ...@@ -1623,7 +1623,7 @@ static int do_move_mount(struct path *path, char *old_name)
err = -ENOENT; err = -ENOENT;
mutex_lock(&path->dentry->d_inode->i_mutex); mutex_lock(&path->dentry->d_inode->i_mutex);
if (IS_DEADDIR(path->dentry->d_inode)) if (cant_mount(path->dentry))
goto out1; goto out1;
if (d_unlinked(path->dentry)) if (d_unlinked(path->dentry))
...@@ -2234,7 +2234,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, ...@@ -2234,7 +2234,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
if (!check_mnt(root.mnt)) if (!check_mnt(root.mnt))
goto out2; goto out2;
error = -ENOENT; error = -ENOENT;
if (IS_DEADDIR(new.dentry->d_inode)) if (cant_mount(old.dentry))
goto out2; goto out2;
if (d_unlinked(new.dentry)) if (d_unlinked(new.dentry))
goto out2; goto out2;
......
...@@ -164,8 +164,8 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_ ...@@ -164,8 +164,8 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_
name, de->name)) name, de->name))
goto found; goto found;
} }
dir_put_page(page);
} }
dir_put_page(page);
if (++n >= npages) if (++n >= npages)
n = 0; n = 0;
......
...@@ -186,6 +186,8 @@ d_iput: no no no yes ...@@ -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_FSNOTIFY_PARENT_WATCHED 0x0080 /* Parent inode is watched by some fsnotify listener */
#define DCACHE_CANT_MOUNT 0x0100
extern spinlock_t dcache_lock; extern spinlock_t dcache_lock;
extern seqlock_t rename_lock; extern seqlock_t rename_lock;
...@@ -358,6 +360,18 @@ static inline int d_unlinked(struct dentry *dentry) ...@@ -358,6 +360,18 @@ static inline int d_unlinked(struct dentry *dentry)
return d_unhashed(dentry) && !IS_ROOT(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) static inline struct dentry *dget_parent(struct dentry *dentry)
{ {
struct dentry *ret; struct dentry *ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment