]> git.ipfire.org Git - thirdparty/linux.git/blobdiff - fs/btrfs/space-info.c
btrfs: avoid starting new transaction when flushing delayed items and refs
[thirdparty/linux.git] / fs / btrfs / space-info.c
index 75e7fa337e66c81ea003e91709a0f0c5d9a84ed6..2db92a2016978866de4877bf992099cdae73bcfe 100644 (file)
@@ -510,6 +510,7 @@ void btrfs_dump_space_info(struct btrfs_fs_info *fs_info,
                           int dump_block_groups)
 {
        struct btrfs_block_group *cache;
+       u64 total_avail = 0;
        int index = 0;
 
        spin_lock(&info->lock);
@@ -523,18 +524,27 @@ void btrfs_dump_space_info(struct btrfs_fs_info *fs_info,
        down_read(&info->groups_sem);
 again:
        list_for_each_entry(cache, &info->block_groups[index], list) {
+               u64 avail;
+
                spin_lock(&cache->lock);
+               avail = cache->length - cache->used - cache->pinned -
+                       cache->reserved - cache->delalloc_bytes -
+                       cache->bytes_super - cache->zone_unusable;
                btrfs_info(fs_info,
-                       "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %llu zone_unusable %s",
-                       cache->start, cache->length, cache->used, cache->pinned,
-                       cache->reserved, cache->zone_unusable,
-                       cache->ro ? "[readonly]" : "");
+"block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %llu delalloc %llu super %llu zone_unusable (%llu bytes available) %s",
+                          cache->start, cache->length, cache->used, cache->pinned,
+                          cache->reserved, cache->delalloc_bytes,
+                          cache->bytes_super, cache->zone_unusable,
+                          avail, cache->ro ? "[readonly]" : "");
                spin_unlock(&cache->lock);
                btrfs_dump_free_space(cache, bytes);
+               total_avail += avail;
        }
        if (++index < BTRFS_NR_RAID_TYPES)
                goto again;
        up_read(&info->groups_sem);
+
+       btrfs_info(fs_info, "%llu bytes available across all block groups", total_avail);
 }
 
 static inline u64 calc_reclaim_items_nr(const struct btrfs_fs_info *fs_info,
@@ -715,9 +725,11 @@ static void flush_space(struct btrfs_fs_info *fs_info,
                else
                        nr = -1;
 
-               trans = btrfs_join_transaction(root);
+               trans = btrfs_join_transaction_nostart(root);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
+                       if (ret == -ENOENT)
+                               ret = 0;
                        break;
                }
                ret = btrfs_run_delayed_items_nr(trans, nr);
@@ -733,9 +745,11 @@ static void flush_space(struct btrfs_fs_info *fs_info,
                break;
        case FLUSH_DELAYED_REFS_NR:
        case FLUSH_DELAYED_REFS:
-               trans = btrfs_join_transaction(root);
+               trans = btrfs_join_transaction_nostart(root);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
+                       if (ret == -ENOENT)
+                               ret = 0;
                        break;
                }
                if (state == FLUSH_DELAYED_REFS_NR)
@@ -1408,8 +1422,18 @@ static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info,
                }
        }
 
-       /* Attempt to steal from the global rsv if we can. */
-       if (!steal_from_global_rsv(fs_info, space_info, ticket)) {
+       /*
+        * Attempt to steal from the global rsv if we can, except if the fs was
+        * turned into error mode due to a transaction abort when flushing space
+        * above, in that case fail with the abort error instead of returning
+        * success to the caller if we can steal from the global rsv - this is
+        * just to have caller fail immeditelly instead of later when trying to
+        * modify the fs, making it easier to debug -ENOSPC problems.
+        */
+       if (BTRFS_FS_ERROR(fs_info)) {
+               ticket->error = BTRFS_FS_ERROR(fs_info);
+               remove_ticket(space_info, ticket);
+       } else if (!steal_from_global_rsv(fs_info, space_info, ticket)) {
                ticket->error = -ENOSPC;
                remove_ticket(space_info, ticket);
        }