diff options
author | Heinz Mauelshagen <heinzm@redhat.com> | 2014-10-17 13:38:50 +0200 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2014-12-14 16:23:49 +0000 |
commit | bfe9c9984fa995f4671ad4ea0cc994271b6d1bc5 (patch) | |
tree | 39d5afd8b6ee9654d0a6d915107c9d1bfb9d36d4 /drivers/md/dm-raid.c | |
parent | c342e03d3f853c019613ec5a2d1a24ae46014c87 (diff) | |
download | kernel_samsung_smdk4412-bfe9c9984fa995f4671ad4ea0cc994271b6d1bc5.zip kernel_samsung_smdk4412-bfe9c9984fa995f4671ad4ea0cc994271b6d1bc5.tar.gz kernel_samsung_smdk4412-bfe9c9984fa995f4671ad4ea0cc994271b6d1bc5.tar.bz2 |
dm raid: ensure superblock's size matches device's logical block size
commit 40d43c4b4cac4c2647bf07110d7b07d35f399a84 upstream.
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: "Liuhua Wang" <lwang@suse.com>
Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'drivers/md/dm-raid.c')
-rw-r--r-- | drivers/md/dm-raid.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c index 86862ea..8158f63 100644 --- a/drivers/md/dm-raid.c +++ b/drivers/md/dm-raid.c @@ -591,8 +591,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) @@ -625,7 +624,7 @@ static void super_sync(struct mddev *mddev, struct md_rdev *rdev) if ((r->raid_disk >= 0) && test_bit(Faulty, &r->flags)) failed_devices |= (1ULL << r->raid_disk); - 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 */ @@ -660,7 +659,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) |