Linux block layer
 help / color / mirror / Atom feed
* Re: [PATCH v3] blk-mq: bound blk_hctx_poll() to one jiffy
From: Jens Axboe @ 2026-06-26 16:41 UTC (permalink / raw)
  To: hch, kbusch, lidiangang, changfengnan, tom.leiming, nj.shetty,
	joshi.k, anuj1072538, Anuj Gupta
  Cc: linux-block, Alok Rathore
In-Reply-To: <20260617155051.1266079-1-anuj20.g@samsung.com>


On Wed, 17 Jun 2026 21:20:51 +0530, Anuj Gupta wrote:
> blk_hctx_poll() can busy-poll until a completion is found or
> need_resched() becomes true. On preemptible kernels, the scheduler can
> set TIF_NEED_RESCHED on the timer tick and preempt the task at IRQ
> return before the loop condition re-evaluates it. After the context
> switch, the flag is cleared, so the poller can continue spinning instead
> of returning to its caller.
> 
> [...]

Applied, thanks!

[1/1] blk-mq: bound blk_hctx_poll() to one jiffy
      commit: 30e542a36228db353e81efcd39e4dbc7a95c88c5

Best regards,
-- 
Jens Axboe




^ permalink raw reply

* Re: block: partitions: Use seq_buf_putc() in cmdline_partition()
From: Markus Elfring @ 2026-06-26 16:48 UTC (permalink / raw)
  To: linux-block, Andy Shevchenko, Jens Axboe, Josh Law, Kees Cook
  Cc: LKML, kernel-janitors, Woradorn Laodhanadhaworn
In-Reply-To: <59dfd2ef-2fda-4dd0-a288-52c35613e778@web.de>

> All affected source code places could be adjusted at once
> if the change acceptance would evolve accordingly.
> 
> 18 source files are left over for similar development considerations.
> 
> 
>  block/partitions/cmdline.c | 4 +---

Will development interests grow for remaining update candidates?

See also:
Clarification approach “Using seq_buf_putc() calls more often?”
https://lore.kernel.org/cocci/3455eaa7-297f-46c9-a8ab-91e5bfbe0105@web.de/
https://sympa.inria.fr/sympa/arc/cocci/2026-06/msg00030.html

Regards,
Markus

^ permalink raw reply

* Re: [PATCH v2 10/83] block: rust: allow `hrtimer::Timer` in `RequestData`
From: 하승종 @ 2026-06-26 17:41 UTC (permalink / raw)
  To: Andreas Hindborg
  Cc: Liam R. Howlett, Alice Ryhl, Anna-Maria Behnsen, Benno Lossin,
	Björn Roy Baron, Boqun Feng, Danilo Krummrich,
	FUJITA Tomonori, Frederic Weisbecker, Gary Guo, Jens Axboe,
	John Stultz, Lorenzo Stoakes, Lyude Paul, Miguel Ojeda,
	Stephen Boyd, Thomas Gleixner, Trevor Gross, linux-block,
	linux-kernel, linux-mm, rust-for-linux
In-Reply-To: <20260609-rnull-v6-19-rc5-send-v2-10-82c7404542e2@kernel.org>

2026년 6월 10일 (수) 오전 4:23, Andreas Hindborg <a.hindborg@kernel.org>님이 작성:

