Linux block layer
 help / color / mirror / Atom feed
* [PATCH v6 2/4] iomap: use BIO_COMPLETE_IN_TASK for dropbehind writeback
From: Tal Zussman @ 2026-05-14 21:51 UTC (permalink / raw)
  To: Jens Axboe, Matthew Wilcox (Oracle), Christian Brauner,
	Darrick J. Wong, Carlos Maiolino, Alexander Viro, Jan Kara,
	Christoph Hellwig
  Cc: Dave Chinner, Bart Van Assche, linux-block, linux-kernel,
	linux-xfs, linux-fsdevel, linux-mm, Gao Xiang, Tal Zussman
In-Reply-To: <20260514-blk-dontcache-v6-0-782e2fa7477b@columbia.edu>

Set BIO_COMPLETE_IN_TASK on iomap writeback bios when a dropbehind folio
is added. This ensures that bi_end_io runs in task context, where
folio_end_dropbehind() can safely invalidate folios.

With the bio layer now handling task-context deferral generically,
IOMAP_IOEND_DONTCACHE is no longer needed, as XFS no longer needs to
route DONTCACHE ioends through its completion workqueue. Remove the flag
and its NOMERGE entry.

Without the NOMERGE, regular I/Os that get merged with a dropbehind
folio will also have their completion deferred to task context.

Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
 fs/iomap/ioend.c      | 5 +++--
 fs/xfs/xfs_aops.c     | 4 ----
 include/linux/iomap.h | 5 +----
 3 files changed, 4 insertions(+), 10 deletions(-)

diff --git a/fs/iomap/ioend.c b/fs/iomap/ioend.c
index acf3cf98b23a..892dbfc77ae9 100644
--- a/fs/iomap/ioend.c
+++ b/fs/iomap/ioend.c
@@ -237,8 +237,6 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
 
 	if (wpc->iomap.flags & IOMAP_F_SHARED)
 		ioend_flags |= IOMAP_IOEND_SHARED;
-	if (folio_test_dropbehind(folio))
-		ioend_flags |= IOMAP_IOEND_DONTCACHE;
 	if (pos == wpc->iomap.offset && (wpc->iomap.flags & IOMAP_F_BOUNDARY))
 		ioend_flags |= IOMAP_IOEND_BOUNDARY;
 
@@ -255,6 +253,9 @@ ssize_t iomap_add_to_ioend(struct iomap_writepage_ctx *wpc, struct folio *folio,
 	if (!bio_add_folio(&ioend->io_bio, folio, map_len, poff))
 		goto new_ioend;
 
+	if (folio_test_dropbehind(folio))
+		bio_set_flag(&ioend->io_bio, BIO_COMPLETE_IN_TASK);
+
 	/*
 	 * Clamp io_offset and io_size to the incore EOF so that ondisk
 	 * file size updates in the ioend completion are byte-accurate.
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index f279055fcea0..0dcf78beae8a 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -511,10 +511,6 @@ xfs_ioend_needs_wq_completion(
 	if (ioend->io_flags & (IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_SHARED))
 		return true;
 
-	/* Page cache invalidation cannot be done in irq context. */
-	if (ioend->io_flags & IOMAP_IOEND_DONTCACHE)
-		return true;
-
 	return false;
 }
 
diff --git a/include/linux/iomap.h b/include/linux/iomap.h
index 2c5685adf3a9..fef04e01116f 100644
--- a/include/linux/iomap.h
+++ b/include/linux/iomap.h
@@ -399,16 +399,13 @@ sector_t iomap_bmap(struct address_space *mapping, sector_t bno,
 #define IOMAP_IOEND_BOUNDARY		(1U << 2)
 /* is direct I/O */
 #define IOMAP_IOEND_DIRECT		(1U << 3)
-/* is DONTCACHE I/O */
-#define IOMAP_IOEND_DONTCACHE		(1U << 4)
 
 /*
  * Flags that if set on either ioend prevent the merge of two ioends.
  * (IOMAP_IOEND_BOUNDARY also prevents merges, but only one-way)
  */
 #define IOMAP_IOEND_NOMERGE_FLAGS \
-	(IOMAP_IOEND_SHARED | IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_DIRECT | \
-	 IOMAP_IOEND_DONTCACHE)
+	(IOMAP_IOEND_SHARED | IOMAP_IOEND_UNWRITTEN | IOMAP_IOEND_DIRECT)
 
 /*
  * Structure for writeback I/O completions.

-- 
2.39.5


^ permalink raw reply related

* [PATCH v6 3/4] buffer: add dropbehind writeback support
From: Tal Zussman @ 2026-05-14 21:51 UTC (permalink / raw)
  To: Jens Axboe, Matthew Wilcox (Oracle), Christian Brauner,
	Darrick J. Wong, Carlos Maiolino, Alexander Viro, Jan Kara,
	Christoph Hellwig
  Cc: Dave Chinner, Bart Van Assche, linux-block, linux-kernel,
	linux-xfs, linux-fsdevel, linux-mm, Gao Xiang, Tal Zussman
In-Reply-To: <20260514-blk-dontcache-v6-0-782e2fa7477b@columbia.edu>

Add block_write_begin_iocb() which threads the kiocb through to
__filemap_get_folio() so that buffer_head-based I/O can use DONTCACHE
behavior. When the iocb has IOCB_DONTCACHE set, FGP_DONTCACHE is
passed to mark the folio for dropbehind. The existing
block_write_begin() is preserved as a wrapper that passes a NULL iocb.

Set BIO_COMPLETE_IN_TASK in submit_bh_wbc() when the folio has
dropbehind set, so that buffer_head writeback completions get deferred
to task context.

Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
 fs/buffer.c                 | 19 +++++++++++++++++--
 include/linux/buffer_head.h |  3 +++
 2 files changed, 20 insertions(+), 2 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index b0b3792b1496..d0abaf44d782 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2138,14 +2138,19 @@ EXPORT_SYMBOL(block_commit_write);
  *
  * The filesystem needs to handle block truncation upon failure.
  */
-int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
+int block_write_begin_iocb(const struct kiocb *iocb,
+		struct address_space *mapping, loff_t pos, unsigned len,
 		struct folio **foliop, get_block_t *get_block)
 {
 	pgoff_t index = pos >> PAGE_SHIFT;
+	fgf_t fgp_flags = FGP_WRITEBEGIN;
 	struct folio *folio;
 	int status;
 
-	folio = __filemap_get_folio(mapping, index, FGP_WRITEBEGIN,
+	if (iocb && iocb->ki_flags & IOCB_DONTCACHE)
+		fgp_flags |= FGP_DONTCACHE;
+
+	folio = __filemap_get_folio(mapping, index, fgp_flags,
 			mapping_gfp_mask(mapping));
 	if (IS_ERR(folio))
 		return PTR_ERR(folio);
@@ -2160,6 +2165,13 @@ int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
 	*foliop = folio;
 	return status;
 }
+
+int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
+		struct folio **foliop, get_block_t *get_block)
+{
+	return block_write_begin_iocb(NULL, mapping, pos, len, foliop,
+				      get_block);
+}
 EXPORT_SYMBOL(block_write_begin);
 
 int block_write_end(loff_t pos, unsigned len, unsigned copied,
@@ -2715,6 +2727,9 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,
 
 	bio = bio_alloc(bh->b_bdev, 1, opf, GFP_NOIO);
 
+	if (folio_test_dropbehind(bh->b_folio))
+		bio_set_flag(bio, BIO_COMPLETE_IN_TASK);
+
 	if (IS_ENABLED(CONFIG_FS_ENCRYPTION))
 		buffer_set_crypto_ctx(bio, bh, GFP_NOIO);
 
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index e4939e33b4b5..4ce50882d621 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -260,6 +260,9 @@ int block_read_full_folio(struct folio *, get_block_t *);
 bool block_is_partially_uptodate(struct folio *, size_t from, size_t count);
 int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len,
 		struct folio **foliop, get_block_t *get_block);
+int block_write_begin_iocb(const struct kiocb *iocb,
+		struct address_space *mapping, loff_t pos, unsigned len,
+		struct folio **foliop, get_block_t *get_block);
 int __block_write_begin(struct folio *folio, loff_t pos, unsigned len,
 		get_block_t *get_block);
 int block_write_end(loff_t pos, unsigned len, unsigned copied, struct folio *);

-- 
2.39.5


^ permalink raw reply related

* [PATCH v6 4/4] block: enable RWF_DONTCACHE for block devices
From: Tal Zussman @ 2026-05-14 21:51 UTC (permalink / raw)
  To: Jens Axboe, Matthew Wilcox (Oracle), Christian Brauner,
	Darrick J. Wong, Carlos Maiolino, Alexander Viro, Jan Kara,
	Christoph Hellwig
  Cc: Dave Chinner, Bart Van Assche, linux-block, linux-kernel,
	linux-xfs, linux-fsdevel, linux-mm, Gao Xiang, Tal Zussman
In-Reply-To: <20260514-blk-dontcache-v6-0-782e2fa7477b@columbia.edu>

Block device buffered reads and writes already pass through
filemap_read() and iomap_file_buffered_write() respectively, both of
which handle IOCB_DONTCACHE. Enable RWF_DONTCACHE for block device files
by setting FOP_DONTCACHE in def_blk_fops.

For CONFIG_BUFFER_HEAD=y paths, use block_write_begin_iocb() in
blkdev_write_begin() to thread the kiocb through so that buffer_head
writeback gets dropbehind support.

CONFIG_BUFFER_HEAD=n paths are handled by the previously added iomap
BIO_COMPLETE_IN_TASK support.

This support is useful for databases that operate on raw block devices,
among other userspace applications.

Signed-off-by: Tal Zussman <tz2294@columbia.edu>
---
 block/fops.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/block/fops.c b/block/fops.c
index bb6642b45937..31b073181d87 100644
--- a/block/fops.c
+++ b/block/fops.c
@@ -504,7 +504,8 @@ static int blkdev_write_begin(const struct kiocb *iocb,
 			      unsigned len, struct folio **foliop,
 			      void **fsdata)
 {
-	return block_write_begin(mapping, pos, len, foliop, blkdev_get_block);
+	return block_write_begin_iocb(iocb, mapping, pos, len, foliop,
+				     blkdev_get_block);
 }
 
 static int blkdev_write_end(const struct kiocb *iocb,
@@ -966,7 +967,7 @@ const struct file_operations def_blk_fops = {
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= blkdev_fallocate,
 	.uring_cmd	= blkdev_uring_cmd,
-	.fop_flags	= FOP_BUFFER_RASYNC,
+	.fop_flags	= FOP_BUFFER_RASYNC | FOP_DONTCACHE,
 };
 
 static __init int blkdev_init(void)

-- 
2.39.5


^ permalink raw reply related

* Re: [PATCH] Re:[PATCH v3] zram: fix use-after-free in zram_writeback_endio
From: Minchan Kim @ 2026-05-14 22:02 UTC (permalink / raw)
  To: wang wei
  Cc: richardycc, akpm, axboe, bgeffon, linux-block, linux-kernel,
	linux-mm, liumartin, senozhatsky, stable
In-Reply-To: <20260513140218.7425-1-a929244872@163.com>

On Wed, May 13, 2026 at 10:02:18PM +0800, wang wei wrote:
> >@@ -847,7 +849,7 @@ static void release_wb_ctl(struct zram_wb_ctl *wb_ctl)
> > 		release_wb_req(req);
> > 	}
> >
> >-	kfree(wb_ctl);
> >+	kfree_rcu(wb_ctl, rcu);
> > }
> 
> Do we need to add a 'rcu_assign_pointer(wb_ctl, NULL);' before 'kfree_rcu(wb_ctl, rcu)'?
> 
> Signed-off-by: wang wei <a929244872@163.com>

