btrfs: fix race between finishing block group creation and its item update
[linux-2.6-microblaze.git] / fs / btrfs / block-group.c
index 0cb1dee..b2e5107 100644 (file)
@@ -3028,8 +3028,16 @@ static int update_block_group_item(struct btrfs_trans_handle *trans,
        btrfs_mark_buffer_dirty(leaf);
 fail:
        btrfs_release_path(path);
-       /* We didn't update the block group item, need to revert @commit_used. */
-       if (ret < 0) {
+       /*
+        * We didn't update the block group item, need to revert commit_used
+        * unless the block group item didn't exist yet - this is to prevent a
+        * race with a concurrent insertion of the block group item, with
+        * insert_block_group_item(), that happened just after we attempted to
+        * update. In that case we would reset commit_used to 0 just after the
+        * insertion set it to a value greater than 0 - if the block group later
+        * becomes with 0 used bytes, we would incorrectly skip its update.
+        */
+       if (ret < 0 && ret != -ENOENT) {
                spin_lock(&cache->lock);
                cache->commit_used = old_commit_used;
                spin_unlock(&cache->lock);