aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2009-01-08 16:31:10 -0500
committerNeilBrown <neilb@suse.de>2009-01-08 16:31:10 -0500
commitefeb53c0e57213e843b7ef3cc6ebcdea7d6186ac (patch)
treeef580effd8809fb0bc5d6ffa6f3b8abaa9180539
parentd3374825ce57ba2214d375023979f6197ccc1385 (diff)
md: Allow md devices to be created by name.
Using sequential numbers to identify md devices is somewhat artificial. Using names can be a lot more user-friendly. Also, creating md devices by opening the device special file is a bit awkward. So this patch provides a new option for creating and naming devices. Writing a name such as "md_home" to /sys/modules/md_mod/parameters/new_array will cause an array with that name to be created. It will appear in /sys/block/ /proc/partitions and /proc/mdstat as 'md_home'. It will have an arbitrary minor number allocated. md devices that a created by an open are destroyed on the last close when the device is inactive. For named md devices, they will not be destroyed until the array is explicitly stopped, either with the STOP_ARRAY ioctl or by writing 'clear' to /sys/block/md_XXXX/md/array_state. The name of the array must start 'md_' to avoid conflict with other devices. Signed-off-by: NeilBrown <neilb@suse.de>
-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,