diff options
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r-- | drivers/md/md.c | 100 |
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 | ||
660 | struct super_type { | 660 | struct 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 | */ | ||
1012 | static unsigned long long | ||
1013 | super_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 | ||
1355 | static unsigned long long | ||
1356 | super_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 | ||
1332 | static struct super_type super_types[] = { | 1392 | static 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 |