Why do we need it?

My understanding is rcu_assign_pointer() is typically used to publish NULL to
a shared pointer variable so that future RCU readers (using rcu_dereference)
won't access the object before kfree_rcu().

However, in our case, wb_ctl is not stored in any shared pointer variable.
It is a local variable in writeback_store() and RCU readers (zram_writeback_endio)
do not look up wb_ctl from a shared pointer. They obtain it directly from
bio->bi_private of the specific bio they are completing.

Please let me know if I missed anything.

^ permalink raw reply

* [PATCH v2] loop: Fix NULL pointer dereference by synchronizing lo_release and loop_queue_rq
From: Tetsuo Handa @ 2026-05-15  1:38 UTC (permalink / raw)
  To: Bart Van Assche, Jens Axboe, Christoph Hellwig, Damien Le Moal
  Cc: linux-block, LKML, Andrew Morton
In-Reply-To: <af2205e3-205e-4743-a767-8593c2c4747a@I-love.SAKURA.ne.jp>

The loop driver relies on lo_release() to automatically clear the loop
device via __loop_clr_fd() when the last file descriptor is closed
(LO_FLAGS_AUTOCLEAR). Although the backing file structure itself remains
allocated in memory thanks to proper file reference counting (f_count is
not zero), a severe race condition exists regarding the visibility of
the lo->lo_backing_file pointer.

