Btrfs: fix lockdep warning about log_mutex
authorLiu Bo <bo.li.liu@oracle.com>
Thu, 1 Dec 2016 00:20:25 +0000 (16:20 -0800)
committerDavid Sterba <dsterba@suse.com>
Tue, 3 Jan 2017 14:19:28 +0000 (15:19 +0100)
While checking INODE_REF/INODE_EXTREF for a corner case, we may acquire a
different inode's log_mutex with holding the current inode's log_mutex, and
lockdep has complained this with a possilble deadlock warning.

Fix this by using mutex_lock_nested() when processing the other inode's
log_mutex.

Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Liu Bo <bo.li.liu@oracle.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/tree-log.c

index f10bf5213ed8a48b95a8cf3cf51dc3c2c81b8463..eeffff84f280958cfd117e860055d7b9fc683377 100644 (file)
@@ -37,6 +37,7 @@
  */
 #define LOG_INODE_ALL 0
 #define LOG_INODE_EXISTS 1
+#define LOG_OTHER_INODE 2
 
 /*
  * directory trouble cases
@@ -4641,7 +4642,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        if (S_ISDIR(inode->i_mode) ||
            (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC,
                       &BTRFS_I(inode)->runtime_flags) &&
-            inode_only == LOG_INODE_EXISTS))
+            inode_only >= LOG_INODE_EXISTS))
                max_key.type = BTRFS_XATTR_ITEM_KEY;
        else
                max_key.type = (u8)-1;
@@ -4665,7 +4666,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
                return ret;
        }
 
-       mutex_lock(&BTRFS_I(inode)->log_mutex);
+       if (inode_only == LOG_OTHER_INODE) {
+               inode_only = LOG_INODE_EXISTS;
+               mutex_lock_nested(&BTRFS_I(inode)->log_mutex,
+                                 SINGLE_DEPTH_NESTING);
+       } else {
+               mutex_lock(&BTRFS_I(inode)->log_mutex);
+       }
 
        /*
         * a brute force approach to making sure we get the most uptodate
@@ -4817,7 +4824,7 @@ again:
                                 * unpin it.
                                 */
                                err = btrfs_log_inode(trans, root, other_inode,
-                                                     LOG_INODE_EXISTS,
+                                                     LOG_OTHER_INODE,
                                                      0, LLONG_MAX, ctx);
                                iput(other_inode);
                                if (err)