Stable-dep-of: d301f164c3fb ("badblocks: use sector_t instead of int to avoid truncation of badblocks length")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- block/badblocks.c | 41 +++++++++++++++++------------------
- drivers/block/null_blk/main.c | 14 ++++++------
- drivers/md/md.c | 35 +++++++++++++++---------------
- drivers/nvdimm/badrange.c | 2 +-
- include/linux/badblocks.h | 6 ++---
+ block/badblocks.c | 41 ++++++++++++++++++++---------------------
+ drivers/block/null_blk/main.c | 14 +++++++-------
+ drivers/md/md.c | 35 ++++++++++++++++++-----------------
+ drivers/nvdimm/badrange.c | 2 +-
+ include/linux/badblocks.h | 6 +++---
5 files changed, 49 insertions(+), 49 deletions(-)
-diff --git a/block/badblocks.c b/block/badblocks.c
-index f84a35d683b1f..753250a04c3fa 100644
--- a/block/badblocks.c
+++ b/block/badblocks.c
-@@ -836,8 +836,8 @@ static bool try_adjacent_combine(struct badblocks *bb, int prev)
+@@ -836,8 +836,8 @@ static bool try_adjacent_combine(struct
}
/* Do exact work to set bad block range into the bad block table */
{
int len = 0, added = 0;
struct badblocks_context bad;
-@@ -847,11 +847,11 @@ static int _badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+@@ -847,11 +847,11 @@ static int _badblocks_set(struct badbloc
if (bb->shift < 0)
/* badblocks are disabled */
if (bb->shift) {
/* round the start down, and the end up */
-@@ -981,7 +981,7 @@ static int _badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+@@ -981,7 +981,7 @@ out:
write_sequnlock_irqrestore(&bb->lock, flags);
}
/*
-@@ -1052,21 +1052,20 @@ static int front_splitting_clear(struct badblocks *bb, int prev,
+@@ -1052,21 +1052,20 @@ static int front_splitting_clear(struct
}
/* Do the exact work to clear bad block range from the bad block table */
if (bb->shift) {
sector_t target;
-@@ -1186,9 +1185,9 @@ static int _badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
+@@ -1186,9 +1185,9 @@ update_sectors:
write_sequnlock_irq(&bb->lock);
if (!cleared)
{
return _badblocks_clear(bb, s, sectors);
}
-@@ -1489,10 +1488,10 @@ ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
+@@ -1489,10 +1488,10 @@ ssize_t badblocks_store(struct badblocks
return -EINVAL;
}
}
EXPORT_SYMBOL_GPL(badblocks_store);
-diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
-index cca278f1d2ce7..f2a5f65abbf8b 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
-@@ -561,14 +561,14 @@ static ssize_t nullb_device_badblocks_store(struct config_item *item,
+@@ -559,14 +559,14 @@ static ssize_t nullb_device_badblocks_st
goto out;
/* enable badblocks */
cmpxchg(&t_dev->badblocks.shift, -1, 0);
out:
kfree(orig);
return ret;
-diff --git a/drivers/md/md.c b/drivers/md/md.c
-index f501bc5f68f1a..ef859ccb03661 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
-@@ -1754,7 +1754,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
+@@ -1754,7 +1754,7 @@ static int super_1_load(struct md_rdev *
count <<= sb->bblog_shift;
if (bb + 1 == 0)
break;
return -EINVAL;
}
} else if (sb->bblog_offset != 0)
-@@ -9850,7 +9850,6 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+@@ -9850,7 +9850,6 @@ int rdev_set_badblocks(struct md_rdev *r
int is_new)
{
struct mddev *mddev = rdev->mddev;
/*
* Recording new badblocks for faulty rdev will force unnecessary
-@@ -9866,33 +9865,35 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors,
+@@ -9866,33 +9865,35 @@ int rdev_set_badblocks(struct md_rdev *r
s += rdev->new_data_offset;
else
s += rdev->data_offset;
}
EXPORT_SYMBOL_GPL(rdev_clear_badblocks);
-diff --git a/drivers/nvdimm/badrange.c b/drivers/nvdimm/badrange.c
-index a002ea6fdd842..ee478ccde7c6c 100644
--- a/drivers/nvdimm/badrange.c
+++ b/drivers/nvdimm/badrange.c
-@@ -167,7 +167,7 @@ static void set_badblock(struct badblocks *bb, sector_t s, int num)
+@@ -167,7 +167,7 @@ static void set_badblock(struct badblock
dev_dbg(bb->dev, "Found a bad range (0x%llx, 0x%llx)\n",
(u64) s * 512, (u64) num * 512);
/* this isn't an error as the hardware will still throw an exception */
dev_info_once(bb->dev, "%s: failed for sector %llx\n",
__func__, (u64) s);
}
-diff --git a/include/linux/badblocks.h b/include/linux/badblocks.h
-index 670f2dae692fb..8764bed9ff167 100644
--- a/include/linux/badblocks.h
+++ b/include/linux/badblocks.h
@@ -50,9 +50,9 @@ struct badblocks_context {
void ack_all_badblocks(struct badblocks *bb);
ssize_t badblocks_show(struct badblocks *bb, char *page, int unack);
ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
---
-2.39.5
-
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
- block/badblocks.c | 20 ++++++++------------
- drivers/block/null_blk/main.c | 3 +--
- drivers/md/md.h | 6 +++---
- drivers/md/raid1-10.c | 2 +-
- drivers/md/raid1.c | 4 ++--
- drivers/md/raid10.c | 8 ++++----
- drivers/nvdimm/nd.h | 2 +-
- drivers/nvdimm/pfn_devs.c | 7 ++++---
- drivers/nvdimm/pmem.c | 2 +-
- include/linux/badblocks.h | 8 ++++----
+ block/badblocks.c | 20 ++++++++------------
+ drivers/block/null_blk/main.c | 3 +--
+ drivers/md/md.h | 6 +++---
+ drivers/md/raid1-10.c | 2 +-
+ drivers/md/raid1.c | 4 ++--
+ drivers/md/raid10.c | 8 ++++----
+ drivers/nvdimm/nd.h | 2 +-
+ drivers/nvdimm/pfn_devs.c | 7 ++++---
+ drivers/nvdimm/pmem.c | 2 +-
+ include/linux/badblocks.h | 8 ++++----
10 files changed, 29 insertions(+), 33 deletions(-)
-diff --git a/block/badblocks.c b/block/badblocks.c
-index 753250a04c3fa..dc147c0179612 100644
--- a/block/badblocks.c
+++ b/block/badblocks.c
-@@ -836,7 +836,7 @@ static bool try_adjacent_combine(struct badblocks *bb, int prev)
+@@ -836,7 +836,7 @@ static bool try_adjacent_combine(struct
}
/* Do exact work to set bad block range into the bad block table */
int acknowledged)
{
int len = 0, added = 0;
-@@ -960,8 +960,6 @@ static bool _badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+@@ -960,8 +960,6 @@ update_sectors:
if (sectors > 0)
goto re_insert;
/*
* Check whether the following already set range can be
* merged. (prev < 0) condition is not handled here,
-@@ -1052,7 +1050,7 @@ static int front_splitting_clear(struct badblocks *bb, int prev,
+@@ -1052,7 +1050,7 @@ static int front_splitting_clear(struct
}
/* Do the exact work to clear bad block range from the bad block table */
{
struct badblocks_context bad;
int prev = -1, hint = -1;
-@@ -1175,8 +1173,6 @@ static bool _badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
+@@ -1175,8 +1173,6 @@ update_sectors:
if (sectors > 0)
goto re_clear;
if (cleared) {
badblocks_update_acked(bb);
set_changed(bb);
-@@ -1191,8 +1187,8 @@ static bool _badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
+@@ -1191,8 +1187,8 @@ update_sectors:
}
/* Do the exact work to check bad blocks range from the bad block table */
{
int prev = -1, hint = -1, set = 0;
struct badblocks_context bad;
-@@ -1302,8 +1298,8 @@ static int _badblocks_check(struct badblocks *bb, sector_t s, int sectors,
+@@ -1302,8 +1298,8 @@ update_sectors:
* -1: there are bad blocks which have not yet been acknowledged in metadata.
* plus the start/length of the first bad section we overlap.
*/
{
return _badblocks_clear(bb, s, sectors);
}
-diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
-index f2a5f65abbf8b..59a10b0d122ce 100644
--- a/drivers/block/null_blk/main.c
+++ b/drivers/block/null_blk/main.c
-@@ -1327,8 +1327,7 @@ blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, sector_t sector,
+@@ -1300,8 +1300,7 @@ static inline blk_status_t null_handle_b
+ sector_t nr_sectors)
+ {
struct badblocks *bb = &cmd->nq->dev->badblocks;
- struct nullb_device *dev = cmd->nq->dev;
- unsigned int block_sectors = dev->blocksize >> SECTOR_SHIFT;
- sector_t first_bad;
- int bad_sectors;
+ sector_t first_bad, bad_sectors;
- unsigned int partial_io_sectors = 0;
- if (!badblocks_check(bb, sector, *nr_sectors, &first_bad, &bad_sectors))
-diff --git a/drivers/md/md.h b/drivers/md/md.h
-index def808064ad8e..cc31c795369da 100644
+ if (badblocks_check(bb, sector, nr_sectors, &first_bad, &bad_sectors))
+ return BLK_STS_IOERR;
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -266,8 +266,8 @@ enum flag_bits {
{
if (unlikely(rdev->badblocks.count)) {
int rv = badblocks_check(&rdev->badblocks, rdev->data_offset + s,
-@@ -284,7 +284,7 @@ static inline int rdev_has_badblock(struct md_rdev *rdev, sector_t s,
+@@ -284,7 +284,7 @@ static inline int rdev_has_badblock(stru
int sectors)
{
sector_t first_bad;
return is_badblock(rdev, s, sectors, &first_bad, &bad_sectors);
}
-diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
-index 4378d3250bd75..62b980b12f93a 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
-@@ -247,7 +247,7 @@ static inline int raid1_check_read_range(struct md_rdev *rdev,
+@@ -247,7 +247,7 @@ static inline int raid1_check_read_range
sector_t this_sector, int *len)
{
sector_t first_bad;
/* no bad block overlap */
if (!is_badblock(rdev, this_sector, *len, &first_bad, &bad_sectors))
-diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
-index 44dcfebff4f03..15829ab192d2b 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
-@@ -1535,7 +1535,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
+@@ -1535,7 +1535,7 @@ static void raid1_write_request(struct m
atomic_inc(&rdev->nr_pending);
if (test_bit(WriteErrorSeen, &rdev->flags)) {
sector_t first_bad;
int is_bad;
is_bad = is_badblock(rdev, r1_bio->sector, max_sectors,
-@@ -2882,7 +2882,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
+@@ -2882,7 +2882,7 @@ static sector_t raid1_sync_request(struc
} else {
/* may need to read from here */
sector_t first_bad = MaxSector;
if (is_badblock(rdev, sector_nr, good_sectors,
&first_bad, &bad_sectors)) {
-diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
-index 918a09f0ddd45..af010b64be63b 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
-@@ -747,7 +747,7 @@ static struct md_rdev *read_balance(struct r10conf *conf,
+@@ -747,7 +747,7 @@ static struct md_rdev *read_balance(stru
for (slot = 0; slot < conf->copies ; slot++) {
sector_t first_bad;
sector_t dev_sector;
unsigned int pending;
bool nonrot;
-@@ -1430,7 +1430,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
+@@ -1430,7 +1430,7 @@ static void raid10_write_request(struct
if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) {
sector_t first_bad;
sector_t dev_sector = r10_bio->devs[i].addr;
int is_bad;
is_bad = is_badblock(rdev, dev_sector, max_sectors,
-@@ -3404,7 +3404,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
+@@ -3404,7 +3404,7 @@ static sector_t raid10_sync_request(stru
sector_t from_addr, to_addr;
struct md_rdev *rdev = conf->mirrors[d].rdev;
sector_t sector, first_bad;
if (!rdev ||
!test_bit(In_sync, &rdev->flags))
continue;
-@@ -3600,7 +3600,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
+@@ -3600,7 +3600,7 @@ static sector_t raid10_sync_request(stru
for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
sector_t first_bad, sector;
struct md_rdev *rdev;
if (r10_bio->devs[i].repl_bio)
-diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h
-index 5ca06e9a2d292..cc5c8f3f81e8d 100644
--- a/drivers/nvdimm/nd.h
+++ b/drivers/nvdimm/nd.h
-@@ -673,7 +673,7 @@ static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
+@@ -673,7 +673,7 @@ static inline bool is_bad_pmem(struct ba
{
if (bb->count) {
sector_t first_bad;
return !!badblocks_check(bb, sector, len / 512, &first_bad,
&num_bad);
-diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c
-index cfdfe0eaa5121..8f3e816e805d8 100644
--- a/drivers/nvdimm/pfn_devs.c
+++ b/drivers/nvdimm/pfn_devs.c
-@@ -367,9 +367,10 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
+@@ -367,9 +367,10 @@ static int nd_pfn_clear_memmap_errors(st
struct nd_namespace_common *ndns = nd_pfn->ndns;
void *zero_page = page_address(ZERO_PAGE(0));
struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb;
if (nd_pfn->mode != PFN_MODE_PMEM)
return 0;
-@@ -394,7 +395,7 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
+@@ -394,7 +395,7 @@ static int nd_pfn_clear_memmap_errors(st
bb_present = badblocks_check(&nd_region->bb, meta_start,
meta_num, &first_bad, &num_bad);
if (bb_present) {
num_bad, first_bad);
nsoff = ALIGN_DOWN((nd_region->ndr_start
+ (first_bad << 9)) - nsio->res.start,
-@@ -413,7 +414,7 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
+@@ -413,7 +414,7 @@ static int nd_pfn_clear_memmap_errors(st
}
if (rc) {
dev_err(&nd_pfn->dev,
num_bad, first_bad);
return rc;
}
-diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c
-index d81faa9d89c93..43156e1576c93 100644
--- a/drivers/nvdimm/pmem.c
+++ b/drivers/nvdimm/pmem.c
-@@ -249,7 +249,7 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
+@@ -249,7 +249,7 @@ __weak long __pmem_direct_access(struct
unsigned int num = PFN_PHYS(nr_pages) >> SECTOR_SHIFT;
struct badblocks *bb = &pmem->bb;
sector_t first_bad;
if (kaddr)
*kaddr = pmem->virt_addr + offset;
-diff --git a/include/linux/badblocks.h b/include/linux/badblocks.h
-index 8764bed9ff167..996493917f366 100644
--- a/include/linux/badblocks.h
+++ b/include/linux/badblocks.h
@@ -48,11 +48,11 @@ struct badblocks_context {
void ack_all_badblocks(struct badblocks *bb);
ssize_t badblocks_show(struct badblocks *bb, char *page, int unack);
ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len,
---
-2.39.5
-
+++ /dev/null
-From 32000fec7c7f3a5b813eb3317e48ebd84d78ed75 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 26 Feb 2025 19:06:13 +0900
-Subject: null_blk: do partial IO for bad blocks
-
-From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-
-[ Upstream commit 567abc989e3c74c7f4e245492707208c37d27693 ]
-
-The current null_blk implementation checks if any bad blocks exist in
-the target blocks of each IO. If so, the IO fails and data is not
-transferred for all of the IO target blocks. However, when real storage
-devices have bad blocks, the devices may transfer data partially up to
-the first bad blocks (e.g., SAS drives). Especially, when the IO is a
-write operation, such partial IO leaves partially written data on the
-device.
-
-To simulate such partial IO using null_blk, introduce the new parameter
-'badblocks_partial_io'. When this parameter is set,
-null_handle_badblocks() returns the number of the sectors for the
-partial IO as its third pointer argument. Pass the returned number of
-sectors to the following calls to null_handle_memory_backend() in
-null_process_cmd() and null_zone_write().
-
-Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
-Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
-Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
-Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-Link: https://lore.kernel.org/r/20250226100613.1622564-6-shinichiro.kawasaki@wdc.com
-Signed-off-by: Jens Axboe <axboe@kernel.dk>
-Stable-dep-of: d301f164c3fb ("badblocks: use sector_t instead of int to avoid truncation of badblocks length")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/block/null_blk/main.c | 40 ++++++++++++++++++++++++-------
- drivers/block/null_blk/null_blk.h | 4 ++--
- drivers/block/null_blk/zoned.c | 9 ++++---
- 3 files changed, 40 insertions(+), 13 deletions(-)
-
-diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
-index b0b009b1136d5..cca278f1d2ce7 100644
---- a/drivers/block/null_blk/main.c
-+++ b/drivers/block/null_blk/main.c
-@@ -474,6 +474,7 @@ NULLB_DEVICE_ATTR(shared_tag_bitmap, bool, NULL);
- NULLB_DEVICE_ATTR(fua, bool, NULL);
- NULLB_DEVICE_ATTR(rotational, bool, NULL);
- NULLB_DEVICE_ATTR(badblocks_once, bool, NULL);
-+NULLB_DEVICE_ATTR(badblocks_partial_io, bool, NULL);
-
- static ssize_t nullb_device_power_show(struct config_item *item, char *page)
- {
-@@ -595,6 +596,7 @@ CONFIGFS_ATTR_WO(nullb_device_, zone_offline);
- static struct configfs_attribute *nullb_device_attrs[] = {
- &nullb_device_attr_badblocks,
- &nullb_device_attr_badblocks_once,
-+ &nullb_device_attr_badblocks_partial_io,
- &nullb_device_attr_blocking,
- &nullb_device_attr_blocksize,
- &nullb_device_attr_cache_size,
-@@ -1309,19 +1311,40 @@ static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
- return sts;
- }
-
-+/*
-+ * Check if the command should fail for the badblocks. If so, return
-+ * BLK_STS_IOERR and return number of partial I/O sectors to be written or read,
-+ * which may be less than the requested number of sectors.
-+ *
-+ * @cmd: The command to handle.
-+ * @sector: The start sector for I/O.
-+ * @nr_sectors: Specifies number of sectors to write or read, and returns the
-+ * number of sectors to be written or read.
-+ */
- blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, sector_t sector,
-- sector_t nr_sectors)
-+ unsigned int *nr_sectors)
- {
- struct badblocks *bb = &cmd->nq->dev->badblocks;
-+ struct nullb_device *dev = cmd->nq->dev;
-+ unsigned int block_sectors = dev->blocksize >> SECTOR_SHIFT;
- sector_t first_bad;
- int bad_sectors;
-+ unsigned int partial_io_sectors = 0;
-
-- if (!badblocks_check(bb, sector, nr_sectors, &first_bad, &bad_sectors))
-+ if (!badblocks_check(bb, sector, *nr_sectors, &first_bad, &bad_sectors))
- return BLK_STS_OK;
-
- if (cmd->nq->dev->badblocks_once)
- badblocks_clear(bb, first_bad, bad_sectors);
-
-+ if (cmd->nq->dev->badblocks_partial_io) {
-+ if (!IS_ALIGNED(first_bad, block_sectors))
-+ first_bad = ALIGN_DOWN(first_bad, block_sectors);
-+ if (sector < first_bad)
-+ partial_io_sectors = first_bad - sector;
-+ }
-+ *nr_sectors = partial_io_sectors;
-+
- return BLK_STS_IOERR;
- }
-
-@@ -1380,18 +1403,19 @@ blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
- sector_t sector, unsigned int nr_sectors)
- {
- struct nullb_device *dev = cmd->nq->dev;
-+ blk_status_t badblocks_ret = BLK_STS_OK;
- blk_status_t ret;
-
-- if (dev->badblocks.shift != -1) {
-- ret = null_handle_badblocks(cmd, sector, nr_sectors);
-+ if (dev->badblocks.shift != -1)
-+ badblocks_ret = null_handle_badblocks(cmd, sector, &nr_sectors);
-+
-+ if (dev->memory_backed && nr_sectors) {
-+ ret = null_handle_memory_backed(cmd, op, sector, nr_sectors);
- if (ret != BLK_STS_OK)
- return ret;
- }
-
-- if (dev->memory_backed)
-- return null_handle_memory_backed(cmd, op, sector, nr_sectors);
--
-- return BLK_STS_OK;
-+ return badblocks_ret;
- }
-
- static void null_handle_cmd(struct nullb_cmd *cmd, sector_t sector,
-diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
-index ee60f3a887967..7bb6128dbaafb 100644
---- a/drivers/block/null_blk/null_blk.h
-+++ b/drivers/block/null_blk/null_blk.h
-@@ -64,6 +64,7 @@ struct nullb_device {
- unsigned int curr_cache;
- struct badblocks badblocks;
- bool badblocks_once;
-+ bool badblocks_partial_io;
-
- unsigned int nr_zones;
- unsigned int nr_zones_imp_open;
-@@ -133,11 +134,10 @@ blk_status_t null_handle_discard(struct nullb_device *dev, sector_t sector,
- blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
- sector_t sector, unsigned int nr_sectors);
- blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, sector_t sector,
-- sector_t nr_sectors);
-+ unsigned int *nr_sectors);
- blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd, enum req_op op,
- sector_t sector, sector_t nr_sectors);
-
--
- #ifdef CONFIG_BLK_DEV_ZONED
- int null_init_zoned_dev(struct nullb_device *dev, struct queue_limits *lim);
- int null_register_zoned_dev(struct nullb *nullb);
-diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
-index 7677f6cf23f46..4e5728f459899 100644
---- a/drivers/block/null_blk/zoned.c
-+++ b/drivers/block/null_blk/zoned.c
-@@ -353,6 +353,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
- struct nullb_device *dev = cmd->nq->dev;
- unsigned int zno = null_zone_no(dev, sector);
- struct nullb_zone *zone = &dev->zones[zno];
-+ blk_status_t badblocks_ret = BLK_STS_OK;
- blk_status_t ret;
-
- trace_nullb_zone_op(cmd, zno, zone->cond);
-@@ -413,9 +414,11 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
- }
-
- if (dev->badblocks.shift != -1) {
-- ret = null_handle_badblocks(cmd, sector, nr_sectors);
-- if (ret != BLK_STS_OK)
-+ badblocks_ret = null_handle_badblocks(cmd, sector, &nr_sectors);
-+ if (badblocks_ret != BLK_STS_OK && !nr_sectors) {
-+ ret = badblocks_ret;
- goto unlock_zone;
-+ }
- }
-
- if (dev->memory_backed) {
-@@ -438,7 +441,7 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
- zone->cond = BLK_ZONE_COND_FULL;
- }
-
-- ret = BLK_STS_OK;
-+ ret = badblocks_ret;
-
- unlock_zone:
- null_unlock_zone(dev, zone);
---
-2.39.5
-
+++ /dev/null
-From 1a23a8372e02346183b027cf5a4939d7e19a961c Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 26 Feb 2025 19:06:09 +0900
-Subject: null_blk: generate null_blk configfs features string
-
-From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-
-[ Upstream commit 2cadb8ef25a6157b5bd3e8fe0d3e23f32defec25 ]
-
-The null_blk configfs file 'features' provides a string that lists
-available null_blk features for userspace programs to reference.
-The string is defined as a long constant in the code, which tends to be
-forgotten for updates. It also causes checkpatch.pl to report
-"WARNING: quoted string split across lines".
-
-To avoid these drawbacks, generate the feature string on the fly. Refer
-to the ca_name field of each element in the nullb_device_attrs table and
-concatenate them in the given buffer. Also, sorted nullb_device_attrs
-table elements in alphabetical order.
-
-Of note is that the feature "index" was missing before this commit.
-This commit adds it to the generated string.
-
-Suggested-by: Bart Van Assche <bvanassche@acm.org>
-Reviewed-by: Bart Van Assche <bvanassche@acm.org>
-Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
-Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
-Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
-Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-Link: https://lore.kernel.org/r/20250226100613.1622564-2-shinichiro.kawasaki@wdc.com
-Signed-off-by: Jens Axboe <axboe@kernel.dk>
-Stable-dep-of: d301f164c3fb ("badblocks: use sector_t instead of int to avoid truncation of badblocks length")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/block/null_blk/main.c | 86 ++++++++++++++++++++---------------
- 1 file changed, 49 insertions(+), 37 deletions(-)
-
-diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
-index fdc7a0b2af109..18520d0e38c61 100644
---- a/drivers/block/null_blk/main.c
-+++ b/drivers/block/null_blk/main.c
-@@ -592,41 +592,41 @@ static ssize_t nullb_device_zone_offline_store(struct config_item *item,
- CONFIGFS_ATTR_WO(nullb_device_, zone_offline);
-
- static struct configfs_attribute *nullb_device_attrs[] = {
-- &nullb_device_attr_size,
-+ &nullb_device_attr_badblocks,
-+ &nullb_device_attr_blocking,
-+ &nullb_device_attr_blocksize,
-+ &nullb_device_attr_cache_size,
- &nullb_device_attr_completion_nsec,
-- &nullb_device_attr_submit_queues,
-- &nullb_device_attr_poll_queues,
-+ &nullb_device_attr_discard,
-+ &nullb_device_attr_fua,
- &nullb_device_attr_home_node,
-- &nullb_device_attr_queue_mode,
-- &nullb_device_attr_blocksize,
-- &nullb_device_attr_max_sectors,
-- &nullb_device_attr_irqmode,
- &nullb_device_attr_hw_queue_depth,
- &nullb_device_attr_index,
-- &nullb_device_attr_blocking,
-- &nullb_device_attr_use_per_node_hctx,
-- &nullb_device_attr_power,
-- &nullb_device_attr_memory_backed,
-- &nullb_device_attr_discard,
-+ &nullb_device_attr_irqmode,
-+ &nullb_device_attr_max_sectors,
- &nullb_device_attr_mbps,
-- &nullb_device_attr_cache_size,
-- &nullb_device_attr_badblocks,
-- &nullb_device_attr_zoned,
-- &nullb_device_attr_zone_size,
-+ &nullb_device_attr_memory_backed,
-+ &nullb_device_attr_no_sched,
-+ &nullb_device_attr_poll_queues,
-+ &nullb_device_attr_power,
-+ &nullb_device_attr_queue_mode,
-+ &nullb_device_attr_rotational,
-+ &nullb_device_attr_shared_tag_bitmap,
-+ &nullb_device_attr_shared_tags,
-+ &nullb_device_attr_size,
-+ &nullb_device_attr_submit_queues,
-+ &nullb_device_attr_use_per_node_hctx,
-+ &nullb_device_attr_virt_boundary,
-+ &nullb_device_attr_zone_append_max_sectors,
- &nullb_device_attr_zone_capacity,
-- &nullb_device_attr_zone_nr_conv,
-- &nullb_device_attr_zone_max_open,
-+ &nullb_device_attr_zone_full,
- &nullb_device_attr_zone_max_active,
-- &nullb_device_attr_zone_append_max_sectors,
-- &nullb_device_attr_zone_readonly,
-+ &nullb_device_attr_zone_max_open,
-+ &nullb_device_attr_zone_nr_conv,
- &nullb_device_attr_zone_offline,
-- &nullb_device_attr_zone_full,
-- &nullb_device_attr_virt_boundary,
-- &nullb_device_attr_no_sched,
-- &nullb_device_attr_shared_tags,
-- &nullb_device_attr_shared_tag_bitmap,
-- &nullb_device_attr_fua,
-- &nullb_device_attr_rotational,
-+ &nullb_device_attr_zone_readonly,
-+ &nullb_device_attr_zone_size,
-+ &nullb_device_attr_zoned,
- NULL,
- };
-
-@@ -704,16 +704,28 @@ nullb_group_drop_item(struct config_group *group, struct config_item *item)
-
- static ssize_t memb_group_features_show(struct config_item *item, char *page)
- {
-- return snprintf(page, PAGE_SIZE,
-- "badblocks,blocking,blocksize,cache_size,fua,"
-- "completion_nsec,discard,home_node,hw_queue_depth,"
-- "irqmode,max_sectors,mbps,memory_backed,no_sched,"
-- "poll_queues,power,queue_mode,shared_tag_bitmap,"
-- "shared_tags,size,submit_queues,use_per_node_hctx,"
-- "virt_boundary,zoned,zone_capacity,zone_max_active,"
-- "zone_max_open,zone_nr_conv,zone_offline,zone_readonly,"
-- "zone_size,zone_append_max_sectors,zone_full,"
-- "rotational\n");
-+
-+ struct configfs_attribute **entry;
-+ char delimiter = ',';
-+ size_t left = PAGE_SIZE;
-+ size_t written = 0;
-+ int ret;
-+
-+ for (entry = &nullb_device_attrs[0]; *entry && left > 0; entry++) {
-+ if (!*(entry + 1))
-+ delimiter = '\n';
-+ ret = snprintf(page + written, left, "%s%c", (*entry)->ca_name,
-+ delimiter);
-+ if (ret >= left) {
-+ WARN_ONCE(1, "Too many null_blk features to print\n");
-+ memzero_explicit(page, PAGE_SIZE);
-+ return -ENOBUFS;
-+ }
-+ left -= ret;
-+ written += ret;
-+ }
-+
-+ return written;
- }
-
- CONFIGFS_ATTR_RO(memb_group_, features);
---
-2.39.5
-
+++ /dev/null
-From 275d2fac17595f39a6998537703606dead1e9481 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 26 Feb 2025 19:06:10 +0900
-Subject: null_blk: introduce badblocks_once parameter
-
-From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-
-[ Upstream commit 800c24391676143695d284f70af297b28a809886 ]
-
-When IO errors happen on real storage devices, the IOs repeated to the
-same target range can success by virtue of recovery features by devices,
-such as reserved block assignment. To simulate such IO errors and
-recoveries, introduce the new parameter badblocks_once parameter. When
-this parameter is set to 1, the specified badblocks are cleared after
-the first IO error, so that the next IO to the blocks succeed.
-
-Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
-Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
-Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
-Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-Link: https://lore.kernel.org/r/20250226100613.1622564-3-shinichiro.kawasaki@wdc.com
-Signed-off-by: Jens Axboe <axboe@kernel.dk>
-Stable-dep-of: d301f164c3fb ("badblocks: use sector_t instead of int to avoid truncation of badblocks length")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/block/null_blk/main.c | 11 ++++++++---
- drivers/block/null_blk/null_blk.h | 1 +
- 2 files changed, 9 insertions(+), 3 deletions(-)
-
-diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
-index 18520d0e38c61..164c62f20f109 100644
---- a/drivers/block/null_blk/main.c
-+++ b/drivers/block/null_blk/main.c
-@@ -473,6 +473,7 @@ NULLB_DEVICE_ATTR(shared_tags, bool, NULL);
- NULLB_DEVICE_ATTR(shared_tag_bitmap, bool, NULL);
- NULLB_DEVICE_ATTR(fua, bool, NULL);
- NULLB_DEVICE_ATTR(rotational, bool, NULL);
-+NULLB_DEVICE_ATTR(badblocks_once, bool, NULL);
-
- static ssize_t nullb_device_power_show(struct config_item *item, char *page)
- {
-@@ -593,6 +594,7 @@ CONFIGFS_ATTR_WO(nullb_device_, zone_offline);
-
- static struct configfs_attribute *nullb_device_attrs[] = {
- &nullb_device_attr_badblocks,
-+ &nullb_device_attr_badblocks_once,
- &nullb_device_attr_blocking,
- &nullb_device_attr_blocksize,
- &nullb_device_attr_cache_size,
-@@ -1315,10 +1317,13 @@ static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
- sector_t first_bad;
- int bad_sectors;
-
-- if (badblocks_check(bb, sector, nr_sectors, &first_bad, &bad_sectors))
-- return BLK_STS_IOERR;
-+ if (!badblocks_check(bb, sector, nr_sectors, &first_bad, &bad_sectors))
-+ return BLK_STS_OK;
-
-- return BLK_STS_OK;
-+ if (cmd->nq->dev->badblocks_once)
-+ badblocks_clear(bb, first_bad, bad_sectors);
-+
-+ return BLK_STS_IOERR;
- }
-
- static inline blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd,
-diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
-index 6f9fe61710870..3c4c07f0418b0 100644
---- a/drivers/block/null_blk/null_blk.h
-+++ b/drivers/block/null_blk/null_blk.h
-@@ -63,6 +63,7 @@ struct nullb_device {
- unsigned long flags; /* device flags */
- unsigned int curr_cache;
- struct badblocks badblocks;
-+ bool badblocks_once;
-
- unsigned int nr_zones;
- unsigned int nr_zones_imp_open;
---
-2.39.5
-
+++ /dev/null
-From 79be7fe7f31f9ae02a9eeb31f6ac2087f256ad78 Mon Sep 17 00:00:00 2001
-From: Sasha Levin <sashal@kernel.org>
-Date: Wed, 26 Feb 2025 19:06:11 +0900
-Subject: null_blk: replace null_process_cmd() call in null_zone_write()
-
-From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-
-[ Upstream commit 4f235000b1e88934d1e6117dc43ed814710ef4e2 ]
-
-As a preparation to support partial data transfer due to badblocks,
-replace the null_process_cmd() call in null_zone_write() with equivalent
-calls to null_handle_badblocks() and null_handle_memory_backed(). This
-commit does not change behavior. It will enable null_handle_badblocks()
-to return the size of partial data transfer in the following commit,
-allowing null_zone_write() to move write pointers appropriately.
-
-Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
-Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
-Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
-Link: https://lore.kernel.org/r/20250226100613.1622564-4-shinichiro.kawasaki@wdc.com
-Signed-off-by: Jens Axboe <axboe@kernel.dk>
-Stable-dep-of: d301f164c3fb ("badblocks: use sector_t instead of int to avoid truncation of badblocks length")
-Signed-off-by: Sasha Levin <sashal@kernel.org>
----
- drivers/block/null_blk/main.c | 11 ++++-------
- drivers/block/null_blk/null_blk.h | 5 +++++
- drivers/block/null_blk/zoned.c | 15 ++++++++++++---
- 3 files changed, 21 insertions(+), 10 deletions(-)
-
-diff --git a/drivers/block/null_blk/main.c b/drivers/block/null_blk/main.c
-index 164c62f20f109..b0b009b1136d5 100644
---- a/drivers/block/null_blk/main.c
-+++ b/drivers/block/null_blk/main.c
-@@ -1309,9 +1309,8 @@ static inline blk_status_t null_handle_throttled(struct nullb_cmd *cmd)
- return sts;
- }
-
--static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
-- sector_t sector,
-- sector_t nr_sectors)
-+blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, sector_t sector,
-+ sector_t nr_sectors)
- {
- struct badblocks *bb = &cmd->nq->dev->badblocks;
- sector_t first_bad;
-@@ -1326,10 +1325,8 @@ static inline blk_status_t null_handle_badblocks(struct nullb_cmd *cmd,
- return BLK_STS_IOERR;
- }
-
--static inline blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd,
-- enum req_op op,
-- sector_t sector,
-- sector_t nr_sectors)
-+blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd, enum req_op op,
-+ sector_t sector, sector_t nr_sectors)
- {
- struct nullb_device *dev = cmd->nq->dev;
-
-diff --git a/drivers/block/null_blk/null_blk.h b/drivers/block/null_blk/null_blk.h
-index 3c4c07f0418b0..ee60f3a887967 100644
---- a/drivers/block/null_blk/null_blk.h
-+++ b/drivers/block/null_blk/null_blk.h
-@@ -132,6 +132,11 @@ blk_status_t null_handle_discard(struct nullb_device *dev, sector_t sector,
- sector_t nr_sectors);
- blk_status_t null_process_cmd(struct nullb_cmd *cmd, enum req_op op,
- sector_t sector, unsigned int nr_sectors);
-+blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, sector_t sector,
-+ sector_t nr_sectors);
-+blk_status_t null_handle_memory_backed(struct nullb_cmd *cmd, enum req_op op,
-+ sector_t sector, sector_t nr_sectors);
-+
-
- #ifdef CONFIG_BLK_DEV_ZONED
- int null_init_zoned_dev(struct nullb_device *dev, struct queue_limits *lim);
-diff --git a/drivers/block/null_blk/zoned.c b/drivers/block/null_blk/zoned.c
-index 0d5f9bf952292..7677f6cf23f46 100644
---- a/drivers/block/null_blk/zoned.c
-+++ b/drivers/block/null_blk/zoned.c
-@@ -412,9 +412,18 @@ static blk_status_t null_zone_write(struct nullb_cmd *cmd, sector_t sector,
- zone->cond = BLK_ZONE_COND_IMP_OPEN;
- }
-
-- ret = null_process_cmd(cmd, REQ_OP_WRITE, sector, nr_sectors);
-- if (ret != BLK_STS_OK)
-- goto unlock_zone;
-+ if (dev->badblocks.shift != -1) {
-+ ret = null_handle_badblocks(cmd, sector, nr_sectors);
-+ if (ret != BLK_STS_OK)
-+ goto unlock_zone;
-+ }
-+
-+ if (dev->memory_backed) {
-+ ret = null_handle_memory_backed(cmd, REQ_OP_WRITE, sector,
-+ nr_sectors);
-+ if (ret != BLK_STS_OK)
-+ goto unlock_zone;
-+ }
-
- zone->wp += nr_sectors;
- if (zone->wp == zone->start + zone->capacity) {
---
-2.39.5
-
badblocks-fix-the-using-of-max_badblocks.patch
badblocks-fix-merge-issue-when-new-badblocks-align-w.patch
badblocks-fix-missing-bad-blocks-on-retry-in-_badblo.patch
-null_blk-generate-null_blk-configfs-features-string.patch
-null_blk-introduce-badblocks_once-parameter.patch
-null_blk-replace-null_process_cmd-call-in-null_zone_.patch
-null_blk-do-partial-io-for-bad-blocks.patch
badblocks-return-boolean-from-badblocks_set-and-badb.patch
badblocks-use-sector_t-instead-of-int-to-avoid-trunc.patch
firmware-arm_scmi-use-ioread64-instead-of-ioread64_h.patch