Merge branch 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Jan 2010 19:17:05 +0000 (11:17 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 2 Jan 2010 19:17:05 +0000 (11:17 -0800)
* 'reiserfs/kill-bkl' of git://git.kernel.org/pub/scm/linux/kernel/git/frederic/random-tracing:
  reiserfs: Safely acquire i_mutex from xattr_rmdir
  reiserfs: Safely acquire i_mutex from reiserfs_for_each_xattr
  reiserfs: Fix journal mutex <-> inode mutex lock inversion
  reiserfs: Fix unwanted recursive reiserfs lock in reiserfs_unlink()
  reiserfs: Relax lock before open xattr dir in reiserfs_xattr_set_handle()
  reiserfs: Relax reiserfs lock while freeing the journal
  reiserfs: Fix reiserfs lock <-> i_mutex dependency inversion on xattr
  reiserfs: Warn on lock relax if taken recursively
  reiserfs: Fix reiserfs lock <-> i_xattr_sem dependency inversion
  reiserfs: Fix remaining in-reclaim-fs <-> reclaim-fs-on locking inversion
  reiserfs: Fix reiserfs lock <-> inode mutex dependency inversion
  reiserfs: Fix reiserfs lock and journal lock inversion dependency
  reiserfs: Fix possible recursive lock

fs/reiserfs/bitmap.c
fs/reiserfs/inode.c
fs/reiserfs/journal.c
fs/reiserfs/lock.c
fs/reiserfs/namei.c
fs/reiserfs/xattr.c
include/linux/reiserfs_fs.h

index 685495707181c7f168ec280e69b72ba3a1bcc230..65c872761177e10d5b074d97800e5245208c9fe1 100644 (file)
@@ -1277,7 +1277,10 @@ int reiserfs_init_bitmap_cache(struct super_block *sb)
        struct reiserfs_bitmap_info *bitmap;
        unsigned int bmap_nr = reiserfs_bmap_count(sb);
 
+       /* Avoid lock recursion in fault case */
+       reiserfs_write_unlock(sb);
        bitmap = vmalloc(sizeof(*bitmap) * bmap_nr);
+       reiserfs_write_lock(sb);
        if (bitmap == NULL)
                return -ENOMEM;
 
index 290ae38fca8ae915c749c287ce3e4a19307d3d89..1150ebb2536fd0fad8aa2ed9bdb27c557e95fb20 100644 (file)
@@ -31,11 +31,12 @@ void reiserfs_delete_inode(struct inode *inode)
            JOURNAL_PER_BALANCE_CNT * 2 +
            2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
        struct reiserfs_transaction_handle th;
+       int depth;
        int err;
 
        truncate_inode_pages(&inode->i_data, 0);
 
-       reiserfs_write_lock(inode->i_sb);
+       depth = reiserfs_write_lock_once(inode->i_sb);
 
        /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
        if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) {  /* also handles bad_inode case */
@@ -74,7 +75,7 @@ void reiserfs_delete_inode(struct inode *inode)
       out:
        clear_inode(inode);     /* note this must go after the journal_end to prevent deadlock */
        inode->i_blocks = 0;
-       reiserfs_write_unlock(inode->i_sb);
+       reiserfs_write_unlock_once(inode->i_sb, depth);
 }
 
 static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid,
index 2f8a7e7b8dabf04b8641e7b4426b02b3bba8e570..83ac4d3b3cb0f019f128b30c81f6e2e94e8b5a98 100644 (file)
@@ -2009,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;
 }
 
@@ -2758,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));
@@ -2771,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 */
index ee2cfc0fd8a77411f3b581ee759792b3579046ae..b87aa2c1afc14fc9165c6f3a4a42c1c06063c0fa 100644 (file)
@@ -86,3 +86,12 @@ void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
                reiserfs_panic(sb, "%s called without kernel lock held %d",
                               caller);
 }
+
+#ifdef CONFIG_REISERFS_CHECK
+void reiserfs_lock_check_recursive(struct super_block *sb)
+{
+       struct reiserfs_sb_info *sb_i = REISERFS_SB(sb);
+
+       WARN_ONCE((sb_i->lock_depth > 0), "Unwanted recursive reiserfs lock!\n");
+}
+#endif
index e296ff72a6ccb2bc2e99cfbb97472c7da39f3253..9d4dcf0b07cbdcd65353915de08e9a27e9f99848 100644 (file)
@@ -921,6 +921,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
        struct reiserfs_transaction_handle th;
        int jbegin_count;
        unsigned long savelink;
+       int depth;
 
        inode = dentry->d_inode;
 
@@ -932,7 +933,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
            JOURNAL_PER_BALANCE_CNT * 2 + 2 +
            4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
 
-       reiserfs_write_lock(dir->i_sb);
+       depth = reiserfs_write_lock_once(dir->i_sb);
        retval = journal_begin(&th, dir->i_sb, jbegin_count);
        if (retval)
                goto out_unlink;
@@ -993,7 +994,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
 
        retval = journal_end(&th, dir->i_sb, jbegin_count);
        reiserfs_check_path(&path);
-       reiserfs_write_unlock(dir->i_sb);
+       reiserfs_write_unlock_once(dir->i_sb, depth);
        return retval;
 
       end_unlink:
@@ -1003,7 +1004,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
        if (err)
                retval = err;
       out_unlink:
