aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
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/md/md.c
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/md/md.c')
-rw-r--r--drivers/md/md.c112
1 files changed, 105 insertions, 7 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;