]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
badblocks: use sector_t instead of int to avoid truncation of badblocks length
authorZheng Qixing <zhengqixing@huawei.com>
Thu, 27 Feb 2025 07:55:07 +0000 (15:55 +0800)
committerJens Axboe <axboe@kernel.dk>
Thu, 6 Mar 2025 15:04:52 +0000 (08:04 -0700)
There is a truncation of badblocks length issue when set badblocks as
follow:

echo "2055 4294967299" > bad_blocks
cat bad_blocks
2055 3

Change 'sectors' argument type from 'int' to 'sector_t'.

This change avoids truncation of badblocks length for large sectors by
replacing 'int' with 'sector_t' (u64), enabling proper handling of larger
disk sizes and ensuring compatibility with 64-bit sector addressing.

Fixes: 9e0e252a048b ("badblocks: Add core badblock management code")
Signed-off-by: Zheng Qixing <zhengqixing@huawei.com>
Reviewed-by: Yu Kuai <yukuai3@huawei.com>
Acked-by: Coly Li <colyli@kernel.org>
Link: https://lore.kernel.org/r/20250227075507.151331-13-zhengqixing@huaweicloud.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/badblocks.c
drivers/block/null_blk/main.c
drivers/md/md.h
drivers/md/raid1-10.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/nvdimm/nd.h
drivers/nvdimm/pfn_devs.c
drivers/nvdimm/pmem.c
include/linux/badblocks.h

index e326a16fd05691e83a8e9ae824ea1a352fd3cf96..673ef068423a66cd1367c37514747a78ded9e6ce 100644 (file)
@@ -836,7 +836,7 @@ static bool try_adjacent_combine(struct badblocks *bb, int prev)
 }
 
 /* Do exact work to set bad block range into the bad block table */
-static bool _badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+static bool _badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors,
                           int acknowledged)
 {
        int len = 0, added = 0;
@@ -956,8 +956,6 @@ update_sectors:
        if (sectors > 0)
                goto re_insert;
 
-       WARN_ON(sectors < 0);
-
        /*
         * Check whether the following already set range can be
         * merged. (prev < 0) condition is not handled here,
@@ -1048,7 +1046,7 @@ static int front_splitting_clear(struct badblocks *bb, int prev,
 }
 
 /* Do the exact work to clear bad block range from the bad block table */
-static bool _badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
+static bool _badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors)
 {
        struct badblocks_context bad;
        int prev = -1, hint = -1;
@@ -1171,8 +1169,6 @@ update_sectors:
        if (sectors > 0)
                goto re_clear;
 
-       WARN_ON(sectors < 0);
-
        if (cleared) {
                badblocks_update_acked(bb);
                set_changed(bb);
@@ -1187,8 +1183,8 @@ update_sectors:
 }
 
 /* Do the exact work to check bad blocks range from the bad block table */
-static int _badblocks_check(struct badblocks *bb, sector_t s, int sectors,
-                           sector_t *first_bad, int *bad_sectors)
+static int _badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors,
+                           sector_t *first_bad, sector_t *bad_sectors)
 {
        int prev = -1, hint = -1, set = 0;
        struct badblocks_context bad;
@@ -1298,8 +1294,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.
  */
-int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
-                       sector_t *first_bad, int *bad_sectors)
+int badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors,
+                       sector_t *first_bad, sector_t *bad_sectors)
 {
        unsigned int seq;
        int rv;
@@ -1341,7 +1337,7 @@ EXPORT_SYMBOL_GPL(badblocks_check);
  *  false: failed to set badblocks (out of space). Parital setting will be
  *  treated as failure.
  */
-bool badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+bool badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors,
                   int acknowledged)
 {
        return _badblocks_set(bb, s, sectors, acknowledged);
@@ -1362,7 +1358,7 @@ EXPORT_SYMBOL_GPL(badblocks_set);
  *  true: success
  *  false: failed to clear badblocks
  */
-bool badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
+bool badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors)
 {
        return _badblocks_clear(bb, s, sectors);
 }
index 8f6025efc54305737dd7bbfc4187635f9cec0918..4a5cd288dc07bc64bf5abd8fb4623845493d2e49 100644 (file)
@@ -1339,8 +1339,7 @@ blk_status_t null_handle_badblocks(struct nullb_cmd *cmd, sector_t sector,
        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))
index 923a0ef51efe273f58d2ac2e2855ff87739fddb3..6edc0f71b7d4b8157b2f8c7c60ad04c7153f2278 100644 (file)
@@ -266,8 +266,8 @@ enum flag_bits {
        Nonrot,                 /* non-rotational device (SSD) */
 };
 
-static inline int is_badblock(struct md_rdev *rdev, sector_t s, int sectors,
-                             sector_t *first_bad, int *bad_sectors)
+static inline int is_badblock(struct md_rdev *rdev, sector_t s, sector_t sectors,
+                             sector_t *first_bad, sector_t *bad_sectors)
 {
        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,
                                    int sectors)
 {
        sector_t first_bad;
-       int bad_sectors;
+       sector_t bad_sectors;
 
        return is_badblock(rdev, s, sectors, &first_bad, &bad_sectors);
 }
