Skip to content

Commit

Permalink
btrfs: add kbps discard rate limit for async discard
Browse files Browse the repository at this point in the history
Provide the ability to rate limit based on kbps in addition to iops as
additional guides for the target discard rate. The delay used ends up
being max(kbps_delay, iops_delay).

Signed-off-by: Dennis Zhou <[email protected]>
Reviewed-by: David Sterba <[email protected]>
Signed-off-by: David Sterba <[email protected]>
  • Loading branch information
dennisszhou authored and kdave committed Jan 20, 2020
1 parent a230930 commit e93591b
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 2 deletions.
2 changes: 2 additions & 0 deletions fs/btrfs/ctree.h
Original file line number Diff line number Diff line change
Expand Up @@ -466,10 +466,12 @@ struct btrfs_discard_ctl {
spinlock_t lock;
struct btrfs_block_group *block_group;
struct list_head discard_list[BTRFS_NR_DISCARD_LISTS];
u64 prev_discard;
atomic_t discardable_extents;
atomic64_t discardable_bytes;
unsigned long delay;
u32 iops_limit;
u32 kbps_limit;
};

/* delayed seq elem */
Expand Down
23 changes: 21 additions & 2 deletions fs/btrfs/discard.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <linux/kernel.h>
#include <linux/ktime.h>
#include <linux/list.h>
#include <linux/math64.h>
#include <linux/sizes.h>
#include <linux/workqueue.h>
#include "ctree.h"
Expand Down Expand Up @@ -222,8 +223,8 @@ void btrfs_discard_queue_work(struct btrfs_discard_ctl *discard_ctl,
* @override: override the current timer
*
* Discards are issued by a delayed workqueue item. @override is used to
* update the current delay as the baseline delay interview is reevaluated
* on transaction commit. This is also maxed with any other rate limit.
* update the current delay as the baseline delay interval is reevaluated on
* transaction commit. This is also maxed with any other rate limit.
*/
void btrfs_discard_schedule_work(struct btrfs_discard_ctl *discard_ctl,
bool override)
Expand All @@ -242,6 +243,20 @@ void btrfs_discard_schedule_work(struct btrfs_discard_ctl *discard_ctl,
block_group = find_next_block_group(discard_ctl, now);
if (block_group) {
unsigned long delay = discard_ctl->delay;
u32 kbps_limit = READ_ONCE(discard_ctl->kbps_limit);

/*
* A single delayed workqueue item is responsible for
* discarding, so we can manage the bytes rate limit by keeping
* track of the previous discard.
*/
if (kbps_limit && discard_ctl->prev_discard) {
u64 bps_limit = ((u64)kbps_limit) * SZ_1K;
u64 bps_delay = div64_u64(discard_ctl->prev_discard *
MSEC_PER_SEC, bps_limit);

delay = max(delay, msecs_to_jiffies(bps_delay));
}

/*
* This timeout is to hopefully prevent immediate discarding
Expand Down Expand Up @@ -316,6 +331,8 @@ static void btrfs_discard_workfn(struct work_struct *work)
btrfs_block_group_end(block_group),
0, true);

discard_ctl->prev_discard = trimmed;

/* Determine next steps for a block_group */
if (block_group->discard_cursor >= btrfs_block_group_end(block_group)) {
if (discard_state == BTRFS_DISCARD_BITMAPS) {
Expand Down Expand Up @@ -507,10 +524,12 @@ void btrfs_discard_init(struct btrfs_fs_info *fs_info)
for (i = 0; i < BTRFS_NR_DISCARD_LISTS; i++)
INIT_LIST_HEAD(&discard_ctl->discard_list[i]);

discard_ctl->prev_discard = 0;
atomic_set(&discard_ctl->discardable_extents, 0);
atomic64_set(&discard_ctl->discardable_bytes, 0);
discard_ctl->delay = BTRFS_DISCARD_MAX_DELAY_MSEC;
discard_ctl->iops_limit = BTRFS_DISCARD_MAX_IOPS;
discard_ctl->kbps_limit = 0;
}

void btrfs_discard_cleanup(struct btrfs_fs_info *fs_info)
Expand Down
31 changes: 31 additions & 0 deletions fs/btrfs/sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,10 +396,41 @@ static ssize_t btrfs_discard_iops_limit_store(struct kobject *kobj,
BTRFS_ATTR_RW(discard, iops_limit, btrfs_discard_iops_limit_show,
btrfs_discard_iops_limit_store);

static ssize_t btrfs_discard_kbps_limit_show(struct kobject *kobj,
struct kobj_attribute *a,
char *buf)
{
struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);

return snprintf(buf, PAGE_SIZE, "%u\n",
READ_ONCE(fs_info->discard_ctl.kbps_limit));
}

static ssize_t btrfs_discard_kbps_limit_store(struct kobject *kobj,
struct kobj_attribute *a,
const char *buf, size_t len)
{
struct btrfs_fs_info *fs_info = discard_to_fs_info(kobj);
struct btrfs_discard_ctl *discard_ctl = &fs_info->discard_ctl;
u32 kbps_limit;
int ret;

ret = kstrtou32(buf, 10, &kbps_limit);
if (ret)
return -EINVAL;

WRITE_ONCE(discard_ctl->kbps_limit, kbps_limit);

return len;
}
BTRFS_ATTR_RW(discard, kbps_limit, btrfs_discard_kbps_limit_show,
btrfs_discard_kbps_limit_store);

static const struct attribute *discard_debug_attrs[] = {
BTRFS_ATTR_PTR(discard, discardable_bytes),
BTRFS_ATTR_PTR(discard, discardable_extents),
BTRFS_ATTR_PTR(discard, iops_limit),
BTRFS_ATTR_PTR(discard, kbps_limit),
NULL,
};

Expand Down

0 comments on commit e93591b

Please sign in to comment.