This race window was exposed by commit 65565ca5f99b ("block: unify
the synchronous bi_end_io callbacks"). By unifying and optimizing
the synchronous I/O completion path, the timing and scheduling behavior of
the block layer altered significantly.
As a result, a highly-concurrent execution pipeline emerged where
lo_release() can progress to __loop_clr_fd() and nullify
lo->lo_backing_file while an already-scheduled asynchronous I/O work
(lo_rw_aio) is just about to be executed by a kworker thread.

Since the kworker enters lo_rw_aio() after lo->lo_backing_file has been
cleared, it attempts to dereference the now-NULL pointer when initializing
the kiocb, leading to the reported NULL pointer dereference bug.

To close this race safely without introducing heavy fast-path checks,
we must ensure that any running or scheduled dispatch threads have
completed before we nullify the pointer. Since loop_queue_rq() operates
within the block layer's RCU read-side critical section, invoke
synchronize_rcu() and drain_workqueue() in __loop_clr_fd() prior to
clearing lo->lo_backing_file.

Reported-by: syzbot+cd8a9a308e879a4e2c28@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=cd8a9a308e879a4e2c28
Reported-by: syzbot+bc273027d5643e48e5b3@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=bc273027d5643e48e5b3
Analyzed-by: AI Mode in Google Search (no mail address)
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
---
 drivers/block/loop.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 0000913f7efc..ff117f340b2f 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1118,6 +1118,17 @@ static void __loop_clr_fd(struct loop_device *lo)
 	struct file *filp;
 	gfp_t gfp = lo->old_gfp_mask;
 
+	/*
+	 * Now that loop_queue_rq() sees lo->lo_state != Lo_bound,
+	 * wait for already started loop_queue_rq() to complete.
+	 */
+	synchronize_rcu();
+	/*
+	 * Now that no more works are scheduled by loop_queue_rq(),
+	 * wait for already scheduled works to complete.
+	 */
+	drain_workqueue(lo->workqueue);
+
 	spin_lock_irq(&lo->lo_lock);
 	filp = lo->lo_backing_file;
 	lo->lo_backing_file = NULL;
-- 
2.54.0



^ permalink raw reply related

* Re: [PATCH v6 1/4] block: add task-context bio completion infrastructure
From: Hillf Danton @ 2026-05-15  2:38 UTC (permalink / raw)
  To: Tal Zussman
  Cc: Matthew Wilcox (Oracle), Christoph Hellwig, linux-block,
	linux-kernel
In-Reply-To: <20260514-blk-dontcache-v6-1-782e2fa7477b@columbia.edu>

On Thu, 14 May 2026 17:51:14 -0400 Tal Zussman wrote:
> +
> +static void bio_complete_work_fn(struct work_struct *w)
> +{
> +	struct delayed_work *dw = to_delayed_work(w);
> +	struct bio_complete_batch *batch =
> +		container_of(dw, struct bio_complete_batch, work);
> +
> +	while (1) {
> +		struct bio_list list;
> +		struct bio *bio;
> +
> +		local_lock_irq(&bio_complete_batch.lock);
> +		list = batch->list;
> +		bio_list_init(&batch->list);
> +		local_unlock_irq(&bio_complete_batch.lock);
> +
> +		if (bio_list_empty(&list))
> +			break;
> +
> +		while ((bio = bio_list_pop(&list)))
> +			bio->bi_end_io(bio);
> +
> +		if (need_resched()) {
> +			bool is_empty;
> +
Checking resched is not needed as workqueue worker can be preempted
while processing bios.Given batch and delayed work, I suspect completing
more than batch, the bios accumulated within a jiff, makes sense.

> +			local_lock_irq(&bio_complete_batch.lock);
> +			is_empty = bio_list_empty(&batch->list);
> +			local_unlock_irq(&bio_complete_batch.lock);
> +			if (!is_empty)
> +				mod_delayed_work_on(batch->cpu,
> +						    bio_complete_wq,
> +						    &batch->work, 0);
> +			break;
> +		}
> +	}
> +}
> +

^ permalink raw reply

* Re: fix block layer bounce buffering for block size > PAGE_SIZE v2
From: Christoph Hellwig @ 2026-05-15  4:28 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Christoph Hellwig, Christian Brauner, Darrick J. Wong,
	Pankaj Raghav, linux-block, linux-xfs, linux-fsdevel
In-Reply-To: <30acedd3-e994-4810-8952-613b7d0bd9ca@kernel.dk>

On Wed, May 13, 2026 at 01:56:09PM -0600, Jens Axboe wrote:
> > Can we get some Fixes tags on these, please?
> 
> Looked myself to not delay this any further, both marked with:
> 
> Fixes: 8dd5e7c75d7b ("block: add helpers to bounce buffer an iov_iter into bios")

Sorry.  The tag looks correct.


^ permalink raw reply

* Re: [PATCH V4 0/3] md/nvme: Enable PCI P2PDMA support for RAID0 and NVMe Multipath
From: Christoph Hellwig @ 2026-05-15  4:35 UTC (permalink / raw)
  To: Chaitanya Kulkarni
  Cc: song, yukuai, linan122, kbusch, axboe, sagi, linux-block,
	linux-raid, linux-nvme, kmodukuri
In-Reply-To: <20260513185153.95552-1-kch@nvidia.com>

Still looks good to me as per the reviews.


^ permalink raw reply

* remove dead code and export
From: Christoph Hellwig @ 2026-05-15  4:55 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block

Hi Jens,

this series removes some minor dead code and dead exports in the block code.

Diffstat:
 block/bio.c            |   44 ++++++++++++++++++--------------------------
 block/blk-core.c       |    2 --
 block/blk.h            |    2 ++
 include/linux/bio.h    |    9 +--------
 include/linux/blkdev.h |    1 -
 5 files changed, 21 insertions(+), 37 deletions(-)

^ permalink raw reply

* [PATCH 1/5] block: remove zero_fill_bio_iter
From: Christoph Hellwig @ 2026-05-15  4:55 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block
In-Reply-To: <20260515045547.3790129-1-hch@lst.de>

Only used to implement zero_fill_bio, so directly implement that.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/bio.c         | 6 +++---
 include/linux/bio.h | 7 +------
 2 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index b8972dba68a0..b990c453d72f 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -635,15 +635,15 @@ struct bio *bio_kmalloc(unsigned short nr_vecs, gfp_t gfp_mask)
 }
 EXPORT_SYMBOL(bio_kmalloc);
 
-void zero_fill_bio_iter(struct bio *bio, struct bvec_iter start)
+void zero_fill_bio(struct bio *bio)
 {
 	struct bio_vec bv;
 	struct bvec_iter iter;
 
-	__bio_for_each_segment(bv, bio, iter, start)
+	bio_for_each_segment(bv, bio, iter)
 		memzero_bvec(&bv);
 }
-EXPORT_SYMBOL(zero_fill_bio_iter);
+EXPORT_SYMBOL(zero_fill_bio);
 
 /**
  * bio_truncate - truncate the bio to small size of @new_size
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 97d747320b35..84643fc0fb08 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -482,13 +482,8 @@ extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
 			       struct bio *src, struct bvec_iter *src_iter);
 extern void bio_copy_data(struct bio *dst, struct bio *src);
 extern void bio_free_pages(struct bio *bio);
+void zero_fill_bio(struct bio *bio);
 void guard_bio_eod(struct bio *bio);
-void zero_fill_bio_iter(struct bio *bio, struct bvec_iter iter);
-
-static inline void zero_fill_bio(struct bio *bio)
-{
-	zero_fill_bio_iter(bio, bio->bi_iter);
-}
 
 static inline void bio_release_pages(struct bio *bio, bool mark_dirty)
 {
-- 
2.53.0


^ permalink raw reply related

* [PATCH 2/5] block: remove bio_copy_data_iter
From: Christoph Hellwig @ 2026-05-15  4:55 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block
In-Reply-To: <20260515045547.3790129-1-hch@lst.de>

Only used by bio_copy_data, so implement that directly.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/bio.c         | 36 +++++++++++++++---------------------
 include/linux/bio.h |  2 --
 2 files changed, 15 insertions(+), 23 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index b990c453d72f..57d5a87b3e2f 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1575,26 +1575,6 @@ void __bio_advance(struct bio *bio, unsigned bytes)
 }
 EXPORT_SYMBOL(__bio_advance);
 
-void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
-			struct bio *src, struct bvec_iter *src_iter)
-{
-	while (src_iter->bi_size && dst_iter->bi_size) {
-		struct bio_vec src_bv = bio_iter_iovec(src, *src_iter);
-		struct bio_vec dst_bv = bio_iter_iovec(dst, *dst_iter);
-		unsigned int bytes = min(src_bv.bv_len, dst_bv.bv_len);
-		void *src_buf = bvec_kmap_local(&src_bv);
-		void *dst_buf = bvec_kmap_local(&dst_bv);
-
-		memcpy(dst_buf, src_buf, bytes);
-
-		kunmap_local(dst_buf);
-		kunmap_local(src_buf);
-
-		bio_advance_iter_single(src, src_iter, bytes);
-		bio_advance_iter_single(dst, dst_iter, bytes);
-	}
-}
-EXPORT_SYMBOL(bio_copy_data_iter);
 
 /**
  * bio_copy_data - copy contents of data buffers from one bio to another
@@ -1609,7 +1589,21 @@ void bio_copy_data(struct bio *dst, struct bio *src)
 	struct bvec_iter src_iter = src->bi_iter;
 	struct bvec_iter dst_iter = dst->bi_iter;
 
-	bio_copy_data_iter(dst, &dst_iter, src, &src_iter);
+	while (src_iter.bi_size && dst_iter.bi_size) {
+		struct bio_vec src_bv = bio_iter_iovec(src, src_iter);
+		struct bio_vec dst_bv = bio_iter_iovec(dst, dst_iter);
+		unsigned int bytes = min(src_bv.bv_len, dst_bv.bv_len);
+		void *src_buf = bvec_kmap_local(&src_bv);
+		void *dst_buf = bvec_kmap_local(&dst_bv);
+
+		memcpy(dst_buf, src_buf, bytes);
+
+		kunmap_local(dst_buf);
+		kunmap_local(src_buf);
+
+		bio_advance_iter_single(src, &src_iter, bytes);
+		bio_advance_iter_single(dst, &dst_iter, bytes);
+	}
 }
 EXPORT_SYMBOL(bio_copy_data);
 
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 84643fc0fb08..85463981d0f5 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -478,8 +478,6 @@ extern void bio_check_pages_dirty(struct bio *bio);
 int bio_iov_iter_bounce(struct bio *bio, struct iov_iter *iter, size_t maxlen);
 void bio_iov_iter_unbounce(struct bio *bio, bool is_error, bool mark_dirty);
 
-extern void bio_copy_data_iter(struct bio *dst, struct bvec_iter *dst_iter,
-			       struct bio *src, struct bvec_iter *src_iter);
 extern void bio_copy_data(struct bio *dst, struct bio *src);
 extern void bio_free_pages(struct bio *bio);
 void zero_fill_bio(struct bio *bio);
-- 
2.53.0


^ permalink raw reply related

* [PATCH 3/5] block: unexport blk_io_schedule
From: Christoph Hellwig @ 2026-05-15  4:55 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block
In-Reply-To: <20260515045547.3790129-1-hch@lst.de>

Only used in built-in code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/blk-core.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index 17450058ea6d..d7de87e86994 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1270,7 +1270,6 @@ void blk_io_schedule(void)
 	else
 		io_schedule();
 }
-EXPORT_SYMBOL_GPL(blk_io_schedule);
 
 int __init blk_dev_init(void)
 {
-- 
2.53.0


^ permalink raw reply related

* [PATCH 4/5] block: unexport blk_status_to_str
From: Christoph Hellwig @ 2026-05-15  4:55 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block
In-Reply-To: <20260515045547.3790129-1-hch@lst.de>

Only used in core block code, so unexport and move the prototype to
blk.h.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/blk-core.c       | 1 -
 block/blk.h            | 2 ++
 include/linux/blkdev.h | 1 -
 3 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/block/blk-core.c b/block/blk-core.c
index d7de87e86994..22af5dec112b 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -197,7 +197,6 @@ const char *blk_status_to_str(blk_status_t status)
 		return "<null>";
 	return blk_errors[idx].name;
 }
-EXPORT_SYMBOL_GPL(blk_status_to_str);
 
 /**
  * blk_sync_queue - cancel any pending callbacks on a queue
diff --git a/block/blk.h b/block/blk.h
index b998a7761faf..bf1a80493ff1 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -49,6 +49,8 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
 					      gfp_t flags);
 void blk_free_flush_queue(struct blk_flush_queue *q);
 
+const char *blk_status_to_str(blk_status_t status);
+
 bool __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic);
 bool blk_queue_start_drain(struct request_queue *q);
 bool __blk_freeze_queue_start(struct request_queue *q,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 890128cdea1c..17270a28c66d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1040,7 +1040,6 @@ extern const char *blk_op_str(enum req_op op);
 
 int blk_status_to_errno(blk_status_t status);
 blk_status_t errno_to_blk_status(int errno);
-const char *blk_status_to_str(blk_status_t status);
 
 /* only poll the hardware once, don't continue until a completion was found */
 #define BLK_POLL_ONESHOT		(1 << 0)
-- 
2.53.0


^ permalink raw reply related

* [PATCH 5/5] block: unexport bio_{set,check}_pages_dirty
From: Christoph Hellwig @ 2026-05-15  4:55 UTC (permalink / raw)
  To: Jens Axboe; +Cc: linux-block
In-Reply-To: <20260515045547.3790129-1-hch@lst.de>

Only used in built-in code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 block/bio.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/block/bio.c b/block/bio.c
index 57d5a87b3e2f..2d880d1255fe 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1650,7 +1650,6 @@ void bio_set_pages_dirty(struct bio *bio)
 		folio_unlock(fi.folio);
 	}
 }
