diff options
Diffstat (limited to 'fs/super.c')
-rw-r--r-- | fs/super.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/fs/super.c b/fs/super.c index 61dce001dd57..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); |
@@ -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 | } |