aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/md/md.c119
-rw-r--r--include/linux/raid/md_k.h1
2 files changed, 102 insertions, 18 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 38697283aaf4..f5cbb9d2371a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -249,17 +249,51 @@ static mddev_t * mddev_find(dev_t unit)
249 249
250 retry: 250 retry:
251 spin_lock(&all_mddevs_lock); 251 spin_lock(&all_mddevs_lock);
252 list_for_each_entry(mddev, &all_mddevs, all_mddevs) 252
253 if (mddev->unit == unit) { 253 if (unit) {
254 mddev_get(mddev); 254 list_for_each_entry(mddev, &all_mddevs, all_mddevs)
255 if (mddev->unit == unit) {
256 mddev_get(mddev);
257 spin_unlock(&all_mddevs_lock);
258 kfree(new);
259 return mddev;
260 }
261
262 if (new) {
263 list_add(&new->all_mddevs, &all_mddevs);
255 spin_unlock(&all_mddevs_lock); 264 spin_unlock(&all_mddevs_lock);
256 kfree(new); 265 new->hold_active = UNTIL_IOCTL;
257 return mddev; 266 return new;
258 } 267 }
259 268 } else if (new) {
260 if (new) { 269 /* find an unused unit number */
270 static int next_minor = 512;
271 int start = next_minor;
272 int is_free = 0;
273 int dev = 0;
274 while (!is_free) {
275 dev = MKDEV(MD_MAJOR, next_minor);
276 next_minor++;
277 if (next_minor > MINORMASK)
278 next_minor = 0;
279 if (next_minor == start) {
280 /* Oh dear, all in use. */
281 spin_unlock(&all_mddevs_lock);
282 kfree(new);
283 return NULL;
284 }
285
286 is_free = 1;
287 list_for_each_entry(mddev, &all_mddevs, all_mddevs)
288 if (mddev->unit == dev) {
289 is_free = 0;
290 break;
291 }
292 }
293 new->unit = dev;
294 new->md_minor = MINOR(dev);
295 new->hold_active = UNTIL_STOP;
261 list_add(&new->all_mddevs, &all_mddevs); 296 list_add(&new->all_mddevs, &all_mddevs);
262 mddev->hold_active = UNTIL_IOCTL;
263 spin_unlock(&all_mddevs_lock); 297 spin_unlock(&all_mddevs_lock);
264 return new; 298 return new;
265 } 299 }
@@ -3491,18 +3525,22 @@ static struct kobj_type md_ktype = {
3491 3525
3492int mdp_major = 0; 3526int mdp_major = 0;
3493 3527
3494static struct kobject *md_probe(dev_t dev, int *part, void *data) 3528static int md_alloc(dev_t dev, char *name)
3495{ 3529{
3496 static DEFINE_MUTEX(disks_mutex); 3530 static DEFINE_MUTEX(disks_mutex);
3497 mddev_t *mddev = mddev_find(dev); 3531 mddev_t *mddev = mddev_find(dev);
3498 struct gendisk *disk; 3532 struct gendisk *disk;
3499 int partitioned = (MAJOR(dev) != MD_MAJOR); 3533 int partitioned;
3500 int shift = partitioned ? MdpMinorShift : 0; 3534 int shift;
3501 int unit = MINOR(dev) >> shift; 3535 int unit;
3502 int error; 3536 int error;
3503 3537
3504 if (!mddev) 3538 if (!mddev)
3505 return NULL; 3539 return -ENODEV;
3540
3541 partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
3542 shift = partitioned ? MdpMinorShift : 0;
3543 unit = MINOR(mddev->unit) >> shift;
3506 3544
3507 /* wait for any previous instance if this device 3545 /* wait for any previous instance if this device
3508 * to be completed removed (mddev_delayed_delete). 3546 * to be completed removed (mddev_delayed_delete).
@@ -3513,14 +3551,29 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
3513 if (mddev->gendisk) { 3551 if (mddev->gendisk) {
3514 mutex_unlock(&disks_mutex); 3552 mutex_unlock(&disks_mutex);
3515 mddev_put(mddev); 3553 mddev_put(mddev);
3516 return NULL; 3554 return -EEXIST;
3555 }
3556
3557 if (name) {
3558 /* Need to ensure that 'name' is not a duplicate.
3559 */
3560 mddev_t *mddev2;
3561 spin_lock(&all_mddevs_lock);
3562
3563 list_for_each_entry(mddev2, &all_mddevs, all_mddevs)
3564 if (mddev2->gendisk &&
3565 strcmp(mddev2->gendisk->disk_name, name) == 0) {
3566 spin_unlock(&all_mddevs_lock);
3567 return -EEXIST;
3568 }
3569 spin_unlock(&all_mddevs_lock);
3517 } 3570 }
3518 3571
3519 mddev->queue = blk_alloc_queue(GFP_KERNEL); 3572 mddev->queue = blk_alloc_queue(GFP_KERNEL);
3520 if (!mddev->queue) { 3573 if (!mddev->queue) {
3521 mutex_unlock(&disks_mutex); 3574 mutex_unlock(&disks_mutex);
3522 mddev_put(mddev); 3575 mddev_put(mddev);
3523 return NULL; 3576 return -ENOMEM;
3524 } 3577 }
3525 /* Can be unlocked because the queue is new: no concurrency */ 3578 /* Can be unlocked because the queue is new: no concurrency */
3526 queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue); 3579 queue_flag_set_unlocked(QUEUE_FLAG_CLUSTER, mddev->queue);
@@ -3533,11 +3586,13 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
3533 blk_cleanup_queue(mddev->queue); 3586 blk_cleanup_queue(mddev->queue);
3534 mddev->queue = NULL; 3587 mddev->queue = NULL;
3535 mddev_put(mddev); 3588 mddev_put(mddev);
3536 return NULL; 3589 return -ENOMEM;
3537 } 3590 }
3538 disk->major = MAJOR(dev); 3591 disk->major = MAJOR(mddev->unit);
3539 disk->first_minor = unit << shift; 3592 disk->first_minor = unit << shift;
3540 if (partitioned) 3593 if (name)
3594 strcpy(disk->disk_name, name);
3595 else if (partitioned)
3541 sprintf(disk->disk_name, "md_d%d", unit); 3596 sprintf(disk->disk_name, "md_d%d", unit);
3542 else 3597 else
3543 sprintf(disk->disk_name, "md%d", unit); 3598 sprintf(disk->disk_name, "md%d", unit);
@@ -3562,9 +3617,34 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
3562 mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state"); 3617 mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
3563 } 3618 }
3564 mddev_put(mddev); 3619 mddev_put(mddev);
3620 return 0;
3621}
3622
3623static struct kobject *md_probe(dev_t dev, int *part, void *data)
3624{
3625 md_alloc(dev, NULL);
3565 return NULL; 3626 return NULL;
3566} 3627}
3567 3628
3629static int add_named_array(const char *val, struct kernel_param *kp)
3630{
3631 /* val must be "md_*" where * is not all digits.
3632 * We allocate an array with a large free minor number, and
3633 * set the name to val. val must not already be an active name.
3634 */
3635 int len = strlen(val);
3636 char buf[DISK_NAME_LEN];
3637
3638 while (len && val[len-1] == '\n')
3639 len--;
3640 if (len >= DISK_NAME_LEN)
3641 return -E2BIG;
3642 strlcpy(buf, val, len+1);
3643 if (strncmp(buf, "md_", 3) != 0)
3644 return -EINVAL;
3645 return md_alloc(0, buf);
3646}
3647
3568static void md_safemode_timeout(unsigned long data) 3648static void md_safemode_timeout(unsigned long data)
3569{ 3649{
3570 mddev_t *mddev = (mddev_t *) data; 3650 mddev_t *mddev = (mddev_t *) data;
@@ -4025,6 +4105,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
4025 mddev->barriers_work = 0; 4105 mddev->barriers_work = 0;
4026 mddev->safemode = 0; 4106 mddev->safemode = 0;
4027 kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE); 4107 kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
4108 if (mddev->hold_active == UNTIL_STOP)
4109 mddev->hold_active = 0;
4028 4110
4029 } else if (mddev->pers) 4111 } else if (mddev->pers)
4030 printk(KERN_INFO "md: %s switched to read-only mode.\n", 4112 printk(KERN_INFO "md: %s switched to read-only mode.\n",
@@ -6502,6 +6584,7 @@ static int set_ro(const char *val, struct kernel_param *kp)
6502module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR); 6584module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
6503module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR); 6585module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
6504 6586
6587module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR);
6505 6588
6506EXPORT_SYMBOL(register_md_personality); 6589EXPORT_SYMBOL(register_md_personality);
6507EXPORT_SYMBOL(unregister_md_personality); 6590EXPORT_SYMBOL(unregister_md_personality);
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index e3d17c7f954e..dac4217194b8 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -139,6 +139,7 @@ struct mddev_s
139 struct kobject kobj; 139 struct kobject kobj;
140 int hold_active; 140 int hold_active;
141#define UNTIL_IOCTL 1 141#define UNTIL_IOCTL 1
142#define UNTIL_STOP 2
142 143
143 /* Superblock information */ 144 /* Superblock information */
144 int major_version, 145 int major_version,