@@ -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
34923526int 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+
35683648static 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)
65026584module_param_call (start_ro , set_ro , get_ro , NULL , S_IRUSR |S_IWUSR );
65036585module_param (start_dirty_degraded , int , S_IRUGO |S_IWUSR );
65046586
6587+ module_param_call (new_array , add_named_array , NULL , NULL , S_IWUSR );
65056588
65066589EXPORT_SYMBOL (register_md_personality );
65076590EXPORT_SYMBOL (unregister_md_personality );
0 commit comments