> +    fn cancel(&mut self) -> bool {
> +        let request_data_ptr = &self.inner.wrapper_ref().data as *const T::RequestData;

I think this trips clippy::ref_as_ptr, which is enabled in the top-level
Makefile (-Wclippy::ref_as_ptr), so `make CLIPPY=1` fails here under
CONFIG_RUST_WERROR. IMO core::ptr::from_ref() would read better.

> +        let pdu_ptr = self.data_ref() as *const T::RequestData;

Same here, I'd go with:

    let pdu_ptr = core::ptr::from_ref(self.data_ref());

I applied both changes on top of rnull-v7.1-rc2 and `make CLIPPY=1` passes
cleanly here (the two ref_as_ptr errors go away, no new warnings).

Best regards,
SeungJong Ha

---
I'm not a regular reviewer for this subsystem — I just ran into this while
building your rnull tree with clippy. Let me know if drive-by notes like this
aren't the right fit here.

^ permalink raw reply

* general protection fault in reset_interrupt
From: sanan.hasanou @ 2026-06-26 21:29 UTC (permalink / raw)
  To: efremov, axboe, linux-block, linux-kernel; +Cc: syzkaller, contact

Good day, dear maintainers,

We found a bug using a modified version of syzkaller.

Kernel Branch: 7.0-rc1
Kernel Config: <https://drive.google.com/open?id=1pfjd_xagvCCoLD4kK7OQIvvdEBYpavwn>
Unfortunately, we don't have any reproducer for this bug yet.
Thank you!

Best regards,
Sanan Hasanov

floppy0: floppy_shutdown: timeout handler died.  
floppy0: get result error. Fdc=0 Last status=ffffffff Read bytes=0
floppy driver state
-------------------
now=4294939504 last interrupt=4294939495 diff=9 last called handler=reset_interrupt
timeout_message=do wakeup
last output bytes:
 0  0 0
 0  0 0
 0  0 0
 0  0 0
 0  0 0
 0  0 0
 8 80 4294938128
 8 80 4294938128
 8 80 4294938128
 8 80 4294938128
 e 80 4294938128
13 80 4294938128
 0 90 4294938128
1a 90 4294938128
 0 90 4294938128
12 80 4294938128
 0 90 4294938128
14 80 4294938128
18 80 4294938128
 8 80 4294939495
last result at 4294939495
last redo_fd_request at 4294939495
status=d0
fdc_busy=0
cont=0000000000000000
current_req=0000000000000000
command_status=-1
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000002: 0000 [#1] SMP KASAN
KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
CPU: 1 UID: 0 PID: 39 Comm: kworker/u8:3 Not tainted 7.0.0-rc1 #1 PREEMPT(full) 
Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Workqueue: floppy floppy_work_workfn
RIP: 0010:reset_interrupt+0x136/0x1b0 drivers/block/floppy.c:1790
Code: 62 8d 48 c7 c2 60 ff b9 8b e8 86 98 22 fb e9 3e ff ff ff e8 9c 23 c7 fb 48 8b 1d c5 52 d5 0d 48 83 c3 10 48 89 d8 48 c1 e8 03 <42> 80 3c 30 00 74 08 48 89 df e8 6b d4 32 fc 48 8b 33 48 c7 c7 80
RSP: 0018:ffffc90000297ab0 EFLAGS: 00010212
RAX: 0000000000000002 RBX: 0000000000000010 RCX: ffff888015b53a00
RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000000
RBP: ffffc90000297ac0 R08: ffffffff8f76bd77 R09: 1ffffffff1eed7ae
R10: dffffc0000000000 R11: fffffbfff1eed7af R12: ffff888015718818
R13: ffffffff819609fe R14: dffffc0000000000 R15: dffffc0000000000
FS:  0000000000000000(0000) GS:ffff8880dbbbb000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 000000000db2b000 CR4: 00000000000006f0
Call Trace:
 <TASK>
 floppy_work_workfn+0x18/0x20 drivers/block/floppy.c:993
 process_one_work kernel/workqueue.c:3275 [inline]
 process_scheduled_works+0xa30/0x13d0 kernel/workqueue.c:3358
 worker_thread+0xacb/0x1060 kernel/workqueue.c:3439
 kthread+0x388/0x470 kernel/kthread.c:467
 ret_from_fork+0x5e4/0xb90 arch/x86/kernel/process.c:158
 ret_from_fork_asm+0x11/0x20 arch/x86/entry/entry_64.S:245
 </TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:reset_interrupt+0x136/0x1b0 drivers/block/floppy.c:1790
Code: 62 8d 48 c7 c2 60 ff b9 8b e8 86 98 22 fb e9 3e ff ff ff e8 9c 23 c7 fb 48 8b 1d c5 52 d5 0d 48 83 c3 10 48 89 d8 48 c1 e8 03 <42> 80 3c 30 00 74 08 48 89 df e8 6b d4 32 fc 48 8b 33 48 c7 c7 80
RSP: 0018:ffffc90000297ab0 EFLAGS: 00010212
RAX: 0000000000000002 RBX: 0000000000000010 RCX: ffff888015b53a00
RDX: 0000000000000000 RSI: 0000000000000004 RDI: 0000000000000000
RBP: ffffc90000297ac0 R08: ffffffff8f76bd77 R09: 1ffffffff1eed7ae
R10: dffffc0000000000 R11: fffffbfff1eed7af R12: ffff888015718818
R13: ffffffff819609fe R14: dffffc0000000000 R15: dffffc0000000000
FS:  0000000000000000(0000) GS:ffff8880dbbbb000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 000000000db2b000 CR4: 00000000000006f0
----------------
Code disassembly (best guess), 1 bytes skipped:
   0:	8d 48 c7             	lea    -0x39(%rax),%ecx
   3:	c2 60 ff             	ret    $0xff60
   6:	b9 8b e8 86 98       	mov    $0x9886e88b,%ecx
   b:	22 fb                	and    %bl,%bh
   d:	e9 3e ff ff ff       	jmp    0xffffff50
  12:	e8 9c 23 c7 fb       	call   0xfbc723b3
  17:	48 8b 1d c5 52 d5 0d 	mov    0xdd552c5(%rip),%rbx        # 0xdd552e3
  1e:	48 83 c3 10          	add    $0x10,%rbx
  22:	48 89 d8             	mov    %rbx,%rax
  25:	48 c1 e8 03          	shr    $0x3,%rax
* 29:	42 80 3c 30 00       	cmpb   $0x0,(%rax,%r14,1) <-- trapping instruction
  2e:	74 08                	je     0x38
  30:	48 89 df             	mov    %rbx,%rdi
  33:	e8 6b d4 32 fc       	call   0xfc32d4a3
  38:	48 8b 33             	mov    (%rbx),%rsi
  3b:	48                   	rex.W
  3c:	c7                   	.byte 0xc7
  3d:	c7                   	.byte 0xc7
  3e:	80                   	.byte 0x80

<<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>

^ permalink raw reply

* Re: [PATCH] block: avoid potential deadlock on zone revalidation failure
From: Damien Le Moal @ 2026-06-26 22:42 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Jens Axboe, linux-block
In-Reply-To: <20260625115232.GC18076@lst.de>

On 6/25/26 20:52, Christoph Hellwig wrote:
> On Thu, Jun 25, 2026 at 03:28:24PM +0900, Damien Le Moal wrote:
> 
> [very long lockdep trace]
> 
>> +	/*
>> +	 * We may already have a zone write plug workqueue as this function may
>> +	 * be called after disk_free_zone_resources(), which does not destroy
>> +	 * the workqueue (the zone write plugs workqueue is destroyed at
>> +	 * disk_release() time).
>> +	 */
>> +	if (!disk->zone_wplugs_wq) {
> 
> Can't we just allocate this at add_disk time instead of the magic NULL
> check here to mirror the freeing side?

I checked and this is not simple to do because most drivers (null_blk, zloop,
ublk, virtio_blk, DM and nvme) call blk_revalidate_disk_zones() *before* calling
add_disk(). Which makes sense as we really want to check everything before the
disk is visible to the user. SCSI sd is an exception here.

And I do not see a better way without the addition of something like a new
disk_create_one_resources() that all drivers would need to call.


-- 
Damien Le Moal
Western Digital Research

^ permalink raw reply

* [PATCH] block: fix error injection static_branch dec imbalance
From: dayou5941 @ 2026-06-27  2:37 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block, liyouhong

From: liyouhong <liyouhong@kylinos.cn>

error_inject_add() only increments blk_error_injection_enabled when
adding the first rule to a given disk, but error_inject_removeall()
always decrements the static key.  blk_error_injection_exit() is
invoked from blk_unregister_queue() for every gendisk teardown, including
disks that never configured any injection rules.

Removing an unrelated block device therefore decrements the global
static key without a matching increment, which can silently disable
error injection on disks that still have rules in their
error_injection_list.  Repeated teardown of unconfigured disks can
further trigger a static_key underflow WARN in jump_label.c.

Only decrement the static key when removing a disk that actually had
entries, mirroring the list_empty() guard in error_inject_add().

Fixes: e8dcf2d142bd ("block: add configurable error injection")
Signed-off-by: liyouhong <liyouhong@kylinos.cn>
---
 block/error-injection.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/block/error-injection.c b/block/error-injection.c
index d24c90e9a25f..d210bd5fd8fb 100644
--- a/block/error-injection.c
+++ b/block/error-injection.c
@@ -118,15 +118,24 @@ static int error_inject_add(struct gendisk *disk, enum req_op op,
 static void error_inject_removeall(struct gendisk *disk)
 {
 	struct blk_error_inject *inj;
+	bool had_entries;
 
 	mutex_lock(&disk->error_injection_lock);
+	had_entries = !list_empty(&disk->error_injection_list);
 	clear_bit(GD_ERROR_INJECT, &disk->state);
 	while ((inj = list_first_entry_or_null(&disk->error_injection_list,
 			struct blk_error_inject, entry))) {
 		list_del_rcu(&inj->entry);
 		kfree_rcu_mightsleep(inj);
 	}
-	static_branch_dec(&blk_error_injection_enabled);
+	/*
+	 * blk_error_injection_exit() runs for every gendisk teardown, not
+	 * only for disks that configured rules.  Only adjust the global
+	 * static key if this disk ever contributed to it, mirroring the
+	 * list_empty() check in error_inject_add().
+	 */
+	if (had_entries)
+		static_branch_dec(&blk_error_injection_enabled);
 	mutex_unlock(&disk->error_injection_lock);
 }
 
-- 
2.25.1


^ permalink raw reply related

* [PATCH] block: assert blk_iou_cmd fits in the io_uring_cmd PDU
From: dayou5941 @ 2026-06-27  3:27 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block, liyouhong

From: liyouhong <liyouhong@kylinos.cn>

blk_iou_cmd is stored in io_uring_cmd->pdu via io_uring_cmd_to_pdu() for
block device io_uring commands (e.g. discard).  The PDU is only 32 bytes
inline storage; add a static_assert matching scsi_bsg.c so that future
struct growth cannot silently overflow it.

Signed-off-by: liyouhong <liyouhong@kylinos.cn>
---
 block/ioctl.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/block/ioctl.c b/block/ioctl.c
index ab2c9ed79946..3c8fd365aa9f 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -856,12 +856,17 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
 }
 #endif
 
+/*
+ * Per-command block io_uring PDU stored in io_uring_cmd.pdu[32].
+ * Holds discard state between submission, completion and task work.
+ */
 struct blk_iou_cmd {
 	u64 start;
 	u64 len;
 	int res;
 	bool nowait;
 };
+static_assert(sizeof(struct blk_iou_cmd) <= sizeof_field(struct io_uring_cmd, pdu));
 
 static void blk_cmd_complete(struct io_tw_req tw_req, io_tw_token_t tw)
 {
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH blktests] block/044: basic block error injection sanity test
From: Shin'ichiro Kawasaki @ 2026-06-27  4:06 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-block
In-Reply-To: <20260626045650.GA8752@lst.de>

On Jun 26, 2026 / 06:56, Christoph Hellwig wrote:
> On Fri, Jun 26, 2026 at 01:31:06PM +0900, Shin'ichiro Kawasaki wrote:
> > > > Nit: Majority of the blktests test cases have GPL-3.0+. If you do not mind,
> > > > I suggest GPL-3.0+.
> > > 
> > > Well a mix of licenses is obviously bad, although I hate the GPL 3 with
> > > passion.
> > 
> > I see, I respoect author's choice.
> 
> Well, if the common bits are GPLv3+ we can't actually legally combine
> them with test that have a pure GPLv2 license.  So I need at least
> GPL-2.0+.

I see... I read back GPLv2 and v3. My understanding is that:

 - GPL v3 adds additional restrictions on top of v2, such as section 6
   "Installation information" or section 3 "Legal Rights from Antci-
   Circumvention Law".
 - The v3 additions conflict with the GPL v2 section6, that says:
   "You may not impose any further restrictions on the recepients'
    excercise of the rights granted here in."

> 
> And we need to as a few authors to also fix this up for:
> 
> block/029
> block/030
> block/031
> block/040
> block/042
> block/043
> block/044

Thanks. I will list up original authors and contributors of the test cases,
and then bring up license fix up discussion.

^ permalink raw reply

* Re: [PATCH v2 2/4] blk-cgroup: fix race between policy activation and blkg destruction
From: yu kuai @ 2026-06-27  4:13 UTC (permalink / raw)
  To: Nilay Shroff, Tejun Heo, Josef Bacik, Jens Axboe
  Cc: Zheng Qixing, Christoph Hellwig, Tang Yizhou, Ming Lei, cgroups,
	linux-block, linux-kernel, yukuai
In-Reply-To: <866644be-3b07-49f9-9c5d-e0f94ad1c793@linux.ibm.com>

Hi,

在 2026/6/26 14:12, Nilay Shroff 写道:
> On 6/26/26 7:22 AM, yu kuai wrote:
>> Hi,
>>
>> 在 2026/6/26 9:50, yu kuai 写道:
>>> Hi,
>>>
>>> 在 2026/6/25 23:08, Nilay Shroff 写道:
>>>> On 6/24/26 12:16 PM, Yu Kuai wrote:
>>>>> diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
>>>>> index 7baccfb690fe..f7e788a7fe95 100644
>>>>> --- a/block/blk-cgroup.c
>>>>> +++ b/block/blk-cgroup.c
>>>>> @@ -1563,10 +1563,12 @@ int blkcg_activate_policy(struct gendisk
>>>>> *disk, const struct blkcg_policy *pol)
>>>>>         if (WARN_ON_ONCE(!pol->pd_alloc_fn || !pol->pd_free_fn))
>>>>>             return -EINVAL;
>>>>>           if (queue_is_mq(q))
>>>>>             memflags = blk_mq_freeze_queue(q);
>>>>> +
>>>>> +    mutex_lock(&q->blkcg_mutex);
>>>>>     retry:
>>>>>         spin_lock_irq(&q->queue_lock);
>>>>>           /* blkg_list is pushed at the head, reverse walk to
>>>>> initialize parents first */
>>>>>         list_for_each_entry_reverse(blkg, &q->blkg_list, q_node) {
>>>>> @@ -1625,10 +1627,11 @@ int blkcg_activate_policy(struct gendisk
>>>>> *disk, const struct blkcg_policy *pol)
>>>>>         __set_bit(pol->plid, q->blkcg_pols);
>>>>>         ret = 0;
>>>>>           spin_unlock_irq(&q->queue_lock);
>>>>>     out:
>>>>> +    mutex_unlock(&q->blkcg_mutex);
>>>>>         if (queue_is_mq(q))
>>>>>             blk_mq_unfreeze_queue(q, memflags);
>>>>>         if (pinned_blkg)
>>>>>             blkg_put(pinned_blkg);
>>>>>         if (pd_prealloc)
>>>> If the policy allocation fails, we jump to the lable enomem: and
>>>> teardown pds.
>>>> But I see this path still only acquires ->queue_lock. Don't we also 
>>>> need
>>>> to protect it with ->blkcg_mutex?
>>> Yes, I agree we should protect it as well.
>>
>> Just take a closer look at the code, the enomem is already protected by
>> blkcg_mutex :)
>>
>
> Oh yes, but the ->blkcg_mutex is never released if we jump to enomem.
> So that may potentially cause deadlock. We need to release ->blkcg_mutex
> once blkcg_policy_teardown_pds() returns. Or may be refactor code (or add
> comment) so that it's easy to realize or spot the ->blkcg_mutex is 
> acquired
> and then released around blkcg_policy_teardown_pds().

the enomem will goto out at last, and blkcg_mutex do released. The code is
a bit hacky.

>
>>>
>>>> Moreover I still see race between blkg insertion in blkg_create() 
>>>> which
>>>> still doesn't use ->blkcg_mutex and so list traversal in
>>>> bfq_end_wr_async()
>>>> may still race with blkg_create(), isn't it? I remember you once told
>>>> this will be handled in another series but I couldn't find that yet.
>>> This is the set:
>>>
>>> [PATCH 0/8] blk-cgroup: remove queue_lock nesting from blkcg paths - Yu
>>> Kuai <https://lore.kernel.org/all/cover.1780621988.git.yukuai@fygo.io/>
>>>
>>> Noted that set just make sure queue_lock is not nested under other 
>>> atomic
>>> context, and that set do not acquire blkcg_mutex for blkg_create() 
>>> yet. Howerver,
>>> with that set it'll be easy to convert all queue_lock to blkcg_mtuex 
>>> for blkg
>>> protection, and together with lots of blk-cgroup code cleanups.
>>>
>
> Okay, so are you planning to send a follow-up patchset that replaces 
> ->queue_lock
> with ->blkcg_mutex for protecting the blkg_list? If so, I'd still 
> prefer acquiring
> ->blkcg_mutex around blkg_create() in this patchset. That would 
> address the race
> between blkg_create() and the blkg_list traversal in 
> bfq_end_wr_async(), while the
> subsequent series can focus on cleaning up and removing the remaining 
> ->queue_lock
> usage for blkg protection.

Yes, there is a follow-up patchset. When this set was posted, blkg_create is still
called with queue_lock held, so I can't do that. However, not that the other set
is already applied, I can hold blkcg_mutex for blkg_create() now.

>
> Thanks,
> --Nilay
>
-- 
Thanks,
Kuai

^ permalink raw reply

* Re: [PATCH 1/1] block: partition: aix: bound LV name formatting
From: tt roxy @ 2026-06-27  4:37 UTC (permalink / raw)
  To: Philippe De Muyter
  Cc: Ren Wei, linux-block, axboe, kees, hexlabsecurity, objecting,
	akpm, yuantan098, bird
In-Reply-To: <20260626090929.GA4627@frolo.corp.macq.eu>

On Sat, Jun 27, 2026 at 4:50 AM Philippe De Muyter <phdm@macqel.be> wrote:
>
> Hello Ren Wei,
>
> On Fri, Jun 26, 2026 at 03:21:22PM +0800, Ren Wei wrote:
> > From: Zhiling Zou <roxy520tt@gmail.com>
> >
> > AIX logical volume names are stored on disk as fixed-size fields.
> > The partition parser reads them into struct lvname, but later formats
> > the fields with %s. If an on-disk name is not NUL-terminated, the string
> > formatting code can keep reading past the end of the 64-byte name field.
> >
> > Limit the formatted string length to the size of the on-disk name field
> > when printing AIX logical volume names.
> >
> > Fixes: 6ceea22bbbc8 ("partitions: add aix lvm partition support files")
> > Cc: stable@vger.kernel.org
> > Reported-by: Yuan Tan <yuantan098@gmail.com>
> > Reported-by: Xin Liu <bird@lzu.edu.cn>
> > Assisted-by: Codex:gpt-5.4
> > Signed-off-by: Zhiling Zou <roxy520tt@gmail.com>
> > Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
> > ---
> >  block/partitions/aix.c | 6 ++++--
> >  1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/block/partitions/aix.c b/block/partitions/aix.c
> > index f3c4174e003e..de19c19c85b2 100644
> > --- a/block/partitions/aix.c
> > +++ b/block/partitions/aix.c
> > @@ -261,7 +261,8 @@ int aix_partition(struct parsed_partitions *state)
> >                               put_partition(state, lv_ix + 1,
> >                                 (i + 1 - lp_ix) * pp_blocks_size + psn_part1,
> >                                 lvip[lv_ix].pps_per_lv * pp_blocks_size);
> > -                             seq_buf_printf(&state->pp_buf, " <%s>\n",
> > +                             seq_buf_printf(&state->pp_buf, " <%.*s>\n",
> > +                                            (int)sizeof(n[lv_ix].name),
> >                                              n[lv_ix].name);
> >                               lvip[lv_ix].lv_is_contiguous = 1;
> >                               ret = 1;
> > @@ -273,7 +274,8 @@ int aix_partition(struct parsed_partitions *state)
> >                       if (lvip[i].pps_found && !lvip[i].lv_is_contiguous) {
> >                               char tmp[sizeof(n[i].name) + 1]; // null char
> >
> > -                             snprintf(tmp, sizeof(tmp), "%s", n[i].name);
> > +                             snprintf(tmp, sizeof(tmp), "%.*s",
> > +                                      (int)sizeof(n[i].name), n[i].name);
>
> Is this change necessary ? snprintf always adds a NULL terminator and
> truncates the input if needed, isn't it ?
>

Yes, snprintf() guarantees that the destination buffer is
NUL-terminated and truncates the output.

However, with %s and no precision, snprintf() still treats n[i].name as
a NUL-terminated source string. If the on-disk fixed-size name field is
not NUL-terminated, snprintf() can keep reading past the end of
n[i].name while looking for the terminator, before truncating the output
into tmp.

So the issue is not an overflow of tmp, but an out-of-bounds read from
the fixed-width source field. The precision is needed to bound that
source read to sizeof(n[i].name).

> >                               pr_warn("partition %s (%u pp's found) is "
> >                                       "not contiguous\n",
> >                                       tmp, lvip[i].pps_found);
> > --
> > 2.43.0
>
> Best Regards
>
> Philippe De Muyter

^ permalink raw reply

* Re: block: partitions: Use seq_buf_putc() in cmdline_partition()
From: Christophe JAILLET @ 2026-06-27  5:30 UTC (permalink / raw)
  To: Markus Elfring, linux-block, Andy Shevchenko, Jens Axboe,
	Josh Law, Kees Cook
  Cc: LKML, kernel-janitors, Woradorn Laodhanadhaworn
In-Reply-To: <196e07e8-aeb4-478d-bb05-1faaea976e08@web.de>

Le 26/06/2026 à 18:48, Markus Elfring a écrit :
>> All affected source code places could be adjusted at once
>> if the change acceptance would evolve accordingly.
>>
>> 18 source files are left over for similar development considerations.
>>
>>
>>   block/partitions/cmdline.c | 4 +---
> 
> Will development interests grow for remaining update candidates?

These changes are pointless and already performed by the compiler. See [1].
So from my PoV, they only trash git blame output and make future 
backport harder.

Just my 2c.

CJ


[1]: 
https://elixir.bootlin.com/linux/v7.1-rc6/source/include/linux/seq_file.h#L127

> 
> See also:
> Clarification approach “Using seq_buf_putc() calls more often?”
> https://lore.kernel.org/cocci/3455eaa7-297f-46c9-a8ab-91e5bfbe0105@web.de/
> https://sympa.inria.fr/sympa/arc/cocci/2026-06/msg00030.html
> 
> Regards,
> Markus
> 
> 


^ permalink raw reply

* [PATCH v4 0/5] block: use integrity interval instead of sector as seed
From: Caleb Sander Mateos @ 2026-06-27  5:42 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
	Martin K. Petersen
  Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
	linux-kernel, Caleb Sander Mateos

The block integrity layer currently sets the integrity seed (initial
reference tag) in units of 512-byte sectors. However, Type 1 and Type 2
ref tags are actually in units of integrity intervals. On devices with
integrity interval size > 512 bytes, ref tags are seeded incorrectly.

Ref tag "remapping" in blk_integrity_{prepare,complete}() covers up this
ref tag seed discrepancy by offsetting all ref tags in each bio to
convert to/from the absolute integrity interval numbers. But
REQ_OP_ZONE_APPEND operations don't have their ref tags remapped, so the
ref tags using units of sectors will be stored to the device. As future
optimizations, the ref tag remapping could be avoided entirely on NVMe
and some SCSI devices by passing the ref tag seed instead of the
absolute integrity interval as the expected initial ref tag.

So avoid relying on remapping to convert between the ref tag seed in
units of sectors and stored ref tags in units of integrity intervals.
Initialize the ref tag seed as the integrity interval, not sector.

The subsequent commits clean up the integrity ref tag seed code a bit.

v4:
- Drop patch already applied

v3: https://lore.kernel.org/linux-block/20260417015732.2692434-1-csander@purestorage.com/T/
- Drop bi and bip arguments to bip_set_seed() (Christoph)

v2:
- Reorder fixes before refactoring commits
- Use u64, SECTOR_SHIFT (Christoph)
- Don't take sector_t in bip_set_seed() (Christoph)

Caleb Sander Mateos (5):
  block: use integrity interval instead of sector as seed
  blk-integrity: take u64 in bio_integrity_intervals()
  bio-integrity-fs: use integrity interval instead of sector as seed
  t10-pi: use bio_integrity_intervals() helper
  blk-integrity: avoid sector_t in bip_{get,set}_seed()

 block/bio-integrity-fs.c            |  2 +-
 block/bio-integrity.c               |  4 ++--
 block/t10-pi.c                      |  7 ++++---
 drivers/nvme/target/io-cmd-bdev.c   |  3 +--
 drivers/target/target_core_iblock.c |  3 +--
 include/linux/bio-integrity.h       | 11 -----------
 include/linux/blk-integrity.h       | 27 ++++++++++++++++++++-------
 include/linux/bvec.h                |  1 +
 8 files changed, 30 insertions(+), 28 deletions(-)

-- 
2.54.0


^ permalink raw reply

* [PATCH v4 1/5] block: use integrity interval instead of sector as seed
From: Caleb Sander Mateos @ 2026-06-27  5:42 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
	Martin K. Petersen
  Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
	linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>

bio_integrity_setup_default() and blk_integrity_iterate() set the
integrity seed (initial reference tag) to the absolute address in the
block device in units of 512-byte sectors. However, Type 1 and Type 2
ref tags are actually the least significant bits of the integrity
interval number. On devices with integrity interval size > 512 bytes,
the ref tag seed thus isn't the correct initial ref tag. The ref tag
seed is correctly incremented/decremented in units of integrity
intervals in bio_integrity_map_iter(), bio_integrity_advance(), and
blk_integrity_interval().

For REQ_OP_{WRITE,READ}, blk_integrity_{prepare,complete}() covers up
this ref tag seed discrepancy by adding/subtracting the difference
between the initial integrity interval and ref tag values to/from each
ref tag in the protection information. However, REQ_OP_ZONE_APPEND can
also carry PI but doesn't go through blk_integrity_prepare() because the
final data location on the zoned block device isn't known until the
operation completes. As a result, the REQ_OP_ZONE_APPEND PI ref tags
start from the ref tag seed, which isn't in integrity interval units.
Subsequent reads of the appended blocks will fail to remap the ref tags
from the expected integrity interval numbers to sector numbers.

Additionally, NVMe and many SCSI transports support offloading ref tag
remapping to the device by specifying the expected initial ref tag in
the command. The kernel doesn't currently take advantage of this, always
remapping ref tags in software for reads and writes and setting the
expected initial ref tag to the integrity interval. Setting the ref tag
seed in units of integrity intervals would be a prerequisite to allowing
the kernel to skip the software remapping and pass the ref tag seed as
the expected initial ref tag in the command.

So compute the ref tag seed in units of integrity intervals instead of
sectors to avoid relying on ref tag remapping for the conversion.

Fixes: 0512a75b98f8 ("block: Introduce REQ_OP_ZONE_APPEND")
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 block/bio-integrity.c | 3 ++-
 block/t10-pi.c        | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index b23e2434d80c..d20f9002c7c9 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -102,12 +102,13 @@ void bio_integrity_free_buf(struct bio_integrity_payload *bip)
 
 void bio_integrity_setup_default(struct bio *bio)
 {
 	struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
 	struct bio_integrity_payload *bip = bio_integrity(bio);
+	u64 seed = bio->bi_iter.bi_sector >> (bi->interval_exp - SECTOR_SHIFT);
 
-	bip_set_seed(bip, bio->bi_iter.bi_sector);
+	bip_set_seed(bip, seed);
 
 	if (bi->csum_type) {
 		bip->bip_flags |= BIP_CHECK_GUARD;
 		if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
 			bip->bip_flags |= BIP_IP_CHECKSUM;
diff --git a/block/t10-pi.c b/block/t10-pi.c
index a19b4e102a83..e58d5eb6cefb 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -308,18 +308,19 @@ static blk_status_t blk_integrity_iterate(struct bio *bio,
 					  struct bvec_iter *data_iter,
 					  bool verify)
 {
 	struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
 	struct bio_integrity_payload *bip = bio_integrity(bio);
+	u64 seed = data_iter->bi_sector >> (bi->interval_exp - SECTOR_SHIFT);
 	struct blk_integrity_iter iter = {
 		.bio = bio,
 		.bip = bip,
 		.bi = bi,
 		.data_iter = *data_iter,
 		.prot_iter = bip->bip_iter,
 		.interval_remaining = 1 << bi->interval_exp,
-		.seed = data_iter->bi_sector,
+		.seed = seed,
 		.csum = 0,
 	};
 	blk_status_t ret = BLK_STS_OK;
 
 	while (iter.data_iter.bi_size && ret == BLK_STS_OK) {
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 4/5] t10-pi: use bio_integrity_intervals() helper
From: Caleb Sander Mateos @ 2026-06-27  5:42 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
	Martin K. Petersen
  Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
	linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>

Use bio_integrity_intervals() to convert blk_rq_pos(rq) to integrity
intervals to reduce code duplication.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 block/t10-pi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/block/t10-pi.c b/block/t10-pi.c
index e58d5eb6cefb..787950dec50a 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -541,11 +541,11 @@ static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi,
 
 static void blk_integrity_remap(struct request *rq, unsigned int nr_bytes,
 				bool prep)
 {
 	struct blk_integrity *bi = &rq->q->limits.integrity;
-	u64 ref = blk_rq_pos(rq) >> (bi->interval_exp - SECTOR_SHIFT);
+	u64 ref = bio_integrity_intervals(bi, blk_rq_pos(rq));
 	unsigned intervals = nr_bytes >> bi->interval_exp;
 	struct bio *bio;
 
 	if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
 		return;
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 5/5] blk-integrity: avoid sector_t in bip_{get,set}_seed()
From: Caleb Sander Mateos @ 2026-06-27  5:42 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
	Martin K. Petersen
  Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
	linux-kernel, Caleb Sander Mateos, Christoph Hellwig
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>

bip_set_seed() and bip_get_seed() take/return a sector_t value that's
actually an integrity interval number. This is confusing, so pass
struct bio instead to bip_set_seed() and convert the bio's device
address to integrity intervals.

Open-code the access to bip->bip_iter.bi_sector in the one caller of
bip_set_seed() that doesn't use the bio device address for the seed.
Open-code bip_get_seed() in its one caller.

Add a comment to struct bvec_iter's bi_sector field explaining its
alternate use for bip_iter.

Suggested-by: Christoph Hellwig <hch@infradead.org>
Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
 block/bio-integrity.c               |  5 ++---
 block/t10-pi.c                      |  2 +-
 drivers/nvme/target/io-cmd-bdev.c   |  3 +--
 drivers/target/target_core_iblock.c |  3 +--
 include/linux/bio-integrity.h       | 11 -----------
 include/linux/blk-integrity.h       | 13 +++++++++++++
 include/linux/bvec.h                |  1 +
 7 files changed, 19 insertions(+), 19 deletions(-)

diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index d20f9002c7c9..7e5fb9b44848 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -102,13 +102,12 @@ void bio_integrity_free_buf(struct bio_integrity_payload *bip)
 
 void bio_integrity_setup_default(struct bio *bio)
 {
 	struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
 	struct bio_integrity_payload *bip = bio_integrity(bio);
-	u64 seed = bio->bi_iter.bi_sector >> (bi->interval_exp - SECTOR_SHIFT);
 
-	bip_set_seed(bip, seed);
+	bip_set_seed(bio);
 
 	if (bi->csum_type) {
 		bip->bip_flags |= BIP_CHECK_GUARD;
 		if (bi->csum_type == BLK_INTEGRITY_CSUM_IP)
 			bip->bip_flags |= BIP_IP_CHECKSUM;
@@ -488,11 +487,11 @@ int bio_integrity_map_iter(struct bio *bio, struct uio_meta *meta)
 
 	it.count = integrity_bytes;
 	ret = bio_integrity_map_user(bio, &it);
 	if (!ret) {
 		bio_uio_meta_to_bip(bio, meta);
-		bip_set_seed(bio_integrity(bio), meta->seed);
+		bio_integrity(bio)->bip_iter.bi_sector = meta->seed;
 		iov_iter_advance(&meta->iter, integrity_bytes);
 		meta->seed += bio_integrity_intervals(bi, bio_sectors(bio));
 	}
 	return ret;
 }
diff --git a/block/t10-pi.c b/block/t10-pi.c
index 787950dec50a..71367fd082bd 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -510,11 +510,11 @@ static void blk_reftag_remap_prepare(struct blk_integrity *bi,
 static void __blk_reftag_remap(struct bio *bio, struct blk_integrity *bi,
 			       unsigned *intervals, u64 *ref, bool prep)
 {
 	struct bio_integrity_payload *bip = bio_integrity(bio);
 	struct bvec_iter iter = bip->bip_iter;
-	u64 virt = bip_get_seed(bip);
+	u64 virt = bip->bip_iter.bi_sector;
 	union pi_tuple *ptuple;
 	union pi_tuple tuple;
 
 	if (prep && bip->bip_flags & BIP_MAPPED_INTEGRITY) {
 		*ref += bio->bi_iter.bi_size >> bi->interval_exp;
diff --git a/drivers/nvme/target/io-cmd-bdev.c b/drivers/nvme/target/io-cmd-bdev.c
index f2d9e8901df4..65fce51b024a 100644
--- a/drivers/nvme/target/io-cmd-bdev.c
+++ b/drivers/nvme/target/io-cmd-bdev.c
@@ -218,12 +218,11 @@ static int nvmet_bdev_alloc_bip(struct nvmet_req *req, struct bio *bio,
 		pr_err("Unable to allocate bio_integrity_payload\n");
 		return PTR_ERR(bip);
 	}
 
 	/* virtual start sector must be in integrity interval units */
-	bip_set_seed(bip, bio->bi_iter.bi_sector >>
-		     (bi->interval_exp - SECTOR_SHIFT));
+	bip_set_seed(bio);
 
 	resid = bio_integrity_bytes(bi, bio_sectors(bio));
 	while (resid > 0 && sg_miter_next(miter)) {
 		len = min_t(size_t, miter->length, resid);
 		rc = bio_integrity_add_page(bio, miter->page, len,
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 1087d1d17c36..1aeb5be529a8 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -706,12 +706,11 @@ iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio,
 		pr_err("Unable to allocate bio_integrity_payload\n");
 		return PTR_ERR(bip);
 	}
 
 	/* virtual start sector must be in integrity interval units */
-	bip_set_seed(bip, bio->bi_iter.bi_sector >>
-				  (bi->interval_exp - SECTOR_SHIFT));
+	bip_set_seed(bio);
 
 	pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size,
 		 (unsigned long long)bip->bip_iter.bi_sector);
 
 	resid = bio_integrity_bytes(bi, bio_sectors(bio));
diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h
index c3dda32fd803..992cb1622c2c 100644
--- a/include/linux/bio-integrity.h
+++ b/include/linux/bio-integrity.h
@@ -56,21 +56,10 @@ static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag)
 		return bip->bip_flags & flag;
 
 	return false;
 }
 
-static inline sector_t bip_get_seed(struct bio_integrity_payload *bip)
-{
-	return bip->bip_iter.bi_sector;
-}
-
-static inline void bip_set_seed(struct bio_integrity_payload *bip,
-				sector_t seed)
-{
-	bip->bip_iter.bi_sector = seed;
-}
-
 void bio_integrity_init(struct bio *bio, struct bio_integrity_payload *bip,
 		struct bio_vec *bvecs, unsigned int nr_vecs);
 struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio, gfp_t gfp,
 		unsigned int nr);
 int bio_integrity_add_page(struct bio *bio, struct page *page, unsigned int len,
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index 825d777c078b..c82b2f6fe194 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -85,10 +85,23 @@ static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
 					       unsigned int sectors)
 {
 	return bio_integrity_intervals(bi, sectors) * bi->metadata_size;
 }
 
+/**
+ * bip_set_seed - Set bip reference tag seed from bio device address
+ * @bio:	struct bio whose integrity payload's ref tag seed to initialize
+ */
+static inline void bip_set_seed(struct bio *bio)
+{
+	struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
+	struct bio_integrity_payload *bip = bio_integrity(bio);
+
+	bip->bip_iter.bi_sector =
+		bio_integrity_intervals(bi, bio->bi_iter.bi_sector);
+}
+
 static inline bool blk_integrity_rq(const struct request *rq)
 {
 	return rq->cmd_flags & REQ_INTEGRITY;
 }
 
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index 92837e2743f1..22bded380bbf 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -91,10 +91,11 @@ static inline struct folio *bvec_folio(const struct bio_vec *bv)
 
 struct bvec_iter {
 	/*
 	 * Current device address in 512 byte sectors. Only updated by the bio
 	 * iter wrappers and not the bvec iterator helpers themselves.
+	 * For bip_iter, this is overloaded to represent the integrity interval.
 	 */
 	sector_t		bi_sector;
 
 	/*
 	 * Remaining size in bytes.
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 3/5] bio-integrity-fs: use integrity interval instead of sector as seed
From: Caleb Sander Mateos @ 2026-06-27  5:42 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
	Martin K. Petersen
  Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
	linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>

bip_iter.bi_sector is meant to be in units of integrity intervals rather
than 512-byte sectors. bio_integrity_verify() doesn't actually use it
currently (it uses the passed in struct bvec_iter's bi_sector instead).
But let's set it to the expected value for consistency.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 block/bio-integrity-fs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/block/bio-integrity-fs.c b/block/bio-integrity-fs.c
index 9c5fe5fa8f0d..770eacb2220f 100644
--- a/block/bio-integrity-fs.c
+++ b/block/bio-integrity-fs.c
@@ -65,11 +65,11 @@ int fs_bio_integrity_verify(struct bio *bio, sector_t sector, unsigned int size)
 	 *
 	 * This is for use in the submitter after the driver is done with the
 	 * bio.  Requires the submitter to remember the sector and the size.
 	 */
 	memset(&bip->bip_iter, 0, sizeof(bip->bip_iter));
-	bip->bip_iter.bi_sector = sector;
+	bip->bip_iter.bi_sector = bio_integrity_intervals(bi, sector);
 	bip->bip_iter.bi_size = bio_integrity_bytes(bi, size >> SECTOR_SHIFT);
 	return blk_status_to_errno(bio_integrity_verify(bio, &data_iter));
 }
 
 static int __init fs_bio_integrity_init(void)
-- 
2.54.0


^ permalink raw reply related

* [PATCH v4 2/5] blk-integrity: take u64 in bio_integrity_intervals()
From: Caleb Sander Mateos @ 2026-06-27  5:42 UTC (permalink / raw)
  To: Jens Axboe, Christoph Hellwig, Sagi Grimberg, Chaitanya Kulkarni,
	Martin K. Petersen
  Cc: Anuj Gupta, linux-block, linux-nvme, linux-scsi, target-devel,
	linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627054220.2174166-1-csander@purestorage.com>

To allow bio_integrity_intervals() to convert an absolute sector to an
absolute integrity interval, use u64 for its argument and return types.
Also use SECTOR_SHIFT instead of the magic constant 9.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
Reviewed-by: Anuj Gupta <anuj20.g@samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 include/linux/blk-integrity.h | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index b1b530613c34..825d777c078b 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -64,23 +64,23 @@ queue_max_integrity_segments(const struct request_queue *q)
 {
 	return q->limits.max_integrity_segments;
 }
 
 /**
- * bio_integrity_intervals - Return number of integrity intervals for a bio
+ * bio_integrity_intervals - Convert sectors to integrity intervals
  * @bi:		blk_integrity profile for device
- * @sectors:	Size of the bio in 512-byte sectors
+ * @sectors:	Number of 512-byte sectors
  *
  * Description: The block layer calculates everything in 512 byte
  * sectors but integrity metadata is done in terms of the data integrity
  * interval size of the storage device.  Convert the block layer sectors
  * to the appropriate number of integrity intervals.
  */
-static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi,
-						   unsigned int sectors)
+static inline u64 bio_integrity_intervals(const struct blk_integrity *bi,
+					  u64 sectors)
 {
-	return sectors >> (bi->interval_exp - 9);
+	return sectors >> (bi->interval_exp - SECTOR_SHIFT);
 }
 
 static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
 					       unsigned int sectors)
 {
@@ -151,12 +151,12 @@ static inline unsigned short
 queue_max_integrity_segments(const struct request_queue *q)
 {
 	return 0;
 }
 
-static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi,
-						   unsigned int sectors)
+static inline u64 bio_integrity_intervals(const struct blk_integrity *bi,
+					  u64 sectors)
 {
 	return 0;
 }
 
 static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH] block: assert blk_iou_cmd fits in the io_uring_cmd PDU
From: Caleb Sander Mateos @ 2026-06-27  5:52 UTC (permalink / raw)
  To: dayou5941; +Cc: Jens Axboe, linux-block, liyouhong
In-Reply-To: <20260627032731.2878510-1-dayou5941@163.com>

On Fri, Jun 26, 2026 at 8:28 PM <dayou5941@163.com> wrote:
>
> From: liyouhong <liyouhong@kylinos.cn>
>
> blk_iou_cmd is stored in io_uring_cmd->pdu via io_uring_cmd_to_pdu() for
> block device io_uring commands (e.g. discard).  The PDU is only 32 bytes
> inline storage; add a static_assert matching scsi_bsg.c so that future
> struct growth cannot silently overflow it.
>
> Signed-off-by: liyouhong <liyouhong@kylinos.cn>
> ---
>  block/ioctl.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/block/ioctl.c b/block/ioctl.c
> index ab2c9ed79946..3c8fd365aa9f 100644
> --- a/block/ioctl.c
> +++ b/block/ioctl.c
> @@ -856,12 +856,17 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
>  }
>  #endif
>
> +/*
> + * Per-command block io_uring PDU stored in io_uring_cmd.pdu[32].
> + * Holds discard state between submission, completion and task work.
> + */
>  struct blk_iou_cmd {
>         u64 start;
>         u64 len;
>         int res;
>         bool nowait;
>  };
> +static_assert(sizeof(struct blk_iou_cmd) <= sizeof_field(struct io_uring_cmd, pdu));

Doesn't io_uring_cmd_to_pdu() already have this assertion?

static inline void io_uring_cmd_private_sz_check(size_t cmd_sz)
{
        BUILD_BUG_ON(cmd_sz > sizeof_field(struct io_uring_cmd, pdu));
}
#define io_uring_cmd_to_pdu(cmd, pdu_type) ( \
        io_uring_cmd_private_sz_check(sizeof(pdu_type)), \
        ((pdu_type *)&(cmd)->pdu) \
)

Best,
Caleb

^ permalink raw reply

* [RFC PATCH 1/2] blk-integrity: add BLK_EXPECTED_REF_TAG_CAPABLE
From: Caleb Sander Mateos @ 2026-06-27  6:19 UTC (permalink / raw)
  To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
	Martin K. Petersen
  Cc: linux-block, linux-nvme, linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627061933.2187447-1-csander@purestorage.com>

Add BLK_EXPECTED_REF_TAG_CAPABLE to enum blk_integrity_flags to allow a
device to report support for specifying an expected initial ref tag in
I/O. Make blk_integrity_remap() a no-op if the flag is set, as the ref
tag seed used to generate/verify ref tags in the protection information
can be passed as the expected initial ref tag.

Ref tag remapping is necessary to merge bios with non-contiguous ref tag
seeds, as it converts both bios' ref tags to/from absolute integrity
interval numbers, which are contiguous. So don't merge bios to a
BLK_EXPECTED_REF_TAG_CAPABLE device if the next bio's ref tag seed
doesn't match the ref tag that would follow the end of the first bio.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
 block/blk-integrity.c         | 18 ++++++++++++++++++
 block/t10-pi.c                |  3 ++-
 include/linux/blk-integrity.h |  2 ++
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/block/blk-integrity.c b/block/blk-integrity.c
index 964eebbee14d..85ebe13f0912 100644
--- a/block/blk-integrity.c
+++ b/block/blk-integrity.c
@@ -139,10 +139,12 @@ EXPORT_SYMBOL_GPL(blk_rq_integrity_map_user);
 
 bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
 			    struct request *next)
 {
 	struct bio_integrity_payload *bip, *bip_next;
+	struct blk_integrity *bi;
+	u64 intervals;
 
 	if (blk_integrity_rq(req) == 0 && blk_integrity_rq(next) == 0)
 		return true;
 
 	if (blk_integrity_rq(req) == 0 || blk_integrity_rq(next) == 0)
@@ -155,10 +157,17 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
 
 	if (bip->bip_flags & BIP_CHECK_APPTAG &&
 	    bip->app_tag != bip_next->app_tag)
 		return false;
 
+	bi = blk_get_integrity(req->bio->bi_bdev->bd_disk);
+	intervals = blk_rq_bytes(req) >> bi->interval_exp;
+	if (bip->bip_flags & BIP_CHECK_REFTAG &&
+	    bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE &&
+	    bip->bip_iter.bi_sector + intervals != bip_next->bip_iter.bi_sector)
+		return false;
+
 	if (req->nr_integrity_segments + next->nr_integrity_segments >
 	    q->limits.max_integrity_segments)
 		return false;
 
 	if (integrity_req_gap_back_merge(req, next->bio))
@@ -169,11 +178,13 @@ bool blk_integrity_merge_rq(struct request_queue *q, struct request *req,
 
 bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
 			     struct bio *bio)
 {
 	struct bio_integrity_payload *bip, *bip_bio = bio_integrity(bio);
+	struct blk_integrity *bi;
 	int nr_integrity_segs;
+	u64 intervals;
 
 	if (blk_integrity_rq(req) == 0 && bip_bio == NULL)
 		return true;
 
 	if (blk_integrity_rq(req) == 0 || bip_bio == NULL)
@@ -185,10 +196,17 @@ bool blk_integrity_merge_bio(struct request_queue *q, struct request *req,
 
 	if (bip->bip_flags & BIP_CHECK_APPTAG &&
 	    bip->app_tag != bip_bio->app_tag)
 		return false;
 
+	bi = blk_get_integrity(req->bio->bi_bdev->bd_disk);
+	intervals = blk_rq_bytes(req) >> bi->interval_exp;
+	if (bip->bip_flags & BIP_CHECK_REFTAG &&
+	    bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE &&
+	    bip->bip_iter.bi_sector + intervals != bip_bio->bip_iter.bi_sector)
+		return false;
+
 	nr_integrity_segs = blk_rq_count_integrity_sg(q, bio);
 	if (req->nr_integrity_segments + nr_integrity_segs >
 	    q->limits.max_integrity_segments)
 		return false;
 
diff --git a/block/t10-pi.c b/block/t10-pi.c
index 71367fd082bd..becf3e316b06 100644
--- a/block/t10-pi.c
+++ b/block/t10-pi.c
@@ -545,11 +545,12 @@ static void blk_integrity_remap(struct request *rq, unsigned int nr_bytes,
 	struct blk_integrity *bi = &rq->q->limits.integrity;
 	u64 ref = bio_integrity_intervals(bi, blk_rq_pos(rq));
 	unsigned intervals = nr_bytes >> bi->interval_exp;
 	struct bio *bio;
 
-	if (!(bi->flags & BLK_INTEGRITY_REF_TAG))
+	if (!(bi->flags & BLK_INTEGRITY_REF_TAG) ||
+	    bi->flags & BLK_EXPECTED_REF_TAG_CAPABLE)
 		return;
 
 	__rq_for_each_bio(bio, rq) {
 		__blk_reftag_remap(bio, bi, &intervals, &ref, prep);
 		if (!intervals)
diff --git a/include/linux/blk-integrity.h b/include/linux/blk-integrity.h
index c82b2f6fe194..e314d22d9922 100644
--- a/include/linux/blk-integrity.h
+++ b/include/linux/blk-integrity.h
@@ -13,10 +13,12 @@ enum blk_integrity_flags {
 	BLK_INTEGRITY_NOGENERATE	= 1 << 1,
 	BLK_INTEGRITY_DEVICE_CAPABLE	= 1 << 2,
 	BLK_INTEGRITY_REF_TAG		= 1 << 3,
 	BLK_INTEGRITY_STACKED		= 1 << 4,
 	BLK_SPLIT_INTERVAL_CAPABLE	= 1 << 5,
+	/* Device I/O specifies expected initial ref tag independent of LBA */
+	BLK_EXPECTED_REF_TAG_CAPABLE	= 1 << 6,
 };
 
 const char *blk_integrity_profile_name(struct blk_integrity *bi);
 bool queue_limits_stack_integrity(struct queue_limits *t,
 		struct queue_limits *b);
-- 
2.54.0


^ permalink raw reply related

* [RFC PATCH 2/2] nvme/core: advertise BLK_EXPECTED_REF_TAG_CAPABLE
From: Caleb Sander Mateos @ 2026-06-27  6:19 UTC (permalink / raw)
  To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
	Martin K. Petersen
  Cc: linux-block, linux-nvme, linux-kernel, Caleb Sander Mateos
In-Reply-To: <20260627061933.2187447-1-csander@purestorage.com>

NVMe Read, Write, and Write Zeroes commands include an (E)ILBRT field to
specify the expected initial reference tag for the controller to check
against the ref tags in the protection information buffer. However, the
NVMe driver currently always sets (E)ILBRT to the lower bits of the LBA.
The block integrity layer generates/verifies the PI ref tags according
to the bio's ref tag seed, so it must "remap" the ref tags, adjusting
for the difference between the ref tag seed and the absolute integrity
interval number (= LBA).

If a request has an integrity payload, set (E)ILBRT to its ref tag seed
so no ref tag remapping is required. Set BLK_EXPECTED_REF_TAG_CAPABLE in
NVMe devices' enum blk_integrity_flags to skip the block integrity layer
ref tag remapping.

Signed-off-by: Caleb Sander Mateos <csander@purestorage.com>
---
 drivers/nvme/host/core.c | 20 ++++++++++----------
 include/linux/t10-pi.h   |  5 -----
 2 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index 453c1f0b2dd0..8202ca706c97 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -914,34 +914,34 @@ static void nvme_set_app_tag(struct request *req, struct nvme_command *cmnd)
 }
 
 static void nvme_set_ref_tag(struct nvme_ns *ns, struct nvme_command *cmnd,
 			      struct request *req)
 {
-	u32 upper, lower;
-	u64 ref48;
+	u64 ref_tag;
 
 	/* only type1 and type 2 PI formats have a reftag */
 	switch (ns->head->pi_type) {
 	case NVME_NS_DPS_PI_TYPE1:
 	case NVME_NS_DPS_PI_TYPE2:
 		break;
 	default:
 		return;
 	}
 
+	ref_tag = full_pi_ref_tag(req);
+	if (blk_integrity_rq(req))
+		ref_tag = bio_integrity(req->bio)->bip_iter.bi_sector;
+
 	/* both rw and write zeroes share the same reftag format */
 	switch (ns->head->guard_type) {
 	case NVME_NVM_NS_16B_GUARD:
-		cmnd->rw.reftag = cpu_to_le32(t10_pi_ref_tag(req));
+		cmnd->rw.reftag = cpu_to_le32(lower_32_bits(ref_tag));
 		break;
 	case NVME_NVM_NS_64B_GUARD:
-		ref48 = ext_pi_ref_tag(req);
-		lower = lower_32_bits(ref48);
-		upper = upper_32_bits(ref48);
-
-		cmnd->rw.reftag = cpu_to_le32(lower);
-		cmnd->rw.cdw3 = cpu_to_le32(upper);
+		ref_tag = lower_48_bits(ref_tag);
+		cmnd->rw.reftag = cpu_to_le32(lower_32_bits(ref_tag));
+		cmnd->rw.cdw3 = cpu_to_le32(upper_32_bits(ref_tag));
 		break;
 	default:
 		break;
 	}
 }
@@ -1889,11 +1889,11 @@ static bool nvme_init_integrity(struct nvme_ns_head *head,
 		break;
 	default:
 		break;
 	}
 
-	bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE;
+	bi->flags |= BLK_SPLIT_INTERVAL_CAPABLE | BLK_EXPECTED_REF_TAG_CAPABLE;
 	bi->metadata_size = head->ms;
 	if (bi->csum_type) {
 		bi->pi_tuple_size = head->pi_size;
 		bi->pi_offset = info->pi_offset;
 	}
diff --git a/include/linux/t10-pi.h b/include/linux/t10-pi.h
index b6c2496866ea..5cf4859877f5 100644
--- a/include/linux/t10-pi.h
+++ b/include/linux/t10-pi.h
@@ -66,11 +66,6 @@ struct crc64_pi_tuple {
 static inline u64 lower_48_bits(u64 n)
 {
 	return n & ((1ull << 48) - 1);
 }
 
-static inline u64 ext_pi_ref_tag(struct request *rq)
-{
-	return lower_48_bits(full_pi_ref_tag(rq));
-}
-
 #endif
-- 
2.54.0


^ permalink raw reply related

* [RFC PATCH 0/2] Avoid software ref tag remapping for NVMe devices
From: Caleb Sander Mateos @ 2026-06-27  6:19 UTC (permalink / raw)
  To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
	Martin K. Petersen
  Cc: linux-block, linux-nvme, linux-kernel, Caleb Sander Mateos

Currently, each bio has a reference tag seed which is used to generate
the sequential ref tags in its protection information. In principle, the
ref tag seed can be any value as long as the same value is used when
blocks are written as when they are read back. However, some devices
(e.g. T10 DIF) require the ref tags to match the low bits of the
absolute integrity interval numbers. So the block integrity layer always
"remaps" ref tags to absolute integrity intervals using
blk_integrity_prepare() on writes and blk_integrity_complete() on reads.

On devices which do support an explicit "expected initial reference tag"
field in addition to the logical block address on each I/O, the software
ref tag remapping could be skipped by just passing the ref tag seed as
the expected initial ref tag.

Introduce a BLK_EXPECTED_REF_TAG_CAPABLE flag for devices to advertise
support for an expected initial ref tag. On devices that set this flag,
skip the block integrity layer ref tag remapping. Also take care not to
merge bios with non-contiguous ref tags, as the merged bio's ref tags
would no longer come from a single ref tag seed.

Set BLK_EXPECTED_REF_TAG_CAPABLE for NVMe devices and plumb the ref tag
seed (if provided) to the NVMe Read/Write (E)ILBRT field.

One potential concern would be NVMe devices which already have ref tags
written by an old kernel, which did perform the remapping (persisting
ref tags set to the low bits of the LBAs). When a new kernel that skips
the remapping reads back the ref tags, it would expect them to match the
ref tag seed, which would fail the ref tag verification.

Caleb Sander Mateos (2):
  blk-integrity: add BLK_EXPECTED_REF_TAG_CAPABLE
  nvme/core: advertise BLK_EXPECTED_REF_TAG_CAPABLE

 block/blk-integrity.c         | 18 ++++++++++++++++++
 block/t10-pi.c                |  3 ++-
 drivers/nvme/host/core.c      | 20 ++++++++++----------
 include/linux/blk-integrity.h |  2 ++
 include/linux/t10-pi.h        |  5 -----
 5 files changed, 32 insertions(+), 16 deletions(-)

-- 
2.54.0


^ permalink raw reply

* [PATCH 1/3] zram: fix zstd dict use-after-free on per-CPU error path
From: Haoqin Huang @ 2026-06-27  7:02 UTC (permalink / raw)
  To: minchan, senozhatsky, axboe, terrelln, dsterba, akpm
  Cc: linux-kernel, linux-block, haoqinhuang7, rongwei.wrw,
	Haoqin Huang, Rongwei Wang

From: Haoqin Huang <haoqinhuang@tencent.com>

zstd_setup_params() creates global cdict and ddict stored in
params->drv_data, shared across all per-CPU contexts. When a
per-CPU zstd_create() failed, its error path called
zstd_release_params() which freed those shared objects while
other per-CPU contexts might already hold references to them.

Remove the premature zstd_release_params() from the per-CPU
error path, the global cdict/ddict are properly released later
by zstd_release_params(), called from zcomp_init()'s cleanup
or from zcomp_destroy().

Fixes: 6a559ecd6e7e ("zram: add dictionary support to zstd backend")
Signed-off-by: Haoqin Huang <haoqinhuang@tencent.com>
Reviewed-by: Rongwei Wang <zigiwang@tencent.com>
---
 drivers/block/zram/backend_zstd.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index d00b548056dc..2584f47c9b3c 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -161,7 +161,6 @@ static int zstd_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
 	return 0;
 
 error:
-	zstd_release_params(params);
 	zstd_destroy(ctx);
 	return -EINVAL;
 }
-- 
2.43.7


^ permalink raw reply related

* [PATCH 2/3] zram: add per-backend capability flags and validate parameters early
From: Haoqin Huang @ 2026-06-27  7:02 UTC (permalink / raw)
  To: minchan, senozhatsky, axboe, terrelln, dsterba, akpm
  Cc: linux-kernel, linux-block, haoqinhuang7, rongwei.wrw,
	Haoqin Huang, Rongwei Wang
In-Reply-To: <20260627070216.13511-1-haoqinhuang7@gmail.com>

From: Haoqin Huang <haoqinhuang@tencent.com>

Writing dict or level parameters for algorithms that don't support
them was silently accepted but had no effect.  Out-of-range levels
were silently clamped by the underlying library.  Dict read failures
always lost the real error from kernel_read_file_from_path().

Add caps, level_min and level_max to zcomp_ops and validate
user-supplied parameters in algorithm_params_store() before storing,
giving immediate error feedback. Also fix comp_params_store() to
read the new dict into a temporary buffer before resetting old
parameters, making the update atomic.

Signed-off-by: Haoqin Huang <haoqinhuang@tencent.com>
Reviewed-by: Rongwei Wang <zigiwang@tencent.com>
---
 drivers/block/zram/backend_842.c     |  1 +
 drivers/block/zram/backend_deflate.c |  3 +++
 drivers/block/zram/backend_lz4.c     |  3 +++
 drivers/block/zram/backend_lz4hc.c   |  3 +++
 drivers/block/zram/backend_lzo.c     |  1 +
 drivers/block/zram/backend_lzorle.c  |  1 +
 drivers/block/zram/backend_zstd.c    |  3 +++
 drivers/block/zram/zcomp.c           | 23 ++++++++++++++++++++
 drivers/block/zram/zcomp.h           |  8 +++++++
 drivers/block/zram/zram_drv.c        | 32 +++++++++++++++++++++-------
 include/linux/zstd_lib.h             |  1 +
 lib/zstd/compress/clevels.h          |  1 -
 12 files changed, 71 insertions(+), 9 deletions(-)

diff --git a/drivers/block/zram/backend_842.c b/drivers/block/zram/backend_842.c
index 10d9d5c60f53..d796ebda1fa0 100644
--- a/drivers/block/zram/backend_842.c
+++ b/drivers/block/zram/backend_842.c
@@ -57,5 +57,6 @@ const struct zcomp_ops backend_842 = {
 	.destroy_ctx	= destroy_842,
 	.setup_params	= setup_params_842,
 	.release_params	= release_params_842,
+	.caps		= 0,
 	.name		= "842",
 };
diff --git a/drivers/block/zram/backend_deflate.c b/drivers/block/zram/backend_deflate.c
index f92a52a720d1..cedc3daad33a 100644
--- a/drivers/block/zram/backend_deflate.c
+++ b/drivers/block/zram/backend_deflate.c
@@ -144,5 +144,8 @@ const struct zcomp_ops backend_deflate = {
 	.destroy_ctx	= deflate_destroy,
 	.setup_params	= deflate_setup_params,
 	.release_params	= deflate_release_params,
+	.caps		= ZCOMP_CAP_LEVEL,
+	.level_min	= Z_DEFAULT_COMPRESSION,
+	.level_max	= Z_BEST_COMPRESSION,
 	.name		= "deflate",
 };
diff --git a/drivers/block/zram/backend_lz4.c b/drivers/block/zram/backend_lz4.c
index c449d511ba86..bd1e5ca4d134 100644
--- a/drivers/block/zram/backend_lz4.c
+++ b/drivers/block/zram/backend_lz4.c
@@ -146,5 +146,8 @@ const struct zcomp_ops backend_lz4 = {
 	.destroy_ctx	= lz4_destroy,
 	.setup_params	= lz4_setup_params,
 	.release_params	= lz4_release_params,
+	.caps		= ZCOMP_CAP_DICT | ZCOMP_CAP_LEVEL,
+	.level_min	= LZ4_ACCELERATION_DEFAULT,
+	.level_max	= 65535,
 	.name		= "lz4",
 };
diff --git a/drivers/block/zram/backend_lz4hc.c b/drivers/block/zram/backend_lz4hc.c
index f6a336acfe20..0e0d7c68a7d4 100644
--- a/drivers/block/zram/backend_lz4hc.c
+++ b/drivers/block/zram/backend_lz4hc.c
@@ -124,5 +124,8 @@ const struct zcomp_ops backend_lz4hc = {
 	.destroy_ctx	= lz4hc_destroy,
 	.setup_params	= lz4hc_setup_params,
 	.release_params	= lz4hc_release_params,
+	.caps		= ZCOMP_CAP_DICT | ZCOMP_CAP_LEVEL,
+	.level_min	= LZ4HC_MIN_CLEVEL,
+	.level_max	= LZ4HC_MAX_CLEVEL,
 	.name		= "lz4hc",
 };
diff --git a/drivers/block/zram/backend_lzo.c b/drivers/block/zram/backend_lzo.c
index 4c906beaae6b..965f007e2ca8 100644
--- a/drivers/block/zram/backend_lzo.c
+++ b/drivers/block/zram/backend_lzo.c
@@ -55,5 +55,6 @@ const struct zcomp_ops backend_lzo = {
 	.destroy_ctx	= lzo_destroy,
 	.setup_params	= lzo_setup_params,
 	.release_params	= lzo_release_params,
+	.caps		= 0,
 	.name		= "lzo",
 };
diff --git a/drivers/block/zram/backend_lzorle.c b/drivers/block/zram/backend_lzorle.c
index 10640c96cbfc..757b4598be03 100644
--- a/drivers/block/zram/backend_lzorle.c
+++ b/drivers/block/zram/backend_lzorle.c
@@ -55,5 +55,6 @@ const struct zcomp_ops backend_lzorle = {
 	.destroy_ctx	= lzorle_destroy,
 	.setup_params	= lzorle_setup_params,
 	.release_params	= lzorle_release_params,
+	.caps		= 0,
 	.name		= "lzo-rle",
 };
diff --git a/drivers/block/zram/backend_zstd.c b/drivers/block/zram/backend_zstd.c
index 2584f47c9b3c..0fbd2460883a 100644
--- a/drivers/block/zram/backend_zstd.c
+++ b/drivers/block/zram/backend_zstd.c
@@ -212,5 +212,8 @@ const struct zcomp_ops backend_zstd = {
 	.destroy_ctx	= zstd_destroy,
 	.setup_params	= zstd_setup_params,
 	.release_params	= zstd_release_params,
+	.caps		= ZCOMP_CAP_DICT | ZCOMP_CAP_LEVEL,
+	.level_min	= (int)-ZSTD_TARGETLENGTH_MAX,
+	.level_max	= ZSTD_MAX_CLEVEL,
 	.name		= "zstd",
 };
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
index 974c4691887e..15de28b50d42 100644
--- a/drivers/block/zram/zcomp.c
+++ b/drivers/block/zram/zcomp.c
@@ -9,6 +9,9 @@
 #include <linux/cpuhotplug.h>
 #include <linux/vmalloc.h>
 #include <linux/sysfs.h>
+#include <linux/lz4.h>
+#include <linux/zlib.h>
+#include <linux/zstd.h>
 
 #include "zcomp.h"
 
@@ -94,6 +97,26 @@ const char *zcomp_lookup_backend_name(const char *comp)
 	return NULL;
 }
 
+unsigned int zcomp_get_caps(const char *comp)
+{
+	const struct zcomp_ops *backend = lookup_backend_ops(comp);
+
+	return backend ? backend->caps : 0;
+}
+
+int zcomp_validate_level(const char *comp, s32 level)
+{
+	const struct zcomp_ops *backend = lookup_backend_ops(comp);
+
+	if (!backend)
+		return -EINVAL;
+	if (!(backend->caps & ZCOMP_CAP_LEVEL))
+		return -EOPNOTSUPP;
+	if (level < backend->level_min || level > backend->level_max)
+		return -EINVAL;
+	return 0;
+}
+
 /* show available compressors */
 ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at)
 {
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
index 81a0f3f6ff48..16f812a94c67 100644
--- a/drivers/block/zram/zcomp.h
+++ b/drivers/block/zram/zcomp.h
@@ -7,6 +7,9 @@
 
 #define ZCOMP_PARAM_NOT_SET	INT_MIN
 
+#define ZCOMP_CAP_DICT		BIT(0)	/* dictionary support */
+#define ZCOMP_CAP_LEVEL		BIT(1)	/* adjustable compression level */
+
 struct deflate_params {
 	s32 winbits;
 };
@@ -66,6 +69,9 @@ struct zcomp_ops {
 	int (*setup_params)(struct zcomp_params *params);
 	void (*release_params)(struct zcomp_params *params);
 
+	unsigned int caps;
+	s32 level_min;
+	s32 level_max;
 	const char *name;
 };
 
@@ -81,6 +87,8 @@ int zcomp_cpu_up_prepare(unsigned int cpu, struct hlist_node *node);
 int zcomp_cpu_dead(unsigned int cpu, struct hlist_node *node);
 ssize_t zcomp_available_show(const char *comp, char *buf, ssize_t at);
 const char *zcomp_lookup_backend_name(const char *comp);
+unsigned int zcomp_get_caps(const char *comp);
+int zcomp_validate_level(const char *comp, s32 level);
 
 struct zcomp *zcomp_create(const char *alg, struct zcomp_params *params);
 void zcomp_destroy(struct zcomp *comp);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index ace65c586072..a667d0672720 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -1699,21 +1699,24 @@ static int comp_params_store(struct zram *zram, u32 prio, s32 level,
 			     const char *dict_path,
 			     struct deflate_params *deflate_params)
 {
+	void *new_dict = NULL;
 	ssize_t sz = 0;
 
-	comp_params_reset(zram, prio);
-
 	if (dict_path) {
-		sz = kernel_read_file_from_path(dict_path, 0,
-						&zram->params[prio].dict,
-						INT_MAX,
-						NULL,
-						READING_POLICY);
-		if (sz < 0)
+		sz = kernel_read_file_from_path(dict_path, 0, &new_dict,
+						INT_MAX, NULL, READING_POLICY);
+		if (sz < 0) {
+			vfree(new_dict);
+			return sz;
+		} else if (sz == 0) {
+			vfree(new_dict);
 			return -EINVAL;
+		}
 	}
 
+	comp_params_reset(zram, prio);
 	zram->params[prio].dict_sz = sz;
+	zram->params[prio].dict = new_dict;
 	zram->params[prio].level = level;
 	zram->params[prio].deflate.winbits = deflate_params->winbits;
 	return 0;
@@ -1794,6 +1797,19 @@ static ssize_t algorithm_params_store(struct device *dev,
 			return -EINVAL;
 	}
 
+	if (zram->comp_algs[prio]) {
+		unsigned int caps = zcomp_get_caps(zram->comp_algs[prio]);
+
+		if (dict_path && !(caps & ZCOMP_CAP_DICT))
+			return -EOPNOTSUPP;
+
+		if (level != ZCOMP_PARAM_NOT_SET) {
+			ret = zcomp_validate_level(zram->comp_algs[prio], level);
+			if (ret)
+				return ret;
+		}
+	}
+
 	ret = comp_params_store(zram, prio, level, dict_path, &deflate_params);
 	return ret ? ret : len;
 }
diff --git a/include/linux/zstd_lib.h b/include/linux/zstd_lib.h
index e295d4125dde..f4b26844e53a 100644
--- a/include/linux/zstd_lib.h
+++ b/include/linux/zstd_lib.h
@@ -1241,6 +1241,7 @@ ZSTDLIB_API size_t ZSTD_sizeof_DDict(const ZSTD_DDict* ddict);
 #define ZSTD_SEARCHLOG_MIN        1
 #define ZSTD_MINMATCH_MAX         7   /* only for ZSTD_fast, other strategies are limited to 6 */
 #define ZSTD_MINMATCH_MIN         3   /* only for ZSTD_btopt+, faster strategies are limited to 4 */
+#define ZSTD_MAX_CLEVEL		22
 #define ZSTD_TARGETLENGTH_MAX    ZSTD_BLOCKSIZE_MAX
 #define ZSTD_TARGETLENGTH_MIN     0   /* note : comparing this constant to an unsigned results in a tautological test */
 #define ZSTD_STRATEGY_MIN        ZSTD_fast
diff --git a/lib/zstd/compress/clevels.h b/lib/zstd/compress/clevels.h
index 6ab8be6532ef..db3b275b502e 100644
--- a/lib/zstd/compress/clevels.h
+++ b/lib/zstd/compress/clevels.h
@@ -17,7 +17,6 @@
 
 /*-=====  Pre-defined compression levels  =====-*/
 
-#define ZSTD_MAX_CLEVEL     22
 
 __attribute__((__unused__))
 
-- 
2.43.7


^ permalink raw reply related

* [PATCH 3/3] zram: reset per-priority params when changing algorithm before init
From: Haoqin Huang @ 2026-06-27  7:02 UTC (permalink / raw)
  To: minchan, senozhatsky, axboe, terrelln, dsterba, akpm
  Cc: linux-kernel, linux-block, haoqinhuang7, rongwei.wrw,
	Haoqin Huang, Rongwei Wang
In-Reply-To: <20260627070216.13511-1-haoqinhuang7@gmail.com>

From: Haoqin Huang <haoqinhuang@tencent.com>

Parameters validated against one algorithm may be invalid for another
(e.g. lz4 accepts level=65535 but zstd does not).  Although algorithm
changes are blocked after disksize is set, they are allowed before
device initialization.  Reset per-priority params on algorithm change
so that stale parameters do not silently carry over.

Signed-off-by: Haoqin Huang <haoqinhuang@tencent.com>
Reviewed-by: Rongwei Wang <zigiwang@tencent.com>
---
 drivers/block/zram/zram_drv.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index a667d0672720..6b47586e8718 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -57,6 +57,7 @@ static size_t huge_class_size;
 static const struct block_device_operations zram_devops;
 
 static void slot_free(struct zram *zram, u32 index);
+static void comp_params_reset(struct zram *zram, u32 prio);
 #define slot_dep_map(zram, index) (&(zram)->table[(index)].dep_map)
 
 static void slot_lock_init(struct zram *zram, u32 index)
@@ -1681,6 +1682,7 @@ static int __comp_algorithm_store(struct zram *zram, u32 prio, const char *buf)
 	}
 
 	comp_algorithm_set(zram, prio, alg);
+	comp_params_reset(zram, prio);
 	return 0;
 }
 
-- 
2.43.7


^ permalink raw reply related

* Re: block: partitions: Use seq_buf_putc() in cmdline_partition()
From: Markus Elfring @ 2026-06-27  7:28 UTC (permalink / raw)
  To: Christophe Jaillet, linux-block, Andy Shevchenko, Jens Axboe,
	Josh Law, Kees Cook
  Cc: LKML, kernel-janitors, Woradorn Laodhanadhaworn, Steven Rostedt
In-Reply-To: <630e1d4c-3302-4d2c-a90c-5b3aedfe8f6b@wanadoo.fr>

…
>>>   block/partitions/cmdline.c | 4 +---
>>
>> Will development interests grow for remaining update candidates?
> 
> These changes are pointless and already performed by the compiler.

I got other impressions.


>                                                                    See [1].
> So from my PoV, they only trash git blame output and make future backport harder.
> 
> Just my 2c.
> [1]: https://elixir.bootlin.com/linux/v7.1-rc6/source/include/linux/seq_file.h#L127

Why do you refer to the sequence file programming interface
when I propose refinements for the application of sequence buffers?
https://elixir.bootlin.com/linux/v7.1.1/source/include/linux/seq_buf.h#L176-L177

Regards,
Markus

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox