vfs: add missing unlock in sget()
[safe/jmp/linux-2.6] / fs / super.c
index 61dce00..6ce5014 100644 (file)
@@ -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);
@@ -356,8 +371,10 @@ retry:
                                continue;
                        if (!grab_super(old))
                                goto retry;
-                       if (s)
+                       if (s) {
+                               up_write(&s->s_umount);
                                destroy_super(s);
+                       }
                        return old;
                }
        }
@@ -372,6 +389,7 @@ retry:
        err = set(s, data);
        if (err) {
                spin_unlock(&sb_lock);
+               up_write(&s->s_umount);
                destroy_super(s);
                return ERR_PTR(err);
        }