| From foo@baz Fri Aug 4 15:15:01 PDT 2017 |
| From: Liu Bo <bo.li.liu@oracle.com> |
| Date: Wed, 30 Nov 2016 16:20:25 -0800 |
| Subject: Btrfs: fix lockdep warning about log_mutex |
| |
| From: Liu Bo <bo.li.liu@oracle.com> |
| |
| |
| [ Upstream commit 781feef7e6befafd4d9787d1f7ada1f9ccd504e4 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/btrfs/tree-log.c | 13 ++++++++++--- |
| 1 file changed, 10 insertions(+), 3 deletions(-) |
| |
| --- a/fs/btrfs/tree-log.c |
| +++ b/fs/btrfs/tree-log.c |
| @@ -37,6 +37,7 @@ |
| */ |
| #define LOG_INODE_ALL 0 |
| #define LOG_INODE_EXISTS 1 |
| +#define LOG_OTHER_INODE 2 |
| |
| /* |
| * directory trouble cases |
| @@ -4623,7 +4624,7 @@ static int btrfs_log_inode(struct btrfs_ |
| 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; |
| @@ -4647,7 +4648,13 @@ static int btrfs_log_inode(struct btrfs_ |
| 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 |
| @@ -4799,7 +4806,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) |