Skip to content

Commit d611add

Browse files
fdmananakdave
authored andcommitted
btrfs: fix reclaim counter leak of space_info objects
Whenever we add a ticket to a space_info object we increment the object's reclaim_size counter witht the ticket's bytes, and we decrement it with the corresponding amount only when we are able to grant the requested space to the ticket. When we are not able to grant the space to a ticket, or when the ticket is removed due to a signal (e.g. an application has received sigterm from the terminal) we never decrement the counter with the corresponding bytes from the ticket. This leak can result in the space reclaim code to later do much more work than necessary. So fix it by decrementing the counter when those two cases happen as well. Fixes: db16180 ("btrfs: account ticket size at add/delete time") Reviewed-by: Nikolay Borisov <[email protected]> Signed-off-by: Filipe Manana <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 7af5974 commit d611add

File tree

2 files changed

+15
-6
lines changed

2 files changed

+15
-6
lines changed

fs/btrfs/block-group.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3370,6 +3370,7 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
33703370
space_info->bytes_reserved > 0 ||
33713371
space_info->bytes_may_use > 0))
33723372
btrfs_dump_space_info(info, space_info, 0, 0);
3373+
WARN_ON(space_info->reclaim_size > 0);
33733374
list_del(&space_info->list);
33743375
btrfs_sysfs_remove_space_info(space_info);
33753376
}

fs/btrfs/space-info.c

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,16 @@ int btrfs_can_overcommit(struct btrfs_fs_info *fs_info,
361361
return 0;
362362
}
363363

364+
static void remove_ticket(struct btrfs_space_info *space_info,
365+
struct reserve_ticket *ticket)
366+
{
367+
if (!list_empty(&ticket->list)) {
368+
list_del_init(&ticket->list);
369+
ASSERT(space_info->reclaim_size >= ticket->bytes);
370+
space_info->reclaim_size -= ticket->bytes;
371+
}
372+
}
373+
364374
/*
365375
* This is for space we already have accounted in space_info->bytes_may_use, so
366376
* basically when we're returning space from block_rsv's.
@@ -388,9 +398,7 @@ void btrfs_try_granting_tickets(struct btrfs_fs_info *fs_info,
388398
btrfs_space_info_update_bytes_may_use(fs_info,
389399
space_info,
390400
ticket->bytes);
391-
list_del_init(&ticket->list);
392-
ASSERT(space_info->reclaim_size >= ticket->bytes);
393-
space_info->reclaim_size -= ticket->bytes;
401+
remove_ticket(space_info, ticket);
394402
ticket->bytes = 0;
395403
space_info->tickets_id++;
396404
wake_up(&ticket->wait);
@@ -899,7 +907,7 @@ static bool maybe_fail_all_tickets(struct btrfs_fs_info *fs_info,
899907
btrfs_info(fs_info, "failing ticket with %llu bytes",
900908
ticket->bytes);
901909

902-
list_del_init(&ticket->list);
910+
remove_ticket(space_info, ticket);
903911
ticket->error = -ENOSPC;
904912
wake_up(&ticket->wait);
905913

@@ -1063,7 +1071,7 @@ static void wait_reserve_ticket(struct btrfs_fs_info *fs_info,
10631071
* despite getting an error, resulting in a space leak
10641072
* (bytes_may_use counter of our space_info).
10651073
*/
1066-
list_del_init(&ticket->list);
1074+
remove_ticket(space_info, ticket);
10671075
ticket->error = -EINTR;
10681076
break;
10691077
}
@@ -1121,7 +1129,7 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info,
11211129
* either the async reclaim job deletes the ticket from the list
11221130
* or we delete it ourselves at wait_reserve_ticket().
11231131
*/
1124-
list_del_init(&ticket->list);
1132+
remove_ticket(space_info, ticket);
11251133
if (!ret)
11261134
ret = -ENOSPC;
11271135
}

0 commit comments

Comments
 (0)