Skip to content

Commit efeb53c

Browse files
committed
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>
1 parent d337482 commit efeb53c

File tree

2 files changed

+102
-18
lines changed

2 files changed

+102
-18
lines changed

drivers/md/md.c

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -249,17 +249,51 @@ static mddev_t * mddev_find(dev_t unit)
249249

250250
retry:
251251
spin_lock(&all_mddevs_lock);
252-
list_for_each_entry(mddev, &all_mddevs, all_mddevs)
253-
if (mddev->unit == unit) {
254-
mddev_get(mddev);
252+
253+
if (unit) {
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);
255264
spin_unlock(&all_mddevs_lock);
256-
kfree(new);
257-
return mddev;
265+
new->hold_active = UNTIL_IOCTL;
266+
return new;
258267
}
259-
260-
if (new) {
268+
} else 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;
261296
list_add(&new->all_mddevs, &all_mddevs);
262-
mddev->hold_active = UNTIL_IOCTL;
263297
spin_unlock(&all_mddevs_lock);
264298
return new;
265299
}
@@ -3491,18 +3525,22 @@ static struct kobj_type md_ktype = {
34913525

34923526
int mdp_major = 0;
34933527

3494-
static struct kobject *md_probe(dev_t dev, int *part, void *data)
3528+
static int md_alloc(dev_t dev, char *name)
34953529
{
34963530
static DEFINE_MUTEX(disks_mutex);
34973531
mddev_t *mddev = mddev_find(dev);
34983532
struct gendisk *disk;
3499-
int partitioned = (MAJOR(dev) != MD_MAJOR);
3500-
int shift = partitioned ? MdpMinorShift : 0;
3501-
int unit = MINOR(dev) >> shift;
3533+
int partitioned;
3534+
int shift;
3535+
int unit;
35023536
int error;
35033537

35043538
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;
35063544

35073545
/* wait for any previous instance if this device
35083546
* to be completed removed (mddev_delayed_delete).
@@ -3513,14 +3551,29 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
35133551
if (mddev->gendisk) {
35143552
mutex_unlock(&disks_mutex);
35153553
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);
35173570
}
35183571

35193572
mddev->queue = blk_alloc_queue(GFP_KERNEL);
35203573
if (!mddev->queue) {
35213574
mutex_unlock(&disks_mutex);
35223575
mddev_put(mddev);
3523-
return NULL;
3576+
return -ENOMEM;
35243577
}
35253578
/* Can be unlocked because the queue is new: no concurrency */
35263579
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)
35333586
blk_cleanup_queue(mddev->queue);
35343587
mddev->queue = NULL;
35353588
mddev_put(mddev);
3536-
return NULL;
3589+
return -ENOMEM;
35373590
}
3538-
disk->major = MAJOR(dev);
3591+
disk->major = MAJOR(mddev->unit);
35393592
disk->first_minor = unit << shift;
3540-
if (partitioned)
3593+
if (name)
3594+
strcpy(disk->disk_name, name);
3595+
else if (partitioned)
35413596
sprintf(disk->disk_name, "md_d%d", unit);
35423597
else
35433598
sprintf(disk->disk_name, "md%d", unit);
@@ -3562,9 +3617,34 @@ static struct kobject *md_probe(dev_t dev, int *part, void *data)
35623617
mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state");
35633618
}
35643619
mddev_put(mddev);
3620+
return 0;
3621+
}
3622+
3623+
static struct kobject *md_probe(dev_t dev, int *part, void *data)
3624+
{
3625+
md_alloc(dev, NULL);
35653626
return NULL;
35663627
}
35673628

3629+
static 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+
35683648
static void md_safemode_timeout(unsigned long data)
35693649
{
35703650
mddev_t *mddev = (mddev_t *) data;
@@ -4025,6 +4105,8 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
40254105
mddev->barriers_work = 0;
40264106
mddev->safemode = 0;
40274107
kobject_uevent(&disk_to_dev(mddev->gendisk)->kobj, KOBJ_CHANGE);
4108+
if (mddev->hold_active == UNTIL_STOP)
4109+
mddev->hold_active = 0;
40284110

40294111
} else if (mddev->pers)
40304112
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)
65026584
module_param_call(start_ro, set_ro, get_ro, NULL, S_IRUSR|S_IWUSR);
65036585
module_param(start_dirty_degraded, int, S_IRUGO|S_IWUSR);
65046586

6587+
module_param_call(new_array, add_named_array, NULL, NULL, S_IWUSR);
65056588

65066589
EXPORT_SYMBOL(register_md_personality);
65076590
EXPORT_SYMBOL(unregister_md_personality);

include/linux/raid/md_k.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ struct mddev_s
139139
struct kobject kobj;
140140
int hold_active;
141141
#define UNTIL_IOCTL 1
142+
#define UNTIL_STOP 2
142143

143144
/* Superblock information */
144145
int major_version,

0 commit comments

Comments
 (0)