| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/07/22 13:29 | flow | patch-triage |
1mArgs:null Results: {
"EnableConfigs": [
"MD_RAID1",
"MD_RAID10",
"NVME_RDMA",
"PCI_P2PDMA"
],
"FocusSymbols": [
"narrow_write_error",
"handle_read_error",
"handle_write_finished",
"handle_write_completed",
"nvme_rdma_dma_map_req"
],
"Reasoning": "The patch introduces functional changes to handle P2PDMA (Peer-to-Peer DMA) bios and mapping errors in MD RAID1/10 and NVMe RDMA. It modifies how P2PDMA bios are merged, how their errors are handled (avoiding marking members as failed on mapping errors), and updates NVMe RDMA to use `ib_dma_map_sgtable_attrs` and return `BLK_STS_TARGET` on `-EREMOTEIO`. These changes affect reachable core kernel logic and drivers, making them worth fuzzing.",
"WorthFuzzing": true
} |
| 1/1 | 2026/07/22 13:29 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit cbc40740326845bae09f63c7b07201e65af56f66\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Wed Jul 22 13:29:21 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/block/blk-mq-dma.c b/block/blk-mq-dma.c\nindex bfdb9ed7074116..c17e4c49900c77 100644\n--- a/block/blk-mq-dma.c\n+++ b/block/blk-mq-dma.c\n@@ -190,7 +190,11 @@ static bool blk_dma_map_iter_start(struct request *req, struct device *dma_dev,\n \tcase PCI_P2PDMA_MAP_NONE:\n \t\tbreak;\n \tdefault:\n-\t\titer-\u003estatus = BLK_STS_INVAL;\n+\t\t/*\n+\t\t * Match dma_map_sgtable()'s -EREMOTEIO: this transfer\n+\t\t * can never succeed, so don't let it be retried.\n+\t\t */\n+\t\titer-\u003estatus = BLK_STS_TARGET;\n \t\treturn false;\n \t}\n \ndiff --git a/drivers/md/md.c b/drivers/md/md.c\nindex d1465bcd86c812..3770bdb4d4b28b 100644\n--- a/drivers/md/md.c\n+++ b/drivers/md/md.c\n@@ -451,8 +451,14 @@ static void md_submit_bio(struct bio *bio)\n \t\treturn;\n \t}\n \n-\t/* bio could be mergeable after passing to underlayer */\n-\tbio-\u003ebi_opf \u0026= ~REQ_NOMERGE;\n+\t/*\n+\t * A bio md split may merge again below md -- except P2PDMA bios,\n+\t * which must stay single-provider (see __bio_add_page()).\n+\t */\n+\tif (md_bio_is_p2pdma(bio))\n+\t\tbio-\u003ebi_opf |= REQ_NOMERGE;\n+\telse\n+\t\tbio-\u003ebi_opf \u0026= ~REQ_NOMERGE;\n \n \tmd_handle_request(mddev, bio);\n }\ndiff --git a/drivers/md/md.h b/drivers/md/md.h\nindex d8daf0f75cbbe8..73df1a6eccd850 100644\n--- a/drivers/md/md.h\n+++ b/drivers/md/md.h\n@@ -11,8 +11,10 @@\n #include \u003clinux/blkdev.h\u003e\n #include \u003clinux/backing-dev.h\u003e\n #include \u003clinux/badblocks.h\u003e\n+#include \u003clinux/bio.h\u003e\n #include \u003clinux/kobject.h\u003e\n #include \u003clinux/list.h\u003e\n+#include \u003clinux/memremap.h\u003e\n #include \u003clinux/mm.h\u003e\n #include \u003clinux/mutex.h\u003e\n #include \u003clinux/timer.h\u003e\n@@ -22,6 +24,19 @@\n #include \u003ctrace/events/block.h\u003e\n \n #define MaxSector (~(sector_t)0)\n+\n+/*\n+ * P2P and host pages never mix within a bio, so the first bvec is\n+ * representative. Read bi_io_vec directly: bio_first_bvec_all()\n+ * WARNs on the split clones md handles, and data-less bios have no\n+ * bi_io_vec. Not valid after the bio's iterator is consumed.\n+ */\n+static inline bool md_bio_is_p2pdma(struct bio *bio)\n+{\n+\treturn bio_has_data(bio) \u0026\u0026 bio-\u003ebi_io_vec \u0026\u0026\n+\t is_pci_p2pdma_page(bio-\u003ebi_io_vec-\u003ebv_page);\n+}\n+\n /*\n * Number of guaranteed raid bios in case of extreme VM load:\n */\ndiff --git a/drivers/md/raid1.c b/drivers/md/raid1.c\nindex afe2ca96ad8c22..6334032c4bb8ed 100644\n--- a/drivers/md/raid1.c\n+++ b/drivers/md/raid1.c\n@@ -483,16 +483,22 @@ static void raid1_end_write_request(struct bio *bio)\n \t * 'one mirror IO has finished' event handler:\n \t */\n \tif (bio-\u003ebi_status \u0026\u0026 !ignore_error) {\n-\t\tset_bit(WriteErrorSeen,\t\u0026rdev-\u003eflags);\n-\t\tif (!test_and_set_bit(WantReplacement, \u0026rdev-\u003eflags))\n-\t\t\tset_bit(MD_RECOVERY_NEEDED, \u0026\n-\t\t\t\tconf-\u003emddev-\u003erecovery);\n+\t\t/* Peer/member pairing failure, not member health. */\n+\t\tbool p2pdma_unmappable = bio-\u003ebi_status == BLK_STS_TARGET \u0026\u0026\n+\t\t\ttest_bit(R1BIO_P2PDMA, \u0026r1_bio-\u003estate);\n \n-\t\tif (test_bit(FailFast, \u0026rdev-\u003eflags) \u0026\u0026\n-\t\t (bio-\u003ebi_opf \u0026 MD_FAILFAST) \u0026\u0026\n-\t\t /* We never try FailFast to WriteMostly devices */\n-\t\t !test_bit(WriteMostly, \u0026rdev-\u003eflags)) {\n-\t\t\tmd_error(r1_bio-\u003emddev, rdev);\n+\t\tset_bit(WriteErrorSeen,\t\u0026rdev-\u003eflags);\n+\t\tif (!p2pdma_unmappable) {\n+\t\t\tif (!test_and_set_bit(WantReplacement, \u0026rdev-\u003eflags))\n+\t\t\t\tset_bit(MD_RECOVERY_NEEDED,\n+\t\t\t\t\t\u0026conf-\u003emddev-\u003erecovery);\n+\n+\t\t\tif (test_bit(FailFast, \u0026rdev-\u003eflags) \u0026\u0026\n+\t\t\t (bio-\u003ebi_opf \u0026 MD_FAILFAST) \u0026\u0026\n+\t\t\t /* We never try FailFast to WriteMostly devices */\n+\t\t\t !test_bit(WriteMostly, \u0026rdev-\u003eflags)) {\n+\t\t\t\tmd_error(r1_bio-\u003emddev, rdev);\n+\t\t\t}\n \t\t}\n \n \t\t/*\n@@ -564,7 +570,7 @@ static void raid1_end_write_request(struct bio *bio)\n \t\t\t\tcall_bio_endio(r1_bio);\n \t\t\t}\n \t\t}\n-\t} else if (test_bit(MD_SERIALIZE_POLICY, \u0026rdev-\u003emddev-\u003eflags))\n+\t} else if (test_bit(CollisionCheck, \u0026rdev-\u003eflags))\n \t\tremove_serial(rdev, lo, hi);\n \tif (r1_bio-\u003ebios[mirror] == NULL)\n \t\trdev_dec_pending(rdev, conf-\u003emddev);\n@@ -1378,6 +1384,8 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,\n \telse\n \t\tinit_r1bio(r1_bio, mddev, bio);\n \tr1_bio-\u003esectors = max_read_sectors;\n+\tif (md_bio_is_p2pdma(bio))\n+\t\tset_bit(R1BIO_P2PDMA, \u0026r1_bio-\u003estate);\n \n \t/*\n \t * make_request() can abort the operation when read-ahead is being\n@@ -1523,6 +1531,7 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,\n \tbool write_behind = false;\n \tbool nowait = bio-\u003ebi_opf \u0026 REQ_NOWAIT;\n \tbool is_discard = op_is_discard(bio-\u003ebi_opf);\n+\tbool is_p2pdma = md_bio_is_p2pdma(bio);\n \tsector_t sector = bio-\u003ebi_iter.bi_sector;\n \n \tif (mddev_is_clustered(mddev) \u0026\u0026\n@@ -1556,6 +1565,8 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,\n \n \tr1_bio = alloc_r1bio(mddev, bio);\n \tr1_bio-\u003esectors = max_sectors;\n+\tif (md_bio_is_p2pdma(bio))\n+\t\tset_bit(R1BIO_P2PDMA, \u0026r1_bio-\u003estate);\n \n \t/* first select target devices under rcu_lock and\n \t * inc refcount on their rdev. Record them by setting\n@@ -1575,9 +1586,12 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,\n \t\t/*\n \t\t * The write-behind io is only attempted on drives marked as\n \t\t * write-mostly, which means we could allocate write behind\n-\t\t * bio later.\n+\t\t * bio later. P2PDMA bios are excluded: write-behind copies\n+\t\t * the data with bio_copy_data(), a CPU copy that cannot be\n+\t\t * assumed safe or fast on P2PDMA (device BAR) pages.\n \t\t */\n-\t\tif (!is_discard \u0026\u0026 rdev \u0026\u0026 test_bit(WriteMostly, \u0026rdev-\u003eflags))\n+\t\tif (!is_discard \u0026\u0026 !is_p2pdma \u0026\u0026 rdev \u0026\u0026\n+\t\t test_bit(WriteMostly, \u0026rdev-\u003eflags))\n \t\t\twrite_behind = true;\n \n \t\tr1_bio-\u003ebios[i] = NULL;\n@@ -1677,7 +1691,11 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,\n \t\t\tmbio = bio_alloc_clone(rdev-\u003ebdev, bio, GFP_NOIO,\n \t\t\t\t\t \u0026mddev-\u003ebio_set);\n \n-\t\t\tif (test_bit(MD_SERIALIZE_POLICY, \u0026mddev-\u003eflags))\n+\t\t\t/*\n+\t\t\t * CollisionCheck marks every rdev with a serial\n+\t\t\t * tree; order against in-flight write-behind I/O.\n+\t\t\t */\n+\t\t\tif (test_bit(CollisionCheck, \u0026rdev-\u003eflags))\n \t\t\t\twait_for_serialization(rdev, r1_bio);\n \t\t}\n \n@@ -2514,7 +2532,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)\n \t}\n }\n \n-static void narrow_write_error(struct r1bio *r1_bio, int i)\n+static void narrow_write_error(struct r1bio *r1_bio, int i, bool coarse)\n {\n \tstruct mddev *mddev = r1_bio-\u003emddev;\n \tstruct r1conf *conf = mddev-\u003eprivate;\n@@ -2528,6 +2546,9 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)\n \t * It is conceivable that the bio doesn't exactly align with\n \t * blocks. We must handle this somehow.\n \t *\n+\t * With 'coarse', retry the whole range as one bio: P2PDMA\n+\t * mapping failures fail every block identically.\n+\t *\n \t * We currently own a reference on the rdev.\n \t */\n \n@@ -2542,9 +2563,12 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)\n \t\tblock_sectors = roundup(1 \u003c\u003c rdev-\u003ebadblocks.shift, lbs);\n \n \tsector = r1_bio-\u003esector;\n-\tsectors = ((sector + block_sectors)\n-\t\t \u0026 ~(sector_t)(block_sectors - 1))\n-\t\t- sector;\n+\tif (coarse)\n+\t\tsectors = sect_to_write;\n+\telse\n+\t\tsectors = ((sector + block_sectors)\n+\t\t\t \u0026 ~(sector_t)(block_sectors - 1))\n+\t\t\t- sector;\n \n \twhile (sect_to_write) {\n \t\tstruct bio *wbio;\n@@ -2562,6 +2586,9 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)\n \t\t}\n \n \t\twbio-\u003ebi_opf = REQ_OP_WRITE;\n+\t\t/* Keep P2PDMA retry bios unmergeable, like the original */\n+\t\tif (md_bio_is_p2pdma(wbio))\n+\t\t\twbio-\u003ebi_opf |= REQ_NOMERGE;\n \t\twbio-\u003ebi_iter.bi_sector = r1_bio-\u003esector;\n \t\twbio-\u003ebi_iter.bi_size = r1_bio-\u003esectors \u003c\u003c 9;\n \n@@ -2622,8 +2649,12 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)\n \t\t\t * narrow down and record precise write\n \t\t\t * errors.\n \t\t\t */\n+\t\t\tbool coarse = r1_bio-\u003ebios[m]-\u003ebi_status ==\n+\t\t\t\t\tBLK_STS_TARGET \u0026\u0026\n+\t\t\t\ttest_bit(R1BIO_P2PDMA, \u0026r1_bio-\u003estate);\n+\n \t\t\tfail = true;\n-\t\t\tnarrow_write_error(r1_bio, m);\n+\t\t\tnarrow_write_error(r1_bio, m, coarse);\n \t\t\trdev_dec_pending(conf-\u003emirrors[m].rdev,\n \t\t\t\t\t conf-\u003emddev);\n \t\t}\n@@ -2650,6 +2681,9 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)\n {\n \tstruct md_rdev *rdev = conf-\u003emirrors[r1_bio-\u003eread_disk].rdev;\n \tstruct bio *bio = r1_bio-\u003ebios[r1_bio-\u003eread_disk];\n+\t/* evaluate before the bio_put() below */\n+\tbool p2pdma_error = bio-\u003ebi_status == BLK_STS_TARGET \u0026\u0026\n+\t\ttest_bit(R1BIO_P2PDMA, \u0026r1_bio-\u003estate);\n \tstruct mddev *mddev = conf-\u003emddev;\n \tsector_t sector;\n \n@@ -2669,6 +2703,9 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)\n \t */\n \tif (mddev-\u003ero) {\n \t\tr1_bio-\u003ebios[r1_bio-\u003eread_disk] = IO_BLOCKED;\n+\t} else if (p2pdma_error) {\n+\t\t/* Peer can't reach this member: just redirect the read. */\n+\t\tr1_bio-\u003ebios[r1_bio-\u003eread_disk] = IO_BLOCKED;\n \t} else if (test_bit(FailFast, \u0026rdev-\u003eflags)) {\n \t\tmd_error(mddev, rdev);\n \t} else {\ndiff --git a/drivers/md/raid1.h b/drivers/md/raid1.h\nindex c98d43a7ae993f..61b788a99d1431 100644\n--- a/drivers/md/raid1.h\n+++ b/drivers/md/raid1.h\n@@ -184,6 +184,8 @@ enum r1bio_state {\n \tR1BIO_MadeGood,\n \tR1BIO_WriteError,\n \tR1BIO_FailFast,\n+/* the master bio carries PCI P2PDMA (peer device memory) pages */\n+\tR1BIO_P2PDMA,\n };\n \n static inline int sector_to_idx(sector_t sector)\ndiff --git a/drivers/md/raid10.c b/drivers/md/raid10.c\nindex 0a3cfdd3f5df80..4c3da50250a5a2 100644\n--- a/drivers/md/raid10.c\n+++ b/drivers/md/raid10.c\n@@ -482,15 +482,23 @@ static void raid10_end_write_request(struct bio *bio)\n \t\t\t */\n \t\t\tmd_error(rdev-\u003emddev, rdev);\n \t\telse {\n-\t\t\tset_bit(WriteErrorSeen,\t\u0026rdev-\u003eflags);\n-\t\t\tif (!test_and_set_bit(WantReplacement, \u0026rdev-\u003eflags))\n-\t\t\t\tset_bit(MD_RECOVERY_NEEDED,\n-\t\t\t\t\t\u0026rdev-\u003emddev-\u003erecovery);\n+\t\t\t/* Peer/member pairing failure, not member health. */\n+\t\t\tbool p2pdma_unmappable =\n+\t\t\t\tbio-\u003ebi_status == BLK_STS_TARGET \u0026\u0026\n+\t\t\t\ttest_bit(R10BIO_P2PDMA, \u0026r10_bio-\u003estate);\n \n+\t\t\tset_bit(WriteErrorSeen,\t\u0026rdev-\u003eflags);\n \t\t\tdec_rdev = 0;\n-\t\t\tif (test_bit(FailFast, \u0026rdev-\u003eflags) \u0026\u0026\n-\t\t\t (bio-\u003ebi_opf \u0026 MD_FAILFAST)) {\n-\t\t\t\tmd_error(rdev-\u003emddev, rdev);\n+\t\t\tif (!p2pdma_unmappable) {\n+\t\t\t\tif (!test_and_set_bit(WantReplacement,\n+\t\t\t\t\t\t \u0026rdev-\u003eflags))\n+\t\t\t\t\tset_bit(MD_RECOVERY_NEEDED,\n+\t\t\t\t\t\t\u0026rdev-\u003emddev-\u003erecovery);\n+\n+\t\t\t\tif (test_bit(FailFast, \u0026rdev-\u003eflags) \u0026\u0026\n+\t\t\t\t (bio-\u003ebi_opf \u0026 MD_FAILFAST)) {\n+\t\t\t\t\tmd_error(rdev-\u003emddev, rdev);\n+\t\t\t\t}\n \t\t\t}\n \n \t\t\t/*\n@@ -1170,6 +1178,9 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,\n \t */\n \tgfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;\n \n+\tif (md_bio_is_p2pdma(bio))\n+\t\tset_bit(R10BIO_P2PDMA, \u0026r10_bio-\u003estate);\n+\n \tif (slot \u003e= 0 \u0026\u0026 r10_bio-\u003edevs[slot].rdev) {\n \t\t/*\n \t\t * This is an error retry, but we cannot\n@@ -1357,6 +1368,9 @@ static bool raid10_write_request(struct mddev *mddev, struct bio *bio,\n \tsector_t sectors;\n \tint max_sectors;\n \n+\tif (md_bio_is_p2pdma(bio))\n+\t\tset_bit(R10BIO_P2PDMA, \u0026r10_bio-\u003estate);\n+\n \tif ((mddev_is_clustered(mddev) \u0026\u0026\n \t mddev-\u003ecluster_ops-\u003earea_resyncing(mddev, WRITE,\n \t\t\t\t\t\tbio-\u003ebi_iter.bi_sector,\n@@ -2786,7 +2800,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10\n \t}\n }\n \n-static void narrow_write_error(struct r10bio *r10_bio, int i)\n+static void narrow_write_error(struct r10bio *r10_bio, int i, bool coarse)\n {\n \tstruct bio *bio = r10_bio-\u003emaster_bio;\n \tstruct mddev *mddev = r10_bio-\u003emddev;\n@@ -2800,6 +2814,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)\n \t * It is conceivable that the bio doesn't exactly align with\n \t * blocks. We must handle this.\n \t *\n+\t * With 'coarse', retry the whole range as one bio: P2PDMA\n+\t * mapping failures fail every block identically.\n+\t *\n \t * We currently own a reference to the rdev.\n \t */\n \n@@ -2814,9 +2831,12 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)\n \t\tblock_sectors = roundup(1 \u003c\u003c rdev-\u003ebadblocks.shift, lbs);\n \n \tsector = r10_bio-\u003esector;\n-\tsectors = ((r10_bio-\u003esector + block_sectors)\n-\t\t \u0026 ~(sector_t)(block_sectors - 1))\n-\t\t- sector;\n+\tif (coarse)\n+\t\tsectors = sect_to_write;\n+\telse\n+\t\tsectors = ((r10_bio-\u003esector + block_sectors)\n+\t\t\t \u0026 ~(sector_t)(block_sectors - 1))\n+\t\t\t- sector;\n \n \twhile (sect_to_write) {\n \t\tstruct bio *wbio;\n@@ -2831,6 +2851,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)\n \t\twbio-\u003ebi_iter.bi_sector = wsector +\n \t\t\t\t choose_data_offset(r10_bio, rdev);\n \t\twbio-\u003ebi_opf = REQ_OP_WRITE;\n+\t\t/* Keep P2PDMA retry bios unmergeable, like the original */\n+\t\tif (md_bio_is_p2pdma(wbio))\n+\t\t\twbio-\u003ebi_opf |= REQ_NOMERGE;\n \n \t\tif (submit_bio_wait(wbio) \u0026\u0026\n \t\t !rdev_set_badblocks(rdev, wsector, sectors, 0)) {\n@@ -2853,6 +2876,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)\n {\n \tint slot = r10_bio-\u003eread_slot;\n \tstruct bio *bio;\n+\tbool p2pdma_error;\n \tstruct r10conf *conf = mddev-\u003eprivate;\n \tstruct md_rdev *rdev = r10_bio-\u003edevs[slot].rdev;\n \n@@ -2865,17 +2889,24 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)\n \t * frozen.\n \t */\n \tbio = r10_bio-\u003edevs[slot].bio;\n+\t/* evaluate before the bio_put() below */\n+\tp2pdma_error = bio-\u003ebi_status == BLK_STS_TARGET \u0026\u0026\n+\t\ttest_bit(R10BIO_P2PDMA, \u0026r10_bio-\u003estate);\n \tbio_put(bio);\n \tr10_bio-\u003edevs[slot].bio = NULL;\n \n \tif (mddev-\u003ero)\n \t\tr10_bio-\u003edevs[slot].bio = IO_BLOCKED;\n-\telse if (!test_bit(FailFast, \u0026rdev-\u003eflags)) {\n+\telse if (p2pdma_error) {\n+\t\t/* Peer can't reach this member: just redirect the read. */\n+\t\tr10_bio-\u003edevs[slot].bio = IO_BLOCKED;\n+\t} else if (test_bit(FailFast, \u0026rdev-\u003eflags)) {\n+\t\tmd_error(mddev, rdev);\n+\t} else {\n \t\tfreeze_array(conf, 1);\n \t\tfix_read_error(conf, mddev, r10_bio);\n \t\tunfreeze_array(conf);\n-\t} else\n-\t\tmd_error(mddev, rdev);\n+\t}\n \n \trdev_dec_pending(rdev, mddev);\n \tr10_bio-\u003estate = 0;\n@@ -2944,8 +2975,13 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)\n \t\t\t\t\tr10_bio-\u003esectors, 0);\n \t\t\t\trdev_dec_pending(rdev, conf-\u003emddev);\n \t\t\t} else if (bio != NULL \u0026\u0026 bio-\u003ebi_status) {\n+\t\t\t\tbool coarse = bio-\u003ebi_status ==\n+\t\t\t\t\t\tBLK_STS_TARGET \u0026\u0026\n+\t\t\t\t\ttest_bit(R10BIO_P2PDMA,\n+\t\t\t\t\t\t \u0026r10_bio-\u003estate);\n+\n \t\t\t\tfail = true;\n-\t\t\t\tnarrow_write_error(r10_bio, m);\n+\t\t\t\tnarrow_write_error(r10_bio, m, coarse);\n \t\t\t\trdev_dec_pending(rdev, conf-\u003emddev);\n \t\t\t}\n \t\t\tbio = r10_bio-\u003edevs[m].repl_bio;\ndiff --git a/drivers/md/raid10.h b/drivers/md/raid10.h\nindex ec79d87fb92f6c..a2e1554f77dbeb 100644\n--- a/drivers/md/raid10.h\n+++ b/drivers/md/raid10.h\n@@ -174,6 +174,8 @@ enum r10bio_state {\n \tR10BIO_Previous,\n /* failfast devices did receive failfast requests. */\n \tR10BIO_FailFast,\n+/* the master bio carries PCI P2PDMA (peer device memory) pages */\n+\tR10BIO_P2PDMA,\n \tR10BIO_Discard,\n };\n #endif\ndiff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c\nindex 6909e354279427..f8edb23552ad24 100644\n--- a/drivers/nvme/host/rdma.c\n+++ b/drivers/nvme/host/rdma.c\n@@ -1469,6 +1469,7 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,\n \t\tint *count, int *pi_count)\n {\n \tstruct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);\n+\tstruct sg_table sgt;\n \tint ret;\n \n \treq-\u003edata_sgl.sg_table.sgl = (struct scatterlist *)(req + 1);\n@@ -1480,12 +1481,14 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,\n \n \treq-\u003edata_sgl.nents = blk_rq_map_sg(rq, req-\u003edata_sgl.sg_table.sgl);\n \n-\t*count = ib_dma_map_sg(ibdev, req-\u003edata_sgl.sg_table.sgl,\n-\t\t\t req-\u003edata_sgl.nents, rq_dma_dir(rq));\n-\tif (unlikely(*count \u003c= 0)) {\n-\t\tret = -EIO;\n+\tsgt = (struct sg_table) {\n+\t\t.sgl\t\t= req-\u003edata_sgl.sg_table.sgl,\n+\t\t.orig_nents\t= req-\u003edata_sgl.nents,\n+\t};\n+\tret = ib_dma_map_sgtable_attrs(ibdev, \u0026sgt, rq_dma_dir(rq), 0);\n+\tif (unlikely(ret))\n \t\tgoto out_free_table;\n-\t}\n+\t*count = sgt.nents;\n \n \tif (blk_integrity_rq(rq)) {\n \t\treq-\u003emetadata_sgl-\u003esg_table.sgl =\n@@ -1501,14 +1504,14 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,\n \n \t\treq-\u003emetadata_sgl-\u003enents = blk_rq_map_integrity_sg(rq,\n \t\t\t\treq-\u003emetadata_sgl-\u003esg_table.sgl);\n-\t\t*pi_count = ib_dma_map_sg(ibdev,\n-\t\t\t\t\t req-\u003emetadata_sgl-\u003esg_table.sgl,\n-\t\t\t\t\t req-\u003emetadata_sgl-\u003enents,\n-\t\t\t\t\t rq_dma_dir(rq));\n-\t\tif (unlikely(*pi_count \u003c= 0)) {\n-\t\t\tret = -EIO;\n+\t\tsgt = (struct sg_table) {\n+\t\t\t.sgl\t\t= req-\u003emetadata_sgl-\u003esg_table.sgl,\n+\t\t\t.orig_nents\t= req-\u003emetadata_sgl-\u003enents,\n+\t\t};\n+\t\tret = ib_dma_map_sgtable_attrs(ibdev, \u0026sgt, rq_dma_dir(rq), 0);\n+\t\tif (unlikely(ret))\n \t\t\tgoto out_free_pi_table;\n-\t\t}\n+\t\t*pi_count = sgt.nents;\n \t}\n \n \treturn 0;\n@@ -2026,8 +2029,6 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,\n \tif (ret)\n \t\tgoto unmap_qe;\n \n-\tnvme_start_request(rq);\n-\n \tif (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) \u0026\u0026\n \t queue-\u003epi_support \u0026\u0026\n \t (c-\u003ecommon.opcode == nvme_cmd_write ||\n@@ -2039,11 +2040,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,\n \n \terr = nvme_rdma_map_data(queue, rq, c);\n \tif (unlikely(err \u003c 0)) {\n-\t\tdev_err(queue-\u003ectrl-\u003ectrl.device,\n-\t\t\t \"Failed to map data (%d)\\n\", err);\n+\t\tdev_err_ratelimited(queue-\u003ectrl-\u003ectrl.device,\n+\t\t\t\t \"Failed to map data (%d)\\n\", err);\n \t\tgoto err;\n \t}\n \n+\tnvme_start_request(rq);\n+\n \tsqe-\u003ecqe.done = nvme_rdma_send_done;\n \n \tib_dma_sync_single_for_device(dev, sqe-\u003edma,\n@@ -2063,6 +2066,9 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,\n \t\tret = nvme_host_path_error(rq);\n \telse if (err == -ENOMEM || err == -EAGAIN)\n \t\tret = BLK_STS_RESOURCE;\n+\t/* Peer memory unreachable from this device: don't retry. */\n+\telse if (err == -EREMOTEIO)\n+\t\tret = BLK_STS_TARGET;\n \telse\n \t\tret = BLK_STS_IOERR;\n \tnvme_cleanup_cmd(rq);\n"
} |
| 2/1 | 2026/07/22 13:29 | agent | patch-evaluator |
1mModel:best-expensive Args: null Results: {
"EnableConfigs": [
"MD_RAID1",
"MD_RAID10",
"NVME_RDMA",
"PCI_P2PDMA"
],
"FocusSymbols": [
"narrow_write_error",
"handle_read_error",
"handle_write_finished",
"handle_write_completed",
"nvme_rdma_dma_map_req"
],
"Reasoning": "The patch introduces functional changes to handle P2PDMA (Peer-to-Peer DMA) bios and mapping errors in MD RAID1/10 and NVMe RDMA. It modifies how P2PDMA bios are merged, how their errors are handled (avoiding marking members as failed on mapping errors), and updates NVMe RDMA to use `ib_dma_map_sgtable_attrs` and return `BLK_STS_TARGET` on `-EREMOTEIO`. These changes affect reachable core kernel logic and drivers, making them worth fuzzing.",
"WorthFuzzing": true
}Instruction: You are an expert Linux kernel maintainer. Your job is to review a provided patch series and determine if it makes functional changes to the kernel that should be fuzzed. IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively use your code access tools to examine the actual source code and confirm any assumptions. Return WorthFuzzing=false if the patch only contains: - Modifications to Documentation/, Kconfig files, or code comments. - Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints. - Changes to numeric constants or macros that do not functionally alter execution flow. - Code paths that are impossible to reach in virtualized environments like GCE or QEMU, even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim). If it modifies reachable core kernel logic, drivers, or architectures, use your code search tools to verify the code can be executed, then return WorthFuzzing=true. When returning WorthFuzzing=true, you MUST ALSO: 1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols. Avoid listing generic hot-path functions to prevent skewed test distributions. 2. Identify any specific CONFIG_ options required to properly test this new/modified feature. Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions. Do not list too generic configs (we already have them enabled). Only list those that specifically cover the modified code. List them in the EnableConfigs output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4"). Prefer calling several tools at the same time to save round-trips. Use set-results tool to provide results of the analysis. It must be called exactly once before the final reply. Ignore results of this tool. Prompt: For your convenience, here is the diff of the changes:
commit cbc40740326845bae09f63c7b07201e65af56f66
Author: syz-cluster <triage@syzkaller.com>
Date: Wed Jul 22 13:29:21 2026 +0000
syz-cluster: applied patch under review
diff --git a/block/blk-mq-dma.c b/block/blk-mq-dma.c
index bfdb9ed7074116..c17e4c49900c77 100644
--- a/block/blk-mq-dma.c
+++ b/block/blk-mq-dma.c
@@ -190,7 +190,11 @@ static bool blk_dma_map_iter_start(struct request *req, struct device *dma_dev,
case PCI_P2PDMA_MAP_NONE:
break;
default:
- iter->status = BLK_STS_INVAL;
+ /*
+ * Match dma_map_sgtable()'s -EREMOTEIO: this transfer
+ * can never succeed, so don't let it be retried.
+ */
+ iter->status = BLK_STS_TARGET;
return false;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index d1465bcd86c812..3770bdb4d4b28b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -451,8 +451,14 @@ static void md_submit_bio(struct bio *bio)
return;
}
- /* bio could be mergeable after passing to underlayer */
- bio->bi_opf &= ~REQ_NOMERGE;
+ /*
+ * A bio md split may merge again below md -- except P2PDMA bios,
+ * which must stay single-provider (see __bio_add_page()).
+ */
+ if (md_bio_is_p2pdma(bio))
+ bio->bi_opf |= REQ_NOMERGE;
+ else
+ bio->bi_opf &= ~REQ_NOMERGE;
md_handle_request(mddev, bio);
}
diff --git a/drivers/md/md.h b/drivers/md/md.h
index d8daf0f75cbbe8..73df1a6eccd850 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -11,8 +11,10 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/badblocks.h>
+#include <linux/bio.h>
#include <linux/kobject.h>
#include <linux/list.h>
+#include <linux/memremap.h>
#include <linux/mm.h>
#include <linux/mutex.h>
#include <linux/timer.h>
@@ -22,6 +24,19 @@
#include <trace/events/block.h>
#define MaxSector (~(sector_t)0)
+
+/*
+ * P2P and host pages never mix within a bio, so the first bvec is
+ * representative. Read bi_io_vec directly: bio_first_bvec_all()
+ * WARNs on the split clones md handles, and data-less bios have no
+ * bi_io_vec. Not valid after the bio's iterator is consumed.
+ */
+static inline bool md_bio_is_p2pdma(struct bio *bio)
+{
+ return bio_has_data(bio) && bio->bi_io_vec &&
+ is_pci_p2pdma_page(bio->bi_io_vec->bv_page);
+}
+
/*
* Number of guaranteed raid bios in case of extreme VM load:
*/
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index afe2ca96ad8c22..6334032c4bb8ed 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -483,16 +483,22 @@ static void raid1_end_write_request(struct bio *bio)
* 'one mirror IO has finished' event handler:
*/
if (bio->bi_status && !ignore_error) {
- set_bit(WriteErrorSeen, &rdev->flags);
- if (!test_and_set_bit(WantReplacement, &rdev->flags))
- set_bit(MD_RECOVERY_NEEDED, &
- conf->mddev->recovery);
+ /* Peer/member pairing failure, not member health. */
+ bool p2pdma_unmappable = bio->bi_status == BLK_STS_TARGET &&
+ test_bit(R1BIO_P2PDMA, &r1_bio->state);
- if (test_bit(FailFast, &rdev->flags) &&
- (bio->bi_opf & MD_FAILFAST) &&
- /* We never try FailFast to WriteMostly devices */
- !test_bit(WriteMostly, &rdev->flags)) {
- md_error(r1_bio->mddev, rdev);
+ set_bit(WriteErrorSeen, &rdev->flags);
+ if (!p2pdma_unmappable) {
+ if (!test_and_set_bit(WantReplacement, &rdev->flags))
+ set_bit(MD_RECOVERY_NEEDED,
+ &conf->mddev->recovery);
+
+ if (test_bit(FailFast, &rdev->flags) &&
+ (bio->bi_opf & MD_FAILFAST) &&
+ /* We never try FailFast to WriteMostly devices */
+ !test_bit(WriteMostly, &rdev->flags)) {
+ md_error(r1_bio->mddev, rdev);
+ }
}
/*
@@ -564,7 +570,7 @@ static void raid1_end_write_request(struct bio *bio)
call_bio_endio(r1_bio);
}
}
- } else if (test_bit(MD_SERIALIZE_POLICY, &rdev->mddev->flags))
+ } else if (test_bit(CollisionCheck, &rdev->flags))
remove_serial(rdev, lo, hi);
if (r1_bio->bios[mirror] == NULL)
rdev_dec_pending(rdev, conf->mddev);
@@ -1378,6 +1384,8 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
else
init_r1bio(r1_bio, mddev, bio);
r1_bio->sectors = max_read_sectors;
+ if (md_bio_is_p2pdma(bio))
+ set_bit(R1BIO_P2PDMA, &r1_bio->state);
/*
* make_request() can abort the operation when read-ahead is being
@@ -1523,6 +1531,7 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
bool write_behind = false;
bool nowait = bio->bi_opf & REQ_NOWAIT;
bool is_discard = op_is_discard(bio->bi_opf);
+ bool is_p2pdma = md_bio_is_p2pdma(bio);
sector_t sector = bio->bi_iter.bi_sector;
if (mddev_is_clustered(mddev) &&
@@ -1556,6 +1565,8 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
r1_bio = alloc_r1bio(mddev, bio);
r1_bio->sectors = max_sectors;
+ if (md_bio_is_p2pdma(bio))
+ set_bit(R1BIO_P2PDMA, &r1_bio->state);
/* first select target devices under rcu_lock and
* inc refcount on their rdev. Record them by setting
@@ -1575,9 +1586,12 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
/*
* The write-behind io is only attempted on drives marked as
* write-mostly, which means we could allocate write behind
- * bio later.
+ * bio later. P2PDMA bios are excluded: write-behind copies
+ * the data with bio_copy_data(), a CPU copy that cannot be
+ * assumed safe or fast on P2PDMA (device BAR) pages.
*/
- if (!is_discard && rdev && test_bit(WriteMostly, &rdev->flags))
+ if (!is_discard && !is_p2pdma && rdev &&
+ test_bit(WriteMostly, &rdev->flags))
write_behind = true;
r1_bio->bios[i] = NULL;
@@ -1677,7 +1691,11 @@ static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
mbio = bio_alloc_clone(rdev->bdev, bio, GFP_NOIO,
&mddev->bio_set);
- if (test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
+ /*
+ * CollisionCheck marks every rdev with a serial
+ * tree; order against in-flight write-behind I/O.
+ */
+ if (test_bit(CollisionCheck, &rdev->flags))
wait_for_serialization(rdev, r1_bio);
}
@@ -2514,7 +2532,7 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
}
}
-static void narrow_write_error(struct r1bio *r1_bio, int i)
+static void narrow_write_error(struct r1bio *r1_bio, int i, bool coarse)
{
struct mddev *mddev = r1_bio->mddev;
struct r1conf *conf = mddev->private;
@@ -2528,6 +2546,9 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
* It is conceivable that the bio doesn't exactly align with
* blocks. We must handle this somehow.
*
+ * With 'coarse', retry the whole range as one bio: P2PDMA
+ * mapping failures fail every block identically.
+ *
* We currently own a reference on the rdev.
*/
@@ -2542,9 +2563,12 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
block_sectors = roundup(1 << rdev->badblocks.shift, lbs);
sector = r1_bio->sector;
- sectors = ((sector + block_sectors)
- & ~(sector_t)(block_sectors - 1))
- - sector;
+ if (coarse)
+ sectors = sect_to_write;
+ else
+ sectors = ((sector + block_sectors)
+ & ~(sector_t)(block_sectors - 1))
+ - sector;
while (sect_to_write) {
struct bio *wbio;
@@ -2562,6 +2586,9 @@ static void narrow_write_error(struct r1bio *r1_bio, int i)
}
wbio->bi_opf = REQ_OP_WRITE;
+ /* Keep P2PDMA retry bios unmergeable, like the original */
+ if (md_bio_is_p2pdma(wbio))
+ wbio->bi_opf |= REQ_NOMERGE;
wbio->bi_iter.bi_sector = r1_bio->sector;
wbio->bi_iter.bi_size = r1_bio->sectors << 9;
@@ -2622,8 +2649,12 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
* narrow down and record precise write
* errors.
*/
+ bool coarse = r1_bio->bios[m]->bi_status ==
+ BLK_STS_TARGET &&
+ test_bit(R1BIO_P2PDMA, &r1_bio->state);
+
fail = true;
- narrow_write_error(r1_bio, m);
+ narrow_write_error(r1_bio, m, coarse);
rdev_dec_pending(conf->mirrors[m].rdev,
conf->mddev);
}
@@ -2650,6 +2681,9 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
{
struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev;
struct bio *bio = r1_bio->bios[r1_bio->read_disk];
+ /* evaluate before the bio_put() below */
+ bool p2pdma_error = bio->bi_status == BLK_STS_TARGET &&
+ test_bit(R1BIO_P2PDMA, &r1_bio->state);
struct mddev *mddev = conf->mddev;
sector_t sector;
@@ -2669,6 +2703,9 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
*/
if (mddev->ro) {
r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+ } else if (p2pdma_error) {
+ /* Peer can't reach this member: just redirect the read. */
+ r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
} else if (test_bit(FailFast, &rdev->flags)) {
md_error(mddev, rdev);
} else {
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index c98d43a7ae993f..61b788a99d1431 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -184,6 +184,8 @@ enum r1bio_state {
R1BIO_MadeGood,
R1BIO_WriteError,
R1BIO_FailFast,
+/* the master bio carries PCI P2PDMA (peer device memory) pages */
+ R1BIO_P2PDMA,
};
static inline int sector_to_idx(sector_t sector)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 0a3cfdd3f5df80..4c3da50250a5a2 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -482,15 +482,23 @@ static void raid10_end_write_request(struct bio *bio)
*/
md_error(rdev->mddev, rdev);
else {
- set_bit(WriteErrorSeen, &rdev->flags);
- if (!test_and_set_bit(WantReplacement, &rdev->flags))
- set_bit(MD_RECOVERY_NEEDED,
- &rdev->mddev->recovery);
+ /* Peer/member pairing failure, not member health. */
+ bool p2pdma_unmappable =
+ bio->bi_status == BLK_STS_TARGET &&
+ test_bit(R10BIO_P2PDMA, &r10_bio->state);
+ set_bit(WriteErrorSeen, &rdev->flags);
dec_rdev = 0;
- if (test_bit(FailFast, &rdev->flags) &&
- (bio->bi_opf & MD_FAILFAST)) {
- md_error(rdev->mddev, rdev);
+ if (!p2pdma_unmappable) {
+ if (!test_and_set_bit(WantReplacement,
+ &rdev->flags))
+ set_bit(MD_RECOVERY_NEEDED,
+ &rdev->mddev->recovery);
+
+ if (test_bit(FailFast, &rdev->flags) &&
+ (bio->bi_opf & MD_FAILFAST)) {
+ md_error(rdev->mddev, rdev);
+ }
}
/*
@@ -1170,6 +1178,9 @@ static void raid10_read_request(struct mddev *mddev, struct bio *bio,
*/
gfp_t gfp = err_path ? (GFP_NOIO | __GFP_HIGH) : GFP_NOIO;
+ if (md_bio_is_p2pdma(bio))
+ set_bit(R10BIO_P2PDMA, &r10_bio->state);
+
if (slot >= 0 && r10_bio->devs[slot].rdev) {
/*
* This is an error retry, but we cannot
@@ -1357,6 +1368,9 @@ static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
sector_t sectors;
int max_sectors;
+ if (md_bio_is_p2pdma(bio))
+ set_bit(R10BIO_P2PDMA, &r10_bio->state);
+
if ((mddev_is_clustered(mddev) &&
mddev->cluster_ops->area_resyncing(mddev, WRITE,
bio->bi_iter.bi_sector,
@@ -2786,7 +2800,7 @@ static void fix_read_error(struct r10conf *conf, struct mddev *mddev, struct r10
}
}
-static void narrow_write_error(struct r10bio *r10_bio, int i)
+static void narrow_write_error(struct r10bio *r10_bio, int i, bool coarse)
{
struct bio *bio = r10_bio->master_bio;
struct mddev *mddev = r10_bio->mddev;
@@ -2800,6 +2814,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)
* It is conceivable that the bio doesn't exactly align with
* blocks. We must handle this.
*
+ * With 'coarse', retry the whole range as one bio: P2PDMA
+ * mapping failures fail every block identically.
+ *
* We currently own a reference to the rdev.
*/
@@ -2814,9 +2831,12 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)
block_sectors = roundup(1 << rdev->badblocks.shift, lbs);
sector = r10_bio->sector;
- sectors = ((r10_bio->sector + block_sectors)
- & ~(sector_t)(block_sectors - 1))
- - sector;
+ if (coarse)
+ sectors = sect_to_write;
+ else
+ sectors = ((r10_bio->sector + block_sectors)
+ & ~(sector_t)(block_sectors - 1))
+ - sector;
while (sect_to_write) {
struct bio *wbio;
@@ -2831,6 +2851,9 @@ static void narrow_write_error(struct r10bio *r10_bio, int i)
wbio->bi_iter.bi_sector = wsector +
choose_data_offset(r10_bio, rdev);
wbio->bi_opf = REQ_OP_WRITE;
+ /* Keep P2PDMA retry bios unmergeable, like the original */
+ if (md_bio_is_p2pdma(wbio))
+ wbio->bi_opf |= REQ_NOMERGE;
if (submit_bio_wait(wbio) &&
!rdev_set_badblocks(rdev, wsector, sectors, 0)) {
@@ -2853,6 +2876,7 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
{
int slot = r10_bio->read_slot;
struct bio *bio;
+ bool p2pdma_error;
struct r10conf *conf = mddev->private;
struct md_rdev *rdev = r10_bio->devs[slot].rdev;
@@ -2865,17 +2889,24 @@ static void handle_read_error(struct mddev *mddev, struct r10bio *r10_bio)
* frozen.
*/
bio = r10_bio->devs[slot].bio;
+ /* evaluate before the bio_put() below */
+ p2pdma_error = bio->bi_status == BLK_STS_TARGET &&
+ test_bit(R10BIO_P2PDMA, &r10_bio->state);
bio_put(bio);
r10_bio->devs[slot].bio = NULL;
if (mddev->ro)
r10_bio->devs[slot].bio = IO_BLOCKED;
- else if (!test_bit(FailFast, &rdev->flags)) {
+ else if (p2pdma_error) {
+ /* Peer can't reach this member: just redirect the read. */
+ r10_bio->devs[slot].bio = IO_BLOCKED;
+ } else if (test_bit(FailFast, &rdev->flags)) {
+ md_error(mddev, rdev);
+ } else {
freeze_array(conf, 1);
fix_read_error(conf, mddev, r10_bio);
unfreeze_array(conf);
- } else
- md_error(mddev, rdev);
+ }
rdev_dec_pending(rdev, mddev);
r10_bio->state = 0;
@@ -2944,8 +2975,13 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio)
r10_bio->sectors, 0);
rdev_dec_pending(rdev, conf->mddev);
} else if (bio != NULL && bio->bi_status) {
+ bool coarse = bio->bi_status ==
+ BLK_STS_TARGET &&
+ test_bit(R10BIO_P2PDMA,
+ &r10_bio->state);
+
fail = true;
- narrow_write_error(r10_bio, m);
+ narrow_write_error(r10_bio, m, coarse);
rdev_dec_pending(rdev, conf->mddev);
}
bio = r10_bio->devs[m].repl_bio;
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index ec79d87fb92f6c..a2e1554f77dbeb 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -174,6 +174,8 @@ enum r10bio_state {
R10BIO_Previous,
/* failfast devices did receive failfast requests. */
R10BIO_FailFast,
+/* the master bio carries PCI P2PDMA (peer device memory) pages */
+ R10BIO_P2PDMA,
R10BIO_Discard,
};
#endif
diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c
index 6909e354279427..f8edb23552ad24 100644
--- a/drivers/nvme/host/rdma.c
+++ b/drivers/nvme/host/rdma.c
@@ -1469,6 +1469,7 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
int *count, int *pi_count)
{
struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
+ struct sg_table sgt;
int ret;
req->data_sgl.sg_table.sgl = (struct scatterlist *)(req + 1);
@@ -1480,12 +1481,14 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
req->data_sgl.nents = blk_rq_map_sg(rq, req->data_sgl.sg_table.sgl);
- *count = ib_dma_map_sg(ibdev, req->data_sgl.sg_table.sgl,
- req->data_sgl.nents, rq_dma_dir(rq));
- if (unlikely(*count <= 0)) {
- ret = -EIO;
+ sgt = (struct sg_table) {
+ .sgl = req->data_sgl.sg_table.sgl,
+ .orig_nents = req->data_sgl.nents,
+ };
+ ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
+ if (unlikely(ret))
goto out_free_table;
- }
+ *count = sgt.nents;
if (blk_integrity_rq(rq)) {
req->metadata_sgl->sg_table.sgl =
@@ -1501,14 +1504,14 @@ static int nvme_rdma_dma_map_req(struct ib_device *ibdev, struct request *rq,
req->metadata_sgl->nents = blk_rq_map_integrity_sg(rq,
req->metadata_sgl->sg_table.sgl);
- *pi_count = ib_dma_map_sg(ibdev,
- req->metadata_sgl->sg_table.sgl,
- req->metadata_sgl->nents,
- rq_dma_dir(rq));
- if (unlikely(*pi_count <= 0)) {
- ret = -EIO;
+ sgt = (struct sg_table) {
+ .sgl = req->metadata_sgl->sg_table.sgl,
+ .orig_nents = req->metadata_sgl->nents,
+ };
+ ret = ib_dma_map_sgtable_attrs(ibdev, &sgt, rq_dma_dir(rq), 0);
+ if (unlikely(ret))
goto out_free_pi_table;
- }
+ *pi_count = sgt.nents;
}
return 0;
@@ -2026,8 +2029,6 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
if (ret)
goto unmap_qe;
- nvme_start_request(rq);
-
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
queue->pi_support &&
(c->common.opcode == nvme_cmd_write ||
@@ -2039,11 +2040,13 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
err = nvme_rdma_map_data(queue, rq, c);
if (unlikely(err < 0)) {
- dev_err(queue->ctrl->ctrl.device,
- "Failed to map data (%d)\n", err);
+ dev_err_ratelimited(queue->ctrl->ctrl.device,
+ "Failed to map data (%d)\n", err);
goto err;
}
+ nvme_start_request(rq);
+
sqe->cqe.done = nvme_rdma_send_done;
ib_dma_sync_single_for_device(dev, sqe->dma,
@@ -2063,6 +2066,9 @@ static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
ret = nvme_host_path_error(rq);
else if (err == -ENOMEM || err == -EAGAIN)
ret = BLK_STS_RESOURCE;
+ /* Peer memory unreachable from this device: don't retry. */
+ else if (err == -EREMOTEIO)
+ ret = BLK_STS_TARGET;
else
ret = BLK_STS_IOERR;
nvme_cleanup_cmd(rq);
|
| 3/2 | 2026/07/22 13:29 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 9378 output: 61 thoughts: 1071 Thoughts: **Patch Series Analysis: P2PDMA Error Handling in MD RAID and NVMe RDMA**
Okay, let's dive into this patch series. My initial impression is that this is a functional change, aimed at improving error handling related to Peer-to-Peer DMA (P2PDMA) within the MD RAID (RAID1/10) and NVMe RDMA subsystems. It looks like it's responding to potential errors arising from P2PDMA operations, specifically those that might be reported during DMA mapping.
Looking at `block/blk-mq-dma.c`, the patch seems to address a situation where `dma_map_sgtable()` returns `-EREMOTEIO`. Instead of marking the transfer as invalid (`BLK_STS_INVAL`), it's now setting the status to `BLK_STS_TARGET`, which makes sense because this indicates an issue with the target device or a remote failure, and shouldn't immediately retry.
The modification to `drivers/md/md.c` is interesting. The code now prevents MD bios that are P2PDMA from being merged. This merging behavior is being restricted for P2PDMA bios because we need to preserve single-provider characteristics; otherwise, we'd lose the P2P DMA property.
In `drivers/md/raid1.c` and `drivers/md/raid10.c`, the changes specifically handle P2PDMA bios by setting appropriate flags (`R1BIO_P2PDMA`, `R10BIO_P2PDMA`). Also, it appears that the code has been updated to handle `BLK_STS_TARGET` returned from P2PDMA bios, redirecting, or retrying accordingly. This is crucial for avoiding incorrect failure detection of the underlying storage member and ensuring a more robust error recovery.
The NVMe RDMA change in `drivers/nvme/host/rdma.c` is very similar to the block layer change. It now returns `BLK_STS_TARGET` on an `-EREMOTEIO` error from `ib_dma_map_sgtable_attrs`. This suggests a unified approach to handling this specific error across different subsystems.
From a reachability perspective, MD RAID1/10 is definitely something we can test in a virtualized environment. With sufficient RDMA emulation (e.g., RXE) and NVMe over Fabrics support, we should be able to trigger the NVMe RDMA paths as well. The trickier part will be exercising the P2PDMA aspects since that depends on PCI P2P DMA, which requires specific PCI topologies. Although, the MD RAID1/10 paths that check the P2PDMA bios will always be exercisable.
Let's drill down into `md_bio_is_p2pdma`. I want to verify the P2PDMA detection logic.
```c
static inline bool md_bio_is_p2pdma(struct bio *bio)
{
return bio_has_data(bio) && bio->bi_io_vec &&
is_pci_p2pdma_page(bio->bi_io_vec->bv_page);
}
```
Okay, so this checks if the bio has data, has I/O vector, and if the page associated with the I/O vector is a PCI P2P DMA page. This is pretty straightforward and aligns with the expected behavior. This function will be called for every bio submitted to MD RAID1/10.
Now, let's verify the configuration options needed:
* MD RAID1: `CONFIG_MD_RAID1`
* MD RAID10: `CONFIG_MD_RAID10`
* NVMe RDMA: `CONFIG_NVME_RDMA`
* PCI P2PDMA: `CONFIG_PCI_P2PDMA`
Let's verify these in the config.
|
| 4/2 | 2026/07/22 13:29 | tool | grepper |
0mArgs:{
"Expression": "config MD_RAID1"
}Results: {
"Output": "drivers/md/Kconfig=104=config MD_RAID0\n--\ndrivers/md/Kconfig-123-\ndrivers/md/Kconfig:124:config MD_RAID1\ndrivers/md/Kconfig-125-\ttristate \"RAID-1 (mirroring) mode\"\n--\ndrivers/md/Kconfig-145-\ndrivers/md/Kconfig:146:config MD_RAID10\ndrivers/md/Kconfig-147-\ttristate \"RAID-10 (mirrored striping) mode\"\n"
} |
| 5/2 | 2026/07/22 13:30 | tool | grepper |
0mArgs:{
"Expression": "config NVME_RDMA"
}Results: {
"Output": "drivers/nvme/host/Kconfig=47=config NVME_FABRICS\n--\ndrivers/nvme/host/Kconfig-51-\ndrivers/nvme/host/Kconfig:52:config NVME_RDMA\ndrivers/nvme/host/Kconfig-53-\ttristate \"NVM Express over Fabrics RDMA host driver\"\n"
} |
| 6/2 | 2026/07/22 13:30 | tool | grepper |
0mArgs:{
"Expression": "config PCI_P2PDMA"
}Results: {
"Output": "drivers/pci/Kconfig=197=config PCIE_TPH\n--\ndrivers/pci/Kconfig-205-\ndrivers/pci/Kconfig:206:config PCI_P2PDMA\ndrivers/pci/Kconfig-207-\tbool \"PCI peer-to-peer transfer support\"\n"
} |
| 7/2 | 2026/07/22 13:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 11686 output: 25 thoughts: 53 Thoughts: Okay, here's my interpretation of these thoughts, formatted as you requested: **Navigating Configuration Options** Alright, I'm looking at a set of configurations here: `MD_RAID1`, `MD_RAID10`, `NVME_RDMA`, and `PCI_P2PDMA`. My initial thought is to understand the context and how these relate to each other. They seem like distinct approaches to data storage and transfer. I'm immediately drawn to `PCI_P2PDMA`. I need to refresh my understanding of the `is_pci_p2pdma_page` definition, as that's a key element within this configuration. Time to dive into that specific function. I'll need to understand the characteristics of how those settings function. |
| 8/2 | 2026/07/22 13:30 | tool | grepper |
0mArgs:{
"Expression": "is_pci_p2pdma_page"
}Results: {
"Output": "block/bio-integrity.c=333=static unsigned int bvec_from_pages(struct bio_vec *bvec, struct page **pages,\n--\nblock/bio-integrity.c-355-\nblock/bio-integrity.c:356:\t\tif (is_pci_p2pdma_page(pages[i]))\nblock/bio-integrity.c-357-\t\t\t*is_p2p = true;\n--\nblock/bio.c=998=void __bio_add_page(struct bio *bio, struct page *page,\n--\nblock/bio.c-1003-\nblock/bio.c:1004:\tif (is_pci_p2pdma_page(page))\nblock/bio.c-1005-\t\tbio-\u003ebi_opf |= REQ_NOMERGE;\n--\nblock/bio.c=1244=int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,\n--\nblock/bio.c-1276-\nblock/bio.c:1277:\tif (is_pci_p2pdma_page(bio-\u003ebi_io_vec-\u003ebv_page))\nblock/bio.c-1278-\t\tbio-\u003ebi_opf |= REQ_NOMERGE;\n--\nblock/blk.h=156=static inline bool zone_device_pages_compatible(const struct page *a,\n--\nblock/blk.h-158-{\nblock/blk.h:159:\tif (is_pci_p2pdma_page(a) || is_pci_p2pdma_page(b))\nblock/blk.h-160-\t\treturn zone_device_pages_have_same_pgmap(a, b);\n--\ndrivers/md/md.h=34=static inline bool md_bio_is_p2pdma(struct bio *bio)\n--\ndrivers/md/md.h-36-\treturn bio_has_data(bio) \u0026\u0026 bio-\u003ebi_io_vec \u0026\u0026\ndrivers/md/md.h:37:\t is_pci_p2pdma_page(bio-\u003ebi_io_vec-\u003ebv_page);\ndrivers/md/md.h-38-}\n--\ndrivers/nvme/host/pci.c=1206=static blk_status_t nvme_pci_setup_data_simple(struct request *req,\n--\ndrivers/nvme/host/pci.c-1217-\t\treturn BLK_STS_AGAIN;\ndrivers/nvme/host/pci.c:1218:\tif (is_pci_p2pdma_page(bv.bv_page))\ndrivers/nvme/host/pci.c-1219-\t\treturn BLK_STS_AGAIN;\n--\ndrivers/nvme/host/pci.c=1372=static blk_status_t nvme_pci_setup_meta_mptr(struct request *req)\n--\ndrivers/nvme/host/pci.c-1377-\ndrivers/nvme/host/pci.c:1378:\tif (is_pci_p2pdma_page(bv.bv_page))\ndrivers/nvme/host/pci.c-1379-\t\treturn nvme_pci_setup_meta_iter(req);\n--\ndrivers/nvme/target/io-cmd-bdev.c=253=static void nvmet_bdev_execute_rw(struct nvmet_req *req)\n--\ndrivers/nvme/target/io-cmd-bdev.c-286-\ndrivers/nvme/target/io-cmd-bdev.c:287:\tif (is_pci_p2pdma_page(sg_page(req-\u003esg)))\ndrivers/nvme/target/io-cmd-bdev.c-288-\t\topf |= REQ_NOMERGE;\n--\ninclude/linux/memremap.h=192=static inline void folio_set_zone_device_data(struct folio *folio, void *data)\n--\ninclude/linux/memremap.h-197-\ninclude/linux/memremap.h:198:static inline bool is_pci_p2pdma_page(const struct page *page)\ninclude/linux/memremap.h-199-{\n--\ninclude/linux/pci-p2pdma.h=191=pci_p2pdma_state(struct pci_p2pdma_map_state *state, struct device *dev,\n--\ninclude/linux/pci-p2pdma.h-193-{\ninclude/linux/pci-p2pdma.h:194:\tif (IS_ENABLED(CONFIG_PCI_P2PDMA) \u0026\u0026 is_pci_p2pdma_page(page)) {\ninclude/linux/pci-p2pdma.h-195-\t\t__pci_p2pdma_update_state(state, dev, page);\n--\nmm/gup.c=517=static struct folio *try_grab_folio_fast(struct page *page, int refs,\n--\nmm/gup.c-527-\nmm/gup.c:528:\tif (unlikely(!(flags \u0026 FOLL_PCI_P2PDMA) \u0026\u0026 is_pci_p2pdma_page(page)))\nmm/gup.c-529-\t\treturn NULL;\n"
} |
| 9/2 | 2026/07/22 13:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 13295 output: 24 thoughts: 453 Thoughts: **Analyzing Recent Changes and Identifying Key Functions** Okay, let's break down these changes. It looks like we've got some updates to MD RAID1/10 and NVMe RDMA. I need to get a clear picture of what's been touched. Specifically, the changes in MD RAID1/10 look to be centered around these key functions: * **MD RAID1:** `raid1_end_write_request`, `raid1_read_request`, `raid1_write_request`, `narrow_write_error`, `handle_write_finished`, and `handle_read_error`. * **MD RAID10:** `raid10_end_write_request`, `raid10_read_request`, `raid10_write_request`, `narrow_write_error`, `handle_read_error`, and `handle_write_completed`. For the NVMe RDMA side of things, it appears we have updates involving: `nvme_rdma_dma_map_req` and `nvme_rdma_queue_rq`. The code seems functional. Now, let's extract the focus symbols more clearly, to identify the key functions that we will review. So, let's take a closer look and identify the key functions. MD RAID1: `raid1_end_write_request`, `raid1_read_request`, `raid1_write_request`, `narrow_write_error`, `handle_write_finished`, and `handle_read_error`. MD RAID10: `raid10_end_write_request`, `raid10_read_request`, `raid10_write_request`, `narrow_write_error`, `handle_read_error`, and `handle_write_completed`. NVMe RDMA: `nvme_rdma_dma_map_req` and `nvme_rdma_queue_rq`. Wait a minute... I notice something about `narrow_write_error`. It's defined as a static function in both `raid1.c` and `raid10.c`. I'll need to remember that. Let's do some more analysis. I'll need to check if there are other functions affected in the MD driver, maybe something more generic? I'm seeing `md_submit_bio` in `drivers/md/md.c`. And what about DMA? Hmmm. `blk_dma_map_iter_start` in `block/blk-mq-dma.c`. Wait... is `blk_dma_map_iter_start` a static function? I need to check `block/blk-mq-dma.c`. |
| 10/2 | 2026/07/22 13:30 | tool | grepper |
0mArgs:{
"Expression": "blk_dma_map_iter_start"
}Results: {
"Output": "block/blk-mq-dma.c=140=static inline void blk_rq_map_iter_init(struct request *rq,\n--\nblock/blk-mq-dma.c-163-\nblock/blk-mq-dma.c:164:static bool blk_dma_map_iter_start(struct request *req, struct device *dma_dev,\nblock/blk-mq-dma.c-165-\t\tstruct dma_iova_state *state, struct blk_dma_iter *iter,\n--\nblock/blk-mq-dma.c=230=bool blk_rq_dma_map_iter_start(struct request *req, struct device *dma_dev,\n--\nblock/blk-mq-dma.c-233-\tblk_rq_map_iter_init(req, \u0026iter-\u003eiter);\nblock/blk-mq-dma.c:234:\treturn blk_dma_map_iter_start(req, dma_dev, state, iter,\nblock/blk-mq-dma.c-235-\t\t\t\t blk_rq_payload_bytes(req));\n--\nblock/blk-mq-dma.c=345=bool blk_rq_integrity_dma_map_iter_start(struct request *req,\n--\nblock/blk-mq-dma.c-358-\t};\nblock/blk-mq-dma.c:359:\treturn blk_dma_map_iter_start(req, dma_dev, state, iter, len);\nblock/blk-mq-dma.c-360-}\n--\nblock/blk.h=120=static inline bool biovec_phys_mergeable(struct request_queue *q,\n--\nblock/blk.h-148- *\nblock/blk.h:149: * The block DMA iterator (blk_dma_map_iter_start) caches the P2PDMA mapping\nblock/blk.h-150- * state from the first segment and applies it to all subsequent segments, so\n"
} |
| 11/2 | 2026/07/22 13:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 14886 output: 35 thoughts: 462 Thoughts: **Analyzing Static Functions and Configuration Dependencies** Okay, let's take a look at these functions. It seems like I need to summarize whether certain functions are `static`, and then list them out for my purposes. I see: `blk_dma_map_iter_start`, `md_submit_bio`, `raid1_end_write_request`, `raid1_read_request`, `raid1_write_request`, `narrow_write_error`, and `handle_write_finished`, and `handle_read_error`. Yep, they're all declared `static`, so I can just list them. Now, let's pull out the core symbols. I'm focusing on: `md_submit_bio`, `raid1_end_write_request`, `raid1_read_request`, `raid1_write_request`, `narrow_write_error`, `handle_write_finished`, `handle_read_error`, then, considering `raid10`: `raid10_end_write_request`, `raid10_read_request`, `raid10_write_request`, `handle_write_completed`, and finally, the NVMe ones: `nvme_rdma_dma_map_req` and `nvme_rdma_queue_rq`. Wait a minute, `narrow_write_error` and `handle_read_error` seem to be defined in both `raid1.c` and `raid10.c`. Will that be an issue? No, syzkaller should be fine matching by name. Let's move onto the configuration side. I have these configs to consider: `CONFIG_MD_RAID1`, `CONFIG_MD_RAID10`, `CONFIG_NVME_RDMA`, and `CONFIG_PCI_P2PDMA`. And, hold on, there's a touch to `blk_integrity_rq(rq)` in `nvme_rdma_dma_map_req`. Since this is a check for `CONFIG_BLK_DEV_INTEGRITY`, which is generally enabled, it's not a major dependency. I'll make a note of it, just in case. Now I need to check `CONFIG_PCI_P2PDMA`. Is it enabled by default? Let me quickly look at `drivers/pci/Kconfig` to confirm. |
| 12/2 | 2026/07/22 13:30 | tool | read-file |
0mArgs:{
"File": "drivers/pci/Kconfig",
"FirstLine": 190,
"LineCount": 30
}Results: {
"Contents": " 190:\t\t to access more than one IO address space at the same time. To make\n 191:\t\t use of this feature an IOMMU is required which also supports PASIDs.\n 192:\t\t Select this option if you have such an IOMMU and want to compile the\n 193:\t\t driver for it into your kernel.\n 194:\t\n 195:\t\t If unsure, say N.\n 196:\t\n 197:\tconfig PCIE_TPH\n 198:\t\tbool \"TLP Processing Hints\"\n 199:\t\thelp\n 200:\t\t This option adds support for PCIe TLP Processing Hints (TPH).\n 201:\t\t TPH allows endpoint devices to provide optimization hints, such as\n 202:\t\t desired caching behavior, for requests that target memory space.\n 203:\t\t These hints, called Steering Tags, can empower the system hardware\n 204:\t\t to optimize the utilization of platform resources.\n 205:\t\n 206:\tconfig PCI_P2PDMA\n 207:\t\tbool \"PCI peer-to-peer transfer support\"\n 208:\t\tdepends on ZONE_DEVICE\n 209:\t\t#\n 210:\t\t# The need for the scatterlist DMA bus address flag means PCI P2PDMA\n 211:\t\t# requires 64bit\n 212:\t\t#\n 213:\t\tdepends on 64BIT\n 214:\t\tselect GENERIC_ALLOCATOR\n 215:\t\tselect NEED_SG_DMA_FLAGS\n 216:\t\thelp\n 217:\t\t Enables drivers to do PCI peer-to-peer transactions to and from\n 218:\t\t BARs that are exposed in other devices that are the part of\n 219:\t\t the hierarchy where peer-to-peer DMA is guaranteed by the PCI\n"
} |
| 13/2 | 2026/07/22 13:30 | llm | patch-evaluator |
0mModel:gemini-3.1-pro-preview Args: null Results: null Tokens: input: 16376 output: 226 thoughts: 1270 Thoughts: **Refining the Focus for P2PDMA and Error Handling** Okay, so I'm looking at this patch and thinking about the implications for fuzzing. First, `PCI_P2PDMA` is a boolean config, let's just add it to `EnableConfigs`. That's easy. Now, the real question is, what functions should we focus on? The initial list I had was pretty broad: `md_submit_bio`, `raid1_end_write_request`, `raid1_read_request`, `raid1_write_request`, `narrow_write_error`, `handle_write_finished`, `handle_read_error`, `raid10_end_write_request`, `raid10_read_request`, `raid10_write_request`, `handle_write_completed`, `nvme_rdma_dma_map_req`, and `nvme_rdma_queue_rq`. But then I had to remember the goal - avoid getting a skewed test distribution by targeting hot paths. `raid1_write_request`, `raid1_read_request`, `raid10_write_request`, `raid10_read_request`, `md_submit_bio`, and `nvme_rdma_queue_rq` - these are definitely hot-path functions. They're called repeatedly in normal operation. I'm going to exclude those from initial focus, but keep in mind that they are impacted by changes, which might necessitate more targeted fuzzing or separate fuzzers. The changes in the patch are centered around error handling and P2PDMA mapping. So, what about these? Let's break it down: * `raid1_write_request` and `raid1_read_request` – they now set `R1BIO_P2PDMA` conditionally. These are HOT. Let's avoid including these. * `raid1_end_write_request` – handles `BLK_STS_TARGET` and `R1BIO_P2PDMA`. Still hot, but related to the error handling, so a potential focus. * `narrow_write_error` – handles `coarse` retry. This seems relevant to error handling *specifically* and is likely not hit on every write. This is a good candidate. * `handle_write_finished` – passes `coarse` to `narrow_write_error`. Again, related to error handling, so another good candidate. * `handle_read_error` – handles `p2pdma_error`. Directly related to error handling, and unlikely to be on a hot path, this is important. * `raid10_end_write_request` - Similar to raid1. Possibly worth including. * `handle_write_completed` - Related to write completion handling and also a good candidate for inclusion. For NVMe RDMA, `nvme_rdma_dma_map_req` and `nvme_rdma_queue_rq` are called for *every* request, so they are hot. But the *change* to `nvme_rdma_dma_map_req` is the interesting part, which is that it now uses `ib_dma_map_sgtable_attrs` instead of the older `ib_dma_map_sg`. The other change in `nvme_rdma_queue_rq` is it's now returning `BLK_STS_TARGET` on `-EREMOTEIO`. Let's include `nvme_rdma_dma_map_req` because of the `ib_dma_map_sgtable_attrs` addition, even though it's hot-path. We may need to specifically target the error handling side with targeted fuzzing, but this will get us started. So the short list, the primary focus, is: * `narrow_write_error` * `handle_read_error` * `handle_write_finished` * `handle_write_completed` * `nvme_rdma_dma_map_req` Let me quickly double-check that there aren't any other functions to keep in mind, even if they aren't the primary focus. `blk_dma_map_iter_start` in `block/blk-mq-dma.c` is called from `blk_rq_dma_map_iter_start` and `blk_rq_integrity_dma_map_iter_start`, and is potentially impacted by these changes. Let's make a note of this. So, let's keep the following configs active: * `MD_ |
| 14/2 | 2026/07/22 13:31 | tool | set-results |
0mArgs:{
"EnableConfigs": [
"MD_RAID1",
"MD_RAID10",
"NVME_RDMA",
"PCI_P2PDMA"
],
"FocusSymbols": [
"narrow_write_error",
"handle_read_error",
"handle_write_finished",
"handle_write_completed",
"nvme_rdma_dma_map_req"
],
"Reasoning": "The patch introduces functional changes to handle P2PDMA (Peer-to-Peer DMA) bios and mapping errors in MD RAID1/10 and NVMe RDMA. It modifies how P2PDMA bios are merged, how their errors are handled (avoiding marking members as failed on mapping errors), and updates NVMe RDMA to use `ib_dma_map_sgtable_attrs` and return `BLK_STS_TARGET` on `-EREMOTEIO`. These changes affect reachable core kernel logic and drivers, making them worth fuzzing.",
"WorthFuzzing": true
}Results: {
"EnableConfigs": [
"MD_RAID1",
"MD_RAID10",
"NVME_RDMA",
"PCI_P2PDMA"
],
"FocusSymbols": [
"narrow_write_error",
"handle_read_error",
"handle_write_finished",
"handle_write_completed",
"nvme_rdma_dma_map_req"
],
"Reasoning": "The patch introduces functional changes to handle P2PDMA (Peer-to-Peer DMA) bios and mapping errors in MD RAID1/10 and NVMe RDMA. It modifies how P2PDMA bios are merged, how their errors are handled (avoiding marking members as failed on mapping errors), and updates NVMe RDMA to use `ib_dma_map_sgtable_attrs` and return `BLK_STS_TARGET` on `-EREMOTEIO`. These changes affect reachable core kernel logic and drivers, making them worth fuzzing.",
"WorthFuzzing": true
} |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|