summaryrefslogtreecommitdiffstats
path: root/fs/super.c
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2009-03-13 21:44:51 +0000
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-03-13 21:44:51 +0000
commit97fb44eb6bc01f4ffed4300e475aa15e44877375 (patch)
tree481ed6efd0babe7185cae04f2fd295426b36411d /fs/super.c
parente4707dd3e9d0cb57597b6568a5e51fea5d6fca41 (diff)
parent148854c65ea8046b045672fd49f4333aefaa3ab5 (diff)
Merge branch 'for-rmk' of git://git.pengutronix.de/git/imx/linux-2.6 into devel
Conflicts: arch/arm/mach-at91/gpio.c
Diffstat (limited to 'fs/super.c')
-rw-r--r--fs/super.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/fs/super.c b/fs/super.c
index 645e5403f2a..8349ed6b141 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -82,7 +82,22 @@ static struct super_block *alloc_super(struct file_system_type *type)
* lock ordering than usbfs:
*/
lockdep_set_class(&s->s_lock, &type->s_lock_key);
- down_write(&s->s_umount);
+ /*
+ * sget() can have s_umount recursion.
+ *
+ * When it cannot find a suitable sb, it allocates a new
+ * one (this one), and tries again to find a suitable old
+ * one.
+ *
+ * In case that succeeds, it will acquire the s_umount
+ * lock of the old one. Since these are clearly distrinct
+ * locks, and this object isn't exposed yet, there's no
+ * risk of deadlocks.
+ *
+ * Annotate this by putting this lock in a different
+ * subclass.
+ */
+ down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
s->s_count = S_BIAS;
atomic_set(&s->s_active, 1);
mutex_init(&s->s_vfs_rename_mutex);
@@ -301,7 +316,7 @@ void generic_shutdown_super(struct super_block *sb)
/*
* wait for asynchronous fs operations to finish before going further
*/
- async_synchronize_full_special(&sb->s_async_list);
+ async_synchronize_full_domain(&sb->s_async_list);
/* bad name - it should be evict_inodes() */
invalidate_inodes(sb);
@@ -470,7 +485,7 @@ restart:
sb->s_count++;
spin_unlock(&sb_lock);
down_read(&sb->s_umount);
- async_synchronize_full_special(&sb->s_async_list);
+ async_synchronize_full_domain(&sb->s_async_list);
if (sb->s_root && (wait || sb->s_dirt))
sb->s_op->sync_fs(sb, wait);
up_read(&sb->s_umount);