-EXPORT_SYMBOL_GPL(bio_set_pages_dirty);
 
 /*
  * bio_check_pages_dirty() will check that all the BIO's pages are still dirty.
@@ -1709,7 +1708,6 @@ void bio_check_pages_dirty(struct bio *bio)
 	spin_unlock_irqrestore(&bio_dirty_lock, flags);
 	schedule_work(&bio_dirty_work);
 }
-EXPORT_SYMBOL_GPL(bio_check_pages_dirty);
 
 static inline bool bio_remaining_done(struct bio *bio)
 {
-- 
2.53.0


^ permalink raw reply related

* [PATCH blktests] nbd/rc: redirect nbd-server stderr
From: Shin'ichiro Kawasaki @ 2026-05-15  5:30 UTC (permalink / raw)
  To: linux-block, nbd; +Cc: Shin'ichiro Kawasaki

Recent nbd commit da5e07c057ab ("Reimplement daemonize() without using
daemon()") changed how nbd-server daemonizes itself. After this commit,
nbd-server prints messages to stderr after daemonization. This caused
nbd test cases to fail due to unexpected stderr output.

nbd/001 (resize a connected nbd device)                      [failed]
    runtime  0.865s  ...  0.883s
    --- tests/nbd/001.out	2025-04-22 13:13:27.727873155 +0900
    +++ /home/shin/Blktests/blktests/results/nodev/nbd/001.out.bad	2026-05-15 11:44:46.269000000 +0900
    @@ -1,4 +1,5 @@
     Running nbd/001
    +Error: Session terminated by client
     Disk /dev/nbd0: 10.7GB
     nbd0 43:0 0 10G 0 disk
     Setting size to 1gib

The commit is in nbd version v3.27, which is included in Fedora 44.

To avoid the failures, redirect nbd-server stderr to .full files.

Link: https://github.com/NetworkBlockDevice/nbd/commit/da5e07c057ab
Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
---
 tests/nbd/rc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/tests/nbd/rc b/tests/nbd/rc
index e200ba6..6205c49 100644
--- a/tests/nbd/rc
+++ b/tests/nbd/rc
@@ -72,7 +72,7 @@ allowlist=true
 [export]
 exportname=${TMPDIR}/export
 EOF
-	nbd-server -p "${TMPDIR}/nbd.pid" -C "${TMPDIR}/nbd.conf"
+	nbd-server -p "${TMPDIR}/nbd.pid" -C "${TMPDIR}/nbd.conf" 2> "$FULL"
 
 	# Wait for nbd-server start listening the port
 	for ((i = 0; i < 100; i++)); do
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH] sched: flush plug in schedule_preempt_disabled() to prevent deadlock
From: Xiaosen @ 2026-05-15  6:18 UTC (permalink / raw)
  To: Ming Lei, Peter Zijlstra
  Cc: Tejun Heo, Jens Axboe, linux-block, linux-kernel, Ingo Molnar,
	Juri Lelli, Vincent Guittot, Michael Wu, Thomas Gleixner
In-Reply-To: <agQxg-pBzF8rp1Ii@fedora>

https://lore.kernel.org/lkml/20260427183848.698551-2-jstultz@google.com/
The above change can resolve the deadlock I reported before by setting
task's state to TASK_RUNNING before switching context.

There is the likely alternative fix below.
https://lore.kernel.org/lkml/20260512025635.2840817-1-jstultz@google.com/

Regards,
Xiaosen

On 5/13/2026 4:08 PM, Ming Lei wrote:
> On Wed, May 13, 2026 at 09:30:39AM +0200, Peter Zijlstra wrote:
>> On Wed, May 13, 2026 at 10:07:03AM +0800, Ming Lei wrote:
>>> On Tue, May 12, 2026 at 07:16:36AM -1000, Tejun Heo wrote:
>>>> Hello, Ming.
>>>>
>>>> On Tue, May 12, 2026 at 11:45:14PM +0800, Ming Lei wrote:
>>>>> On Tue, May 12, 2026 at 02:40:21PM +0200, Peter Zijlstra wrote:
>>>>>> On Tue, May 12, 2026 at 02:04:32PM +0200, Peter Zijlstra wrote:
>>>>>>> On Tue, May 12, 2026 at 04:59:39PM +0800, Ming Lei wrote:
>>>>>>>> On preemptible kernels, a deadlock can occur when a task with plugged IO
>>>>>>>> calls schedule_preempt_disabled():
>>>>>>>>
>>>>>>>>   schedule_preempt_disabled()
>>>>>>>>     sched_preempt_enable_no_resched()  // preemption now enabled
>>>>>>>>     schedule()                         // <-- preemption can happen here
>>>>>>>>       sched_submit_work()
>>>>>>>>         blk_flush_plug()
>>>>>>>>
>>>>>>>> After sched_preempt_enable_no_resched() re-enables preemption, the task
>>>>>>>> can be preempted (e.g., by a higher-priority RT task) before reaching
>>>>>>>> blk_flush_plug() in sched_submit_work(). Since the task's state is
>>>>>>>> already TASK_UNINTERRUPTIBLE (set by the mutex/rwsem slowpath caller),
>>>>>>>> requests in current->plug remain unflushed for an unbounded time.
>>>>>>>>
>>>>>>>> If another task depends on those plugged requests to make progress (e.g.,
>>>>>>>> to release a lock the sleeping task needs), a deadlock results:
>>>>>>>>
>>>>>>>>   - Task A (writeback worker): holds plugged IO, preempted before
>>>>>>>>     flushing, stuck on run queue behind higher-priority work
>>>>>>>>   - Task B: waiting for IO completion from Task A's plug, holds a lock
>>>>>>>>     that Task A needs to be woken up
>>>>
>>>> My memory is hazy around io_schedule but the above reads really weird to me.
>>>> A task, regardless of its current state stays on the runqueue when
>>>> preempted, so the condition is temporary. As soon as the preempted task can
>>>> get CPU, it should unwind the situation. That's not a deadlock. Is the
>>>> problem that there can be preemption-induced delay in flushing the plugs?
>>>
>>> IMO, preempting a `!TASK_RUNNING` task can be thought as effective sleep,
>>
>> No it cannot be. Preemption ignores task state.
> 
> Yeah, I get similar conclusion too with AI's assistance.
> 
> But both two reports show that the preempted task aren't switched back for
> long enough time, can you share any idea for Michael & Xiaosen to investigate
> further from scheduler side?
> 
> https://lore.kernel.org/linux-block/20260417082744.30124-1-michael@allwinnertech.com/
> 
> https://lore.kernel.org/linux-block/5660795d-87de-46f5-add4-7729a02225ef@oss.qualcomm.com/
> 
> 
> Thanks,
> Ming


^ permalink raw reply

* [PATCH] blk-cgroup: Fix UAF in blkcg_activate_policy() by using blkg_tryget()
From: Zizhi Wo @ 2026-05-15  6:15 UTC (permalink / raw)
  To: axboe, tj, josef, yukuai, linux-block
  Cc: cgroups, yangerkun, chengzhihao1, wozizhi

[BUG]
Our fuzz testing triggered a blkg use-after-free issue:

  BUG: KASAN: slab-use-after-free in percpu_ref_put_many.constprop.0+0xbe/0xe0
  Call Trace:
  ...
  blkcg_activate_policy+0x347/0xfa0
  bfq_create_group_hierarchy+0x5b/0x140
  bfq_init_queue+0xc1b/0x1470
  ? mutex_init_generic+0x9f/0x100
  ? elevator_alloc+0x166/0x2b0
  blk_mq_init_sched+0x2b0/0x730
  elevator_switch+0x188/0x450
  elevator_change+0x290/0x470
  elv_iosched_store+0x30a/0x3a0
  ...

[CAUSE]
process1						process2
cgroup_rmdir
...
  blkcg_destroy_blkgs
    spin_trylock(&q->queue_lock)
    blkg_destroy
      percpu_ref_kill(&blkg->refcnt)
      ...
        blkg_free
	  INIT_WORK(xxx, blkg_free_workfn)
	  schedule_work
    spin_unlock(&q->queue_lock)
====================================schedule_work
            blkg_free_workfn
							elevator_change
							...
							  bfq_create_group_hierarchy
							    blkcg_activate_policy
							      spin_lock_irq(&q->queue_lock)
							      blkg_get		// get dead ref !!
							      pinned_blkg = blkg
							      spin_unlock_irq(&q->queue_lock)
	      spin_lock_irq(&q->queue_lock)
	      list_del_init(&blkg->q_node)
	      spin_unlock_irq(&q->queue_lock)
	      kfree(blkg)
							      blkg_put(pinned_blkg)	// UAF !!

A blkg killed by blkg_destroy() stays on q->blkg_list until
blkg_free_workfn() grabs queue_lock and unlinks it. blkg_get() on a dead
percpu_ref does not resurrect the blkg, so the later blkg_put() hits freed
memory and triggers this issue.

[Fix]
Replace blkg_get() with blkg_tryget(), which fails on a dead ref and lets
the loop skip dying blkgs.

Also hoist the ref acquisition to the top of the loop so dying blkgs are
filtered out before a pd is allocated and attached. Otherwise a pd attached
to an already-destroyed blkg would never called pd_offline_fn().

Fixes: 9d179b865449 ("blkcg: Fix multiple bugs in blkcg_activate_policy()")
Signed-off-by: Zizhi Wo <wozizhi@huaweicloud.com>
---
 block/blk-cgroup.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 554c87bb4a86..03b6ce934848 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -1621,6 +1621,10 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
 		if (blkg->pd[pol->plid])
 			continue;
 
+		/* a destroyed blkg may still be on q->blkg_list; skip it via tryget */
+		if (!blkg_tryget(blkg))
+			continue;
+
 		/* If prealloc matches, use it; otherwise try GFP_NOWAIT */
 		if (blkg == pinned_blkg) {
 			pd = pd_prealloc;
@@ -1637,7 +1641,6 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
 			 */
 			if (pinned_blkg)
 				blkg_put(pinned_blkg);
-			blkg_get(blkg);
 			pinned_blkg = blkg;
 
 			spin_unlock_irq(&q->queue_lock);
@@ -1666,6 +1669,8 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
 		pd->online = true;
 
 		spin_unlock(&blkg->blkcg->lock);
+
+		blkg_put(blkg);
 	}
 
 	__set_bit(pol->plid, q->blkcg_pols);
-- 
2.52.0


^ permalink raw reply related

* Re: [PATCH blktests v3] nvme/068: add a test for multipath delayed removal
From: Shin'ichiro Kawasaki @ 2026-05-15  6:38 UTC (permalink / raw)
  To: John Garry; +Cc: linux-block, linux-nvme, nilay, dwagner, Chaitanya Kulkarni
In-Reply-To: <20260430084635.2438048-1-john.g.garry@oracle.com>

