aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDan Williams <dan.j.williams@intel.com>2009-03-31 00:00:31 -0400
committerDan Williams <dan.j.williams@intel.com>2009-03-31 00:00:31 -0400
commitb522adcde9c4d3fb7b579cfa9160d8bde7744be8 (patch)
tree4208e3dcec3ebdfa6ad9bc153f76129400532717 /drivers
parent1f403624bde3c678a166984b1e6a727a0ce06f2b (diff)
md: 'array_size' sysfs attribute
Allow userspace to set the size of the array according to the following semantics: 1/ size must be <= to the size returned by mddev->pers->size(mddev, 0, 0) a) If size is set before the array is running, do_md_run will fail if size is greater than the default size b) A reshape attempt that reduces the default size to less than the set array size should be blocked 2/ once userspace sets the size the kernel will not change it 3/ writing 'default' to this attribute returns control of the size to the kernel and reverts to the size reported by the personality Also, convert locations that need to know the default size from directly reading ->array_sectors to <pers>_size. Resync/reshape operations always follow the default size. Finally, fixup other locations that read a number of 1k-blocks from userspace to use strict_blocks_to_sectors() which checks for unsigned long long to sector_t overflow and blocks to sectors overflow. Reviewed-by: Andre Noll <maan@systemlinux.org> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/md/md.c112
-rw-r--r--drivers/md/md.h3
-rw-r--r--drivers/md/raid0.c2
-rw-r--r--drivers/md/raid1.c6
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/md/raid5.c9
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
390static inline int mddev_is_locked(mddev_t *mddev)
391{
392 return mutex_is_locked(&mddev->reconfig_mutex);
393}
394
390static inline int mddev_trylock(mddev_t * mddev) 395static 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
2290static 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
2285static ssize_t 2309static ssize_t
2286rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) 2310rdev_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, &sectors) < 0) 2316 if (strict_blocks_to_sectors(buf, &sectors) < 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, &sectors); 3209 int err = strict_blocks_to_sectors(buf, &sectors);
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
3652static ssize_t
3653array_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
3662static ssize_t
3663array_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, &sectors) < 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
3700static struct md_sysfs_entry md_array_size =
3701__ATTR(array_size, S_IRUGO|S_IWUSR, array_size_show,
3702 array_size_store);
3630 3703
3631static struct attribute *md_default_attrs[] = { 3704static 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
4980void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors) 5065void 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}
4984EXPORT_SYMBOL(md_set_array_sectors); 5074EXPORT_SYMBOL(md_set_array_sectors);
4985 5075
5076void 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}
5082EXPORT_SYMBOL(md_set_array_sectors_lock);
5083
4986static int update_size(mddev_t *mddev, sector_t num_sectors) 5084static 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);
431extern int md_allow_write(mddev_t *mddev); 433extern int md_allow_write(mddev_t *mddev);
432extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev); 434extern void md_wait_for_blocked_rdev(mdk_rdev_t *rdev, mddev_t *mddev);
433extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors); 435extern void md_set_array_sectors(mddev_t *mddev, sector_t array_sectors);
436extern 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
3706static sector_t raid5_size(mddev_t *mddev, sector_t sectors, int raid_disks);
3707
3706static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped) 3708static 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;