reiserfs: Fix recursive lock on lchown
[safe/jmp/linux-2.6] / fs / reiserfs / journal.c
index ffb7f50..83ac4d3 100644 (file)
@@ -537,42 +537,6 @@ static inline void insert_journal_hash(struct reiserfs_journal_cnode **table,
        journal_hash(table, cn->sb, cn->blocknr) = cn;
 }
 
-/*
- * Several mutexes depend on the write lock.
- * However sometimes we want to relax the write lock while we hold
- * these mutexes, according to the release/reacquire on schedule()
- * properties of the Bkl that were used.
- * Reiserfs performances and locking were based on this scheme.
- * Now that the write lock is a mutex and not the bkl anymore, doing so
- * may result in a deadlock:
- *
- * A acquire write_lock
- * A acquire j_commit_mutex
- * A release write_lock and wait for something
- * B acquire write_lock
- * B can't acquire j_commit_mutex and sleep
- * A can't acquire write lock anymore
- * deadlock
- *
- * What we do here is avoiding such deadlock by playing the same game
- * than the Bkl: if we can't acquire a mutex that depends on the write lock,
- * we release the write lock, wait a bit and then retry.
- *
- * The mutexes concerned by this hack are:
- * - The commit mutex of a journal list
- * - The flush mutex
- * - The journal lock
- */
-static inline void reiserfs_mutex_lock_safe(struct mutex *m,
-                              struct super_block *s)
-{
-       while (!mutex_trylock(m)) {
-               reiserfs_write_unlock(s);
-               schedule();
-               reiserfs_write_lock(s);
-       }
-}
-
 /* lock the current transaction */
 static inline void lock_journal(struct super_block *sb)
 {
@@ -2045,10 +2009,11 @@ static int do_journal_release(struct reiserfs_transaction_handle *th,
                destroy_workqueue(commit_wq);
                commit_wq = NULL;
        }
-       reiserfs_write_lock(sb);
 
        free_journal_ram(sb);
 
+       reiserfs_write_lock(sb);
+
        return 0;
 }
 
@@ -2794,11 +2759,18 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        struct reiserfs_journal *journal;
        struct reiserfs_journal_list *jl;
        char b[BDEVNAME_SIZE];
+       int ret;
 
+       /*
+        * Unlock here to avoid various RECLAIM-FS-ON <-> IN-RECLAIM-FS
+        * dependency inversion warnings.
+        */
+       reiserfs_write_unlock(sb);
        journal = SB_JOURNAL(sb) = vmalloc(sizeof(struct reiserfs_journal));
        if (!journal) {
                reiserfs_warning(sb, "journal-1256",
                                 "unable to get memory for journal structure");
+               reiserfs_write_lock(sb);
                return 1;
        }
        memset(journal, 0, sizeof(struct reiserfs_journal));
@@ -2807,10 +2779,12 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        INIT_LIST_HEAD(&journal->j_working_list);
        INIT_LIST_HEAD(&journal->j_journal_list);
        journal->j_persistent_trans = 0;
-       if (reiserfs_allocate_list_bitmaps(sb,
-                                          journal->j_list_bitmap,
-                                          reiserfs_bmap_count(sb)))
+       ret = reiserfs_allocate_list_bitmaps(sb, journal->j_list_bitmap,
+                                          reiserfs_bmap_count(sb));
+       reiserfs_write_lock(sb);
+       if (ret)
                goto free_and_return;
+
        allocate_bitmap_nodes(sb);
 
        /* reserved for journal area support */
@@ -2837,11 +2811,27 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
                goto free_and_return;
        }
 
+       /*
+        * We need to unlock here to avoid creating the following
+        * dependency:
+        * reiserfs_lock -> sysfs_mutex
+        * Because the reiserfs mmap path creates the following dependency:
+        * mm->mmap -> reiserfs_lock, hence we have
+        * mm->mmap -> reiserfs_lock ->sysfs_mutex
+        * This would ends up in a circular dependency with sysfs readdir path
+        * which does sysfs_mutex -> mm->mmap_sem
+        * This is fine because the reiserfs lock is useless in mount path,
+        * at least until we call journal_begin. We keep it for paranoid
+        * reasons.
+        */
+       reiserfs_write_unlock(sb);
        if (journal_init_dev(sb, journal, j_dev_name) != 0) {
+               reiserfs_write_lock(sb);
                reiserfs_warning(sb, "sh-462",
                                 "unable to initialize jornal device");
                goto free_and_return;
        }
+       reiserfs_write_lock(sb);
 
        rs = SB_DISK_SUPER_BLOCK(sb);
 
@@ -2953,8 +2943,11 @@ int journal_init(struct super_block *sb, const char *j_dev_name,
        }
 
        reiserfs_mounted_fs_count++;
-       if (reiserfs_mounted_fs_count <= 1)
+       if (reiserfs_mounted_fs_count <= 1) {
+               reiserfs_write_unlock(sb);
                commit_wq = create_workqueue("reiserfs");
+               reiserfs_write_lock(sb);
+       }
 
        INIT_DELAYED_WORK(&journal->j_work, flush_async_commits);
        journal->j_work_sb = sb;