* Re: [PATCH v4 02/12] block/bdev: Annotate the blk_holder_ops callback functions
From: Marco Elver @ 2026-05-11 22:19 UTC (permalink / raw)
To: Bart Van Assche, Peter Zijlstra
Cc: Jens Axboe, linux-block, Christoph Hellwig
In-Reply-To: <20260511163100.1887263-3-bvanassche@acm.org>
On Mon, 11 May 2026 at 18:31, Bart Van Assche <bvanassche@acm.org> wrote:
>
> The four callback functions in blk_holder_ops all release the
> bd_holder_lock. Annotate these functions accordingly.
>
> Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Because of this change we'll need clang 23, or you add:
CONTEXT_ANALYSIS := $(call clang-min-version, 230000)
.. although anything else that includes blkdev.h that has
CONTEXT_ANALYSIS := y, but is compiled with clang 22 will break.
Would have been good to wait for clang 23 to be released (August this
year) - although if we consider the next merge window + final release
of Linux 7.2, it might get reasonably close to August.
> ---
> include/linux/blkdev.h | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
> index 8651af4fe9d7..d0c181da2da0 100644
> --- a/include/linux/blkdev.h
> +++ b/include/linux/blkdev.h
> @@ -1747,22 +1747,26 @@ void blkdev_show(struct seq_file *seqf, off_t offset);
> #endif
>
> struct blk_holder_ops {
> - void (*mark_dead)(struct block_device *bdev, bool surprise);
> + void (*mark_dead)(struct block_device *bdev, bool surprise)
> + __releases(&bdev->bd_holder_lock);
>
> /*
> * Sync the file system mounted on the block device.
> */
> - void (*sync)(struct block_device *bdev);
> + void (*sync)(struct block_device *bdev)
> + __releases(&bdev->bd_holder_lock);
>
> /*
> * Freeze the file system mounted on the block device.
> */
> - int (*freeze)(struct block_device *bdev);
> + int (*freeze)(struct block_device *bdev)
> + __releases(&bdev->bd_holder_lock);
>
> /*
> * Thaw the file system mounted on the block device.
> */
> - int (*thaw)(struct block_device *bdev);
> + int (*thaw)(struct block_device *bdev)
> + __releases(&bdev->bd_holder_lock);
> };
>
> /*
^ permalink raw reply
* [PATCH] block: don't overwrite bip_vcnt in bio_integrity_copy_user()
From: David Carlier @ 2026-05-11 21:51 UTC (permalink / raw)
To: Jens Axboe
Cc: Christoph Hellwig, Martin K . Petersen, Anuj Gupta, Kanchan Joshi,
linux-block, linux-kernel, David Carlier
bio_integrity_add_page() already sets bip_vcnt to 1 for the bounce
segment. Overwriting it with nr_vecs breaks bip_vcnt <= bip_max_vcnt
on WRITE (bip_max_vcnt is 1), so the gap-merge checks in block/blk.h
read past the bip_vec[] flex array. On READ the read is in bounds
but lands on a saved user bvec instead of the bounce.
The line was added for split propagation, but bio_integrity_clone()
doesn't copy bip_vcnt and BIP_CLONE_FLAGS excludes BIP_COPY_USER.
Fixes: 3991657ae707 ("block: set bip_vcnt correctly")
Signed-off-by: David Carlier <devnexen@gmail.com>
---
block/bio-integrity.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index e79eaf047794..869746412949 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -308,7 +308,6 @@ static int bio_integrity_copy_user(struct bio *bio, struct bio_vec *bvec,
}
bip->bip_flags |= BIP_COPY_USER;
- bip->bip_vcnt = nr_vecs;
return 0;
free_bip:
bio_integrity_free(bio);
--
2.53.0
^ permalink raw reply related
* [PATCH] block: recompute nr_integrity_segments in blk_insert_cloned_request
From: Casey Chen @ 2026-05-11 21:22 UTC (permalink / raw)
To: Jens Axboe
Cc: Keith Busch, Christoph Hellwig, Martin K . Petersen, linux-block,
dm-devel, Casey Chen
blk_insert_cloned_request() already recomputes nr_phys_segments
against the bottom queue, because "the queue settings related to
segment counting may differ from the original queue." The exact same
reasoning applies to integrity segments: a stacked driver's underlying
queue can have tighter virt_boundary_mask, seg_boundary_mask, or
max_segment_size than the top queue, in which case
blk_rq_count_integrity_sg() against the bottom queue produces a
different count than the cached rq->nr_integrity_segments inherited
from the source request by blk_rq_prep_clone().
When the cached count is lower than the bottom queue's actual count,
blk_rq_map_integrity_sg() trips
BUG_ON(segments > rq->nr_integrity_segments);
on dispatch. The same families of stacked setups that motivated the
existing nr_phys_segments recompute -- dm-multipath fanning out to
nvme-rdma in particular -- can produce this.
Mirror the nr_phys_segments handling: when the request carries
integrity, recompute nr_integrity_segments against the bottom queue
and reject the request if it exceeds the bottom queue's
max_integrity_segments. blk_rq_count_integrity_sg() and
queue_max_integrity_segments() are both already available via
<linux/blk-integrity.h>, which blk-mq.c includes.
This closes a latent gap in the stacking contract and brings the
integrity-segment accounting in line with the existing
phys-segment accounting.
Fixes: 76c313f658d2 ("blk-integrity: improved sg segment mapping")
Signed-off-by: Casey Chen <cachen@purestorage.com>
---
block/blk-mq.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 4c5c16cce4f8..d0c37daf568f 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -3307,6 +3307,25 @@ blk_status_t blk_insert_cloned_request(struct request *rq)
return BLK_STS_IOERR;
}
+ /*
+ * Integrity segment counting depends on the same queue limits
+ * (virt_boundary_mask, seg_boundary_mask, max_segment_size) that
+ * vary across stacked queues, so recompute against the bottom
+ * queue just like nr_phys_segments above.
+ */
+ if (blk_integrity_rq(rq) && rq->bio) {
+ unsigned short max_int_segs = queue_max_integrity_segments(q);
+
+ rq->nr_integrity_segments =
+ blk_rq_count_integrity_sg(rq->q, rq->bio);
+ if (rq->nr_integrity_segments > max_int_segs) {
+ printk(KERN_ERR "%s: over max integrity segments limit. (%u > %u)\n",
+ __func__, rq->nr_integrity_segments,
+ max_int_segs);
+ return BLK_STS_IOERR;
+ }
+ }
+
if (q->disk && should_fail_request(q->disk->part0, blk_rq_bytes(rq)))
return BLK_STS_IOERR;
--
2.50.1
^ permalink raw reply related
* Re: [PATCH v3 02/12] block/bdev: Annotate the blk_holder_ops callback invocations
From: Marco Elver @ 2026-05-11 18:15 UTC (permalink / raw)
To: Bart Van Assche
Cc: Christoph Hellwig, Jens Axboe, linux-block, Damien Le Moal,
Nathan Chancellor, Peter Zijlstra
In-Reply-To: <0b5bcac4-f58d-4cb0-9d58-fef74238edb8@acm.org>
On Mon, 11 May 2026 at 18:37, Bart Van Assche <bvanassche@acm.org> wrote:
>
> On 5/10/26 11:00 PM, Marco Elver wrote:
> > Clang 23 will have function pointer support:
> > https://github.com/llvm/llvm-project/commit/d1e84bb9ad3b6a844cd902cf70e2764cb8126979
>
> Thanks Marco for having implemented function pointer support in Clang!
>
> As you may already have noticed a new version of this patch series has
> been posted that relies on this feature.
Nice.
> Combining -Wthread-safety with
> annotating function pointers with older versions of Clang results in a
> build error. Should a test be added to the kernel build such that
> config WARN_CONTEXT_ANALYSIS can only be enabled if Clang supports
> annotating function pointers?
Ultimately, we'll be bumping the min. version:
https://lore.kernel.org/all/acqELlVC6vEeEF-W@elver.google.com/
Not sure when Peter wanted to pull that in - I believe we wanted to
wait until distros have a reasonably up-to-date Clang 23-dev version
in their repos.
For the time being, you could do this in the subsystems that need it:
CONTEXT_ANALYSIS := $(call clang-min-version, 230000)
... untested though, so please check it works.
^ permalink raw reply
* Re: [PATCH] loop: Fix NULL pointer dereference by synchronizing lo_release and loop_queue_rq
From: Tetsuo Handa @ 2026-05-11 17:43 UTC (permalink / raw)
To: Bart Van Assche, Andrew Morton
Cc: Jens Axboe, linux-block, LKML, Christoph Hellwig, Damien Le Moal
In-Reply-To: <c0047a38-3d02-4ce5-88b0-2b7d0b9b69fa@acm.org>
Thank you for responding.
Given it is protected by RCU, this might be yet another manifestation of
"is trying to release lock (rcu_read_lock) at:" + "but there are no more locks to release!"-type of
hidden RCU imbalance bugs recently introduced? Andrew, was any progress made for RCU imbalance bugs?
On 2026/04/21 20:05, Tetsuo Handa wrote:
> Since this problem started after the merge window opened, the culprit commit
> might be in between commit a028739a4330 ("Merge tag 'block-7.0-20260305' of
> git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux") and
> commit 7fe6ac157b7e ("Merge tag 'for-7.1/block-20260411' of
> git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux").
> Also, syzbot was not testing changes in linux-next since next-20260403,
> and found this problem in next-20260413.
On 2026/05/12 0:58, Bart Van Assche wrote:
> Why SRCU instead of RCU? The loop driver doesn't set BLK_MQ_F_BLOCKING
> and hence must not sleep inside loop_queue_rq(). Additionally, the block
> layer already holds an RCU lock around all loop_queue_rq() calls. From
> block/blk-mq.h:
>
> /* run the code block in @dispatch_ops with rcu/srcu read lock held */
> #define __blk_mq_run_dispatch_ops(q, check_sleep, dispatch_ops) \
> do { \
> if ((q)->tag_set->flags & BLK_MQ_F_BLOCKING) { \
> struct blk_mq_tag_set *__tag_set = (q)->tag_set; \
> int srcu_idx; \
> \
> might_sleep_if(check_sleep); \
> srcu_idx = srcu_read_lock(__tag_set->srcu); \
> (dispatch_ops); \
> srcu_read_unlock(__tag_set->srcu, srcu_idx); \
> } else { \
> rcu_read_lock(); \
> (dispatch_ops); \
> rcu_read_unlock(); \
> } \
> } while (0)
^ permalink raw reply
* Re: [PATCH v3 02/12] block/bdev: Annotate the blk_holder_ops callback invocations
From: Bart Van Assche @ 2026-05-11 16:36 UTC (permalink / raw)
To: Marco Elver
Cc: Christoph Hellwig, Jens Axboe, linux-block, Damien Le Moal,
Nathan Chancellor, Peter Zijlstra
In-Reply-To: <CANpmjNM6nERjfhNBE=D93E+HMaQtJWyi9s2qHmLWrmtBFt05vg@mail.gmail.com>
On 5/10/26 11:00 PM, Marco Elver wrote:
> Clang 23 will have function pointer support:
> https://github.com/llvm/llvm-project/commit/d1e84bb9ad3b6a844cd902cf70e2764cb8126979
Thanks Marco for having implemented function pointer support in Clang!
As you may already have noticed a new version of this patch series has
been posted that relies on this feature. Combining -Wthread-safety with
annotating function pointers with older versions of Clang results in a
build error. Should a test be added to the kernel build such that
config WARN_CONTEXT_ANALYSIS can only be enabled if Clang supports
annotating function pointers?
Thanks,
Bart.
^ permalink raw reply
* [PATCH v4 12/12] block: Enable lock context analysis
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Now that all block/*.c files have been annotated, enable lock context
analysis for all these source files.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/Makefile | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block/Makefile b/block/Makefile
index 7dce2e44276c..54130faacc21 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -3,6 +3,8 @@
# Makefile for the kernel block layer
#
+CONTEXT_ANALYSIS := y
+
obj-y := bdev.o fops.o bio.o elevator.o blk-core.o blk-sysfs.o \
blk-flush.o blk-settings.o blk-ioc.o blk-map.o \
blk-merge.o blk-timeout.o blk-lib.o blk-mq.o \
^ permalink raw reply related
* [PATCH v4 04/12] block/cgroup: Split blkg_conf_exit()
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Tejun Heo, Yu Kuai, Josef Bacik, Nathan Chancellor
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Split blkg_conf_exit() into blkg_conf_unprep() and blkg_conf_close_bdev()
because blkg_conf_exit() is not compatible with the Clang thread-safety
annotations. Remove blkg_conf_exit(). Rename blkg_conf_exit_frozen() into
blkg_conf_close_bdev_frozen(). Add thread-safety annotations to the new
functions.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/bfq-cgroup.c | 9 ++++--
block/blk-cgroup.c | 57 ++++++++++++++++++------------------
block/blk-cgroup.h | 6 ++--
block/blk-iocost.c | 67 +++++++++++++++++++++----------------------
block/blk-iolatency.c | 19 ++++++------
block/blk-throttle.c | 34 +++++++++++++---------
6 files changed, 101 insertions(+), 91 deletions(-)
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index 38396df9dce7..5d40279d6c9d 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -1053,11 +1053,11 @@ static ssize_t bfq_io_set_device_weight(struct kernfs_open_file *of,
ret = blkg_conf_open_bdev(&ctx);
if (ret)
- goto out;
+ return ret;
ret = blkg_conf_prep(blkcg, &blkcg_policy_bfq, &ctx);
if (ret)
- goto out;
+ goto close_bdev;
if (sscanf(ctx.body, "%llu", &v) == 1) {
/* require "default" on dfl */
@@ -1078,8 +1078,11 @@ static ssize_t bfq_io_set_device_weight(struct kernfs_open_file *of,
bfq_group_set_weight(bfqg, bfqg->entity.weight, v);
ret = 0;
}
+
out:
- blkg_conf_exit(&ctx);
+ blkg_conf_unprep(&ctx);
+close_bdev:
+ blkg_conf_close_bdev(&ctx);
return ret ?: nbytes;
}
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index a8d95d51b866..38d7bcfcbbe8 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -755,7 +755,7 @@ EXPORT_SYMBOL_GPL(__blkg_prfill_u64);
*
* Initialize @ctx which can be used to parse blkg config input string @input.
* Once initialized, @ctx can be used with blkg_conf_open_bdev() and
- * blkg_conf_prep(), and must be cleaned up with blkg_conf_exit().
+ * blkg_conf_prep().
*/
void blkg_conf_init(struct blkg_conf_ctx *ctx, char *input)
{
@@ -817,8 +817,8 @@ EXPORT_SYMBOL_GPL(blkg_conf_open_bdev);
* ensures the correct locking order between freeze queue and q->rq_qos_mutex.
*
* This function returns negative error on failure. On success it returns
- * memflags which must be saved and later passed to blkg_conf_exit_frozen
- * for restoring the memalloc scope.
+ * memflags which must be saved and later passed to
+ * blkg_conf_close_bdev_frozen() for restoring the memalloc scope.
*/
unsigned long __must_check blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx)
{
@@ -858,7 +858,7 @@ unsigned long __must_check blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx)
*
* blkg_conf_open_bdev() must be called on @ctx beforehand. On success, this
* function returns with queue lock held and must be followed by
- * blkg_conf_exit().
+ * blkg_conf_close_bdev().
*/
int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
struct blkg_conf_ctx *ctx)
@@ -968,42 +968,41 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
EXPORT_SYMBOL_GPL(blkg_conf_prep);
/**
- * blkg_conf_exit - clean up per-blkg config update
+ * blkg_conf_unprep - counterpart of blkg_conf_prep()
* @ctx: blkg_conf_ctx initialized with blkg_conf_init()
- *
- * Clean up after per-blkg config update. This function must be called on all
- * blkg_conf_ctx's initialized with blkg_conf_init().
*/
-void blkg_conf_exit(struct blkg_conf_ctx *ctx)
- __releases(&ctx->bdev->bd_queue->queue_lock)
- __releases(&ctx->bdev->bd_queue->rq_qos_mutex)
+void blkg_conf_unprep(struct blkg_conf_ctx *ctx)
{
- if (ctx->blkg) {
- spin_unlock_irq(&bdev_get_queue(ctx->bdev)->queue_lock);
- ctx->blkg = NULL;
- }
+ WARN_ON_ONCE(!ctx->blkg);
+ spin_unlock_irq(&ctx->bdev->bd_disk->queue->queue_lock);
+ ctx->blkg = NULL;
+}
+EXPORT_SYMBOL_GPL(blkg_conf_unprep);
- if (ctx->bdev) {
- mutex_unlock(&ctx->bdev->bd_queue->rq_qos_mutex);
- blkdev_put_no_open(ctx->bdev);
- ctx->body = NULL;
- ctx->bdev = NULL;
- }
+/**
+ * blkg_conf_close_bdev - counterpart of blkg_conf_open_bdev()
+ * @ctx: blkg_conf_ctx initialized with blkg_conf_init()
+ */
+void blkg_conf_close_bdev(struct blkg_conf_ctx *ctx)
+{
+ mutex_unlock(&ctx->bdev->bd_queue->rq_qos_mutex);
+ blkdev_put_no_open(ctx->bdev);
+ ctx->body = NULL;
+ ctx->bdev = NULL;
}
-EXPORT_SYMBOL_GPL(blkg_conf_exit);
+EXPORT_SYMBOL_GPL(blkg_conf_close_bdev);
/*
- * Similar to blkg_conf_exit, but also unfreezes the queue. Should be used
+ * Similar to blkg_close_bdev, but also unfreezes the queue. Should be used
* when blkg_conf_open_bdev_frozen is used to open the bdev.
*/
-void blkg_conf_exit_frozen(struct blkg_conf_ctx *ctx, unsigned long memflags)
+void blkg_conf_close_bdev_frozen(struct blkg_conf_ctx *ctx,
+ unsigned long memflags)
{
- if (ctx->bdev) {
- struct request_queue *q = ctx->bdev->bd_queue;
+ struct request_queue *q = ctx->bdev->bd_queue;
- blkg_conf_exit(ctx);
- blk_mq_unfreeze_queue(q, memflags);
- }
+ blkg_conf_close_bdev(ctx);
+ blk_mq_unfreeze_queue(q, memflags);
}
static void blkg_iostat_add(struct blkg_iostat *dst, struct blkg_iostat *src)
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index 1cce3294634d..ce90f5b60d52 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -222,8 +222,10 @@ int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx);
unsigned long blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx);
int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
struct blkg_conf_ctx *ctx);
-void blkg_conf_exit(struct blkg_conf_ctx *ctx);
-void blkg_conf_exit_frozen(struct blkg_conf_ctx *ctx, unsigned long memflags);
+void blkg_conf_unprep(struct blkg_conf_ctx *ctx);
+void blkg_conf_close_bdev(struct blkg_conf_ctx *ctx);
+void blkg_conf_close_bdev_frozen(struct blkg_conf_ctx *ctx,
+ unsigned long memflags);
/**
* bio_issue_as_root_blkg - see if this bio needs to be issued as root blkg
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index b34f820dedcc..e611dd63d712 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -3142,21 +3142,23 @@ static ssize_t ioc_weight_write(struct kernfs_open_file *of, char *buf,
ret = blkg_conf_open_bdev(&ctx);
if (ret)
- goto err;
+ return ret;
ret = blkg_conf_prep(blkcg, &blkcg_policy_iocost, &ctx);
if (ret)
- goto err;
+ goto close_bdev;
iocg = blkg_to_iocg(ctx.blkg);
+ ret = -EINVAL;
+
if (!strncmp(ctx.body, "default", 7)) {
v = 0;
} else {
if (!sscanf(ctx.body, "%u", &v))
- goto einval;
+ goto unprep;
if (v < CGROUP_WEIGHT_MIN || v > CGROUP_WEIGHT_MAX)
- goto einval;
+ goto unprep;
}
spin_lock(&iocg->ioc->lock);
@@ -3165,14 +3167,15 @@ static ssize_t ioc_weight_write(struct kernfs_open_file *of, char *buf,
weight_updated(iocg, &now);
spin_unlock(&iocg->ioc->lock);
- blkg_conf_exit(&ctx);
- return nbytes;
+ ret = 0;
-einval:
- ret = -EINVAL;
-err:
- blkg_conf_exit(&ctx);
- return ret;
+unprep:
+ blkg_conf_unprep(&ctx);
+
+close_bdev:
+ blkg_conf_close_bdev(&ctx);
+
+ return ret ? ret : nbytes;
}
static u64 ioc_qos_prfill(struct seq_file *sf, struct blkg_policy_data *pd,
@@ -3241,10 +3244,8 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
blkg_conf_init(&ctx, input);
memflags = blkg_conf_open_bdev_frozen(&ctx);
- if (IS_ERR_VALUE(memflags)) {
- ret = memflags;
- goto err;
- }
+ if (IS_ERR_VALUE(memflags))
+ return memflags;
body = ctx.body;
disk = ctx.bdev->bd_disk;
@@ -3361,14 +3362,14 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
blk_mq_unquiesce_queue(disk->queue);
- blkg_conf_exit_frozen(&ctx, memflags);
+ blkg_conf_close_bdev_frozen(&ctx, memflags);
return nbytes;
einval:
spin_unlock_irq(&ioc->lock);
blk_mq_unquiesce_queue(disk->queue);
ret = -EINVAL;
err:
- blkg_conf_exit_frozen(&ctx, memflags);
+ blkg_conf_close_bdev_frozen(&ctx, memflags);
return ret;
}
@@ -3434,20 +3435,20 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
ret = blkg_conf_open_bdev(&ctx);
if (ret)
- goto err;
+ return ret;
body = ctx.body;
q = bdev_get_queue(ctx.bdev);
if (!queue_is_mq(q)) {
ret = -EOPNOTSUPP;
- goto err;
+ goto close_bdev;
}
ioc = q_to_ioc(q);
if (!ioc) {
ret = blk_iocost_init(ctx.bdev->bd_disk);
if (ret)
- goto err;
+ goto close_bdev;
ioc = q_to_ioc(q);
}
@@ -3458,6 +3459,8 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
memcpy(u, ioc->params.i_lcoefs, sizeof(u));
user = ioc->user_cost_model;
+ ret = -EINVAL;
+
while ((p = strsep(&body, " \t\n"))) {
substring_t args[MAX_OPT_ARGS];
char buf[32];
@@ -3475,20 +3478,20 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
else if (!strcmp(buf, "user"))
user = true;
else
- goto einval;
+ goto unlock;
continue;
case COST_MODEL:
match_strlcpy(buf, &args[0], sizeof(buf));
if (strcmp(buf, "linear"))
- goto einval;
+ goto unlock;
continue;
}
tok = match_token(p, i_lcoef_tokens, args);
if (tok == NR_I_LCOEFS)
- goto einval;
+ goto unlock;
if (match_u64(&args[0], &v))
- goto einval;
+ goto unlock;
u[tok] = v;
user = true;
}
@@ -3500,24 +3503,18 @@ static ssize_t ioc_cost_model_write(struct kernfs_open_file *of, char *input,
ioc->user_cost_model = false;
}
ioc_refresh_params(ioc, true);
- spin_unlock_irq(&ioc->lock);
- blk_mq_unquiesce_queue(q);
- blk_mq_unfreeze_queue(q, memflags);
-
- blkg_conf_exit(&ctx);
- return nbytes;
+ ret = 0;
-einval:
+unlock:
spin_unlock_irq(&ioc->lock);
blk_mq_unquiesce_queue(q);
blk_mq_unfreeze_queue(q, memflags);
- ret = -EINVAL;
-err:
- blkg_conf_exit(&ctx);
- return ret;
+close_bdev:
+ blkg_conf_close_bdev(&ctx);
+ return ret ? ret : nbytes;
}
static struct cftype ioc_files[] = {
diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
index 53e8dd2dfa8a..1aaee6fb0f59 100644
--- a/block/blk-iolatency.c
+++ b/block/blk-iolatency.c
@@ -840,7 +840,7 @@ static ssize_t iolatency_set_limit(struct kernfs_open_file *of, char *buf,
ret = blkg_conf_open_bdev(&ctx);
if (ret)
- goto out;
+ return ret;
/*
* blk_iolatency_init() may fail after rq_qos_add() succeeds which can
@@ -850,11 +850,11 @@ static ssize_t iolatency_set_limit(struct kernfs_open_file *of, char *buf,
if (!iolat_rq_qos(ctx.bdev->bd_queue))
ret = blk_iolatency_init(ctx.bdev->bd_disk);
if (ret)
- goto out;
+ goto close_bdev;
ret = blkg_conf_prep(blkcg, &blkcg_policy_iolatency, &ctx);
if (ret)
- goto out;
+ goto close_bdev;
iolat = blkg_to_lat(ctx.blkg);
p = ctx.body;
@@ -865,7 +865,7 @@ static ssize_t iolatency_set_limit(struct kernfs_open_file *of, char *buf,
char val[21]; /* 18446744073709551616 */
if (sscanf(tok, "%15[^=]=%20s", key, val) != 2)
- goto out;
+ goto unprep;
if (!strcmp(key, "target")) {
u64 v;
@@ -875,9 +875,9 @@ static ssize_t iolatency_set_limit(struct kernfs_open_file *of, char *buf,
else if (sscanf(val, "%llu", &v) == 1)
lat_val = v * NSEC_PER_USEC;
else
- goto out;
+ goto unprep;
} else {
- goto out;
+ goto unprep;
}
}
@@ -889,8 +889,11 @@ static ssize_t iolatency_set_limit(struct kernfs_open_file *of, char *buf,
if (oldval != iolat->min_lat_nsec)
iolatency_clear_scaling(blkg);
ret = 0;
-out:
- blkg_conf_exit(&ctx);
+
+unprep:
+ blkg_conf_unprep(&ctx);
+close_bdev:
+ blkg_conf_close_bdev(&ctx);
return ret ?: nbytes;
}
diff --git a/block/blk-throttle.c b/block/blk-throttle.c
index cabf91f0d0dc..8f269310cbf4 100644
--- a/block/blk-throttle.c
+++ b/block/blk-throttle.c
@@ -1353,21 +1353,21 @@ static ssize_t tg_set_conf(struct kernfs_open_file *of,
ret = blkg_conf_open_bdev(&ctx);
if (ret)
- goto out_finish;
+ return ret;
if (!blk_throtl_activated(ctx.bdev->bd_queue)) {
ret = blk_throtl_init(ctx.bdev->bd_disk);
if (ret)
- goto out_finish;
+ goto close_bdev;
}
ret = blkg_conf_prep(blkcg, &blkcg_policy_throtl, &ctx);
if (ret)
- goto out_finish;
+ goto close_bdev;
ret = -EINVAL;
if (sscanf(ctx.body, "%llu", &v) != 1)
- goto out_finish;
+ goto unprep;
if (!v)
v = U64_MAX;
@@ -1381,8 +1381,12 @@ static ssize_t tg_set_conf(struct kernfs_open_file *of,
tg_conf_updated(tg, false);
ret = 0;
-out_finish:
- blkg_conf_exit(&ctx);
+
+unprep:
+ blkg_conf_unprep(&ctx);
+
+close_bdev:
+ blkg_conf_close_bdev(&ctx);
return ret ?: nbytes;
}
@@ -1537,17 +1541,17 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
ret = blkg_conf_open_bdev(&ctx);
if (ret)
- goto out_finish;
+ return ret;
if (!blk_throtl_activated(ctx.bdev->bd_queue)) {
ret = blk_throtl_init(ctx.bdev->bd_disk);
if (ret)
- goto out_finish;
+ goto close_bdev;
}
ret = blkg_conf_prep(blkcg, &blkcg_policy_throtl, &ctx);
if (ret)
- goto out_finish;
+ goto close_bdev;
tg = blkg_to_tg(ctx.blkg);
tg_update_carryover(tg);
@@ -1573,11 +1577,11 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
p = tok;
strsep(&p, "=");
if (!p || (sscanf(p, "%llu", &val) != 1 && strcmp(p, "max")))
- goto out_finish;
+ goto unprep;
ret = -ERANGE;
if (!val)
- goto out_finish;
+ goto unprep;
ret = -EINVAL;
if (!strcmp(tok, "rbps"))
@@ -1589,7 +1593,7 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
else if (!strcmp(tok, "wiops"))
v[3] = min_t(u64, val, UINT_MAX);
else
- goto out_finish;
+ goto unprep;
}
tg->bps[READ] = v[0];
@@ -1599,8 +1603,10 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of,
tg_conf_updated(tg, false);
ret = 0;
-out_finish:
- blkg_conf_exit(&ctx);
+unprep:
+ blkg_conf_unprep(&ctx);
+close_bdev:
+ blkg_conf_close_bdev(&ctx);
return ret ?: nbytes;
}
^ permalink raw reply related
* [PATCH v4 11/12] block/mq-deadline: Make the lock context annotations compatible with Clang
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Nathan Chancellor
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
While sparse ignores the __acquires() and __releases() arguments, Clang
verifies these. Make the arguments of __acquires() and __releases()
acceptable for Clang.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/mq-deadline.c | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/block/mq-deadline.c b/block/mq-deadline.c
index 95917a88976f..824bfc17b2c6 100644
--- a/block/mq-deadline.c
+++ b/block/mq-deadline.c
@@ -794,11 +794,15 @@ static const struct elv_fs_entry deadline_attrs[] = {
__ATTR_NULL
};
+#define RQ_FROM_SEQ_FILE(m) ((struct request_queue *)(m)->private)
+#define DD_DATA_FROM_RQ(rq) \
+ ((struct deadline_data *)(rq)->elevator->elevator_data)
+
#ifdef CONFIG_BLK_DEBUG_FS
#define DEADLINE_DEBUGFS_DDIR_ATTRS(prio, data_dir, name) \
static void *deadline_##name##_fifo_start(struct seq_file *m, \
loff_t *pos) \
- __acquires(&dd->lock) \
+ __acquires(&DD_DATA_FROM_RQ(RQ_FROM_SEQ_FILE(m))->lock) \
{ \
struct request_queue *q = m->private; \
struct deadline_data *dd = q->elevator->elevator_data; \
@@ -819,7 +823,7 @@ static void *deadline_##name##_fifo_next(struct seq_file *m, void *v, \
} \
\
static void deadline_##name##_fifo_stop(struct seq_file *m, void *v) \
- __releases(&dd->lock) \
+ __releases(&DD_DATA_FROM_RQ(RQ_FROM_SEQ_FILE(m))->lock) \
{ \
struct request_queue *q = m->private; \
struct deadline_data *dd = q->elevator->elevator_data; \
@@ -921,7 +925,7 @@ static int dd_owned_by_driver_show(void *data, struct seq_file *m)
}
static void *deadline_dispatch_start(struct seq_file *m, loff_t *pos)
- __acquires(&dd->lock)
+ __acquires(&DD_DATA_FROM_RQ(RQ_FROM_SEQ_FILE(m))->lock)
{
struct request_queue *q = m->private;
struct deadline_data *dd = q->elevator->elevator_data;
@@ -939,7 +943,7 @@ static void *deadline_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
}
static void deadline_dispatch_stop(struct seq_file *m, void *v)
- __releases(&dd->lock)
+ __releases(&DD_DATA_FROM_RQ(RQ_FROM_SEQ_FILE(m))->lock)
{
struct request_queue *q = m->private;
struct deadline_data *dd = q->elevator->elevator_data;
^ permalink raw reply related
* [PATCH v4 10/12] block/kyber: Make the lock context annotations compatible with Clang
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Nathan Chancellor
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
While sparse ignores the __acquires() and __releases() arguments, Clang
verifies these. Make the arguments of __acquires() and __releases()
acceptable for Clang.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/kyber-iosched.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/block/kyber-iosched.c b/block/kyber-iosched.c
index b84163d1f851..971818bcdc9d 100644
--- a/block/kyber-iosched.c
+++ b/block/kyber-iosched.c
@@ -882,6 +882,9 @@ static const struct elv_fs_entry kyber_sched_attrs[] = {
};
#undef KYBER_LAT_ATTR
+#define HCTX_FROM_SEQ_FILE(m) ((struct blk_mq_hw_ctx *)(m)->private)
+#define KYBER_HCTX_DATA(hctx) ((struct kyber_hctx_data *)(hctx)->sched_data)
+
#ifdef CONFIG_BLK_DEBUG_FS
#define KYBER_DEBUGFS_DOMAIN_ATTRS(domain, name) \
static int kyber_##name##_tokens_show(void *data, struct seq_file *m) \
@@ -894,7 +897,7 @@ static int kyber_##name##_tokens_show(void *data, struct seq_file *m) \
} \
\
static void *kyber_##name##_rqs_start(struct seq_file *m, loff_t *pos) \
- __acquires(&khd->lock) \
+ __acquires(&KYBER_HCTX_DATA(HCTX_FROM_SEQ_FILE(m))->lock) \
{ \
struct blk_mq_hw_ctx *hctx = m->private; \
struct kyber_hctx_data *khd = hctx->sched_data; \
@@ -913,7 +916,7 @@ static void *kyber_##name##_rqs_next(struct seq_file *m, void *v, \
} \
\
static void kyber_##name##_rqs_stop(struct seq_file *m, void *v) \
- __releases(&khd->lock) \
+ __releases(&KYBER_HCTX_DATA(HCTX_FROM_SEQ_FILE(m))->lock) \
{ \
struct blk_mq_hw_ctx *hctx = m->private; \
struct kyber_hctx_data *khd = hctx->sched_data; \
^ permalink raw reply related
* [PATCH v4 09/12] block/blk-mq-debugfs: Improve lock context annotations
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Nathan Chancellor
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Make the existing lock context annotations compatible with Clang. Add
the lock context annotations that are missing.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/blk-mq-debugfs.c | 12 ++++++------
block/blk.h | 4 ++++
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/block/blk-mq-debugfs.c b/block/blk-mq-debugfs.c
index 047ec887456b..5c168e82273e 100644
--- a/block/blk-mq-debugfs.c
+++ b/block/blk-mq-debugfs.c
@@ -20,7 +20,7 @@ static int queue_poll_stat_show(void *data, struct seq_file *m)
}
static void *queue_requeue_list_start(struct seq_file *m, loff_t *pos)
- __acquires(&q->requeue_lock)
+ __acquires(&((struct request_queue *)m->private)->requeue_lock)
{
struct request_queue *q = m->private;
@@ -36,7 +36,7 @@ static void *queue_requeue_list_next(struct seq_file *m, void *v, loff_t *pos)
}
static void queue_requeue_list_stop(struct seq_file *m, void *v)
- __releases(&q->requeue_lock)
+ __releases(&((struct request_queue *)m->private)->requeue_lock)
{
struct request_queue *q = m->private;
@@ -298,7 +298,7 @@ int blk_mq_debugfs_rq_show(struct seq_file *m, void *v)
EXPORT_SYMBOL_GPL(blk_mq_debugfs_rq_show);
static void *hctx_dispatch_start(struct seq_file *m, loff_t *pos)
- __acquires(&hctx->lock)
+ __acquires(&((struct blk_mq_hw_ctx *)m->private)->lock)
{
struct blk_mq_hw_ctx *hctx = m->private;
@@ -314,7 +314,7 @@ static void *hctx_dispatch_next(struct seq_file *m, void *v, loff_t *pos)
}
static void hctx_dispatch_stop(struct seq_file *m, void *v)
- __releases(&hctx->lock)
+ __releases(&((struct blk_mq_hw_ctx *)m->private)->lock)
{
struct blk_mq_hw_ctx *hctx = m->private;
@@ -486,7 +486,7 @@ static int hctx_dispatch_busy_show(void *data, struct seq_file *m)
#define CTX_RQ_SEQ_OPS(name, type) \
static void *ctx_##name##_rq_list_start(struct seq_file *m, loff_t *pos) \
- __acquires(&ctx->lock) \
+ __acquires(&((struct blk_mq_ctx *)m->private)->lock) \
{ \
struct blk_mq_ctx *ctx = m->private; \
\
@@ -503,7 +503,7 @@ static void *ctx_##name##_rq_list_next(struct seq_file *m, void *v, \
} \
\
static void ctx_##name##_rq_list_stop(struct seq_file *m, void *v) \
- __releases(&ctx->lock) \
+ __releases(&((struct blk_mq_ctx *)m->private)->lock) \
{ \
struct blk_mq_ctx *ctx = m->private; \
\
diff --git a/block/blk.h b/block/blk.h
index b998a7761faf..70b794e89a67 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -754,16 +754,19 @@ static inline void blk_unfreeze_release_lock(struct request_queue *q)
* reclaim from triggering block I/O.
*/
static inline void blk_debugfs_lock_nomemsave(struct request_queue *q)
+ __acquires(&q->debugfs_mutex)
{
mutex_lock(&q->debugfs_mutex);
}
static inline void blk_debugfs_unlock_nomemrestore(struct request_queue *q)
+ __releases(&q->debugfs_mutex)
{
mutex_unlock(&q->debugfs_mutex);
}
static inline unsigned int __must_check blk_debugfs_lock(struct request_queue *q)
+ __acquires(&q->debugfs_mutex)
{
unsigned int memflags = memalloc_noio_save();
@@ -773,6 +776,7 @@ static inline unsigned int __must_check blk_debugfs_lock(struct request_queue *q
static inline void blk_debugfs_unlock(struct request_queue *q,
unsigned int memflags)
+ __releases(&q->debugfs_mutex)
{
blk_debugfs_unlock_nomemrestore(q);
memalloc_noio_restore(memflags);
^ permalink raw reply related
* [PATCH v4 08/12] block/blk-iocost: Add lock context annotations
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Tejun Heo, Josef Bacik
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Since iocg_lock() and iocg_unlock() both use conditional locking,
annotate both with __no_context_analysis and use token_context_lock() to
introduce a new lock context.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/blk-iocost.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 353c165c5cd4..3bb8ce50af42 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -727,7 +727,11 @@ static void iocg_commit_bio(struct ioc_gq *iocg, struct bio *bio,
put_cpu_ptr(gcs);
}
+token_context_lock(ioc_lock);
+
static void iocg_lock(struct ioc_gq *iocg, bool lock_ioc, unsigned long *flags)
+ __acquires(ioc_lock)
+ __context_unsafe(conditional locking)
{
if (lock_ioc) {
spin_lock_irqsave(&iocg->ioc->lock, *flags);
@@ -738,6 +742,8 @@ static void iocg_lock(struct ioc_gq *iocg, bool lock_ioc, unsigned long *flags)
}
static void iocg_unlock(struct ioc_gq *iocg, bool unlock_ioc, unsigned long *flags)
+ __releases(ioc_lock)
+ __context_unsafe(conditional locking)
{
if (unlock_ioc) {
spin_unlock(&iocg->waitq.lock);
^ permalink raw reply related
* [PATCH v4 06/12] block/cgroup: Inline blkg_conf_{open,close}_bdev_frozen()
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Tejun Heo, Josef Bacik
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
The blkg_conf_open_bdev_frozen() calling convention is not compatible
with lock context annotations. Inline both blkg_conf_open_bdev_frozen()
and blkg_conf_close_bdev_frozen() because these functions only have a
single caller. This patch prepares for enabling lock context analysis.
The type of 'memflags' has been changed from unsigned long into unsigned
int to match the type of current->flags. See also <linux/sched.h>.
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/blk-cgroup.c | 46 ----------------------------------------------
block/blk-cgroup.h | 4 ----
block/blk-iocost.c | 29 +++++++++++++++++++++++------
3 files changed, 23 insertions(+), 56 deletions(-)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 86513c54c217..de0f753b8fe5 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -812,39 +812,6 @@ int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
}
EXPORT_SYMBOL_GPL(blkg_conf_open_bdev);
-/*
- * Similar to blkg_conf_open_bdev, but additionally freezes the queue,
- * ensures the correct locking order between freeze queue and q->rq_qos_mutex.
- *
- * This function returns negative error on failure. On success it returns
- * memflags which must be saved and later passed to
- * blkg_conf_close_bdev_frozen() for restoring the memalloc scope.
- */
-unsigned long __must_check blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx)
-{
- int ret;
- unsigned long memflags;
-
- if (ctx->bdev)
- return -EINVAL;
-
- ret = blkg_conf_open_bdev(ctx);
- if (ret < 0)
- return ret;
- /*
- * At this point, we haven’t started protecting anything related to QoS,
- * so we release q->rq_qos_mutex here, which was first acquired in blkg_
- * conf_open_bdev. Later, we re-acquire q->rq_qos_mutex after freezing
- * the queue to maintain the correct locking order.
- */
- mutex_unlock(&ctx->bdev->bd_queue->rq_qos_mutex);
-
- memflags = blk_mq_freeze_queue(ctx->bdev->bd_queue);
- mutex_lock(&ctx->bdev->bd_queue->rq_qos_mutex);
-
- return memflags;
-}
-
/**
* blkg_conf_prep - parse and prepare for per-blkg config update
* @blkcg: target block cgroup
@@ -991,19 +958,6 @@ void blkg_conf_close_bdev(struct blkg_conf_ctx *ctx)
}
EXPORT_SYMBOL_GPL(blkg_conf_close_bdev);
-/*
- * Similar to blkg_close_bdev, but also unfreezes the queue. Should be used
- * when blkg_conf_open_bdev_frozen is used to open the bdev.
- */
-void blkg_conf_close_bdev_frozen(struct blkg_conf_ctx *ctx,
- unsigned long memflags)
-{
- struct request_queue *q = ctx->bdev->bd_queue;
-
- blkg_conf_close_bdev(ctx);
- blk_mq_unfreeze_queue(q, memflags);
-}
-
static void blkg_iostat_add(struct blkg_iostat *dst, struct blkg_iostat *src)
{
int i;
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index f0a3af520c55..f25fecb87c43 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -220,7 +220,6 @@ struct blkg_conf_ctx {
void blkg_conf_init(struct blkg_conf_ctx *ctx, char *input);
int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
__cond_acquires(0, &ctx->bdev->bd_queue->rq_qos_mutex);
-unsigned long blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx);
int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
struct blkg_conf_ctx *ctx)
__cond_acquires(0, &ctx->bdev->bd_disk->queue->queue_lock);
@@ -228,9 +227,6 @@ void blkg_conf_unprep(struct blkg_conf_ctx *ctx)
__releases(ctx->bdev->bd_disk->queue->queue_lock);
void blkg_conf_close_bdev(struct blkg_conf_ctx *ctx)
__releases(&ctx->bdev->bd_queue->rq_qos_mutex);
-void blkg_conf_close_bdev_frozen(struct blkg_conf_ctx *ctx,
- unsigned long memflags)
- __releases(&ctx->bdev->bd_queue->rq_qos_mutex);
/**
* bio_issue_as_root_blkg - see if this bio needs to be issued as root blkg
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index e611dd63d712..353c165c5cd4 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -3233,19 +3233,30 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
size_t nbytes, loff_t off)
{
struct blkg_conf_ctx ctx;
+ struct request_queue *q;
struct gendisk *disk;
struct ioc *ioc;
u32 qos[NR_QOS_PARAMS];
bool enable, user;
char *body, *p;
- unsigned long memflags;
+ unsigned int memflags;
int ret;
blkg_conf_init(&ctx, input);
- memflags = blkg_conf_open_bdev_frozen(&ctx);
- if (IS_ERR_VALUE(memflags))
- return memflags;
+ ret = blkg_conf_open_bdev(&ctx);
+ if (ret)
+ return ret;
+ /*
+ * At this point, we haven’t started protecting anything related to QoS,
+ * so we release q->rq_qos_mutex here, which was first acquired in blkg_
+ * conf_open_bdev. Later, we re-acquire q->rq_qos_mutex after freezing
+ * the queue to maintain the correct locking order.
+ */
+ mutex_unlock(&ctx.bdev->bd_queue->rq_qos_mutex);
+
+ memflags = blk_mq_freeze_queue(ctx.bdev->bd_queue);
+ mutex_lock(&ctx.bdev->bd_queue->rq_qos_mutex);
body = ctx.body;
disk = ctx.bdev->bd_disk;
@@ -3362,14 +3373,20 @@ static ssize_t ioc_qos_write(struct kernfs_open_file *of, char *input,
blk_mq_unquiesce_queue(disk->queue);
- blkg_conf_close_bdev_frozen(&ctx, memflags);
+ q = ctx.bdev->bd_queue;
+ blkg_conf_close_bdev(&ctx);
+ blk_mq_unfreeze_queue(q, memflags);
+
return nbytes;
+
einval:
spin_unlock_irq(&ioc->lock);
blk_mq_unquiesce_queue(disk->queue);
ret = -EINVAL;
err:
- blkg_conf_close_bdev_frozen(&ctx, memflags);
+ q = ctx.bdev->bd_queue;
+ blkg_conf_close_bdev(&ctx);
+ blk_mq_unfreeze_queue(q, memflags);
return ret;
}
^ permalink raw reply related
* [PATCH v4 07/12] block/crypto: Annotate the crypto functions
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Eric Biggers, Nathan Chancellor
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Add the lock context annotations required for Clang's thread-safety
analysis.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Eric Biggers <ebiggers@kernel.org>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/blk-crypto-profile.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/block/blk-crypto-profile.c b/block/blk-crypto-profile.c
index 4ac74443687a..cf447ba4a66e 100644
--- a/block/blk-crypto-profile.c
+++ b/block/blk-crypto-profile.c
@@ -43,6 +43,7 @@ struct blk_crypto_keyslot {
};
static inline void blk_crypto_hw_enter(struct blk_crypto_profile *profile)
+ __acquires(&profile->lock)
{
/*
* Calling into the driver requires profile->lock held and the device
@@ -55,6 +56,7 @@ static inline void blk_crypto_hw_enter(struct blk_crypto_profile *profile)
}
static inline void blk_crypto_hw_exit(struct blk_crypto_profile *profile)
+ __releases(&profile->lock)
{
up_write(&profile->lock);
if (profile->dev)
^ permalink raw reply related
* [PATCH v4 05/12] block/cgroup: Improve lock context annotations
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Tejun Heo, Josef Bacik
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Add lock context annotations where these are missing. Move the
blkg_conf_prep() annotation into block/blk-cgroup.h to make it visible
to all blkg_conf_prep() callers.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/blk-cgroup.c | 1 -
block/blk-cgroup.h | 15 ++++++++++-----
2 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 38d7bcfcbbe8..86513c54c217 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -862,7 +862,6 @@ unsigned long __must_check blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx)
*/
int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
struct blkg_conf_ctx *ctx)
- __acquires(&bdev->bd_queue->queue_lock)
{
struct gendisk *disk;
struct request_queue *q;
diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index ce90f5b60d52..f0a3af520c55 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -218,14 +218,19 @@ struct blkg_conf_ctx {
};
void blkg_conf_init(struct blkg_conf_ctx *ctx, char *input);
-int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx);
+int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
+ __cond_acquires(0, &ctx->bdev->bd_queue->rq_qos_mutex);
unsigned long blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx);
int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
- struct blkg_conf_ctx *ctx);
-void blkg_conf_unprep(struct blkg_conf_ctx *ctx);
-void blkg_conf_close_bdev(struct blkg_conf_ctx *ctx);
+ struct blkg_conf_ctx *ctx)
+ __cond_acquires(0, &ctx->bdev->bd_disk->queue->queue_lock);
+void blkg_conf_unprep(struct blkg_conf_ctx *ctx)
+ __releases(ctx->bdev->bd_disk->queue->queue_lock);
+void blkg_conf_close_bdev(struct blkg_conf_ctx *ctx)
+ __releases(&ctx->bdev->bd_queue->rq_qos_mutex);
void blkg_conf_close_bdev_frozen(struct blkg_conf_ctx *ctx,
- unsigned long memflags);
+ unsigned long memflags)
+ __releases(&ctx->bdev->bd_queue->rq_qos_mutex);
/**
* bio_issue_as_root_blkg - see if this bio needs to be issued as root blkg
^ permalink raw reply related
* [PATCH v4 03/12] block/cgroup: Split blkg_conf_prep()
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe
Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche,
Tejun Heo, Yu Kuai, Josef Bacik
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Move the blkg_conf_open_bdev() call out of blkg_conf_prep() to make it
possible to add lock context annotations to blkg_conf_prep(). Change an
if-statement in blkg_conf_open_bdev() into a WARN_ON_ONCE() call. Export
blkg_conf_open_bdev() because it is called by the BFQ I/O scheduler and
the BFQ I/O scheduler may be built as a kernel module.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Tejun Heo <tj@kernel.org>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
block/bfq-cgroup.c | 4 ++++
block/blk-cgroup.c | 18 ++++++++----------
block/blk-iocost.c | 4 ++++
3 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
index ac83b0668764..38396df9dce7 100644
--- a/block/bfq-cgroup.c
+++ b/block/bfq-cgroup.c
@@ -1051,6 +1051,10 @@ static ssize_t bfq_io_set_device_weight(struct kernfs_open_file *of,
blkg_conf_init(&ctx, buf);
+ ret = blkg_conf_open_bdev(&ctx);
+ if (ret)
+ goto out;
+
ret = blkg_conf_prep(blkcg, &blkcg_policy_bfq, &ctx);
if (ret)
goto out;
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 554c87bb4a86..a8d95d51b866 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -771,10 +771,7 @@ EXPORT_SYMBOL_GPL(blkg_conf_init);
* @ctx->input and get and store the matching bdev in @ctx->bdev. @ctx->body is
* set to point past the device node prefix.
*
- * This function may be called multiple times on @ctx and the extra calls become
- * NOOPs. blkg_conf_prep() implicitly calls this function. Use this function
- * explicitly if bdev access is needed without resolving the blkcg / policy part
- * of @ctx->input. Returns -errno on error.
+ * Returns: -errno on error.
*/
int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
{
@@ -783,8 +780,8 @@ int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
struct block_device *bdev;
int key_len;
- if (ctx->bdev)
- return 0;
+ if (WARN_ON_ONCE(ctx->bdev))
+ return -EINVAL;
if (sscanf(input, "%u:%u%n", &major, &minor, &key_len) != 2)
return -EINVAL;
@@ -813,6 +810,8 @@ int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
ctx->bdev = bdev;
return 0;
}
+EXPORT_SYMBOL_GPL(blkg_conf_open_bdev);
+
/*
* Similar to blkg_conf_open_bdev, but additionally freezes the queue,
* ensures the correct locking order between freeze queue and q->rq_qos_mutex.
@@ -857,7 +856,7 @@ unsigned long __must_check blkg_conf_open_bdev_frozen(struct blkg_conf_ctx *ctx)
* following MAJ:MIN, @ctx->bdev points to the target block device and
* @ctx->blkg to the blkg being configured.
*
- * blkg_conf_open_bdev() may be called on @ctx beforehand. On success, this
+ * blkg_conf_open_bdev() must be called on @ctx beforehand. On success, this
* function returns with queue lock held and must be followed by
* blkg_conf_exit().
*/
@@ -870,9 +869,8 @@ int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,
struct blkcg_gq *blkg;
int ret;
- ret = blkg_conf_open_bdev(ctx);
- if (ret)
- return ret;
+ if (WARN_ON_ONCE(!ctx->bdev))
+ return -EINVAL;
disk = ctx->bdev->bd_disk;
q = disk->queue;
diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 0cca88a366dc..b34f820dedcc 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -3140,6 +3140,10 @@ static ssize_t ioc_weight_write(struct kernfs_open_file *of, char *buf,
blkg_conf_init(&ctx, buf);
+ ret = blkg_conf_open_bdev(&ctx);
+ if (ret)
+ goto err;
+
ret = blkg_conf_prep(blkcg, &blkcg_policy_iocost, &ctx);
if (ret)
goto err;
^ permalink raw reply related
* [PATCH v4 02/12] block/bdev: Annotate the blk_holder_ops callback functions
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
The four callback functions in blk_holder_ops all release the
bd_holder_lock. Annotate these functions accordingly.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
include/linux/blkdev.h | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 8651af4fe9d7..d0c181da2da0 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1747,22 +1747,26 @@ void blkdev_show(struct seq_file *seqf, off_t offset);
#endif
struct blk_holder_ops {
- void (*mark_dead)(struct block_device *bdev, bool surprise);
+ void (*mark_dead)(struct block_device *bdev, bool surprise)
+ __releases(&bdev->bd_holder_lock);
/*
* Sync the file system mounted on the block device.
*/
- void (*sync)(struct block_device *bdev);
+ void (*sync)(struct block_device *bdev)
+ __releases(&bdev->bd_holder_lock);
/*
* Freeze the file system mounted on the block device.
*/
- int (*freeze)(struct block_device *bdev);
+ int (*freeze)(struct block_device *bdev)
+ __releases(&bdev->bd_holder_lock);
/*
* Thaw the file system mounted on the block device.
*/
- int (*thaw)(struct block_device *bdev);
+ int (*thaw)(struct block_device *bdev)
+ __releases(&bdev->bd_holder_lock);
};
/*
^ permalink raw reply related
* [PATCH v4 01/12] block: Annotate the queue limits functions
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche
In-Reply-To: <20260511163100.1887263-1-bvanassche@acm.org>
Let the thread-safety checker verify whether every start of a queue
limits update is followed by a call to a function that finishes a queue
limits update.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
---
include/linux/blkdev.h | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 890128cdea1c..8651af4fe9d7 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1093,15 +1093,17 @@ static inline unsigned int blk_boundary_sectors_left(sector_t offset,
*/
static inline struct queue_limits
queue_limits_start_update(struct request_queue *q)
+ __acquires(&q->limits_lock)
{
mutex_lock(&q->limits_lock);
return q->limits;
}
int queue_limits_commit_update_frozen(struct request_queue *q,
- struct queue_limits *lim);
+ struct queue_limits *lim) __releases(&q->limits_lock);
int queue_limits_commit_update(struct request_queue *q,
- struct queue_limits *lim);
-int queue_limits_set(struct request_queue *q, struct queue_limits *lim);
+ struct queue_limits *lim) __releases(&q->limits_lock);
+int queue_limits_set(struct request_queue *q, struct queue_limits *lim)
+ __must_not_hold(&q->limits_lock);
int blk_validate_limits(struct queue_limits *lim);
/**
@@ -1113,6 +1115,7 @@ int blk_validate_limits(struct queue_limits *lim);
* starting update.
*/
static inline void queue_limits_cancel_update(struct request_queue *q)
+ __releases(&q->limits_lock)
{
mutex_unlock(&q->limits_lock);
}
^ permalink raw reply related
* [PATCH v4 00/12] Enable lock context analysis
From: Bart Van Assche @ 2026-05-11 16:30 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-block, Christoph Hellwig, Marco Elver, Bart Van Assche
Hi Jens,
During the most recent merge window the following patch series has been merged:
[PATCH v5 00/36] Compiler-Based Context- and Locking-Analysis
(https://lore.kernel.org/lkml/20251219154418.3592607-1-elver@google.com/). That
patch series drops support for verifying lock context annotations with sparse
and introduces support for verifying lock context annotations with Clang. The
support in Clang for lock context annotation and verification is better than
that in sparse. As an example, __cond_acquires() and __guarded_by() are
supported by Clang but not by sparse. Hence this patch series that enables lock
context analysis for the block layer core.
Please consider this patch series for the next merge window.
Thanks,
Bart.
Changes compared to v3:
- Replaced the "block/bdev: Annotate the blk_holder_ops callback invocations"
patch with a patch that adds __releases() annotations to the function
pointers in struct blk_holder_ops.
- Dropped the blk-zoned patch since a better patch from Christoph has
been merged.
Changes compared to v2:
- Retained the block layer core patches and left out the block driver patches.
- Inlined blkg_conf_open_bdev_frozen() and blkg_conf_close_bdev_frozen().
- In blkg_conf_open_bdev(), added a return statement if the
WARN_ON_ONCE() statement triggers.
- Replaced the "block/ioctl: Add lock context annotations" patch with a
__release() annotation.
- Replaced the blk-zoned patch with a patch from Christoph.
Changes compared to v1:
- Rebased this patch series on top of Jens' for-next branch.
- Included two patches that split blkg_conf_prep() and blkg_conf_exit().
- Modified how patches are split. Split the block layer core patch into
multiple patches and moved the CONTEXT_ANALYSIS := y assignments into the
block driver patches.
- Made the new source code comments easier to comprehend.
- Introduced macros in the mq-deadline and Kyber I/O schedulers to make the
__acquires() expressions easier to read.
- Removed the changes from this series that are not block layer changes.
Bart Van Assche (12):
block: Annotate the queue limits functions
block/bdev: Annotate the blk_holder_ops callback functions
block/cgroup: Split blkg_conf_prep()
block/cgroup: Split blkg_conf_exit()
block/cgroup: Improve lock context annotations
block/cgroup: Inline blkg_conf_{open,close}_bdev_frozen()
block/crypto: Annotate the crypto functions
block/blk-iocost: Add lock context annotations
block/blk-mq-debugfs: Improve lock context annotations
block/kyber: Make the lock context annotations compatible with Clang
block/mq-deadline: Make the lock context annotations compatible with
Clang
block: Enable lock context analysis
block/Makefile | 2 +
block/bfq-cgroup.c | 11 ++++-
block/blk-cgroup.c | 98 ++++++++++----------------------------
block/blk-cgroup.h | 13 +++--
block/blk-crypto-profile.c | 2 +
block/blk-iocost.c | 96 +++++++++++++++++++++++--------------
block/blk-iolatency.c | 19 ++++----
block/blk-mq-debugfs.c | 12 ++---
block/blk-throttle.c | 34 +++++++------
block/blk.h | 4 ++
block/kyber-iosched.c | 7 ++-
block/mq-deadline.c | 12 +++--
include/linux/blkdev.h | 21 +++++---
13 files changed, 173 insertions(+), 158 deletions(-)
^ permalink raw reply
* Re: [PATCH] loop: Fix NULL pointer dereference by synchronizing lo_release and loop_queue_rq
From: Bart Van Assche @ 2026-05-11 15:58 UTC (permalink / raw)
To: Tetsuo Handa, Jens Axboe, linux-block, LKML, Christoph Hellwig,
Damien Le Moal
In-Reply-To: <e33b4060-69d9-4d02-a330-2fbd19249237@I-love.SAKURA.ne.jp>
On 5/11/26 4:43 AM, Tetsuo Handa wrote:
> diff --git a/drivers/block/loop.c b/drivers/block/loop.c
> index 0000913f7efc..9be47ce97dab 100644
> --- a/drivers/block/loop.c
> +++ b/drivers/block/loop.c
> @@ -93,6 +93,7 @@ struct loop_cmd {
> static DEFINE_IDR(loop_index_idr);
> static DEFINE_MUTEX(loop_ctl_mutex);
> static DEFINE_MUTEX(loop_validate_mutex);
> +DEFINE_SRCU(loop_io_srcu);
>
> /**
> * loop_global_lock_killable() - take locks for safe loop_validate_file() test
> @@ -1747,8 +1748,19 @@ static void lo_release(struct gendisk *disk)
> need_clear = (lo->lo_state == Lo_rundown);
> mutex_unlock(&lo->lo_mutex);
>
> - if (need_clear)
> + if (need_clear) {
> + /*
> + * Now that loop_queue_rq() sees lo->lo_state != Lo_bound,
> + * wait for already started loop_queue_rq() to complete.
> + */
> + synchronize_srcu(&loop_io_srcu);
> + /*
> + * Now that no more works are scheduled by loop_queue_rq(),
> + * wait for already scheduled works to complete.
> + */
> + drain_workqueue(lo->workqueue);
> __loop_clr_fd(lo);
> + }
> }
There is already a mechanism in the block layer to wait for pending
.queue_rq() calls to complete. Please take a look at
blk_mq_quiesce_queue().
> static void lo_free_disk(struct gendisk *disk)
> @@ -1854,11 +1866,15 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
> struct request *rq = bd->rq;
> struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
> struct loop_device *lo = rq->q->queuedata;
> + int idx;
>
> blk_mq_start_request(rq);
>
> - if (data_race(READ_ONCE(lo->lo_state)) != Lo_bound)
> + idx = srcu_read_lock(&loop_io_srcu);
> + if (data_race(READ_ONCE(lo->lo_state)) != Lo_bound) {
> + srcu_read_unlock(&loop_io_srcu, idx);
> return BLK_STS_IOERR;
> + }
>
> switch (req_op(rq)) {
> case REQ_OP_FLUSH:
> @@ -1888,6 +1904,7 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
> #endif
> loop_queue_work(lo, cmd);
>
> + srcu_read_unlock(&loop_io_srcu, idx);
> return BLK_STS_OK;
> }
Why SRCU instead of RCU? The loop driver doesn't set BLK_MQ_F_BLOCKING
and hence must not sleep inside loop_queue_rq(). Additionally, the block
layer already holds an RCU lock around all loop_queue_rq() calls. From
block/blk-mq.h:
/* run the code block in @dispatch_ops with rcu/srcu read lock held */
#define __blk_mq_run_dispatch_ops(q, check_sleep, dispatch_ops) \
do { \
if ((q)->tag_set->flags & BLK_MQ_F_BLOCKING) { \
struct blk_mq_tag_set *__tag_set = (q)->tag_set; \
int srcu_idx; \
\
might_sleep_if(check_sleep); \
srcu_idx = srcu_read_lock(__tag_set->srcu); \
(dispatch_ops); \
srcu_read_unlock(__tag_set->srcu, srcu_idx); \
} else { \
rcu_read_lock(); \
(dispatch_ops); \
rcu_read_unlock(); \
} \
} while (0)
Thanks,
Bart.
^ permalink raw reply
* xfstests-bld kernel config and automated tsting (Was: blktests: status, expansion plan for the storage stack test framework)
From: Theodore Tso @ 2026-05-11 15:40 UTC (permalink / raw)
To: Shin'ichiro Kawasaki; +Cc: linux-block@vger.kernel.org
In-Reply-To: <agHGnYHo4HEKhYJb@shinmob>
On Mon, May 11, 2026 at 09:27:38PM +0900, Shin'ichiro Kawasaki wrote:
>
> - For easier config:
> - Ted has the config generation tool.
> -> I'm interested in it, and would like to take a look.
The config generation tool is part of my xfstests-bld test appliance:
https://github.com/tytso/xfstests-bld
I have blktests support integrated into gce-xfstests. After setting
gce-xfstests per:
https://github.com/tytso/xfstests-bld/blob/master/Documentation/gce-xfstests.md
Using it is basically as simple as:
cd /usr/src/linux
install-kconfig --blktests
kbuild
gce-xfstests --blktests
The install-kconfig and kbuild scripts can be found in the
kernel-build directory in the xfstests-bld repo:
https://github.com/tytso/xfstests-bld/tree/master/kernel-build
Note: In addition to --blktests, install-kconfig supports other options,
including --lockdep, --kasan, --ubsan, --arch arm64, --kcsan, etc.
Unfortunately, blktests is currently not supported in kvm-xfstests
(aka qemu-xfstests, since it also works on MacOS's HVF). It should be
possible, but currently kvm-xfstests doesn't suport modules, and
blktests is pretty fundamentally tied to modules. With gce-xfstests,
we upload a kernel.deb install it in the system under test. With
kvm-xfstests, we directly boot the kernel directly out of the build
tree, which is much faster (5 seconds from "kvm-xfstests shell" to
shell prompt)--- but doesn't support modules.
Projects to improve blktests in my test appliance:
1. Add support for modules in kvm-xfstests and then enable blktests for
kvm-xfstests.
2. Add support for some kind of machine readable test results file
(e.g., junit XML or kTAP)
The reason why (2) is so interesting is that it allows for a
convenient report generation which summarizes the test run, e.g:
ext4/4k: 615 tests, 1 failures, 74 skipped, 4701 seconds
Flaky: generic/234: 20% (1/5)
ext4/1k: 609 tests, 78 skipped, 5586 seconds
ext4/ext3: 607 tests, 159 skipped, 5044 seconds
ext4/encrypt: 590 tests, 191 skipped, 2768 seconds
ext4/nojournal: 607 tests, 1 failures, 158 skipped, 4111 seconds
Flaky: generic/234: 20% (1/5)
ext4/ext3conv: 612 tests, 2 failures, 76 skipped, 5212 seconds
Flaky: generic/234: 20% (1/5) generic/409: 20% (1/5)
(Note: ext4/4k, ext4/1k, etc. are different file system test
scenarios, which run on a different VM)
The other reason why (2) is handy is that it enables using automated
bisection searches, e.g.:
gce-xfstests ltm --repo linux-stable-gc -c ext4/4k generic/234 \
--bisect-good v7.0.5 --bisect-bad linux-7.0.y
So if we had a machine-readable results file, ala xfstests's "check -R
xunit-quiet", I could add automated bisection for blktests failures to
gce-xfstests.
Cheers,
- Ted
P.S. For more information about my test-appliance system, see:
https://thunk.org/gce-xfstests
https://github.com/tytso/xfstests-bld/blob/master/Documentation/kvm-quickstart.md
https://github.com/tytso/xfstests-bld/blob/master/Documentation/gce-xfstests.md
^ permalink raw reply
* Re: [PATCH] ublk: reject max_sectors smaller than PAGE_SECTORS in parameter validation
From: Jens Axboe @ 2026-05-11 13:44 UTC (permalink / raw)
To: linux-block, Ming Lei; +Cc: Caleb Sander Mateos, Uday Shankar
In-Reply-To: <20260510144843.769031-1-tom.leiming@gmail.com>
On Sun, 10 May 2026 22:48:43 +0800, Ming Lei wrote:
> blk_validate_limits() requires max_hw_sectors >= PAGE_SECTORS and fires
> a WARN_ON_ONCE if this invariant is violated. ublk_validate_params()
> only checked the upper bound of max_sectors against max_io_buf_bytes,
> allowing userspace to pass small values (including zero) that trigger
> the warning when blk_mq_alloc_disk() is called from
> ublk_ctrl_start_dev().
>
> [...]
Applied, thanks!
[1/1] ublk: reject max_sectors smaller than PAGE_SECTORS in parameter validation
commit: 1860c2f85922917d8a46f16a6f4bd2298ffa0fb5
Best regards,
--
Jens Axboe
^ permalink raw reply
* Re: [LSF/MM/BPF ATTEND][LSF/MM/BPF TOPIC] : blktests: status, expansion plan for the storage stack test framework
From: Shin'ichiro Kawasaki @ 2026-05-11 12:27 UTC (permalink / raw)
To: Chaitanya Kulkarni
Cc: linux-block@vger.kernel.org, linux-scsi@vger.kernel.org,
linux-nvme@lists.infradead.org, lsf-pc@lists.linux-foundation.org,
Bart Van Assche, Daniel Wagner, Hannes Reinecke,
Christoph Hellwig, Jens Axboe, sagi@grimberg.me, tytso@mit.edu,
Johannes Thumshirn, Christian Brauner, Martin K. Petersen,
linux-fsdevel@vger.kernel.org, Javier González,
willy@infradead.org, Jan Kara, amir73il@gmail.com, vbabka@suse.cz,
Damien Le Moal
In-Reply-To: <31a2a4c2-8c33-429a-a2b1-e1f3a0e90d72@nvidia.com>
On Feb 11, 2026 / 20:35, Chaitanya Kulkarni wrote:
> Hi all,
>
> Since the discussion at the LSFMM 2017 [1], Omar Sandoval introduced
> the new
> framework "blktests" dedicated for Linux Kernel Block layer testing.
[...]
> For the storage track at LSFMMBPF2026, I propose a session dedicated to
> blktests to discuss expansion plan and CI integration progress.
My thank goes to the session attendees. Here I share my memorandom about what
was discussed there. If I overlook anything, amendments will be appreciated.
----------------------------------------------------------------------------
blktests CI
===========
- Regular test runs for branches (nightly or -rcX)
- It will be helpful to run blktests for -rcX releases and report.
- Ted has resources to run blktests regularly, but it requires someone to
look into the test results [*]
- Repeated test case run
- fstests has the feature to repeat failed test cases 10(x) times.
- kdevops has the feature to find out the failure recreated by 1000x times
repeat
-> This will be a 2nd step topic and looks too early currently.
- Kernel config for CI runs
- Please enable DEBUG_ATOMIC_SLEEP [**]
- Can we specify kernel config for each patch author?
-> It will require too much resource
- PatchWork for linux-nvme
- Good for patch status tracking also
- Should ask kernel.org
- e-mail reporting
- e-mail address should be available at kernel.org
- Do not report the "ALL PASS" case. It will be noisy.
-> Will send out report only for failure cases.
blktests improvement ideas
==========================
- For easier config:
- Ted has the config generation tool.
-> I'm interested in it, and would like to take a look.
- VM integration
- VM integration script will help new users to try out blktests
- Haris thinks this is useful: he created own VM runner like virtme-ng
-> Will introudce virtme-ng script
[*] I would like to volunteer to take the role to look into the results.
[**] I checked later and confirmed that DEBUG_ATOMIC_SLEEP is already enabled.
Ref: current config:
https://github.com/linux-blktests/blktests-ci/blob/be781155bacf49bf318ee8859572fb7ca1f72aea/playbooks/roles/kernel-builder-k8s-job/templates/build-kernel.sh#L22
----------------------------------------------------------------------------
I also had good talks in hallways, and got two new ideas to improve blktests:
1) "machine readable result reports" and 2) "command tracing" for easier test
case debug. I plan to work on them.
Thanks again for all of the discussion!
^ permalink raw reply
* [PATCH] loop: Fix NULL pointer dereference by synchronizing lo_release and loop_queue_rq
From: Tetsuo Handa @ 2026-05-11 11:43 UTC (permalink / raw)
To: Jens Axboe, linux-block, LKML, Christoph Hellwig, Bart Van Assche,
Damien Le Moal
In-Reply-To: <e1d824ba-9ac7-4fde-a791-32eeadcd4258@I-love.SAKURA.ne.jp>
Summary:
This patch addresses a NULL pointer dereference in lo_rw_aio() by
introducing SRCU-based synchronization and explicit workqueue draining
during device release. This race appears to have been exacerbated or
introduced by recent changes in the block layer's request completion and
freezing logic.
Problem Description:
A NULL pointer dereference was reported by syzbot. The crash occurs when
lo_rw_aio() access lo->lo_backing_file which has already been cleared by
__loop_clr_fd().
The investigation suggests a gap between loop_queue_rq() and the driver's
internal workqueue. Even when the block layer attempts to freeze the queue,
requests that have already passed the loop_queue_rq() state check but have
not yet been queued to lo->workqueue can "leak" and execute after
lo_release() has proceeded to teardown the device.
Suspicious Commits and Behavioral Changes:
We suspect this race became visible due to behavioral changes in how the
block layer handles request completion and synchronization, specifically:
1. Commit 65565ca5f99b ("block: unify the synchronous bi_end_io
callbacks"): This unified completion path might have altered the timing
or the visibility of in-flight requests during a queue freeze, allowing
lo_release() to proceed before the loop driver's internal asynchronous
work has been fully accounted for.
2. Changes in blk_mq_freeze_queue(): In older kernels, the freeze mechanism
might have more effectively covered the window between queue_rq and the
driver's execution of that request. The current behavior seems to allow
__loop_clr_fd() to run while loop_queue_rq() is still in the middle of
scheduling work.
Stability and Backporting:
Because the underlying cause is tied to recent block layer refactoring,
this patch should not be backported to older stable kernels without careful
verification, as it may be unnecessary or lead to performance regressions
due to the added SRCU overhead.
Solution:
The patch closes the race window using SRCU:
* loop_queue_rq: Wrapped in srcu_read_lock() to ensure that once a request
passes the Lo_bound check, the corresponding queue_work() must complete
before the teardown path can finish its synchronization.
* lo_release: Calls synchronize_srcu() followed by drain_workqueue(). This
sequence ensures:
* No new work can be scheduled (lo_state change).
* All ongoing scheduling calls have finished (synchronize_srcu).
* All scheduled work has finished executing (drain_workqueue).
* Finally, it is safe to clear lo_backing_file.
Trace Evidence:
Console logs with debug printk() patch confirm that __loop_clr_fd() has
cleared the file for loop3 between multiple lo_rw_aio() requests.
[ 122.956248][ T6148] loop3: detected capacity change from 0 to 32768
[ 122.958217][ T6142] lo_rw_aio(loop3) starting read with raw_refcnt=0x0, refcnt=1
(...snipped...)
[ 123.234786][ T44] lo_rw_aio(loop3) starting read with raw_refcnt=0x0, refcnt=1
[ 123.254716][ T6148] __loop_clr_fd(loop3) clearing lo_backing_file with raw_refcnt=0x0, refcnt=1
[ 123.265134][ T180] lo_rw_aio(loop3) starting write with NULL file (already cleared?)
[ 123.265221][ T180] Oops: general protection fault, probably for non-canonical address 0xdffffc0000000014: 0000 [#1] SMP KASAN PTI
[ 123.265238][ T180] KASAN: null-ptr-deref in range [0x00000000000000a0-0x00000000000000a7]
[ 123.265255][ T180] CPU: 0 UID: 0 PID: 180 Comm: kworker/u8:7 Not tainted syzkaller #0 PREEMPT_{RT,(full)}
[ 123.265276][ T180] Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 04/18/2026
[ 123.265287][ T180] Workqueue: loop3 loop_workfn
[ 123.265320][ T180] RIP: 0010:lo_rw_aio+0xd1d/0x1170
Reported-by: syzbot+cd8a9a308e879a4e2c28@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=cd8a9a308e879a4e2c28
Analyzed-by: AI Mode in Google Search (no mail address)
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
Since this race condition is difficult to reproduce, we can't do bisection.
I hope you can figure out what has changed in the block layer for this merge window.
You might want to revert instead of modifying the loop driver.
drivers/block/loop.c | 21 +++++++++++++++++++--
1 file changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 0000913f7efc..9be47ce97dab 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -93,6 +93,7 @@ struct loop_cmd {
static DEFINE_IDR(loop_index_idr);
static DEFINE_MUTEX(loop_ctl_mutex);
static DEFINE_MUTEX(loop_validate_mutex);
+DEFINE_SRCU(loop_io_srcu);
/**
* loop_global_lock_killable() - take locks for safe loop_validate_file() test
@@ -1747,8 +1748,19 @@ static void lo_release(struct gendisk *disk)
need_clear = (lo->lo_state == Lo_rundown);
mutex_unlock(&lo->lo_mutex);
- if (need_clear)
+ if (need_clear) {
+ /*
+ * Now that loop_queue_rq() sees lo->lo_state != Lo_bound,
+ * wait for already started loop_queue_rq() to complete.
+ */
+ synchronize_srcu(&loop_io_srcu);
+ /*
+ * Now that no more works are scheduled by loop_queue_rq(),
+ * wait for already scheduled works to complete.
+ */
+ drain_workqueue(lo->workqueue);
__loop_clr_fd(lo);
+ }
}
static void lo_free_disk(struct gendisk *disk)
@@ -1854,11 +1866,15 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
struct request *rq = bd->rq;
struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
struct loop_device *lo = rq->q->queuedata;
+ int idx;
blk_mq_start_request(rq);
- if (data_race(READ_ONCE(lo->lo_state)) != Lo_bound)
+ idx = srcu_read_lock(&loop_io_srcu);
+ if (data_race(READ_ONCE(lo->lo_state)) != Lo_bound) {
+ srcu_read_unlock(&loop_io_srcu, idx);
return BLK_STS_IOERR;
+ }
switch (req_op(rq)) {
case REQ_OP_FLUSH:
@@ -1888,6 +1904,7 @@ static blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx,
#endif
loop_queue_work(lo, cmd);
+ srcu_read_unlock(&loop_io_srcu, idx);
return BLK_STS_OK;
}
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v2 8/8] arm64: dts: qcom: arduino-imola: Describe NVMEM layout for WiFi/BT addresses
From: Bartosz Golaszewski @ 2026-05-11 11:30 UTC (permalink / raw)
To: Loic Poulain
Cc: linux-mmc, devicetree, linux-kernel, linux-arm-msm, linux-block,
linux-wireless, ath10k, linux-bluetooth, netdev, daniel,
Konrad Dybcio, Ulf Hansson, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bjorn Andersson, Konrad Dybcio, Jens Axboe,
Johannes Berg, Jeff Johnson, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Balakrishna Godavarthi, Rocky Liao,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Srinivas Kandagatla, Andrew Lunn, Heiner Kallweit,
Russell King, Saravana Kannan
In-Reply-To: <20260507-block-as-nvmem-v2-8-bf17edd5134e@oss.qualcomm.com>
On Thu, 7 May 2026 17:24:43 +0200, Loic Poulain
<loic.poulain@oss.qualcomm.com> said:
> On Arduino Uno-Q, the eMMC boot1 partition is factory provisioned
> with device-specific information such as the WiFi MAC address
> and the Bluetooth BD address. This partition can serve as an
> alternative to additional non-volatile memory, such as a
> dedicated EEPROM.
>
> The eMMC boot partitions are typically good candidates, as they
> are relatively small, read-only by default (and can be enforced
> as hardware read-only), and are not affected by board reflashing
> procedures, which generally target the eMMC user or GP partitions.
>
> Describe the corresponding nvmem-layout for the WiFi and Bluetooth
> addresses, and point the WiFi and Bluetooth nodes to the appropriate
> NVMEM cells to retrieve them.
>
> Signed-off-by: Loic Poulain <loic.poulain@oss.qualcomm.com>
> Reviewed-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
> ---
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox