OSDN Git Service

btrfs: don't steal space from global rsv after a transaction abort
authorFilipe Manana <fdmanana@suse.com>
Wed, 26 Jul 2023 15:57:03 +0000 (16:57 +0100)
committerDavid Sterba <dsterba@suse.com>
Mon, 21 Aug 2023 12:52:17 +0000 (14:52 +0200)
When doing a priority metadata space reclaim, while we are going through
the flush states and running their respective operations, it's possible
that a transaction abort happened, for example when running delayed refs
we hit -ENOSPC or in the critical section of transaction commit we failed
with -ENOSPC or some other error. In these cases a transaction was aborted
and the fs turned into error state. If that happened, then it makes no
sense to steal from the global block reserve and return success to the
caller if the stealing was successful - the caller will later get an
error when attempting to modify the fs. Instead make the ticket fail if
we have the fs in error state and don't attempt to steal from the global
rsv, as it's not only it's pointless, it also simplifies debugging some
-ENOSPC problems.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/space-info.c

index de00442..5b1b71e 100644 (file)
@@ -1418,8 +1418,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 -EROFS 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 = -EROFS;
+               remove_ticket(space_info, ticket);
+       } else if (!steal_from_global_rsv(fs_info, space_info, ticket)) {
                ticket->error = -ENOSPC;
                remove_ticket(space_info, ticket);
        }