aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorChris Webb <chris@arachsys.com>2008-06-27 18:31:46 -0400
committerNeil Brown <neilb@notabene.brown>2008-06-27 18:31:46 -0400
commit0cd17fec983b6bca505eecee1af33138687220b6 (patch)
tree0b2209223c9aeeff0415e9a11c58f8801607006b /drivers/md
parent526647320e696f434647f38421a6ecf65b859c43 (diff)
Support changing rdev size on running arrays.
From: Chris Webb <chris@arachsys.com> Allow /sys/block/mdX/md/rdY/size to change on running arrays, moving the superblock if necessary for this metadata version. We prevent the available space from shrinking to less than the used size, and allow it to be set to zero to fill all the available space on the underlying device. Signed-off-by: Chris Webb <chris@arachsys.com> Signed-off-by: Neil Brown <neilb@suse.de>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/md.c100
1 files changed, 87 insertions, 13 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index dc99d95a1b6d..df1230af02cd 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -658,11 +658,14 @@ static unsigned int calc_sb_csum(mdp_super_t * sb)
658 */ 658 */
659 659
660struct super_type { 660struct super_type {
661 char *name; 661 char *name;
662 struct module *owner; 662 struct module *owner;
663 int (*load_super)(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version); 663 int (*load_super)(mdk_rdev_t *rdev, mdk_rdev_t *refdev,
664 int (*validate_super)(mddev_t *mddev, mdk_rdev_t *rdev); 664 int minor_version);
665 void (*sync_super)(mddev_t *mddev, mdk_rdev_t *rdev); 665 int (*validate_super)(mddev_t *mddev, mdk_rdev_t *rdev);
666 void (*sync_super)(mddev_t *mddev, mdk_rdev_t *rdev);
667 unsigned long long (*rdev_size_change)(mdk_rdev_t *rdev,
668 unsigned long long size);
666}; 669};
667 670
668/* 671/*
@@ -1004,6 +1007,27 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
1004} 1007}
1005 1008
1006/* 1009/*
1010 * rdev_size_change for 0.90.0
1011 */
1012static unsigned long long
1013super_90_rdev_size_change(mdk_rdev_t *rdev, unsigned long long size)
1014{
1015 if (size && size < rdev->mddev->size)
1016 return 0; /* component must fit device */
1017 size *= 2; /* convert to sectors */
1018 if (rdev->mddev->bitmap_offset)
1019 return 0; /* can't move bitmap */
1020 rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
1021 if (!size || size > rdev->sb_offset*2)
1022 size = rdev->sb_offset*2;
1023 md_super_write(rdev->mddev, rdev, rdev->sb_offset << 1, rdev->sb_size,
1024 rdev->sb_page);
1025 md_super_wait(rdev->mddev);
1026 return size/2; /* kB for sysfs */
1027}
1028
1029
1030/*
1007 * version 1 superblock 1031 * version 1 superblock
1008 */ 1032 */
1009 1033
@@ -1328,21 +1352,59 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
1328 sb->sb_csum = calc_sb_1_csum(sb); 1352 sb->sb_csum = calc_sb_1_csum(sb);
1329} 1353}
1330 1354
1355static unsigned long long
1356super_1_rdev_size_change(mdk_rdev_t *rdev, unsigned long long size)
1357{
1358 struct mdp_superblock_1 *sb;
1359 unsigned long long max_size;
1360 if (size && size < rdev->mddev->size)
1361 return 0; /* component must fit device */
1362 size *= 2; /* convert to sectors */
1363 if (rdev->sb_offset < rdev->data_offset/2) {
1364 /* minor versions 1 and 2; superblock before data */
1365 max_size = (rdev->bdev->bd_inode->i_size >> 9);
1366 max_size -= rdev->data_offset;
1367 if (!size || size > max_size)
1368 size = max_size;
1369 } else if (rdev->mddev->bitmap_offset) {
1370 /* minor version 0 with bitmap we can't move */
1371 return 0;
1372 } else {
1373 /* minor version 0; superblock after data */
1374 sector_t sb_offset;
1375 sb_offset = (rdev->bdev->bd_inode->i_size >> 9) - 8*2;
1376 sb_offset &= ~(sector_t)(4*2 - 1);
1377 max_size = rdev->size*2 + sb_offset - rdev->sb_offset*2;
1378 if (!size || size > max_size)
1379 size = max_size;
1380 rdev->sb_offset = sb_offset/2;
1381 }
1382 sb = (struct mdp_superblock_1 *) page_address(rdev->sb_page);
1383 sb->data_size = cpu_to_le64(size);
1384 sb->super_offset = rdev->sb_offset*2;
1385 sb->sb_csum = calc_sb_1_csum(sb);
1386 md_super_write(rdev->mddev, rdev, rdev->sb_offset << 1, rdev->sb_size,
1387 rdev->sb_page);
1388 md_super_wait(rdev->mddev);
1389 return size/2; /* kB for sysfs */
1390}
1331 1391
1332static struct super_type super_types[] = { 1392static struct super_type super_types[] = {
1333 [0] = { 1393 [0] = {
1334 .name = "0.90.0", 1394 .name = "0.90.0",
1335 .owner = THIS_MODULE, 1395 .owner = THIS_MODULE,
1336 .load_super = super_90_load, 1396 .load_super = super_90_load,
1337 .validate_super = super_90_validate, 1397 .validate_super = super_90_validate,
1338 .sync_super = super_90_sync, 1398 .sync_super = super_90_sync,
1399 .rdev_size_change = super_90_rdev_size_change,
1339 }, 1400 },
1340 [1] = { 1401 [1] = {
1341 .name = "md-1", 1402 .name = "md-1",
1342 .owner = THIS_MODULE, 1403 .owner = THIS_MODULE,
1343 .load_super = super_1_load, 1404 .load_super = super_1_load,
1344 .validate_super = super_1_validate, 1405 .validate_super = super_1_validate,
1345 .sync_super = super_1_sync, 1406 .sync_super = super_1_sync,
1407 .rdev_size_change = super_1_rdev_size_change,
1346 }, 1408 },
1347}; 1409};
1348 1410
@@ -2060,8 +2122,20 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
2060 2122
2061 if (e==buf || (*e && *e != '\n')) 2123 if (e==buf || (*e && *e != '\n'))
2062 return -EINVAL; 2124 return -EINVAL;
2063 if (my_mddev->pers && rdev->raid_disk >= 0) 2125 if (my_mddev->pers && rdev->raid_disk >= 0) {
2064 return -EBUSY; 2126 if (rdev->mddev->persistent) {
2127 size = super_types[rdev->mddev->major_version].
2128 rdev_size_change(rdev, size);
2129 if (!size)
2130 return -EBUSY;
2131 } else if (!size) {
2132 size = (rdev->bdev->bd_inode->i_size >> 10);
2133 size -= rdev->data_offset/2;
2134 }
2135 if (size < rdev->mddev->size)
2136 return -EINVAL; /* component must fit device */
2137 }
2138
2065 rdev->size = size; 2139 rdev->size = size;
2066 if (size > oldsize && rdev->mddev->external) { 2140 if (size > oldsize && rdev->mddev->external) {
2067 /* need to check that all other rdevs with the same ->bdev 2141 /* need to check that all other rdevs with the same ->bdev