diff options
-rw-r--r-- | drivers/md/md.c | 112 | ||||
-rw-r--r-- | drivers/md/md.h | 3 | ||||
-rw-r--r-- | drivers/md/raid0.c | 2 | ||||
-rw-r--r-- | drivers/md/raid1.c | 6 | ||||
-rw-r--r-- | drivers/md/raid10.c | 2 | ||||
-rw-r--r-- | drivers/md/raid5.c | 9 |
6 files changed, 121 insertions, 13 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c index 76ba69b31d6a..923d1250b9a9 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -387,6 +387,11 @@ static inline int mddev_lock(mddev_t * mddev) | |||
387 | return mutex_lock_interruptible(&mddev->reconfig_mutex); | 387 | return mutex_lock_interruptible(&mddev->reconfig_mutex); |
388 | } | 388 | } |
389 | 389 | ||
390 | static inline int mddev_is_locked(mddev_t *mddev) | ||
391 | { | ||
392 | return mutex_is_locked(&mddev->reconfig_mutex); | ||
393 | } | ||
394 | |||
390 | static inline int mddev_trylock(mddev_t * mddev) | 395 | static inline int mddev_trylock(mddev_t * mddev) |
391 | { | 396 | { |
392 | return mutex_trylock(&mddev->reconfig_mutex); | 397 | return mutex_trylock(&mddev->reconfig_mutex); |
@@ -2282,16 +2287,34 @@ static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2) | |||
2282 | return 1; | 2287 | return 1; |
2283 | } | 2288 | } |
2284 | 2289 | ||
2290 | static int strict_blocks_to_sectors(const char *buf, sector_t *sectors) | ||
2291 | { | ||
2292 | unsigned long long blocks; | ||
2293 | sector_t new; | ||
2294 | |||
2295 | if (strict_strtoull(buf, 10, &blocks) < 0) | ||
2296 | return -EINVAL; | ||
2297 | |||
2298 | if (blocks & 1ULL << (8 * sizeof(blocks) - 1)) | ||
2299 | return -EINVAL; /* sector conversion overflow */ | ||
2300 | |||
2301 | new = blocks * 2; | ||
2302 | if (new != blocks * 2) | ||
2303 | return -EINVAL; /* unsigned long long to sector_t overflow */ | ||
2304 | |||
2305 | *sectors = new; | ||
2306 | return 0; | ||
2307 | } | ||
2308 | |||
2285 | static ssize_t | 2309 | static ssize_t |
2286 | rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) | 2310 | rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) |
2287 | { | 2311 | { |
2288 | mddev_t *my_mddev = rdev->mddev; | 2312 | mddev_t *my_mddev = rdev->mddev; |
2289 | sector_t oldsectors = rdev->sectors; | 2313 | sector_t oldsectors = rdev->sectors; |
2290 | unsigned long long sectors; | 2314 | sector_t sectors; |
2291 | 2315 | ||
2292 | if (strict_strtoull(buf, 10, §ors) < 0) | 2316 | if (strict_blocks_to_sectors(buf, §ors) < 0) |
2293 | return -EINVAL; | 2317 | return -EINVAL; |
2294 | sectors *= 2; | ||
2295 | if (my_mddev->pers && rdev->raid_disk >= 0) { | 2318 | if (my_mddev->pers && rdev->raid_disk >= 0) { |
2296 | if (my_mddev->persistent) { | 2319 | if (my_mddev->persistent) { |
2297 | sectors = super_types[my_mddev->major_version]. | 2320 | sectors = super_types[my_mddev->major_version]. |
@@ -3182,12 +3205,11 @@ size_store(mddev_t *mddev, const char *buf, size_t len) | |||
3182 | * not increase it (except from 0). | 3205 | * not increase it (except from 0). |
3183 | * If array is active, we can try an on-line resize | 3206 | * If array is active, we can try an on-line resize |
3184 | */ | 3207 | */ |
3185 | unsigned long long sectors; | 3208 | sector_t sectors; |
3186 | int err = strict_strtoull(buf, 10, §ors); | 3209 | int err = strict_blocks_to_sectors(buf, §ors); |
3187 | 3210 | ||
3188 | if (err < 0) | 3211 | if (err < 0) |
3189 | return err; | 3212 | return err; |
3190 | sectors *= 2; | ||
3191 | if (mddev->pers) { | 3213 | if (mddev->pers) { |
3192 | err = update_size(mddev, sectors); | 3214 | err = update_size(mddev, sectors); |
3193 | md_update_sb(mddev, 1); | 3215 | md_update_sb(mddev, 1); |
@@ -3627,6 +3649,57 @@ static struct md_sysfs_entry md_reshape_position = | |||
3627 | __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show, | 3649 | __ATTR(reshape_position, S_IRUGO|S_IWUSR, reshape_position_show, |
3628 | reshape_position_store); | 3650 | reshape_position_store); |
3629 | 3651 | ||
3652 | static ssize_t | ||
3653 | array_size_show(mddev_t *mddev, char *page) | ||
3654 | { | ||
3655 | if (mddev->external_size) | ||
3656 | return sprintf(page, "%llu\n", | ||
3657 | (unsigned long long)mddev->array_sectors/2); | ||
3658 | else | ||
3659 | return sprintf(page, "default\n"); | ||
3660 | } | ||
3661 | |||
3662 | static ssize_t | ||
3663 | array_size_store(mddev_t *mddev, const char *buf, size_t len) | ||
3664 | { | ||
3665 | sector_t sectors; | ||
3666 | |||
3667 | if (strncmp(buf, "default", 7) == 0) { | ||
3668 | if (mddev->pers) | ||
3669 | sectors = mddev->pers->size(mddev, 0, 0); | ||
3670 | else | ||
3671 | sectors = mddev->array_sectors; | ||
3672 | |||
3673 | mddev->external_size = 0; | ||
3674 | } else { | ||
3675 | if (strict_blocks_to_sectors(buf, §ors) < 0) | ||
3676 | return -EINVAL; | ||
3677 | if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) | ||
3678 | return -EINVAL; | ||
3679 | |||
3680 | mddev->external_size = 1; | ||
3681 | } | ||
3682 | |||
3683 | mddev->array_sectors = sectors; | ||
3684 | set_capacity(mddev->gendisk, mddev->array_sectors); | ||
3685 | if (mddev->pers) { | ||
3686 | struct block_device *bdev = bdget_disk(mddev->gendisk, 0); | ||
3687 | |||
3688 | if (bdev) { | ||
3689 | mutex_lock(&bdev->bd_inode->i_mutex); | ||
3690 | i_size_write(bdev->bd_inode, | ||
3691 | (loff_t)mddev->array_sectors << 9); | ||
3692 | mutex_unlock(&bdev->bd_inode->i_mutex); | ||
3693 | bdput(bdev); | ||
3694 | } | ||
3695 | } | ||
3696 | |||
3697 | return len; | ||
3698 | } | ||
3699 | |||
3700 | static struct md_sysfs_entry md_array_size = | ||
3701 | __ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show, | ||
3702 | array_size_store); | ||
3630 | 3703 | ||
3631 | static struct attribute *md_default_attrs[] = { | 3704 | static struct attribute *md_default_attrs[] = { |
3632 | &md_level.attr, | 3705 | &md_level.attr, |
@@ -3640,6 +3713,7 @@ static struct attribute *md_default_attrs[] = { | |||
3640 | &md_safe_delay.attr, | 3713 | &md_safe_delay.attr, |
3641 | &md_array_state.attr, | 3714 | &md_array_state.attr, |
3642 | &md_reshape_position.attr, | 3715 | &md_reshape_position.attr, |
3716 | &md_array_size.attr, | ||
3643 | NULL, | 3717 | NULL, |
3644 | }; | 3718 | }; |
3645 | 3719 | ||
@@ -4045,7 +4119,17 @@ static int do_md_run(mddev_t * mddev) | |||
4045 | err = mddev->pers->run(mddev); | 4119 | err = mddev->pers->run(mddev); |
4046 | if (err) | 4120 | if (err) |
4047 | printk(KERN_ERR "md: pers->run() failed ...\n"); | 4121 | printk(KERN_ERR "md: pers->run() failed ...\n"); |
4048 | else if (mddev->pers->sync_request) { | 4122 | else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) { |
4123 | WARN_ONCE(!mddev->external_size, "%s: default size too small," | ||
4124 | " but 'external_size' not in effect?\n", __func__); | ||
4125 | printk(KERN_ERR | ||
4126 | "md: invalid array_size %llu > default size %llu\n", | ||
4127 | (unsigned long long)mddev->array_sectors / 2, | ||
4128 | (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2); | ||
4129 | err = -EINVAL; | ||
4130 | mddev->pers->stop(mddev); | ||
4131 | } | ||
4132 | if (err == 0 && mddev->pers->sync_request) { | ||
4049 | err = bitmap_create(mddev); | 4133 | err = bitmap_create(mddev); |
4050 | if (err) { | 4134 | if (err) { |
4051 | printk(KERN_ERR "%s: failed to create bitmap (%d)\n", | 4135 | printk(KERN_ERR "%s: failed to create bitmap (%d)\n", |
@@ -4281,6 +4365,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open) | |||
4281 | export_array(mddev); | 4365 | export_array(mddev); |
4282 | 4366 | ||
4283 | mddev->array_sectors = 0; | 4367 | mddev->array_sectors = 0; |
4368 | mddev->external_size = 0; | ||
4284 | mddev->dev_sectors = 0; | 4369 | mddev->dev_sectors = 0; |
4285 | mddev->raid_disks = 0; | 4370 | mddev->raid_disks = 0; |
4286 | mddev->recovery_cp = 0; | 4371 | mddev->recovery_cp = 0; |
@@ -4979,10 +5064,23 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) | |||
4979 | 5064 | ||
4980 | void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors) | 5065 | void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors) |
4981 | { | 5066 | { |
5067 | WARN(!mddev_is_locked(mddev), "%s: unlocked mddev!\n", __func__); | ||
5068 | |||
5069 | if (mddev->external_size) | ||
5070 | return; | ||
5071 | |||
4982 | mddev->array_sectors = array_sectors; | 5072 | mddev->array_sectors = array_sectors; |
4983 | } | 5073 | } |
4984 | EXPORT_SYMBOL(md_set_array_sectors); | 5074 | EXPORT_SYMBOL(md_set_array_sectors); |
4985 | 5075 | ||
5076 | void md_set_array_sectors_lock(mddev_t *mddev, sector_t array_sectors) | ||
5077 | { | ||
5078 | mddev_lock(mddev); | ||
5079 | md_set_array_sectors(mddev, array_sectors); | ||
5080 | mddev_unlock(mddev); | ||
5081 | } | ||
5082 | EXPORT_SYMBOL(md_set_array_sectors_lock); | ||
5083 | |||
4986 | static int update_size(mddev_t *mddev, sector_t num_sectors) | 5084 | static int update_size(mddev_t *mddev, sector_t num_sectors) |
4987 | { | 5085 | { |
4988 | mdk_rdev_t *rdev; | 5086 | mdk_rdev_t *rdev; |
diff --git a/drivers/md/md.h b/drivers/md/md.h index ce89dda24074..d13e34f842e2 100644 --- a/drivers/md/md.h +++ b/drivers/md/md.h | |||
@@ -147,6 +147,8 @@ struct mddev_s | |||
147 | sector_t dev_sectors; /* used size of | 147 | sector_t dev_sectors; /* used size of |
148 | * component devices */ | 148 | * component devices */ |
149 | sector_t array_sectors; /* exported array size */ | 149 | sector_t array_sectors; /* exported array size */ |
150 | int external_size; /* size managed | ||
151 | * externally */ | ||
150 | __u64 events; | 152 | __u64 events; |
151 | 153 | ||
152 | char uuid[16]; | 154 | char uuid[16]; |
@@ -431,3 +433,4 @@ extern void md_new_event(mddev_t *mddev); | |||
431 | extern int md_allow_write(mddev_t *mddev); | 433 | extern int md_allow_write(mddev_t *mddev); |
432 | extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); | 434 | extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); |
433 | extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); | 435 | extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); |
436 | extern void md_set_array_sectors_lock(mddev_t *mddev, sector_t array_sectors); | ||
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 6f7e538c8763..c08d7559be55 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c | |||
@@ -313,7 +313,7 @@ static int raid0_run (mddev_t *mddev) | |||
313 | printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n", | 313 | printk(KERN_INFO "raid0 : conf->spacing is %llu sectors.\n", |
314 | (unsigned long long)conf->spacing); | 314 | (unsigned long long)conf->spacing); |
315 | { | 315 | { |
316 | sector_t s = mddev->array_sectors; | 316 | sector_t s = raid0_size(mddev, 0, 0); |
317 | sector_t space = conf->spacing; | 317 | sector_t space = conf->spacing; |
318 | int round; | 318 | int round; |
319 | conf->sector_shift = 0; | 319 | conf->sector_shift = 0; |
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 044116b53f7a..b4f4badc0068 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c | |||
@@ -2125,14 +2125,16 @@ static int raid1_resize(mddev_t *mddev, sector_t sectors) | |||
2125 | * worth it. | 2125 | * worth it. |
2126 | */ | 2126 | */ |
2127 | md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0)); | 2127 | md_set_array_sectors(mddev, raid1_size(mddev, sectors, 0)); |
2128 | if (mddev->array_sectors > raid1_size(mddev, sectors, 0)) | ||
2129 | return -EINVAL; | ||
2128 | set_capacity(mddev->gendisk, mddev->array_sectors); | 2130 | set_capacity(mddev->gendisk, mddev->array_sectors); |
2129 | mddev->changed = 1; | 2131 | mddev->changed = 1; |
2130 | if (mddev->array_sectors > mddev->dev_sectors && | 2132 | if (sectors > mddev->dev_sectors && |
2131 | mddev->recovery_cp == MaxSector) { | 2133 | mddev->recovery_cp == MaxSector) { |
2132 | mddev->recovery_cp = mddev->dev_sectors; | 2134 | mddev->recovery_cp = mddev->dev_sectors; |
2133 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); | 2135 | set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); |
2134 | } | 2136 | } |
2135 | mddev->dev_sectors = mddev->array_sectors; | 2137 | mddev->dev_sectors = sectors; |
2136 | mddev->resync_max_sectors = sectors; | 2138 | mddev->resync_max_sectors = sectors; |
2137 | return 0; | 2139 | return 0; |
2138 | } | 2140 | } |
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index ad153b24ea0d..e293d92641ac 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c | |||
@@ -2194,7 +2194,7 @@ static int run(mddev_t *mddev) | |||
2194 | * Ok, everything is just fine now | 2194 | * Ok, everything is just fine now |
2195 | */ | 2195 | */ |
2196 | md_set_array_sectors(mddev, raid10_size(mddev, 0, 0)); | 2196 | md_set_array_sectors(mddev, raid10_size(mddev, 0, 0)); |
2197 | mddev->resync_max_sectors = mddev->array_sectors; | 2197 | mddev->resync_max_sectors = raid10_size(mddev, 0, 0); |
2198 | 2198 | ||
2199 | mddev->queue->unplug_fn = raid10_unplug; | 2199 | mddev->queue->unplug_fn = raid10_unplug; |
2200 | mddev->queue->backing_dev_info.congested_fn = raid10_congested; | 2200 | mddev->queue->backing_dev_info.congested_fn = raid10_congested; |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 2930fc26a852..1aebd3ef80b7 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -3703,6 +3703,8 @@ static int make_request(struct request_queue *q, struct bio * bi) | |||
3703 | return 0; | 3703 | return 0; |
3704 | } | 3704 | } |
3705 | 3705 | ||
3706 | static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks); | ||
3707 | |||
3706 | static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) | 3708 | static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) |
3707 | { | 3709 | { |
3708 | /* reshaping is quite different to recovery/resync so it is | 3710 | /* reshaping is quite different to recovery/resync so it is |
@@ -3781,7 +3783,7 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped | |||
3781 | j == sh->qd_idx) | 3783 | j == sh->qd_idx) |
3782 | continue; | 3784 | continue; |
3783 | s = compute_blocknr(sh, j); | 3785 | s = compute_blocknr(sh, j); |
3784 | if (s < mddev->array_sectors) { | 3786 | if (s < raid5_size(mddev, 0, 0)) { |
3785 | skipped = 1; | 3787 | skipped = 1; |
3786 | continue; | 3788 | continue; |
3787 | } | 3789 | } |
@@ -4700,6 +4702,9 @@ static int raid5_resize(mddev_t *mddev, sector_t sectors) | |||
4700 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); | 4702 | sectors &= ~((sector_t)mddev->chunk_size/512 - 1); |
4701 | md_set_array_sectors(mddev, raid5_size(mddev, sectors, | 4703 | md_set_array_sectors(mddev, raid5_size(mddev, sectors, |
4702 | mddev->raid_disks)); | 4704 | mddev->raid_disks)); |
4705 | if (mddev->array_sectors > | ||
4706 | raid5_size(mddev, sectors, mddev->raid_disks)) | ||
4707 | return -EINVAL; | ||
4703 | set_capacity(mddev->gendisk, mddev->array_sectors); | 4708 | set_capacity(mddev->gendisk, mddev->array_sectors); |
4704 | mddev->changed = 1; | 4709 | mddev->changed = 1; |
4705 | if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) { | 4710 | if (sectors > mddev->dev_sectors && mddev->recovery_cp == MaxSector) { |
@@ -4837,7 +4842,7 @@ static void end_reshape(raid5_conf_t *conf) | |||
4837 | if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { | 4842 | if (!test_bit(MD_RECOVERY_INTR, &conf->mddev->recovery)) { |
4838 | mddev_t *mddev = conf->mddev; | 4843 | mddev_t *mddev = conf->mddev; |
4839 | 4844 | ||
4840 | md_set_array_sectors(mddev, raid5_size(mddev, 0, | 4845 | md_set_array_sectors_lock(mddev, raid5_size(mddev, 0, |
4841 | conf->raid_disks)); | 4846 | conf->raid_disks)); |
4842 | set_capacity(mddev->gendisk, mddev->array_sectors); | 4847 | set_capacity(mddev->gendisk, mddev->array_sectors); |
4843 | mddev->changed = 1; | 4848 | mddev->changed = 1; |