diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-15 12:03:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-15 12:03:15 -0400 |
commit | 3f8bf8f0fd79410fbcbf9dd9910dbc9d4882c94f (patch) | |
tree | 86792764365ca7b40a21e5eb8fc4f7b355088535 | |
parent | c28f3f8660697d03afbdb581781b94ff6222a585 (diff) | |
parent | 684bdc7ff95e0c1d4b0bcf236491840b55a54189 (diff) |
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
-rw-r--r-- | drivers/usb/core/inode.c | 1 | ||||
-rw-r--r-- | fs/configfs/dir.c | 4 | ||||
-rw-r--r-- | fs/jfs/super.c | 13 | ||||
-rw-r--r-- | fs/logfs/super.c | 14 | ||||
-rw-r--r-- | fs/namei.c | 21 | ||||
-rw-r--r-- | fs/namespace.c | 6 | ||||
-rw-r--r-- | fs/sysv/dir.c | 2 | ||||
-rw-r--r-- | include/linux/dcache.h | 14 |
8 files changed, 49 insertions, 26 deletions
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index 4a6366a42129..111a01a747fc 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c | |||
@@ -380,6 +380,7 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
380 | mutex_lock(&inode->i_mutex); | 380 | mutex_lock(&inode->i_mutex); |
381 | dentry_unhash(dentry); | 381 | dentry_unhash(dentry); |
382 | if (usbfs_empty(dentry)) { | 382 | if (usbfs_empty(dentry)) { |
383 | dont_mount(dentry); | ||
383 | drop_nlink(dentry->d_inode); | 384 | drop_nlink(dentry->d_inode); |
384 | drop_nlink(dentry->d_inode); | 385 | drop_nlink(dentry->d_inode); |
385 | dput(dentry); | 386 | dput(dentry); |
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 8e48b52205aa..0b502f80c691 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c | |||
@@ -645,6 +645,7 @@ static void detach_groups(struct config_group *group) | |||
645 | 645 | ||
646 | configfs_detach_group(sd->s_element); | 646 | configfs_detach_group(sd->s_element); |
647 | child->d_inode->i_flags |= S_DEAD; | 647 | child->d_inode->i_flags |= S_DEAD; |
648 | dont_mount(child); | ||
648 | 649 | ||
649 | mutex_unlock(&child->d_inode->i_mutex); | 650 | mutex_unlock(&child->d_inode->i_mutex); |
650 | 651 | ||
@@ -840,6 +841,7 @@ static int configfs_attach_item(struct config_item *parent_item, | |||
840 | mutex_lock(&dentry->d_inode->i_mutex); | 841 | mutex_lock(&dentry->d_inode->i_mutex); |
841 | configfs_remove_dir(item); | 842 | configfs_remove_dir(item); |
842 | dentry->d_inode->i_flags |= S_DEAD; | 843 | dentry->d_inode->i_flags |= S_DEAD; |
844 | dont_mount(dentry); | ||
843 | mutex_unlock(&dentry->d_inode->i_mutex); | 845 | mutex_unlock(&dentry->d_inode->i_mutex); |
844 | d_delete(dentry); | 846 | d_delete(dentry); |
845 | } | 847 | } |
@@ -882,6 +884,7 @@ static int configfs_attach_group(struct config_item *parent_item, | |||
882 | if (ret) { | 884 | if (ret) { |
883 | configfs_detach_item(item); | 885 | configfs_detach_item(item); |
884 | dentry->d_inode->i_flags |= S_DEAD; | 886 | dentry->d_inode->i_flags |= S_DEAD; |
887 | dont_mount(dentry); | ||
885 | } | 888 | } |
886 | configfs_adjust_dir_dirent_depth_after_populate(sd); | 889 | configfs_adjust_dir_dirent_depth_after_populate(sd); |
887 | mutex_unlock(&dentry->d_inode->i_mutex); | 890 | mutex_unlock(&dentry->d_inode->i_mutex); |
@@ -1725,6 +1728,7 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys) | |||
1725 | mutex_unlock(&configfs_symlink_mutex); | 1728 | mutex_unlock(&configfs_symlink_mutex); |
1726 | configfs_detach_group(&group->cg_item); | 1729 | configfs_detach_group(&group->cg_item); |
1727 | dentry->d_inode->i_flags |= S_DEAD; | 1730 | dentry->d_inode->i_flags |= S_DEAD; |
1731 | dont_mount(dentry); | ||
1728 | mutex_unlock(&dentry->d_inode->i_mutex); | 1732 | mutex_unlock(&dentry->d_inode->i_mutex); |
1729 | 1733 | ||
1730 | d_delete(dentry); | 1734 | d_delete(dentry); |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 157382fa6256..b66832ac33ac 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
@@ -446,10 +446,8 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) | |||
446 | /* initialize the mount flag and determine the default error handler */ | 446 | /* initialize the mount flag and determine the default error handler */ |
447 | flag = JFS_ERR_REMOUNT_RO; | 447 | flag = JFS_ERR_REMOUNT_RO; |
448 | 448 | ||
449 | if (!parse_options((char *) data, sb, &newLVSize, &flag)) { | 449 | if (!parse_options((char *) data, sb, &newLVSize, &flag)) |
450 | kfree(sbi); | 450 | goto out_kfree; |
451 | return -EINVAL; | ||
452 | } | ||
453 | sbi->flag = flag; | 451 | sbi->flag = flag; |
454 | 452 | ||
455 | #ifdef CONFIG_JFS_POSIX_ACL | 453 | #ifdef CONFIG_JFS_POSIX_ACL |
@@ -458,7 +456,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) | |||
458 | 456 | ||
459 | if (newLVSize) { | 457 | if (newLVSize) { |
460 | printk(KERN_ERR "resize option for remount only\n"); | 458 | printk(KERN_ERR "resize option for remount only\n"); |
461 | return -EINVAL; | 459 | goto out_kfree; |
462 | } | 460 | } |
463 | 461 | ||
464 | /* | 462 | /* |
@@ -478,7 +476,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) | |||
478 | inode = new_inode(sb); | 476 | inode = new_inode(sb); |
479 | if (inode == NULL) { | 477 | if (inode == NULL) { |
480 | ret = -ENOMEM; | 478 | ret = -ENOMEM; |
481 | goto out_kfree; | 479 | goto out_unload; |
482 | } | 480 | } |
483 | inode->i_ino = 0; | 481 | inode->i_ino = 0; |
484 | inode->i_nlink = 1; | 482 | inode->i_nlink = 1; |
@@ -550,9 +548,10 @@ out_mount_failed: | |||
550 | make_bad_inode(sbi->direct_inode); | 548 | make_bad_inode(sbi->direct_inode); |
551 | iput(sbi->direct_inode); | 549 | iput(sbi->direct_inode); |
552 | sbi->direct_inode = NULL; | 550 | sbi->direct_inode = NULL; |
553 | out_kfree: | 551 | out_unload: |
554 | if (sbi->nls_tab) | 552 | if (sbi->nls_tab) |
555 | unload_nls(sbi->nls_tab); | 553 | unload_nls(sbi->nls_tab); |
554 | out_kfree: | ||
556 | kfree(sbi); | 555 | kfree(sbi); |
557 | return ret; | 556 | return ret; |
558 | } | 557 | } |
diff --git a/fs/logfs/super.c b/fs/logfs/super.c index 5866ee6e1327..d7c23ed8349a 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c | |||
@@ -333,27 +333,27 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) | |||
333 | goto fail; | 333 | goto fail; |
334 | 334 | ||
335 | sb->s_root = d_alloc_root(rootdir); | 335 | sb->s_root = d_alloc_root(rootdir); |
336 | if (!sb->s_root) | 336 | if (!sb->s_root) { |
337 | goto fail2; | 337 | iput(rootdir); |
338 | goto fail; | ||
339 | } | ||
338 | 340 | ||
339 | super->s_erase_page = alloc_pages(GFP_KERNEL, 0); | 341 | super->s_erase_page = alloc_pages(GFP_KERNEL, 0); |
340 | if (!super->s_erase_page) | 342 | if (!super->s_erase_page) |
341 | goto fail2; | 343 | goto fail; |
342 | memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE); | 344 | memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE); |
343 | 345 | ||
344 | /* FIXME: check for read-only mounts */ | 346 | /* FIXME: check for read-only mounts */ |
345 | err = logfs_make_writeable(sb); | 347 | err = logfs_make_writeable(sb); |
346 | if (err) | 348 | if (err) |
347 | goto fail3; | 349 | goto fail1; |
348 | 350 | ||
349 | log_super("LogFS: Finished mounting\n"); | 351 | log_super("LogFS: Finished mounting\n"); |
350 | simple_set_mnt(mnt, sb); | 352 | simple_set_mnt(mnt, sb); |
351 | return 0; | 353 | return 0; |
352 | 354 | ||
353 | fail3: | 355 | fail1: |
354 | __free_page(super->s_erase_page); | 356 | __free_page(super->s_erase_page); |
355 | fail2: | ||
356 | iput(rootdir); | ||
357 | fail: | 357 | fail: |
358 | iput(logfs_super(sb)->s_master_inode); | 358 | iput(logfs_super(sb)->s_master_inode); |
359 | return -EIO; | 359 | return -EIO; |
diff --git a/fs/namei.c b/fs/namei.c index 16df7277a92e..b86b96fe1dc3 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
@@ -2176,8 +2176,10 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry) | |||
2176 | error = security_inode_rmdir(dir, dentry); | 2176 | error = security_inode_rmdir(dir, dentry); |
2177 | if (!error) { | 2177 | if (!error) { |
2178 | error = dir->i_op->rmdir(dir, dentry); | 2178 | error = dir->i_op->rmdir(dir, dentry); |
2179 | if (!error) | 2179 | if (!error) { |
2180 | dentry->d_inode->i_flags |= S_DEAD; | 2180 | dentry->d_inode->i_flags |= S_DEAD; |
2181 | dont_mount(dentry); | ||
2182 | } | ||
2181 | } | 2183 | } |
2182 | } | 2184 | } |
2183 | mutex_unlock(&dentry->d_inode->i_mutex); | 2185 | mutex_unlock(&dentry->d_inode->i_mutex); |
@@ -2261,7 +2263,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) | |||
2261 | if (!error) { | 2263 | if (!error) { |
2262 | error = dir->i_op->unlink(dir, dentry); | 2264 | error = dir->i_op->unlink(dir, dentry); |
2263 | if (!error) | 2265 | if (!error) |
2264 | dentry->d_inode->i_flags |= S_DEAD; | 2266 | dont_mount(dentry); |
2265 | } | 2267 | } |
2266 | } | 2268 | } |
2267 | mutex_unlock(&dentry->d_inode->i_mutex); | 2269 | 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 | return error; | 2574 | return error; |
2573 | 2575 | ||
2574 | target = new_dentry->d_inode; | 2576 | target = new_dentry->d_inode; |
2575 | if (target) { | 2577 | if (target) |
2576 | mutex_lock(&target->i_mutex); | 2578 | mutex_lock(&target->i_mutex); |
2577 | dentry_unhash(new_dentry); | ||
2578 | } | ||
2579 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) | 2579 | if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry)) |
2580 | error = -EBUSY; | 2580 | error = -EBUSY; |
2581 | else | 2581 | else { |
2582 | if (target) | ||
2583 | dentry_unhash(new_dentry); | ||
2582 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 2584 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |
2585 | } | ||
2583 | if (target) { | 2586 | if (target) { |
2584 | if (!error) | 2587 | if (!error) { |
2585 | target->i_flags |= S_DEAD; | 2588 | target->i_flags |= S_DEAD; |
2589 | dont_mount(new_dentry); | ||
2590 | } | ||
2586 | mutex_unlock(&target->i_mutex); | 2591 | mutex_unlock(&target->i_mutex); |
2587 | if (d_unhashed(new_dentry)) | 2592 | if (d_unhashed(new_dentry)) |
2588 | d_rehash(new_dentry); | 2593 | d_rehash(new_dentry); |
@@ -2614,7 +2619,7 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry, | |||
2614 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); | 2619 | error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); |
2615 | if (!error) { | 2620 | if (!error) { |
2616 | if (target) | 2621 | if (target) |
2617 | target->i_flags |= S_DEAD; | 2622 | dont_mount(new_dentry); |
2618 | if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) | 2623 | if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) |
2619 | d_move(old_dentry, new_dentry); | 2624 | d_move(old_dentry, new_dentry); |
2620 | } | 2625 | } |
diff --git a/fs/namespace.c b/fs/namespace.c index 8174c8ab5c70..f20cb57d1067 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -1432,7 +1432,7 @@ static int graft_tree(struct vfsmount *mnt, struct path *path) | |||
1432 | 1432 | ||
1433 | err = -ENOENT; | 1433 | err = -ENOENT; |
1434 | mutex_lock(&path->dentry->d_inode->i_mutex); | 1434 | mutex_lock(&path->dentry->d_inode->i_mutex); |
1435 | if (IS_DEADDIR(path->dentry->d_inode)) | 1435 | if (cant_mount(path->dentry)) |
1436 | goto out_unlock; | 1436 | goto out_unlock; |
1437 | 1437 | ||
1438 | err = security_sb_check_sb(mnt, path); | 1438 | err = security_sb_check_sb(mnt, path); |
@@ -1623,7 +1623,7 @@ static int do_move_mount(struct path *path, char *old_name) | |||
1623 | 1623 | ||
1624 | err = -ENOENT; | 1624 | err = -ENOENT; |
1625 | mutex_lock(&path->dentry->d_inode->i_mutex); | 1625 | mutex_lock(&path->dentry->d_inode->i_mutex); |
1626 | if (IS_DEADDIR(path->dentry->d_inode)) | 1626 | if (cant_mount(path->dentry)) |
1627 | goto out1; | 1627 | goto out1; |
1628 | 1628 | ||
1629 | if (d_unlinked(path->dentry)) | 1629 | if (d_unlinked(path->dentry)) |
@@ -2234,7 +2234,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
2234 | if (!check_mnt(root.mnt)) | 2234 | if (!check_mnt(root.mnt)) |
2235 | goto out2; | 2235 | goto out2; |
2236 | error = -ENOENT; | 2236 | error = -ENOENT; |
2237 | if (IS_DEADDIR(new.dentry->d_inode)) | 2237 | if (cant_mount(old.dentry)) |
2238 | goto out2; | 2238 | goto out2; |
2239 | if (d_unlinked(new.dentry)) | 2239 | if (d_unlinked(new.dentry)) |
2240 | goto out2; | 2240 | goto out2; |
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 4e50286a4cc3..1dabed286b4c 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c | |||
@@ -164,8 +164,8 @@ struct sysv_dir_entry *sysv_find_entry(struct dentry *dentry, struct page **res_ | |||
164 | name, de->name)) | 164 | name, de->name)) |
165 | goto found; | 165 | goto found; |
166 | } | 166 | } |
167 | dir_put_page(page); | ||
167 | } | 168 | } |
168 | dir_put_page(page); | ||
169 | 169 | ||
170 | if (++n >= npages) | 170 | if (++n >= npages) |
171 | n = 0; | 171 | n = 0; |
diff --git a/include/linux/dcache.h b/include/linux/dcache.h index 30b93b2a01a4..eebb617c17d8 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h | |||
@@ -186,6 +186,8 @@ d_iput: no no no yes | |||
186 | 186 | ||
187 | #define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 /* Parent inode is watched by some fsnotify listener */ | 187 | #define DCACHE_FSNOTIFY_PARENT_WATCHED 0x0080 /* Parent inode is watched by some fsnotify listener */ |
188 | 188 | ||
189 | #define DCACHE_CANT_MOUNT 0x0100 | ||
190 | |||
189 | extern spinlock_t dcache_lock; | 191 | extern spinlock_t dcache_lock; |
190 | extern seqlock_t rename_lock; | 192 | extern seqlock_t rename_lock; |
191 | 193 | ||
@@ -358,6 +360,18 @@ static inline int d_unlinked(struct dentry *dentry) | |||
358 | return d_unhashed(dentry) && !IS_ROOT(dentry); | 360 | return d_unhashed(dentry) && !IS_ROOT(dentry); |
359 | } | 361 | } |
360 | 362 | ||
363 | static inline int cant_mount(struct dentry *dentry) | ||
364 | { | ||
365 | return (dentry->d_flags & DCACHE_CANT_MOUNT); | ||
366 | } | ||
367 | |||
368 | static inline void dont_mount(struct dentry *dentry) | ||
369 | { | ||
370 | spin_lock(&dentry->d_lock); | ||
371 | dentry->d_flags |= DCACHE_CANT_MOUNT; | ||
372 | spin_unlock(&dentry->d_lock); | ||
373 | } | ||
374 | |||
361 | static inline struct dentry *dget_parent(struct dentry *dentry) | 375 | static inline struct dentry *dget_parent(struct dentry *dentry) |
362 | { | 376 | { |
363 | struct dentry *ret; | 377 | struct dentry *ret; |