Commit d301f164 authored by Zheng Qixing's avatar Zheng Qixing Committed by Jens Axboe
Browse files

badblocks: use sector_t instead of int to avoid truncation of badblocks length



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: 9e0e252a ("badblocks: Add core badblock management code")
Signed-off-by: default avatarZheng Qixing <zhengqixing@huawei.com>
Reviewed-by: default avatarYu Kuai <yukuai3@huawei.com>
Acked-by: default avatarColy Li <colyli@kernel.org>
Link: https://lore.kernel.org/r/20250227075507.151331-13-zhengqixing@huaweicloud.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 7e5102dd
Loading
Loading
Loading
Loading
+8 −12
Original line number Diff line number Diff line
@@ -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 @@ static bool _badblocks_set(struct badblocks *bb, sector_t s, int 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 @@ static bool _badblocks_clear(struct badblocks *bb, sector_t s, int sectors)
	if (sectors > 0)
		goto re_clear;

	WARN_ON(sectors < 0);

	if (cleared) {
		badblocks_update_acked(bb);
		set_changed(bb);
@@ -1187,8 +1183,8 @@ static bool _badblocks_clear(struct badblocks *bb, sector_t s, int 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 @@ static int _badblocks_check(struct badblocks *bb, sector_t s, int 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);
}
+1 −2
Original line number Diff line number Diff line
@@ -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))
+3 −3
Original line number Diff line number Diff line
@@ -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);
}
+1 −1
Original line number Diff line number Diff line
@@ -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))
+2 −2
Original line number Diff line number Diff line
@@ -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)) {
Loading