index 4378d3250bd757c105fd569b1cf5ba3d890b76ea..62b980b12f93aa0b9ff7cf61b7fa6f7ce4d52b9a 100644 (file)
@@ -247,7 +247,7 @@ static inline int raid1_check_read_range(struct md_rdev *rdev,
                                         sector_t this_sector, int *len)
 {
        sector_t first_bad;
-       int bad_sectors;
+       sector_t bad_sectors;
 
        /* no bad block overlap */
        if (!is_badblock(rdev, this_sector, *len, &first_bad, &bad_sectors))
index 8beb8cccc6af7b7d4a1810aa79d5b14c8f652807..0b2839105857805634298ae3b416afad0f73bb47 100644 (file)
@@ -1537,7 +1537,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
                atomic_inc(&rdev->nr_pending);
                if (test_bit(WriteErrorSeen, &rdev->flags)) {
                        sector_t first_bad;
-                       int bad_sectors;
+                       sector_t bad_sectors;
                        int is_bad;
 
                        is_bad = is_badblock(rdev, r1_bio->sector, max_sectors,
@@ -2886,7 +2886,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
                } else {
                        /* may need to read from here */
                        sector_t first_bad = MaxSector;
-                       int bad_sectors;
+                       sector_t bad_sectors;
 
                        if (is_badblock(rdev, sector_nr, good_sectors,
                                        &first_bad, &bad_sectors)) {
index 7ed933181712edcdead50eefbac388d14d77d320..a8664e29aadadeda902c538693a63b6deb6b2015 100644 (file)
@@ -747,7 +747,7 @@ static struct md_rdev *read_balance(struct r10conf *conf,
 
        for (slot = 0; slot < conf->copies ; slot++) {
                sector_t first_bad;
-               int bad_sectors;
+               sector_t bad_sectors;
                sector_t dev_sector;
                unsigned int pending;
                bool nonrot;
@@ -1438,7 +1438,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
                if (rdev && test_bit(WriteErrorSeen, &rdev->flags)) {
                        sector_t first_bad;
                        sector_t dev_sector = r10_bio->devs[i].addr;
-                       int bad_sectors;
+                       sector_t bad_sectors;
                        int is_bad;
 
                        is_bad = is_badblock(rdev, dev_sector, max_sectors,
@@ -3413,7 +3413,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                                sector_t from_addr, to_addr;
                                struct md_rdev *rdev = conf->mirrors[d].rdev;
                                sector_t sector, first_bad;
-                               int bad_sectors;
+                               sector_t bad_sectors;
                                if (!rdev ||
                                    !test_bit(In_sync, &rdev->flags))
                                        continue;
@@ -3609,7 +3609,7 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
                for (i = 0; i < conf->copies; i++) {
                        int d = r10_bio->devs[i].devnum;
                        sector_t first_bad, sector;
-                       int bad_sectors;
+                       sector_t bad_sectors;
                        struct md_rdev *rdev;
 
                        if (r10_bio->devs[i].repl_bio)
index 5ca06e9a2d2925859db8d99597550ebc4f75e061..cc5c8f3f81e8d4c81ee586681cf6fc2606a6d474 100644 (file)
@@ -673,7 +673,7 @@ static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector,
 {
        if (bb->count) {
                sector_t first_bad;
-               int num_bad;
+               sector_t num_bad;
 
                return !!badblocks_check(bb, sector, len / 512, &first_bad,
                                &num_bad);
index cfdfe0eaa51210d98a0985fe3c897ffef4f51c74..8f3e816e805d88ec419108079c6dca5675734e0b 100644 (file)
@@ -367,9 +367,10 @@ static int nd_pfn_clear_memmap_errors(struct nd_pfn *nd_pfn)
        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;
-       int num_bad, meta_num, rc, bb_present;
+       int meta_num, rc, bb_present;
        sector_t first_bad, meta_start;
        struct nd_namespace_io *nsio;
+       sector_t num_bad;
 
        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)
                bb_present = badblocks_check(&nd_region->bb, meta_start,
                                meta_num, &first_bad, &num_bad);
                if (bb_present) {
-                       dev_dbg(&nd_pfn->dev, "meta: %x badblocks at %llx\n",
+                       dev_dbg(&nd_pfn->dev, "meta: %llx badblocks at %llx\n",
                                        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)
                        }
                        if (rc) {
                                dev_err(&nd_pfn->dev,
-                                       "error clearing %x badblocks at %llx\n",
+                                       "error clearing %llx badblocks at %llx\n",
                                        num_bad, first_bad);
                                return rc;
                        }
index d81faa9d89c935285450e69574695b5a13bf2c7c..43156e1576c939280eea123e270e65a27e828f90 100644 (file)
@@ -249,7 +249,7 @@ __weak long __pmem_direct_access(struct pmem_device *pmem, pgoff_t pgoff,
        unsigned int num = PFN_PHYS(nr_pages) >> SECTOR_SHIFT;
        struct badblocks *bb = &pmem->bb;
        sector_t first_bad;
-       int num_bad;
+       sector_t num_bad;
 
        if (kaddr)
                *kaddr = pmem->virt_addr + offset;
index 8764bed9ff167d84c2e2b49f18f0e8bc2f766628..996493917f366e0fa690cb32c9c256214f405159 100644 (file)
@@ -48,11 +48,11 @@ struct badblocks_context {
        int             ack;
 };
 
-int badblocks_check(struct badblocks *bb, sector_t s, int sectors,
-                  sector_t *first_bad, int *bad_sectors);
-bool badblocks_set(struct badblocks *bb, sector_t s, int sectors,
+int badblocks_check(struct badblocks *bb, sector_t s, sector_t sectors,
+                   sector_t *first_bad, sector_t *bad_sectors);
+bool badblocks_set(struct badblocks *bb, sector_t s, sector_t sectors,
                   int acknowledged);
-bool badblocks_clear(struct badblocks *bb, sector_t s, int sectors);
+bool badblocks_clear(struct badblocks *bb, sector_t s, sector_t sectors);
 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,