-       reiserfs_write_unlock(dir->i_sb);
+       reiserfs_write_unlock_once(dir->i_sb, depth);
        return retval;
 }
 
index 8c7033a8b67e43bed5d0acef901875fc2a22aa14..c3b004ee627b34ec23c459b3e8178b6b166c6fd1 100644 (file)
@@ -83,7 +83,8 @@ static int xattr_unlink(struct inode *dir, struct dentry *dentry)
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
        vfs_dq_init(dir);
 
-       mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+       reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
+                                       I_MUTEX_CHILD, dir->i_sb);
        error = dir->i_op->unlink(dir, dentry);
        mutex_unlock(&dentry->d_inode->i_mutex);
 
@@ -98,7 +99,8 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
        BUG_ON(!mutex_is_locked(&dir->i_mutex));
        vfs_dq_init(dir);
 
-       mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD);
+       reiserfs_mutex_lock_nested_safe(&dentry->d_inode->i_mutex,
+                                       I_MUTEX_CHILD, dir->i_sb);
        dentry_unhash(dentry);
        error = dir->i_op->rmdir(dir, dentry);
        if (!error)
@@ -235,16 +237,22 @@ static int reiserfs_for_each_xattr(struct inode *inode,
        if (IS_PRIVATE(inode) || get_inode_sd_version(inode) == STAT_DATA_V1)
                return 0;
 
+       reiserfs_write_unlock(inode->i_sb);
        dir = open_xa_dir(inode, XATTR_REPLACE);
        if (IS_ERR(dir)) {
                err = PTR_ERR(dir);
+               reiserfs_write_lock(inode->i_sb);
                goto out;
        } else if (!dir->d_inode) {
                err = 0;
+               reiserfs_write_lock(inode->i_sb);
                goto out_dir;
        }
 
        mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_XATTR);
+
+       reiserfs_write_lock(inode->i_sb);
+
        buf.xadir = dir;
        err = reiserfs_readdir_dentry(dir, &buf, fill_with_dentries, &pos);
        while ((err == 0 || err == -ENOSPC) && buf.count) {
@@ -283,8 +291,9 @@ static int reiserfs_for_each_xattr(struct inode *inode,
                err = journal_begin(&th, inode->i_sb, blocks);
                if (!err) {
                        int jerror;
-                       mutex_lock_nested(&dir->d_parent->d_inode->i_mutex,
-                                         I_MUTEX_XATTR);
+                       reiserfs_mutex_lock_nested_safe(
+                                         &dir->d_parent->d_inode->i_mutex,
+                                         I_MUTEX_XATTR, inode->i_sb);
                        err = action(dir, data);
                        jerror = journal_end(&th, inode->i_sb, blocks);
                        mutex_unlock(&dir->d_parent->d_inode->i_mutex);
@@ -480,11 +489,16 @@ reiserfs_xattr_set_handle(struct reiserfs_transaction_handle *th,
        if (!buffer)
                return lookup_and_delete_xattr(inode, name);
 
+       reiserfs_write_unlock(inode->i_sb);
        dentry = xattr_lookup(inode, name, flags);
-       if (IS_ERR(dentry))
+       if (IS_ERR(dentry)) {
+               reiserfs_write_lock(inode->i_sb);
                return PTR_ERR(dentry);
+       }
 
-       down_write(&REISERFS_I(inode)->i_xattr_sem);
+       down_read(&REISERFS_I(inode)->i_xattr_sem);
+
+       reiserfs_write_lock(inode->i_sb);
 
        xahash = xattr_hash(buffer, buffer_size);
        while (buffer_pos < buffer_size || buffer_pos == 0) {
index c96c1858fe2c404673810c33560ce0c56701d566..1ba3cf6edfbb4d80f17f76411c19360a0ac978c6 100644 (file)
@@ -62,6 +62,12 @@ void reiserfs_write_unlock(struct super_block *s);
 int reiserfs_write_lock_once(struct super_block *s);
 void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
 
+#ifdef CONFIG_REISERFS_CHECK
+void reiserfs_lock_check_recursive(struct super_block *s);
+#else
+static inline void reiserfs_lock_check_recursive(struct super_block *s) { }
+#endif
+
 /*
  * Several mutexes depend on the write lock.
  * However sometimes we want to relax the write lock while we hold
@@ -92,11 +98,31 @@ void reiserfs_write_unlock_once(struct super_block *s, int lock_depth);
 static inline void reiserfs_mutex_lock_safe(struct mutex *m,
                               struct super_block *s)
 {
+       reiserfs_lock_check_recursive(s);
        reiserfs_write_unlock(s);
        mutex_lock(m);
        reiserfs_write_lock(s);
 }
 
+static inline void
+reiserfs_mutex_lock_nested_safe(struct mutex *m, unsigned int subclass,
+                              struct super_block *s)
+{
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       mutex_lock_nested(m, subclass);
+       reiserfs_write_lock(s);
+}
+
+static inline void
+reiserfs_down_read_safe(struct rw_semaphore *sem, struct super_block *s)
+{
+       reiserfs_lock_check_recursive(s);
+       reiserfs_write_unlock(s);
+       down_read(sem);
+       reiserfs_write_lock(s);
+}
+
 /*
  * When we schedule, we usually want to also release the write lock,
  * according to the previous bkl based locking scheme of reiserfs.