Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40d43c4b authored by Heinz Mauelshagen's avatar Heinz Mauelshagen Committed by Mike Snitzer
Browse files

dm raid: ensure superblock's size matches device's logical block size



The dm-raid superblock (struct dm_raid_superblock) is padded to 512
bytes and that size is being used to read it in from the metadata
device into one preallocated page.

Reading or writing this on a 512-byte sector device works fine but on
a 4096-byte sector device this fails.

Set the dm-raid superblock's size to the logical block size of the
metadata device, because IO at that size is guaranteed too work.  Also
add a size check to avoid silent partial metadata loss in case the
superblock should ever grow past the logical block size or PAGE_SIZE.

[includes pointer math fix from Dan Carpenter]
Reported-by: default avatar"Liuhua Wang" <lwang@suse.com>
Signed-off-by: default avatarHeinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: default avatarDan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
Cc: stable@vger.kernel.org
parent 9d28eb12
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -789,8 +789,7 @@ struct dm_raid_superblock {
	__le32 layout;
	__le32 stripe_sectors;

	__u8 pad[452];		/* Round struct to 512 bytes. */
				/* Always set to 0 when writing. */
	/* Remainder of a logical block is zero-filled when writing (see super_sync()). */
} __packed;

static int read_disk_sb(struct md_rdev *rdev, int size)
@@ -827,7 +826,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev)
		    test_bit(Faulty, &(rs->dev[i].rdev.flags)))
			failed_devices |= (1ULL << i);

	memset(sb, 0, sizeof(*sb));
	memset(sb + 1, 0, rdev->sb_size - sizeof(*sb));

	sb->magic = cpu_to_le32(DM_RAID_MAGIC);
	sb->features = cpu_to_le32(0);	/* No features yet */
@@ -862,7 +861,11 @@ static int super_load(struct md_rdev *rdev, struct md_rdev *refdev)
	uint64_t events_sb, events_refsb;

	rdev->sb_start = 0;
	rdev->sb_size = sizeof(*sb);
	rdev->sb_size = bdev_logical_block_size(rdev->meta_bdev);
	if (rdev->sb_size < sizeof(*sb) || rdev->sb_size > PAGE_SIZE) {
		DMERR("superblock size of a logical block is no longer valid");
		return -EINVAL;
	}

	ret = read_disk_sb(rdev, rdev->sb_size);
	if (ret)