On Apr 30, 2026 / 08:46, John Garry wrote:
> For NVMe multipath, the delayed removal feature allows the multipath
> gendisk to remain present when all available paths are gone. The purpose of
> this feature is to ensure that we keep the gendisk for intermittent path
> failures.
> 
> The delayed removal works on a timer - when all paths are gone, a timer is
> kicked off; once the timer expires and no paths have returned, the gendisk
> is removed.
> 
> When all paths are gone and the gendisk is still present, all reads and
> writes to the disk are queued. If a path returns before the timer
> expiration, the timer canceled and the queued IO is submitted;
> otherwise they fail when the timer expires.
> 
> This testcase covers two scenarios in separate parts:
> a. test that IOs submitted after all paths are removed (and do not return)
>    fail
> b. test that IOs submitted between all paths removed and a path
>    returning succeed
> 
> During the period of the timer being active, it must be ensured that the
> nvme-core module is not removed. Otherwise the driver may not be present
> to handle the timeout expiry. The kernel ensures this by taking a
> reference to the module. Ideally, we would try to remove the module during
> this test to prove that this is not possible (and the kernel behaves as
> expected), but that module will probably not be removable anyway due to
> many references. To test this feature, check that the refcount of the
> nvme-core module is incremented when the delayed timer is active.
> 
> Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
> Reviewed-by: Nilay Shroff <nilay@linux.ibm.com>
> Signed-off-by: John Garry <john.g.garry@oracle.com>

I applied this patch. Thanks!

^ permalink raw reply

* Re: [PATCH] blk-cgroup: Fix UAF in blkcg_activate_policy() by using blkg_tryget()
From: Zizhi Wo @ 2026-05-15 10:16 UTC (permalink / raw)
  To: Zizhi Wo, axboe, tj, josef, yukuai, linux-block
  Cc: cgroups, yangerkun, chengzhihao1
In-Reply-To: <20260515061516.3461291-1-wozizhi@huaweicloud.com>


I just realized that the fix has already been included in this patchset:

https://lore.kernel.org/all/20260304073809.3438679-5-yukuai@fnnas.com/

Please disregard this patch.

在 2026/5/15 14:15, Zizhi Wo 写道:
> [BUG]
> Our fuzz testing triggered a blkg use-after-free issue:
> 
>    BUG: KASAN: slab-use-after-free in percpu_ref_put_many.constprop.0+0xbe/0xe0
>    Call Trace:
>    ...
>    blkcg_activate_policy+0x347/0xfa0
>    bfq_create_group_hierarchy+0x5b/0x140
>    bfq_init_queue+0xc1b/0x1470
>    ? mutex_init_generic+0x9f/0x100
>    ? elevator_alloc+0x166/0x2b0
>    blk_mq_init_sched+0x2b0/0x730
>    elevator_switch+0x188/0x450
>    elevator_change+0x290/0x470
>    elv_iosched_store+0x30a/0x3a0
>    ...
> 
> [CAUSE]
> process1						process2
> cgroup_rmdir
> ...
>    blkcg_destroy_blkgs
>      spin_trylock(&q->queue_lock)
>      blkg_destroy
>        percpu_ref_kill(&blkg->refcnt)
>        ...
>          blkg_free
> 	  INIT_WORK(xxx, blkg_free_workfn)
> 	  schedule_work
>      spin_unlock(&q->queue_lock)
> ====================================schedule_work
>              blkg_free_workfn
> 							elevator_change
> 							...
> 							  bfq_create_group_hierarchy
> 							    blkcg_activate_policy
> 							      spin_lock_irq(&q->queue_lock)
> 							      blkg_get		// get dead ref !!
> 							      pinned_blkg = blkg
> 							      spin_unlock_irq(&q->queue_lock)
> 	      spin_lock_irq(&q->queue_lock)
> 	      list_del_init(&blkg->q_node)
> 	      spin_unlock_irq(&q->queue_lock)
> 	      kfree(blkg)
> 							      blkg_put(pinned_blkg)	// UAF !!
> 
> A blkg killed by blkg_destroy() stays on q->blkg_list until
> blkg_free_workfn() grabs queue_lock and unlinks it. blkg_get() on a dead
> percpu_ref does not resurrect the blkg, so the later blkg_put() hits freed
> memory and triggers this issue.
> 
> [Fix]
> Replace blkg_get() with blkg_tryget(), which fails on a dead ref and lets
> the loop skip dying blkgs.
> 
> Also hoist the ref acquisition to the top of the loop so dying blkgs are
> filtered out before a pd is allocated and attached. Otherwise a pd attached
> to an already-destroyed blkg would never called pd_offline_fn().
> 
> Fixes: 9d179b865449 ("blkcg: Fix multiple bugs in blkcg_activate_policy()")
> Signed-off-by: Zizhi Wo <wozizhi@huaweicloud.com>
> ---
>   block/blk-cgroup.c | 7 ++++++-
>   1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
> index 554c87bb4a86..03b6ce934848 100644
> --- a/block/blk-cgroup.c
> +++ b/block/blk-cgroup.c
> @@ -1621,6 +1621,10 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
>   		if (blkg->pd[pol->plid])
>   			continue;
>   
> +		/* a destroyed blkg may still be on q->blkg_list; skip it via tryget */
> +		if (!blkg_tryget(blkg))
> +			continue;
> +
>   		/* If prealloc matches, use it; otherwise try GFP_NOWAIT */
>   		if (blkg == pinned_blkg) {
>   			pd = pd_prealloc;
> @@ -1637,7 +1641,6 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
>   			 */
>   			if (pinned_blkg)
>   				blkg_put(pinned_blkg);
> -			blkg_get(blkg);
>   			pinned_blkg = blkg;
>   
>   			spin_unlock_irq(&q->queue_lock);
> @@ -1666,6 +1669,8 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
>   		pd->online = true;
>   
>   		spin_unlock(&blkg->blkcg->lock);
> +
> +		blkg_put(blkg);
>   	}
>   
>   	__set_bit(pol->plid, q->blkcg_pols);


^ permalink raw reply

* Re: improve the swap_activate interface
From: Christoph Hellwig @ 2026-05-15 11:33 UTC (permalink / raw)
  To: Steve French
  Cc: Christoph Hellwig, Andrew Morton, Chris Li, Kairui Song,
	Christian Brauner, Darrick J . Wong, Jens Axboe, David Sterba,
	Theodore Ts'o, Jaegeuk Kim, Chao Yu, Trond Myklebust,
	Anna Schumaker, Namjae Jeon, Hyunchul Lee, Steve French,
	Paulo Alcantara, Carlos Maiolino, Damien Le Moal, Naohiro Aota,
	linux-xfs, linux-fsdevel, linux-doc, linux-mm, linux-block,
	linux-btrfs, linux-ext4, linux-f2fs-devel, linux-nfs, linux-cifs
In-Reply-To: <CAH2r5msnYVb3hhXHwqDVHGGC1h4E6mLCRS4ktCrQoD9zdUW81g@mail.gmail.com>

On Wed, May 13, 2026 at 03:34:03PM -0500, Steve French wrote:
> I just tried this on 7.1-rc3 with the swap patches (full kernel build,
> on Ubuntu 25,10) and boot failed with out of memory which I had never
> seen before.  Any idea how to workaround this with the swap patch
> series, or is there a fix for this in the swap series already?

Is that a failure with the patches or also with the baseline?


^ permalink raw reply

* Re: [PATCH 0/1] drbd: fix false positive resync throttling (in-tree 8.4)
From: Ionut Nechita (Wind River) @ 2026-05-15 12:30 UTC (permalink / raw)
  To: drbd-dev, linux-block
  Cc: Philipp Reisner, Christoph Boehmwalder, Lars Ellenberg,
	Jens Axboe, linux-kernel, Ionut Nechita
In-Reply-To: <20260513163905.562722-1-ionut.nechita@windriver.com>

From: Ionut Nechita <ionut.nechita@windriver.com>

Hi Philipp, Christoph,

