OSDN Git Service

Btrfs: fix mutex unlock without prior lock on space cache truncation
authorFilipe Manana <fdmanana@suse.com>
Thu, 30 Apr 2015 16:47:05 +0000 (17:47 +0100)
committerChris Mason <clm@fb.com>
Wed, 3 Jun 2015 02:34:34 +0000 (19:34 -0700)
If the call to btrfs_truncate_inode_items() failed and we don't have a block
group, we were unlocking the cache_write_mutex without having locked it (we
do it only if we have a block group).

Fixes: 1bbc621ef284 ("Btrfs: allow block group cache writeout
                      outside critical section in commit")

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Chris Mason <clm@fb.com>
fs/btrfs/free-space-cache.c

index 9dbe5b5..fb5a6b1 100644 (file)
@@ -231,6 +231,7 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
 {
        int ret = 0;
        struct btrfs_path *path = btrfs_alloc_path();
+       bool locked = false;
 
        if (!path) {
                ret = -ENOMEM;
@@ -238,6 +239,7 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
        }
 
        if (block_group) {
+               locked = true;
                mutex_lock(&trans->transaction->cache_write_mutex);
                if (!list_empty(&block_group->io_list)) {
                        list_del_init(&block_group->io_list);
@@ -269,18 +271,14 @@ int btrfs_truncate_free_space_cache(struct btrfs_root *root,
         */
        ret = btrfs_truncate_inode_items(trans, root, inode,
                                         0, BTRFS_EXTENT_DATA_KEY);
-       if (ret) {
-               mutex_unlock(&trans->transaction->cache_write_mutex);
-               btrfs_abort_transaction(trans, root, ret);
-               return ret;
-       }
+       if (ret)
+               goto fail;
 
        ret = btrfs_update_inode(trans, root, inode);
 
-       if (block_group)
-               mutex_unlock(&trans->transaction->cache_write_mutex);
-
 fail:
+       if (locked)
+               mutex_unlock(&trans->transaction->cache_write_mutex);
        if (ret)
                btrfs_abort_transaction(trans, root, ret);