diff options
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/fs/super.c b/fs/super.c index 645e5403f2a0..6ce501447ada 100644 --- a/fs/super.c +++ b/fs/super.c | |||
@@ -82,7 +82,22 @@ static struct super_block *alloc_super(struct file_system_type *type) | |||
82 | * lock ordering than usbfs: | 82 | * lock ordering than usbfs: |
83 | */ | 83 | */ |
84 | lockdep_set_class(&s->s_lock, &type->s_lock_key); | 84 | lockdep_set_class(&s->s_lock, &type->s_lock_key); |
85 | down_write(&s->s_umount); | 85 | /* |
86 | * sget() can have s_umount recursion. | ||
87 | * | ||
88 | * When it cannot find a suitable sb, it allocates a new | ||
89 | * one (this one), and tries again to find a suitable old | ||
90 | * one. | ||
91 | * | ||
92 | * In case that succeeds, it will acquire the s_umount | ||
93 | * lock of the old one. Since these are clearly distrinct | ||
94 | * locks, and this object isn't exposed yet, there's no | ||
95 | * risk of deadlocks. | ||
96 | * | ||
97 | * Annotate this by putting this lock in a different | ||
98 | * subclass. | ||
99 | */ | ||
100 | down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING); | ||
86 | s->s_count = S_BIAS; | 101 | s->s_count = S_BIAS; |
87 | atomic_set(&s->s_active, 1); | 102 | atomic_set(&s->s_active, 1); |
88 | mutex_init(&s->s_vfs_rename_mutex); | 103 | mutex_init(&s->s_vfs_rename_mutex); |
@@ -301,7 +316,7 @@ void generic_shutdown_super(struct super_block *sb) | |||
301 | /* | 316 | /* |
302 | * wait for asynchronous fs operations to finish before going further | 317 | * wait for asynchronous fs operations to finish before going further |
303 | */ | 318 | */ |
304 | async_synchronize_full_special(&sb->s_async_list); | 319 | async_synchronize_full_domain(&sb->s_async_list); |
305 | 320 | ||
306 | /* bad name - it should be evict_inodes() */ | 321 | /* bad name - it should be evict_inodes() */ |
307 | invalidate_inodes(sb); | 322 | invalidate_inodes(sb); |
@@ -356,8 +371,10 @@ retry: | |||
356 | continue; | 371 | continue; |
357 | if (!grab_super(old)) | 372 | if (!grab_super(old)) |
358 | goto retry; | 373 | goto retry; |
359 | if (s) | 374 | if (s) { |
375 | up_write(&s->s_umount); | ||
360 | destroy_super(s); | 376 | destroy_super(s); |
377 | } | ||
361 | return old; | 378 | return old; |
362 | } | 379 | } |
363 | } | 380 | } |
@@ -372,6 +389,7 @@ retry: | |||
372 | err = set(s, data); | 389 | err = set(s, data); |
373 | if (err) { | 390 | if (err) { |
374 | spin_unlock(&sb_lock); | 391 | spin_unlock(&sb_lock); |
392 | up_write(&s->s_umount); | ||
375 | destroy_super(s); | 393 | destroy_super(s); |
376 | return ERR_PTR(err); | 394 | return ERR_PTR(err); |
377 | } | 395 | } |
@@ -470,7 +488,7 @@ restart: | |||
470 | sb->s_count++; | 488 | sb->s_count++; |
471 | spin_unlock(&sb_lock); | 489 | spin_unlock(&sb_lock); |
472 | down_read(&sb->s_umount); | 490 | down_read(&sb->s_umount); |
473 | async_synchronize_full_special(&sb->s_async_list); | 491 | async_synchronize_full_domain(&sb->s_async_list); |
474 | if (sb->s_root && (wait || sb->s_dirt)) | 492 | if (sb->s_root && (wait || sb->s_dirt)) |
475 | sb->s_op->sync_fs(sb, wait); | 493 | sb->s_op->sync_fs(sb, wait); |
476 | up_read(&sb->s_umount); | 494 | up_read(&sb->s_umount); |