Skip to content

Commit 09af773

Browse files
committed
md: add fallback to correct bitmap_ops on version mismatch
If default bitmap version and on-disk version doesn't match, and mdadm is not the latest version to set bitmap_type, set bitmap_ops based on the disk version. Link: https://lore.kernel.org/linux-raid/20260323054644.3351791-2-yukuai@fnnas.com/ Signed-off-by: Yu Kuai <yukuai@fnnas.com>
1 parent b0cc3ae commit 09af773

1 file changed

Lines changed: 110 additions & 1 deletion

File tree

drivers/md/md.c

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6454,15 +6454,124 @@ static void md_safemode_timeout(struct timer_list *t)
64546454

64556455
static int start_dirty_degraded;
64566456

6457+
/*
6458+
* Read bitmap superblock and return the bitmap_id based on disk version.
6459+
* This is used as fallback when default bitmap version and on-disk version
6460+
* doesn't match, and mdadm is not the latest version to set bitmap_type.
6461+
*/
6462+
static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)
6463+
{
6464+
struct md_rdev *rdev;
6465+
struct page *sb_page;
6466+
bitmap_super_t *sb;
6467+
enum md_submodule_id id = ID_BITMAP_NONE;
6468+
sector_t sector;
6469+
u32 version;
6470+
6471+
if (!mddev->bitmap_info.offset)
6472+
return ID_BITMAP_NONE;
6473+
6474+
sb_page = alloc_page(GFP_KERNEL);
6475+
if (!sb_page) {
6476+
pr_warn("md: %s: failed to allocate memory for bitmap\n",
6477+
mdname(mddev));
6478+
return ID_BITMAP_NONE;
6479+
}
6480+
6481+
sector = mddev->bitmap_info.offset;
6482+
6483+
rdev_for_each(rdev, mddev) {
6484+
u32 iosize;
6485+
6486+
if (!test_bit(In_sync, &rdev->flags) ||
6487+
test_bit(Faulty, &rdev->flags) ||
6488+
test_bit(Bitmap_sync, &rdev->flags))
6489+
continue;
6490+
6491+
iosize = roundup(sizeof(bitmap_super_t),
6492+
bdev_logical_block_size(rdev->bdev));
6493+
if (sync_page_io(rdev, sector, iosize, sb_page, REQ_OP_READ,
6494+
true))
6495+
goto read_ok;
6496+
}
6497+
pr_warn("md: %s: failed to read bitmap from any device\n",
6498+
mdname(mddev));
6499+
goto out;
6500+
6501+
read_ok:
6502+
sb = kmap_local_page(sb_page);
6503+
if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) {
6504+
pr_warn("md: %s: invalid bitmap magic 0x%x\n",
6505+
mdname(mddev), le32_to_cpu(sb->magic));
6506+
goto out_unmap;
6507+
}
6508+
6509+
version = le32_to_cpu(sb->version);
6510+
switch (version) {
6511+
case BITMAP_MAJOR_LO:
6512+
case BITMAP_MAJOR_HI:
6513+
case BITMAP_MAJOR_CLUSTERED:
6514+
id = ID_BITMAP;
6515+
break;
6516+
case BITMAP_MAJOR_LOCKLESS:
6517+
id = ID_LLBITMAP;
6518+
break;
6519+
default:
6520+
pr_warn("md: %s: unknown bitmap version %u\n",
6521+
mdname(mddev), version);
6522+
break;
6523+
}
6524+
6525+
out_unmap:
6526+
kunmap_local(sb);
6527+
out:
6528+
__free_page(sb_page);
6529+
return id;
6530+
}
6531+
64576532
static int md_bitmap_create(struct mddev *mddev)
64586533
{
6534+
enum md_submodule_id orig_id = mddev->bitmap_id;
6535+
enum md_submodule_id sb_id;
6536+
int err;
6537+
64596538
if (mddev->bitmap_id == ID_BITMAP_NONE)
64606539
return -EINVAL;
64616540

64626541
if (!mddev_set_bitmap_ops(mddev))
64636542
return -ENOENT;
64646543

6465-
return mddev->bitmap_ops->create(mddev);
6544+
err = mddev->bitmap_ops->create(mddev);
6545+
if (!err)
6546+
return 0;
6547+
6548+
/*
6549+
* Create failed, if default bitmap version and on-disk version
6550+
* doesn't match, and mdadm is not the latest version to set
6551+
* bitmap_type, set bitmap_ops based on the disk version.
6552+
*/
6553+
mddev_clear_bitmap_ops(mddev);
6554+
6555+
sb_id = md_bitmap_get_id_from_sb(mddev);
6556+
if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
6557+
return err;
6558+
6559+
pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n",
6560+
mdname(mddev), orig_id, sb_id);
6561+
6562+
mddev->bitmap_id = sb_id;
6563+
if (!mddev_set_bitmap_ops(mddev)) {
6564+
mddev->bitmap_id = orig_id;
6565+
return -ENOENT;
6566+
}
6567+
6568+
err = mddev->bitmap_ops->create(mddev);
6569+
if (err) {
6570+
mddev_clear_bitmap_ops(mddev);
6571+
mddev->bitmap_id = orig_id;
6572+
}
6573+
6574+
return err;
64666575
}
64676576

64686577
static void md_bitmap_destroy(struct mddev *mddev)

0 commit comments

Comments
 (0)