Skip to content

Commit ea9ed87

Browse files
isilencekdave
authored andcommitted
btrfs: fix async discard stall
Might happen that bg->discard_eligible_time was changed without rescheduling, so btrfs_discard_workfn() wakes up earlier than that new time, peek_discard_list() returns NULL, and all work halts and goes to sleep without further rescheduling even there are block groups to discard. It happens pretty often, but not so visible from the userspace because after some time it usually will be kicked off anyway by someone else calling btrfs_discard_reschedule_work(). Fix it by continue rescheduling if block group discard lists are not empty. Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Pavel Begunkov <asml.silence@gmail.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 675a4fc commit ea9ed87

1 file changed

Lines changed: 10 additions & 7 deletions

File tree

fs/btrfs/discard.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,16 +199,15 @@ static struct btrfs_block_group *find_next_block_group(
199199
static struct btrfs_block_group *peek_discard_list(
200200
struct btrfs_discard_ctl *discard_ctl,
201201
enum btrfs_discard_state *discard_state,
202-
int *discard_index)
202+
int *discard_index, u64 now)
203203
{
204204
struct btrfs_block_group *block_group;
205-
const u64 now = ktime_get_ns();
206205

207206
spin_lock(&discard_ctl->lock);
208207
again:
209208
block_group = find_next_block_group(discard_ctl, now);
210209

211-
if (block_group && now > block_group->discard_eligible_time) {
210+
if (block_group && now >= block_group->discard_eligible_time) {
212211
if (block_group->discard_index == BTRFS_DISCARD_INDEX_UNUSED &&
213212
block_group->used != 0) {
214213
if (btrfs_is_block_group_data_only(block_group))
@@ -222,12 +221,11 @@ static struct btrfs_block_group *peek_discard_list(
222221
block_group->discard_state = BTRFS_DISCARD_EXTENTS;
223222
}
224223
discard_ctl->block_group = block_group;
224+
}
225+
if (block_group) {
225226
*discard_state = block_group->discard_state;
226227
*discard_index = block_group->discard_index;
227-
} else {
228-
block_group = NULL;
229228
}
230-
231229
spin_unlock(&discard_ctl->lock);
232230

233231
return block_group;
@@ -438,13 +436,18 @@ static void btrfs_discard_workfn(struct work_struct *work)
438436
int discard_index = 0;
439437
u64 trimmed = 0;
440438
u64 minlen = 0;
439+
u64 now = ktime_get_ns();
441440

442441
discard_ctl = container_of(work, struct btrfs_discard_ctl, work.work);
443442

444443
block_group = peek_discard_list(discard_ctl, &discard_state,
445-
&discard_index);
444+
&discard_index, now);
446445
if (!block_group || !btrfs_run_discard_work(discard_ctl))
447446
return;
447+
if (now < block_group->discard_eligible_time) {
448+
btrfs_discard_schedule_work(discard_ctl, false);
449+
return;
450+
}
448451

449452
/* Perform discarding */
450453
minlen = discard_minlen[discard_index];

0 commit comments

Comments
 (0)