Friendly ping on this patch. We are planning to integrate it into our
next release and our engineering team asked whether you could provide
a brief risk assessment or a Reviewed-by tag for the in-tree 8.4
backport.

To summarize the risk profile from our side:

- The change is confined to drbd_rs_c_min_rate_throttle() — only the
  throttle decision, no data path or replication protocol changes.
- Worst-case failure mode (ap_bio_cnt not reflecting reality) is
  equivalent to c-min-rate=0, which is already a supported config.
- The approach is identical to what drbd 9.x already uses.

Could you confirm the patch is correct as-is, or provide a Reviewed-by
/ Acked-by if you're comfortable with it?  If there are any concerns
or suggested changes, happy to spin a v3.

Thanks,
Ionut

^ permalink raw reply

* Re: [PATCH] block: bio-integrity: fix memory leak in bio_integrity_map_user()
From: Christoph Hellwig @ 2026-05-15 13:13 UTC (permalink / raw)
  To: Dmitry Antipov
  Cc: Jens Axboe, Weidong Zhu, Chao Shi, Sungwoo Kim, Dave Tian,
	Keith Busch, Caleb Sander Mateos, Christoph Hellwig, linux-block,
	lvc-project, Kanchan Joshi, Anuj Gupta
In-Reply-To: <20260513070515.528861-1-dmantipov@yandex.ru>

On Wed, May 13, 2026 at 10:05:15AM +0300, Dmitry Antipov wrote:
> Since 'iov_iter_extract_pages()' may allocate new array of pages
> even when it returns non-zero error value, matching cleanup with
> 'vfree()' should be performed on all return paths afterwards. So
> adjust 'bio_integrity_map_user()' to ensure that both 'pages' and
> 'bvec' arrays are always freed on return.
> 
> Fixes: 8582792cf23b ("block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user()")
> Fixes: 492c5d455969 ("block: bio-integrity: directly map user buffers")
> Signed-off-by: Dmitry Antipov <dmantipov@yandex.ru>

The change looks fine:

Reviewed-by: Christoph Hellwig <hch@lst.de>

We'd still be much better off converting it to iov_iter_extract_bvecs
to share common code, and make it more efficient by no needing the
separate pages allocation.

