aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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