Commit 2bf071bf authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds

[PATCH] md: keep better track of dev/array size when assembling md arrays

Move the checks - that dev size is never less than array size - into
bind_rdev_to_array to make sure it always happens properly (there is one place
where currently it doesn't).

Also reject any superblock which claims an array size smaller than the device
in question can hold.
Signed-off-by: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent da943b99
...@@ -695,6 +695,10 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version ...@@ -695,6 +695,10 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version
} }
rdev->size = calc_dev_size(rdev, sb->chunk_size); rdev->size = calc_dev_size(rdev, sb->chunk_size);
if (rdev->size < sb->size && sb->level > 1)
/* "this cannot possibly happen" ... */
ret = -EINVAL;
abort: abort:
return ret; return ret;
} }
...@@ -1039,6 +1043,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) ...@@ -1039,6 +1043,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
rdev->size = le64_to_cpu(sb->data_size)/2; rdev->size = le64_to_cpu(sb->data_size)/2;
if (le32_to_cpu(sb->chunksize)) if (le32_to_cpu(sb->chunksize))
rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1); rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1);
if (le32_to_cpu(sb->size) > rdev->size*2)
return -EINVAL;
return 0; return 0;
} }
...@@ -1224,6 +1231,14 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) ...@@ -1224,6 +1231,14 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
MD_BUG(); MD_BUG();
return -EINVAL; return -EINVAL;
} }
/* make sure rdev->size exceeds mddev->size */
if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) {
if (mddev->pers)
/* Cannot change size, so fail */
return -ENOSPC;
else
mddev->size = rdev->size;
}
same_pdev = match_dev_unit(mddev, rdev); same_pdev = match_dev_unit(mddev, rdev);
if (same_pdev) if (same_pdev)
printk(KERN_WARNING printk(KERN_WARNING
...@@ -2898,12 +2913,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) ...@@ -2898,12 +2913,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
if (info->state & (1<<MD_DISK_WRITEMOSTLY)) if (info->state & (1<<MD_DISK_WRITEMOSTLY))
set_bit(WriteMostly, &rdev->flags); set_bit(WriteMostly, &rdev->flags);
err = bind_rdev_to_array(rdev, mddev);
if (err) {
export_rdev(rdev);
return err;
}
if (!mddev->persistent) { if (!mddev->persistent) {
printk(KERN_INFO "md: nonpersistent superblock ...\n"); printk(KERN_INFO "md: nonpersistent superblock ...\n");
rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
...@@ -2911,8 +2920,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) ...@@ -2911,8 +2920,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
rdev->sb_offset = calc_dev_sboffset(rdev->bdev); rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
rdev->size = calc_dev_size(rdev, mddev->chunk_size); rdev->size = calc_dev_size(rdev, mddev->chunk_size);
if (!mddev->size || (mddev->size > rdev->size)) err = bind_rdev_to_array(rdev, mddev);
mddev->size = rdev->size; if (err) {
export_rdev(rdev);
return err;
}
} }
return 0; return 0;
...@@ -2984,15 +2996,6 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) ...@@ -2984,15 +2996,6 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
size = calc_dev_size(rdev, mddev->chunk_size); size = calc_dev_size(rdev, mddev->chunk_size);
rdev->size = size; rdev->size = size;
if (size < mddev->size) {
printk(KERN_WARNING
"%s: disk size %llu blocks < array size %llu\n",
mdname(mddev), (unsigned long long)size,
(unsigned long long)mddev->size);
err = -ENOSPC;
goto abort_export;
}
if (test_bit(Faulty, &rdev->flags)) { if (test_bit(Faulty, &rdev->flags)) {
printk(KERN_WARNING printk(KERN_WARNING
"md: can not hot-add faulty %s disk to %s!\n", "md: can not hot-add faulty %s disk to %s!\n",
...@@ -3002,7 +3005,9 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev) ...@@ -3002,7 +3005,9 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
} }
clear_bit(In_sync, &rdev->flags); clear_bit(In_sync, &rdev->flags);
rdev->desc_nr = -1; rdev->desc_nr = -1;
bind_rdev_to_array(rdev, mddev); err = bind_rdev_to_array(rdev, mddev);
if (err)
goto abort_export;
/* /*
* The rest should better be atomic, we can have disk failures * The rest should better be atomic, we can have disk failures
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment