btrfs: add correction to handle -1 edge case in async discard
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 <dsterba@suse.com> Signed-off-by: Dennis Zhou <dennis@kernel.org> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
27f0afc737
commit
81b29a3bf7
|
@ -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;
|
||||
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue