Skip to content

Commit

Permalink
btrfs: add correction to handle -1 edge case in async discard
Browse files Browse the repository at this point in the history
From Dave's testing described below, it's possible to drive a file
system to have bogus values of discardable_extents and _bytes.  As
btrfs_discard_calc_delay() is the only user of discardable_extents, we
can correct here for any negative discardable_extents/discardable_bytes.

The problem is not reliably reproducible. The workload that created it
was based on linux git tree, switching between release tags, then
everytihng deleted followed by a full rebalance. At this state the
values of discardable_bytes was 16K and discardable_extents was -1,
expected values 0 and 0.

Repeating the workload again did not correct the bogus values so the
offset seems to be stable once it happens.

Reported-by: David Sterba <[email protected]>
Signed-off-by: Dennis Zhou <[email protected]>
Signed-off-by: David Sterba <[email protected]>
  • Loading branch information
dennisszhou authored and kdave committed Jan 20, 2020
1 parent 27f0afc commit 81b29a3
Showing 1 changed file with 22 additions and 0 deletions.
22 changes: 22 additions & 0 deletions fs/btrfs/discard.c
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ bool btrfs_run_discard_work(struct btrfs_discard_ctl *discard_ctl)
void btrfs_discard_calc_delay(struct btrfs_discard_ctl *discard_ctl)
{
s32 discardable_extents;
s64 discardable_bytes;
u32 iops_limit;
unsigned long delay;
unsigned long lower_limit = BTRFS_DISCARD_MIN_DELAY_MSEC;
Expand All @@ -526,6 +527,27 @@ void btrfs_discard_calc_delay(struct btrfs_discard_ctl *discard_ctl)

spin_lock(&discard_ctl->lock);

/*
* The following is to fix a potential -1 discrepenancy that we're not
* sure how to reproduce. But given that this is the only place that
* utilizes these numbers and this is only called by from
* btrfs_finish_extent_commit() which is synchronized, we can correct
* here.
*/
if (discardable_extents < 0)
atomic_add(-discardable_extents,
&discard_ctl->discardable_extents);

discardable_bytes = atomic64_read(&discard_ctl->discardable_bytes);
if (discardable_bytes < 0)
atomic64_add(-discardable_bytes,
&discard_ctl->discardable_bytes);

if (discardable_extents <= 0) {
spin_unlock(&discard_ctl->lock);
return;
}

iops_limit = READ_ONCE(discard_ctl->iops_limit);
if (iops_limit)
lower_limit = max_t(unsigned long, lower_limit,
Expand Down

0 comments on commit 81b29a3

Please sign in to comment.