> ---
>  block/bio-integrity.c | 21 ++++++---------------
>  1 file changed, 6 insertions(+), 15 deletions(-)
> 
> diff --git a/block/bio-integrity.c b/block/bio-integrity.c
> index e796de1a749e..53fb04adb09b 100644
> --- a/block/bio-integrity.c
> +++ b/block/bio-integrity.c
> @@ -400,7 +400,7 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter)
>  	ret = iov_iter_extract_pages(iter, &pages, bytes, nr_vecs,
>  					extraction_flags, &offset);
>  	if (unlikely(ret < 0))
> -		goto free_bvec;
> +		goto out_free;
>  
>  	/*
>  	 * Handle partial pinning. This can happen when pin_user_pages_fast()
> @@ -414,16 +414,12 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter)
>  			for (i = 0; i < npinned; i++)
>  				unpin_user_page(pages[i]);
>  		}
> -		if (pages != stack_pages)
> -			kvfree(pages);
>  		ret = -EFAULT;
> -		goto free_bvec;
> +		goto out_free;
>  	}
>  
>  	nr_bvecs = bvec_from_pages(bvec, pages, nr_vecs, bytes, offset,
>  				   &is_p2p);
> -	if (pages != stack_pages)
> -		kvfree(pages);
>  	if (nr_bvecs > queue_max_integrity_segments(q))
>  		copy = true;
>  	if (is_p2p)
> @@ -434,15 +430,10 @@ int bio_integrity_map_user(struct bio *bio, struct iov_iter *iter)
>  	else
>  		ret = bio_integrity_init_user(bio, bvec, nr_bvecs, bytes);
>  	if (ret)
> -		goto release_pages;
> -	if (bvec != stack_vec)
> -		kfree(bvec);
> -
> -	return 0;
> -
> -release_pages:
> -	bio_integrity_unpin_bvec(bvec, nr_bvecs);
> -free_bvec:
> +		bio_integrity_unpin_bvec(bvec, nr_bvecs);
> +out_free:
> +	if (pages != stack_pages)
> +		kvfree(pages);
>  	if (bvec != stack_vec)
>  		kfree(bvec);
>  	return ret;
> -- 
> 2.54.0
---end quoted text---

^ permalink raw reply

* [GIT PULL] Block fixes for 7.1-rc4
From: Jens Axboe @ 2026-05-15 14:20 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linux-block@vger.kernel.org

Hi Linus,

Set of fixes for the block area, which should go into the 7.1 kernel
release. This pull request contains:

- NVMe merge request via Keith
	- Fix memory leak on a passthrough integrity mapping failure
	  (Keith)
	- Hide secrets behind debug option (Hannes)
	- Fix pci use-after-free for host memory buffer (Chia-Lin Kao)
	- Fix tcp taregt use-after-free for data digest  (Sagi)
	- Revert a mistaken quirk (Alan Cui)
	- Fix uevent and controller state race condition (Maurizio)
	- Fix apple submission queue re-initialization (Nick Chan)

- Three fixes for blk-integrity, fixing an issue with the user data
  mapping and two problems with recomputing number of segments.

- Two fixes for the iov_iter bounce buffering.

- Fix for the handling of dead zoned write plugs.

- ublk max_sectors validation fix, with associated selftest addition.

Please pull!


The following changes since commit f7700a4415afb3ac1767a556094e4ef8bd440e41:

  ublk: fix use-after-free in ublk_cancel_cmd() (2026-05-08 06:44:42 -0600)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git tags/block-7.1-20260515

for you to fetch changes up to 4141f46daa4cf1f8caa14129f8b6db86f17452f5:

  Merge tag 'nvme-7.1-2026-05-14' of git://git.infradead.org/nvme into block-7.1 (2026-05-14 19:14:33 -0600)

----------------------------------------------------------------
block-7.1-20260515

----------------------------------------------------------------
AlanCui4080 (1):
      Revert "nvme: add quirk NVME_QUIRK_IGNORE_DEV_SUBNQN for 144d:a808"

Casey Chen (1):
      block: recompute nr_integrity_segments in blk_insert_cloned_request

Chia-Lin Kao (AceLan) (1):
      nvme-pci: fix use-after-free in nvme_free_host_mem()

Christoph Hellwig (2):
      block: pass a minsize argument to bio_iov_iter_bounce
      block: align down bounces bios

Damien Le Moal (1):
      block: fix handling of dead zone write plugs

David Carlier (1):
      block: don't overwrite bip_vcnt in bio_integrity_copy_user()

Hannes Reinecke (1):
      nvmet-auth: Do not print DH-HMAC-CHAP secrets

Jens Axboe (1):
      Merge tag 'nvme-7.1-2026-05-14' of git://git.infradead.org/nvme into block-7.1

Keith Busch (2):
      nvme: make prp passthrough usage less scary
      nvme: fix bio leak on mapping failure

Maurizio Lombardi (1):
      nvme: fix race condition between connected uevent and STARTED_ONCE flag

Ming Lei (2):
      ublk: reject max_sectors smaller than PAGE_SECTORS in parameter validation
      selftests: ublk: cap nthreads to kernel's actual nr_hw_queues

Nick Chan (1):
      nvme-apple: Reset q->sq_tail during queue init

Sagi Grimberg (1):
      nvmet-tcp: Fix potential UAF when ddgst mismatch

Sungwoo Kim (1):
      block: bio-integrity: Fix null-ptr-deref in bio_integrity_map_user()

 block/bio-integrity.c                | 19 ++++++++++++++++++-
 block/bio.c                          | 27 +++++++++++++++------------
 block/blk-mq.c                       | 19 +++++++++++++++++++
 block/blk-zoned.c                    | 32 +++++++++++++++++++++++++++-----
 drivers/block/ublk_drv.c             |  3 +++
 drivers/nvme/host/apple.c            |  1 +
 drivers/nvme/host/core.c             |  6 +++++-
 drivers/nvme/host/ioctl.c            | 18 ++++--------------
 drivers/nvme/host/pci.c              |  8 ++++----
 drivers/nvme/target/Kconfig          |  9 +++++++++
 drivers/nvme/target/auth.c           | 13 ++++++++-----
 drivers/nvme/target/tcp.c            |  4 +++-
 fs/iomap/direct-io.c                 |  2 +-
 include/linux/bio.h                  |  3 ++-
 tools/testing/selftests/ublk/kublk.c | 11 +++++++++++
 15 files changed, 130 insertions(+), 45 deletions(-)

-- 
Jens Axboe


^ permalink raw reply

* [REGRESSION] block: virtio-blk + LVM raid1 spurious sector-0 read failures on libaio/threads submit since 5ff3f74e145a ("block: simplify direct io validity check")
From: Vjaceslavs Klimovs @ 2026-05-15 16:52 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Keith Busch, Hannes Reinecke, Martin K. Petersen,
	Christoph Hellwig, linux-block, linux-raid, dm-devel,
	linux-kernel, regressions

Summary
-------
On v6.18, starting a libvirt/QEMU guest with virtio-blk backed by an
LVM "--type raid1" LV (drivers/md/dm-raid.c stacked on
drivers/md/raid1.c) makes md/raid1 register read failures at LV
sector 0 within seconds of "virsh start" and mark rimage_0 Faulty
once max_corrected_read_errors (default 20) is exceeded. Reads
succeed via the redirect path so guests boot, but every guest disk
ends up degraded on every VM start. Same workload on legacy
"--type mirror" (drivers/md/dm-raid1.c) crashes the host: a
zero-length READ reaches the NVMe controller, is rejected with
"Invalid Field in Command", and the dm-mirror recovery path oopses.

Symptom on dm-raid raid1 (post --type raid1)
--------------------------------------------
Per LV, at virsh start, in host dmesg:

  kernel: raid1_end_read_request: 95 callbacks suppressed
  kernel: raid1_read_request: 95 callbacks suppressed
  kernel: md/raid1:mdX: dm-58: rescheduling sector 0
  kernel: md/raid1:mdX: redirecting sector 0 to other mirror: dm-58
  kernel: md/raid1:mdX: dm-58: rescheduling sector 0
  kernel: md/raid1:mdX: redirecting sector 0 to other mirror: dm-58
  [... 10 rescheduling/redirecting pairs ...]
  kernel: md/raid1:mdX: dm-58: Raid device exceeded read_error
threshold [cur 21:max 20]
  kernel: md/raid1:mdX: dm-58: Failing raid device
  kernel: md/raid1:mdX: Disk failure on dm-58, disabling device.
  kernel: md/raid1:mdX: Operation continuing on 1 devices.

  dmeventd: WARNING: Device #0 of raid1 array, vg0-iris_boot, has failed.
  dmeventd: WARNING: Waiting for resynchronization to finish before
initiating repair on RAID device vg0-iris_boot.
  dmeventd: Use 'lvconvert --repair vg0/iris_boot' to replace failed device.

Subsequent "lvs -a":

  WARNING: RaidLV vg0/iris_boot needs to be refreshed!
  See character 'r' at position 9 in the RaidLV's attributes and its SubLV(s).

dmesg | grep nvme is EMPTY on this path. The NVMe driver is not
involved in producing the error; the failure originates between the
virtio-blk bio submission and raid1_end_read_request().

Symptom on legacy dm-mirror (pre-conversion --type mirror)
----------------------------------------------------------
Same workload on drivers/md/dm-raid1.c reaches the NVMe controller
as a zero-length READ and panics the host through dm-mirror's
recovery path:

  kernel: operation not supported error, dev nvme1n1, sector 935446535
op 0x0:(READ) flags 0x0 phys_seg 0 prio class 2
  kernel: nvme1n1: I/O Cmd(0x2) @ LBA 935446535, 0 blocks, I/O Error
(sct 0x0 / sc 0x2)
  [... 10+ identical bursts at same timestamp ...]
  dmeventd: Primary mirror device 252:58 read failed.
  dmeventd: vg0-iris_boot is now in-sync.
  [kernel oops in dm_mirror recovery path, full trace lost to console flash]

The "phys_seg 0", "0 blocks", "sct 0x0/sc 0x2" trio (NVMe Generic,
Invalid Field in Command, NVMe spec 4.1.1.2) is unambiguous: a bio
with bi_iter.bi_size == 0 and bi_vcnt == 0 left the block layer and
hit the controller. dm-raid raid1 hides this by retrying on the
surviving leg, but the upstream-of-md trigger is identical.

Bisect
------
git bisect, v6.12..v6.18, 16 deterministic GOOD/BAD steps, no skips,
~104 minutes:

  5ff3f74e145adc79b49668adb8de276446acf6be is the first bad commit
  block: simplify direct io validity check

  --- a/block/fops.c
  +++ b/block/fops.c
  @@ -38,8 +38,8 @@ static blk_opf_t dio_bio_write_op(struct kiocb *iocb)
   static bool blkdev_dio_invalid(struct block_device *bdev, struct kiocb *iocb,
                                  struct iov_iter *iter)
   {
  -        return iocb->ki_pos & (bdev_logical_block_size(bdev) - 1) ||
  -                !bdev_iter_is_aligned(bdev, iter);
  +        return (iocb->ki_pos | iov_iter_count(iter)) &
  +                        (bdev_logical_block_size(bdev) - 1);
   }

The dropped bdev_iter_is_aligned() used to walk the iov_iter and
reject per-segment misaligned/degenerate vectors at the blkdev fops
entry point. The replacement only validates ki_pos and total length
against the logical block size. Cases that now pass that no longer
get rejected:

  - iter with iov_iter_count(iter) == 0  (degenerate; total length is
    "sector-aligned" since 0 % 512 == 0)
  - iter where total length is sector-aligned but a segment isn't

The commit message justifies the removal with "The block layer
checks all the segments for validity later". This is true for the
io_uring submit path (which enters __blkdev_direct_IO directly and
does its own validation) but not for the libaio aio_read/write_iter
or the worker-pool sync read/write_iter paths that enter via
blkdev_{read,write}_iter() -> blkdev_dio_invalid(). For those paths,
the segment check has no replacement.

Reproducing
----------------------------------------------------------

The trigger requires QEMU virtio-blk's specific submission shape AND
a non-io_uring submit. Userspace libaio alone, userspace
preadv-in-a-thread alone, and QEMU's raw-driver open probes (which
qemu-img info exercises identically) are all insufficient. The
combination that hits the bug is "guest-driven I/O through
virtio-blk-pci with cache.direct=on and aio in {native, threads}".

#regzbot introduced: 5ff3f74e145adc79b49668adb8de276446acf6be

Thanks,
Vjaceslavs Klimovs

^ permalink raw reply

* Re: [GIT PULL] Block fixes for 7.1-rc4
From: pr-tracker-bot @ 2026-05-15 20:10 UTC (permalink / raw)
  To: Jens Axboe; +Cc: Linus Torvalds, linux-block@vger.kernel.org
In-Reply-To: <093dc3c7-5030-4400-9b38-727c41c5f511@kernel.dk>

The pull request you sent on Fri, 15 May 2026 08:20:27 -0600:

> https://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux.git tags/block-7.1-20260515

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/d458a240344c4369bf6f3da203f2779515177738

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ 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