From: Tao Cui <cui.tao@linux.dev>
To: tj@kernel.org, josef@toxicopanda.com, axboe@kernel.dk
Cc: cgroups@vger.kernel.org, linux-block@vger.kernel.org,
linux-kernel@vger.kernel.org, bpf@vger.kernel.org,
andrii@kernel.org, eddyz87@gmail.com, ast@kernel.org,
daniel@iogearbox.net, linux-kselftest@vger.kernel.org,
cui.tao@linux.dev, cuitao@kylinos.cn, ameryhung@gmail.com,
alexei.starovoitov@gmail.com
Subject: [RFC PATCH v7 2/4] selftests/bpf: add iocost cost model test
Date: Thu, 24 Sep 2026 13:45:47 +0800 [thread overview]
Message-ID: <20260924054549.2271705-3-cui.tao@linux.dev> (raw)
In-Reply-To: <20260924054549.2271705-1-cui.tao@linux.dev>
From: Tao Cui <cuitao@kylinos.cn>
Add an example cost model implementing the full builtin linear HDD
formula at double cost, and a test which attaches it to one device:
the dev member of the struct_ops is written through the map's
initial value before load, as hid_bpf tests do with hid_id, and
attaching the struct_ops attaches the model to the device. The test
verifies the model=bpf readback while attached, that a second model
on the same device fails with -EBUSY, and that detaching restores
the builtin model.
Under the same workload the doubled model charges 1.99x the
builtin model (measured 2882us -> 5722us per IO, completed IO count
halved). The example also sets the transfer cost coefficients so
the builtin sizing follows the doubled pricing.
Per-cgroup stream state uses a CGRP_STORAGE map keyed by the cgroup
of the issuing bio, so the model inherits the cgroup
lifetime. opf carries the full bio->bi_opf
including REQ_* flag bits, so the operation must be extracted with a
mask, not compared for equality.
CONFIG_BLK_CGROUP_IOCOST and CONFIG_BLK_CGROUP_IOCOST_BPF are added
to the selftest kernel config: without them vmlinux.h does not
contain iocost_model_ops and the skeletons fail to build; the
runtime skip cannot avoid a build dependency.
Requires root, cgroup v2 and a device given as major:minor in
$IOCOST_TEST_DEV.
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
---
tools/testing/selftests/bpf/config | 2 +
.../selftests/bpf/prog_tests/iocost_model.c | 182 ++++++++++++++++++
.../selftests/bpf/progs/iocost_model.c | 139 +++++++++++++
tools/testing/selftests/bpf/progs/iocost_ms.c | 159 +++++++++++++++
4 files changed, 482 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/iocost_model.c
create mode 100644 tools/testing/selftests/bpf/progs/iocost_model.c
create mode 100644 tools/testing/selftests/bpf/progs/iocost_ms.c
diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config
index d292cb60a5a4..6e005145d3a8 100644
--- a/tools/testing/selftests/bpf/config
+++ b/tools/testing/selftests/bpf/config
@@ -140,3 +140,5 @@ CONFIG_SMC_HS_CTRL_BPF=y
CONFIG_DIBS=y
CONFIG_DIBS_LO=y
CONFIG_PM_WAKELOCKS=y
+CONFIG_BLK_CGROUP_IOCOST=y
+CONFIG_BLK_CGROUP_IOCOST_BPF=y
diff --git a/tools/testing/selftests/bpf/prog_tests/iocost_model.c b/tools/testing/selftests/bpf/prog_tests/iocost_model.c
new file mode 100644
index 000000000000..156c75367af0
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/iocost_model.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include <fcntl.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+#include "iocost_model.skel.h"
+#include "iocost_ms.skel.h"
+
+/*
+ * Read back the io.cost.model line of dev and copy the model= value
+ * into @model. Returns 0 on success.
+ */
+static int readback_model(const char *dev, char *model, size_t model_sz)
+{
+ char line[256], word[256], *m, *end;
+ FILE *fp;
+ int found = 0;
+
+ fp = fopen("/sys/fs/cgroup/io.cost.model", "r");
+ if (!fp)
+ return -1;
+ while (fgets(line, sizeof(line), fp)) {
+ if (sscanf(line, "%255s", word) == 1 && !strcmp(word, dev)) {
+ found = 1;
+ break;
+ }
+ }
+ fclose(fp);
+ if (!found)
+ return -1;
+
+ m = strstr(line, "model=");
+ if (!m)
+ return -1;
+ m += strlen("model=");
+ end = m;
+ while (*end && *end != ' ')
+ end++;
+ snprintf(model, model_sz, "%.*s", (int)(end - m), m);
+ return 0;
+}
+
+/*
+ * Attach the example model to one device, given as major:minor in
+ * $IOCOST_TEST_DEV: the dev member is written through the struct_ops
+ * map's initial value before load, as hid_bpf_ops does with hid_id,
+ * and loading attaches the model to the device. Detaching the
+ * struct_ops restores the builtin model.
+ *
+ * Requires root, cgroup v2 and a device with iocost support.
+ */
+void serial_test_iocost_model(void)
+{
+ struct iocost_model *skel, *second;
+ unsigned int maj, min;
+ __u64 *ops_dev, *sdev;
+ int err;
+ char model[32], *dev;
+
+ dev = getenv("IOCOST_TEST_DEV");
+ if (!dev || geteuid() != 0 || sscanf(dev, "%u:%u", &maj, &min) != 2) {
+ test__skip();
+ return;
+ }
+
+ skel = iocost_model__open();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ return;
+
+ /* dev is the first member of struct iocost_model_ops */
+ ops_dev = bpf_map__initial_value(skel->maps.iocost_2x, NULL);
+ if (!ASSERT_OK_PTR(ops_dev, "initial_value")) {
+ iocost_model__destroy(skel);
+ return;
+ }
+ *ops_dev = makedev(maj, min);
+
+ err = iocost_model__load(skel);
+ if (!ASSERT_OK(err, "skel_load")) {
+ iocost_model__destroy(skel);
+ return;
+ }
+
+ err = iocost_model__attach(skel);
+ if (ASSERT_OK(err, "attach")) {
+ /*
+ * attached: the read path reports model=bpf until the
+ * struct_ops is detached; ctrl keeps describing the
+ * builtin coefficients
+ */
+ err = readback_model(dev, model, sizeof(model));
+ if (ASSERT_OK(err, "readback"))
+ ASSERT_EQ(strcmp(model, "bpf"), 0, "model_bpf");
+
+ /* a second model on the same device fails with -EBUSY */
+ second = iocost_model__open();
+ if (ASSERT_OK_PTR(second, "second_open")) {
+ sdev = bpf_map__initial_value(
+ second->maps.iocost_2x, NULL);
+ if (!ASSERT_OK_PTR(sdev, "second_initial_value"))
+ goto out_destroy;
+ *sdev = makedev(maj, min);
+ err = iocost_model__load(second);
+ if (ASSERT_OK(err, "second_load")) {
+ struct bpf_link *l2;
+
+ /*
+ * the kernel rejects attaching a second
+ * model to the device with EBUSY
+ */
+ l2 = bpf_map__attach_struct_ops(
+ second->maps.iocost_2x);
+ if (!ASSERT_ERR_PTR(l2, "second_ebusy"))
+ bpf_link__destroy(l2);
+ else
+ ASSERT_EQ(libbpf_get_error(l2), -EBUSY,
+ "second_ebusy_errno");
+ }
+out_destroy:
+ iocost_model__destroy(second);
+ }
+
+ iocost_model__detach(skel);
+
+ err = readback_model(dev, model, sizeof(model));
+ if (ASSERT_OK(err, "readback_after_detach"))
+ ASSERT_EQ(strcmp(model, "linear"), 0, "model_linear");
+ }
+
+ iocost_model__destroy(skel);
+}
+/*
+ * Same check for the multi-stream example model. Only one model can
+ * be attached to a device at a time; both tests attach and detach, so
+ * they are serial and independent.
+ */
+void serial_test_iocost_model_streams(void)
+{
+ struct iocost_ms *skel;
+ unsigned int maj, min;
+ __u64 *ops_dev;
+ int err;
+ char model[32], *dev;
+
+ dev = getenv("IOCOST_TEST_DEV");
+ if (!dev || geteuid() != 0 || sscanf(dev, "%u:%u", &maj, &min) != 2) {
+ test__skip();
+ return;
+ }
+
+ skel = iocost_ms__open();
+ if (!ASSERT_OK_PTR(skel, "skel_open"))
+ return;
+
+ ops_dev = bpf_map__initial_value(skel->maps.iocost_ms, NULL);
+ if (!ASSERT_OK_PTR(ops_dev, "initial_value")) {
+ iocost_ms__destroy(skel);
+ return;
+ }
+ *ops_dev = makedev(maj, min);
+
+ err = iocost_ms__load(skel);
+ if (!ASSERT_OK(err, "skel_load")) {
+ iocost_ms__destroy(skel);
+ return;
+ }
+
+ err = iocost_ms__attach(skel);
+ if (ASSERT_OK(err, "attach")) {
+ err = readback_model(dev, model, sizeof(model));
+ if (ASSERT_OK(err, "readback"))
+ ASSERT_EQ(strcmp(model, "bpf"), 0, "model_bpf");
+
+ iocost_ms__detach(skel);
+
+ err = readback_model(dev, model, sizeof(model));
+ if (ASSERT_OK(err, "readback_after_detach"))
+ ASSERT_EQ(strcmp(model, "linear"), 0, "model_linear");
+ }
+
+ iocost_ms__destroy(skel);
+}
diff --git a/tools/testing/selftests/bpf/progs/iocost_model.c b/tools/testing/selftests/bpf/progs/iocost_model.c
new file mode 100644
index 000000000000..369818bda1cf
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/iocost_model.c
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Example iocost cost model: the builtin linear HDD formula with all
+ * costs doubled, for one device given by the dev member of the
+ * struct_ops.
+ *
+ * The constants mirror what calc_lcoefs() derives from the AUTOP_HDD
+ * defaults (rbps=174019176 rseqiops=41708 rrandiops=370, w-side
+ * analog) in vtime units where 1s == 2^37. On a rotational device
+ * still on ctrl=auto, a device with this model attached charges
+ * twice the builtin model under the same workload, so the
+ * doubled cost is a direct check that accounting goes through the
+ * BPF path. On a non-rotational device, or one with user-pinned
+ * coefficients, the ratio to the builtin model is arbitrary.
+ *
+ * A zero cursor means "no previous IO". The cursor advances for
+ * every priced bio with a non-zero size (READ/WRITE), merged ones
+ * included, truncating to whole sectors like the builtin, so flushes
+ * and discards leave it alone and merged streams do not drift past
+ * the 16MB seek threshold.
+ *
+ * The model implements the full linear formula itself, including
+ * flushes: there is no fallback to the builtin model, a dataless
+ * A dataless WRITE|REQ_PREFLUSH keeps the write base: the op is still
+ * WRITE, so it carries WSEQIO (or WRANDIO after a seek) plus one page.
+ */
+
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+/*
+ * VTIME_PER_SEC, IOC_PAGE_SIZE/SHIFT, IOC_SECT_TO_PAGE_SHIFT and
+ * IOCOST_COST_F_MERGE come from vmlinux.h (BTF enum constants)
+ */
+#define LCOEF_RANDIO_PAGES 4096 /* 16MB seek threshold */
+#define IOCOST_REQ_OP_MASK 0xff /* REQ_OP_MASK, not in BTF */
+
+/*
+ * DIV64_U64_ROUND_UP / DIV_ROUND_UP_ULL equivalents, folded at
+ * compile time
+ */
+#define RU(x, y) ((x) / (y) + (((x) % (y)) ? 1 : 0))
+
+#define RBPS 174019176ULL
+#define RSEQIOPS 41708ULL
+#define RRANDIOPS 370ULL
+#define WBPS 178075866ULL
+#define WSEQIOPS 42705ULL
+#define WRANDIOPS 378ULL
+
+#define RPAGE (RU(VTIME_PER_SEC, RU(RBPS, IOC_PAGE_SIZE)))
+#define RSEQIO (RU(VTIME_PER_SEC, RSEQIOPS) - RPAGE)
+#define RRANDIO (RU(VTIME_PER_SEC, RRANDIOPS) - RPAGE)
+#define WPAGE (RU(VTIME_PER_SEC, RU(WBPS, IOC_PAGE_SIZE)))
+#define WSEQIO (RU(VTIME_PER_SEC, WSEQIOPS) - WPAGE)
+#define WRANDIO (RU(VTIME_PER_SEC, WRANDIOPS) - WPAGE)
+
+/*
+ * per-cgroup cursor storage: keyed by the cgroup, freed with it, so
+ * per-cgroup state follows the cgroup lifetime
+ */
+struct {
+ __uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
+ __uint(map_flags, BPF_F_NO_PREALLOC);
+ __type(key, int);
+ __type(value, __u64);
+} cursor_store SEC(".maps");
+
+SEC("struct_ops")
+u64 BPF_PROG(iocost_2x_calc_cost, struct bio *bio, u64 model_flags)
+{
+ u64 opf = bio->bi_opf, nbytes = bio->bi_iter.bi_size;
+ u64 sector = bio->bi_iter.bi_sector;
+ struct blkcg *blkcg = bio->bi_blkg->blkcg;
+ u64 pages, seek_pages = 0, base, coef_page, randio, cost;
+ __u64 *cursor, cur;
+ int priced;
+
+ /* builtin truncates: max(sectors >> IOC_SECT_TO_PAGE_SHIFT, 1) */
+ pages = nbytes >> IOC_PAGE_SHIFT;
+ if (!pages)
+ pages = 1;
+
+ if ((opf & IOCOST_REQ_OP_MASK) == REQ_OP_READ) {
+ base = RSEQIO; coef_page = RPAGE; randio = RRANDIO;
+ } else if ((opf & IOCOST_REQ_OP_MASK) == REQ_OP_WRITE) {
+ base = WSEQIO; coef_page = WPAGE; randio = WRANDIO;
+ } else {
+ /*
+ * a fully owning model must price every op; unknown
+ * ops are priced as a single page write
+ */
+ base = 0; coef_page = WPAGE; randio = 0;
+ }
+
+ /*
+ * mirror the builtin cursor semantics: seek distance is only
+ * computed against a non-zero cursor, and the cursor is
+ * advanced for bios the builtin prices (READ/WRITE with a
+ * non-zero size), merged ones included, so flushes and
+ * discards leave it alone
+ */
+ priced = (opf & IOCOST_REQ_OP_MASK) == REQ_OP_READ ||
+ (opf & IOCOST_REQ_OP_MASK) == REQ_OP_WRITE;
+ cursor = bpf_cgrp_storage_get(&cursor_store,
+ blkcg->css.cgroup, NULL,
+ BPF_LOCAL_STORAGE_GET_F_CREATE);
+ if (!cursor) {
+ if (model_flags & IOCOST_COST_F_MERGE)
+ base = 0;
+ return 2 * (base + pages * coef_page);
+ }
+ cur = *cursor;
+ if (cur && priced) {
+ seek_pages = sector > cur ? sector - cur
+ : cur - sector;
+ seek_pages >>= IOC_SECT_TO_PAGE_SHIFT;
+ if (seek_pages > LCOEF_RANDIO_PAGES)
+ base = randio;
+ }
+ if (priced && nbytes)
+ *cursor = sector + (nbytes >> 9);
+
+ if (model_flags & IOCOST_COST_F_MERGE)
+ base = 0;
+
+ cost = 2 * (base + pages * coef_page);
+ return cost;
+}
+
+SEC(".struct_ops")
+struct iocost_model_ops iocost_2x = {
+ .read_vtime_per_page = 2 * RPAGE,
+ .write_vtime_per_page = 2 * WPAGE,
+ .calc_cost = (void *)iocost_2x_calc_cost,
+};
+
+char LICENSE[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/iocost_ms.c b/tools/testing/selftests/bpf/progs/iocost_ms.c
new file mode 100644
index 000000000000..aaa2e4489c1b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/iocost_ms.c
@@ -0,0 +1,159 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Example multi-stream sequentiality detection cost model.
+ *
+ * The builtin model keeps a single cursor per cgroup, so two
+ * interleaved sequential readers in one cgroup are all priced random
+ * (measured 89x overcharge, 12.9x throughput collapse), while random
+ * IO inside a hot window smaller than the 16MB seek threshold is
+ * priced sequential (measured 107x undercharge). This model replaces
+ * the single cursor with a per-cgroup table of stream slots: an IO is
+ * sequential iff its sector matches the expected next sector of any
+ * tracked stream. Interleaved streams keep their own slots, and
+ * windowed random IO rarely matches a moving expectation.
+ *
+ * Stream state lives in a CGRP_STORAGE map, so it is created and
+ * freed with the cgroup. The model implements the full builtin
+ * linear formula itself, including flush pricing.
+ */
+#include "vmlinux.h"
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_tracing.h>
+
+/*
+ * VTIME_PER_SEC, IOC_PAGE_SIZE/SHIFT, IOC_SECT_TO_PAGE_SHIFT and
+ * IOCOST_COST_F_MERGE come from vmlinux.h (BTF enum constants)
+ */
+#define IOCOST_REQ_OP_MASK 0xff /* REQ_OP_MASK, not in BTF */
+
+/*
+ * DIV64_U64_ROUND_UP / DIV_ROUND_UP_ULL equivalents, folded at
+ * compile time
+ */
+#define RU(x, y) ((x) / (y) + (((x) % (y)) ? 1 : 0))
+
+#define RBPS 174019176ULL
+#define RSEQIOPS 41708ULL
+#define RRANDIOPS 370ULL
+#define WBPS 178075866ULL
+#define WSEQIOPS 42705ULL
+#define WRANDIOPS 378ULL
+
+#define RPAGE (RU(VTIME_PER_SEC, RU(RBPS, IOC_PAGE_SIZE)))
+#define RSEQIO (RU(VTIME_PER_SEC, RSEQIOPS) - RPAGE)
+#define RRANDIO (RU(VTIME_PER_SEC, RRANDIOPS) - RPAGE)
+#define WPAGE (RU(VTIME_PER_SEC, RU(WBPS, IOC_PAGE_SIZE)))
+#define WSEQIO (RU(VTIME_PER_SEC, WSEQIOPS) - WPAGE)
+#define WRANDIO (RU(VTIME_PER_SEC, WRANDIOPS) - WPAGE)
+
+#define NSLOTS 4
+
+struct streams {
+ __u64 expected[NSLOTS]; /* next expected sector, per stream */
+ __u64 stamp[NSLOTS]; /* LRU stamp, 0 = empty */
+};
+
+/*
+ * per-cgroup stream table: keyed by the cgroup, freed with it
+ */
+struct {
+ __uint(type, BPF_MAP_TYPE_CGRP_STORAGE);
+ __uint(map_flags, BPF_F_NO_PREALLOC);
+ __type(key, int);
+ __type(value, struct streams);
+} stream_tab SEC(".maps");
+
+SEC("struct_ops")
+u64 BPF_PROG(iocost_ms_calc_cost, struct bio *bio, u64 model_flags)
+{
+ u64 opf = bio->bi_opf, nbytes = bio->bi_iter.bi_size;
+ u64 sector = bio->bi_iter.bi_sector;
+ struct blkcg *blkcg = bio->bi_blkg->blkcg;
+ struct streams *s;
+ u64 pages, base, coef_page, randio, advance, now;
+ u32 i, victim = 0, found = 0xFFFFFFFF;
+
+ if ((opf & IOCOST_REQ_OP_MASK) == REQ_OP_READ) {
+ base = RSEQIO; coef_page = RPAGE; randio = RRANDIO;
+ } else if ((opf & IOCOST_REQ_OP_MASK) == REQ_OP_WRITE) {
+ base = WSEQIO; coef_page = WPAGE; randio = WRANDIO;
+ } else {
+ /*
+ * a fully owning model must price every op; unknown
+ * ops are priced as per-page writes
+ */
+ base = 0; coef_page = WPAGE; randio = 0;
+ }
+ advance = RU(nbytes, 512); /* sectors */
+
+ /* only bios the builtin prices participate in stream tracking */
+ if (!(((opf & IOCOST_REQ_OP_MASK) == REQ_OP_READ ||
+ (opf & IOCOST_REQ_OP_MASK) == REQ_OP_WRITE) && nbytes)) {
+ pages = nbytes >> IOC_PAGE_SHIFT;
+ if (!pages)
+ pages = 1;
+ return base + pages * coef_page;
+ }
+
+ s = bpf_cgrp_storage_get(&stream_tab, blkcg->css.cgroup, NULL,
+ BPF_LOCAL_STORAGE_GET_F_CREATE);
+ if (!s) {
+ /* no storage: price per page, truncating like the builtin */
+ pages = nbytes >> IOC_PAGE_SHIFT;
+ if (!pages)
+ pages = 1;
+ return base + pages * coef_page;
+ }
+
+ /*
+ * Slot access is lockless, mirroring the builtin single-cursor
+ * update in ioc_rqos_throttle(): concurrent CPUs submitting for
+ * the same cgroup can race on slot updates; mispricing is
+ * bounded and acceptable for an example model.
+ */
+ now = bpf_ktime_get_ns();
+ for (i = 0; i < NSLOTS; i++) {
+ if (s->expected[i] == sector && s->stamp[i]) {
+ found = i;
+ break;
+ }
+ }
+ if (found != 0xFFFFFFFF) {
+ /* sequential: keep the seq base from the op branch */
+ s->expected[found] = sector + advance;
+ s->stamp[found] = now;
+ } else {
+ base = randio;
+ for (i = 1; i < NSLOTS; i++) {
+ if (s->stamp[i] < s->stamp[victim])
+ victim = i;
+ }
+ s->expected[victim] = sector + advance;
+ s->stamp[victim] = now;
+ }
+
+ /* builtin truncates: max(sectors >> IOC_SECT_TO_PAGE_SHIFT, 1) */
+ pages = nbytes >> IOC_PAGE_SHIFT;
+ if (!pages)
+ pages = 1;
+ if (model_flags & IOCOST_COST_F_MERGE) {
+ /*
+ * merged bios skip the base cost but still advance
+ * the stream position above, so a merge at the
+ * expected sector does not make the following new IO
+ * look random
+ */
+ base = 0;
+ }
+
+ return base + pages * coef_page;
+}
+
+SEC(".struct_ops")
+struct iocost_model_ops iocost_ms = {
+ .read_vtime_per_page = RPAGE,
+ .write_vtime_per_page = WPAGE,
+ .calc_cost = (void *)iocost_ms_calc_cost,
+};
+
+char LICENSE[] SEC("license") = "GPL";
--
2.43.0
next prev parent reply other threads:[~2026-09-24 5:46 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-24 5:45 [RFC PATCH v7 0/4] blk-iocost: BPF struct_ops cost model Tao Cui
2026-09-24 5:45 ` [RFC PATCH v7 1/4] blk-iocost: add BPF struct_ops cost model support Tao Cui
2026-09-24 6:00 ` sashiko-bot
2026-09-24 6:30 ` bot+bpf-ci
2026-09-29 0:42 ` Tejun Heo
2026-09-29 13:42 ` Tao Cui
2026-09-29 16:27 ` Tejun Heo
2026-09-30 4:14 ` Tao Cui
2026-09-24 5:45 ` Tao Cui [this message]
2026-09-24 5:57 ` [RFC PATCH v7 2/4] selftests/bpf: add iocost cost model test sashiko-bot
2026-09-24 6:30 ` bot+bpf-ci
2026-09-24 5:45 ` [RFC PATCH v7 3/4] blk-iocost: add iocost_ioc_tick tracepoint for per-period device summary Tao Cui
2026-09-24 6:17 ` bot+bpf-ci
2026-09-29 0:42 ` Tejun Heo
2026-09-29 13:46 ` Tao Cui
2026-09-24 5:45 ` [RFC PATCH v7 4/4] docs: cgroup-v2: document the iocost BPF cost model attachment Tao Cui
2026-09-29 0:42 ` [RFC PATCH v7 0/4] blk-iocost: BPF struct_ops cost model Tejun Heo
2026-09-29 13:39 ` Tao Cui
2026-09-29 16:27 ` Tejun Heo
2026-09-30 4:09 ` Tao Cui
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=20260924054549.2271705-3-cui.tao@linux.dev \
--to=cui.tao@linux.dev \
--cc=alexei.starovoitov@gmail.com \
--cc=ameryhung@gmail.com \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=axboe@kernel.dk \
--cc=bpf@vger.kernel.org \
--cc=cgroups@vger.kernel.org \
--cc=cuitao@kylinos.cn \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=josef@toxicopanda.com \
--cc=linux-block@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--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.