From: Tao Cui <cui.tao@linux.dev>
To: sashiko-reviews@lists.linux.dev
Cc: cui.tao@linux.dev, tj@kernel.org, hannes@cmpxchg.org,
mkoutny@suse.com, bpf@vger.kernel.org
Subject: Re: [RFC PATCH v4 1/5] blk-iocost: add BPF struct_ops cost model support
Date: Wed, 16 Sep 2026 18:31:57 +0800 [thread overview]
Message-ID: <2d6e4798-a3eb-4a63-8575-c3f9cbd7fe62@linux.dev> (raw)
In-Reply-To: <20260916073408.D92471F000FF@smtp.kernel.org>
在 2026/9/16 15:34, sashiko-bot@kernel.org 写道:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [High] bpf: resource leak and broken blkcg notifications on BPF model unbind
> - [High] bpf: coefficient-only writes fail if bound model is unregistered
> - [Low] bpf: multi-line comments do not follow modern kernel style
Thanks for the reviews. All five findings across the two patches are
confirmed and will be fixed in the next revision:
- the lookup in iocost_bpf_model_get() only searched the registry, so
a coefficient-only write on a device using an unregistered model
failed with ENOENT; the lookup will fall back to the notify list,
keeping such a model selectable by name until the last device
unbinds
- the notify-list detach condition in iocost_bpf_model_put() was
wrong for a registered model bound to several devices: the first
unbind removed the node from the lifecycle list early and the last
unbind then failed to find it, leaking the BPF map reference; the
node will leave the notify list only with the last binding
- the 2x example model did not advance its cursor for merged bios,
unlike the builtin backmerge behaviour, so a long merged stream
could drift past the 16MB seek threshold and misprice the
following IO as random
- the multi-line comments use the opening marker on its own line
While testing those fixes we also found and fixed a problem of our
own: two racing io.cost.model writes resolving the same model each
took a reference on it, but the write whose commit found the model
already bound did not drop one, leaking a map reference. The commit
path now drops the redundant reference.
The next revision will follow shortly.
> --
>
> commit 4e914860298423131f3423ab63f79ed4a655051f
> Author: Tao Cui <cuitao@kylinos.cn>
>
> blk-iocost: add BPF struct_ops cost model support
>
> This commit introduces a BPF struct_ops based cost model for blk-iocost,
> replacing the builtin linear model on a device. It implements a
> registration framework where sysfs bindings map a registered model to a
> device.
>
>> diff --git a/block/blk-iocost-bpf.c b/block/blk-iocost-bpf.c
>> new file mode 100644
>> index 0000000000000..7f1f9a2e51cb2
>> --- /dev/null
>> +++ b/block/blk-iocost-bpf.c
>
> [ ... ]
>
>> +const struct iocost_model_ops *iocost_bpf_model_get(const char *name)
>> +{
>> + struct iocost_bpf_model *m;
>> + const struct iocost_model_ops *ops = ERR_PTR(-ENOENT);
>> +
>> + mutex_lock(&iocost_bpf_reg_lock);
>> + list_for_each_entry(m, &iocost_bpf_models, list) {
>
> [Severity: High]
> Will this lookup fail to find models that are unregistered but still
> actively bound to devices? If a user issues a coefficient-only write on
> a device using an unregistered model, ioc_cost_model_write() passes the
> name here, but since this only searches the registry (iocost_bpf_models),
> it returns -ENOENT and rejects the write.
>
>> + if (!strcmp(m->ops->name, name)) {
>
> [ ... ]
>
>> +static void bpf_iocost_unreg(void *kdata, struct bpf_link *link)
>> +{
>> + struct iocost_model_ops *ops = kdata;
>> + struct iocost_bpf_model *m;
>> +
>> + mutex_lock(&iocost_bpf_reg_lock);
>> + m = iocost_bpf_model_lookup(ops);
>> + if (m) {
>> + /* keep the linkage queryable so model_put() can tell a
>> + * still-registered node (one ref held by the registry)
>> + * from one kept alive only by device bindings
>> + */
>
> [Severity: Low]
> Does this comment style follow the BPF subsystem requirements? The
> standard specifies that multi-line comments should have the opening /*
> on its own line.
>
>> + list_del_init(&m->list);
>
> [ ... ]
>
>> +void iocost_bpf_model_put(const struct iocost_model_ops *ops)
>> +{
>> + struct iocost_bpf_model *m;
>> +
>> + mutex_lock(&iocost_bpf_reg_lock);
>> + list_for_each_entry(m, &iocost_bpf_lifecycle, lifecycle) {
>> + if (m->ops == ops)
>> + break;
>> + }
>> + if (&m->lifecycle != &iocost_bpf_lifecycle) {
>> + bool freed = refcount_dec_and_test(&m->refs);
>> +
>> + /* leave the notify list with the last binding: the
>> + * remaining ref is either the registry's (node still on
>> + * iocost_bpf_models) or zero and the node is freed
>> + */
>
> [Severity: Low]
> Similarly here, this multi-line comment is missing the opening /* on its
> own line.
>
>> + if (freed || !list_empty(&m->list))
>> + list_del(&m->lifecycle);
>> + mutex_unlock(&iocost_bpf_reg_lock);
>> + bpf_struct_ops_put(ops);
>> + if (freed)
>> + kfree(m);
>> + return;
>> + }
>
> [Severity: High]
> Can this sequence prematurely detach registered models from the lifecycle
> list and leak BPF map references?
>
> When the first device is unbound from a registered model,
> !list_empty(&m->list) will evaluate to true. This removes the model from
> the lifecycle list early, breaking blkcg notifications.
>
> When subsequent devices are unbound, list_for_each_entry() at the start of
> iocost_bpf_model_put() will fail to find the model, causing execution to
> jump over this block completely. The bpf_struct_ops_put() call will be
> skipped, leading to a map reference leak.
>
>> + mutex_unlock(&iocost_bpf_reg_lock);
>> +}
>
>> diff --git a/block/blk-iocost.c b/block/blk-iocost.c
>> index 2745bffcd5eef..22b2ece52fa58 100644
>> --- a/block/blk-iocost.c
>> +++ b/block/blk-iocost.c
>
> [ ... ]
>
>> @@ -3591,6 +3628,24 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
>> spin_lock_irq(&ioc->lock);
>> memcpy(u, ioc->params.i_lcoefs, sizeof(u));
>> user = ioc->user_cost_model;
>> +#ifdef CONFIG_BLK_CGROUP_IOCOST_BPF
>> + {
>> + const struct iocost_model_ops *model =
>> + rcu_dereference_protected(ioc->model,
>> + lockdep_is_held(&ioc->lock));
>> +
>> + /* seed from the bound model so a coefficient-only write
>> + * keeps it bound; ctrl=auto/user and model=linear are
>> + * the explicit ways back to the builtin model
>> + */
>
> [Severity: Low]
> This comment also places text on the same line as the opening /*, which
> diverges from the preferred BPF multi-line comment style.
>
>> + if (model)
>> + strscpy(bpf_model, model->name, sizeof(bpf_model));
>
next prev parent reply other threads:[~2026-09-16 10:32 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-16 7:22 [RFC PATCH v4 0/5] blk-iocost: BPF struct_ops cost model Tao Cui
2026-09-16 7:22 ` [RFC PATCH v4 1/5] blk-iocost: add BPF struct_ops cost model support Tao Cui
2026-09-16 7:34 ` sashiko-bot
2026-09-16 10:31 ` Tao Cui [this message]
2026-09-16 7:22 ` [RFC PATCH v4 2/5] selftests/bpf: add iocost cost model test Tao Cui
2026-09-16 7:34 ` sashiko-bot
2026-09-16 7:23 ` [RFC PATCH v4 3/5] blk-iocost: add iocost_ioc_tick tracepoint for per-period device summary Tao Cui
2026-09-16 7:23 ` [RFC PATCH v4 4/5] selftests/bpf: add multi-stream sequentiality example model Tao Cui
2026-09-16 7:23 ` [RFC PATCH v4 5/5] docs: cgroup-v2: document io.cost model=<name> binding Tao Cui
2026-09-16 8:22 ` bot+bpf-ci
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2d6e4798-a3eb-4a63-8575-c3f9cbd7fe62@linux.dev \
--to=cui.tao@linux.dev \
--cc=bpf@vger.kernel.org \
--cc=hannes@cmpxchg.org \
--cc=mkoutny@suse.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=tj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.