Home | History | Annotate | Download | only in devfsadm
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <meta.h>
     29 #include <regex.h>
     30 #include <devfsadm.h>
     31 #include <stdio.h>
     32 #include <strings.h>
     33 #include <stdlib.h>
     34 #include <limits.h>
     35 #include <sys/mkdev.h>
     36 #include <sdssc.h>
     37 
     38 #define	MD_LINK_RE_DEVICES	"^md/r?dsk/.+$"
     39 #define	MD_LINK_RE_SHARED	"^md/shared/[0-9]+/r?dsk/.+$"
     40 #define	MD_LINK_RE_ADMIN	"^md/admin"
     41 
     42 /*
     43  * The devfsadm link module require the next section to
     44  * be defined in order to know what and when to call functions
     45  * in the module on device creation and removal.
     46  */
     47 
     48 /* setup for device creation */
     49 
     50 static int md_create(di_minor_t minor, di_node_t node);
     51 
     52 static devfsadm_create_t md_cbt[] = {
     53 	{ "pseudo", "ddi_pseudo", "md",
     54 	    TYPE_EXACT | DRV_EXACT, ILEVEL_0, md_create,
     55 	},
     56 };
     57 
     58 DEVFSADM_CREATE_INIT_V0(md_cbt);
     59 
     60 /*
     61  * remove devices - always allow disks to be dynamically removed. Only allow
     62  *		    admin device to be removed at reboot.
     63  */
     64 
     65 static devfsadm_remove_t md_remove_cbt[] = {
     66 	{"pseudo", MD_LINK_RE_DEVICES, RM_ALWAYS | RM_PRE | RM_HOT,
     67 	    ILEVEL_0, devfsadm_rm_all},
     68 	{"pseudo", MD_LINK_RE_SHARED, RM_ALWAYS | RM_PRE | RM_HOT,
     69 	    ILEVEL_0, devfsadm_rm_all},
     70 	{"pseudo", MD_LINK_RE_ADMIN, RM_ALWAYS | RM_PRE,
     71 	    ILEVEL_0, devfsadm_rm_all},
     72 };
     73 
     74 DEVFSADM_REMOVE_INIT_V0(md_remove_cbt);
     75 
     76 
     77 /*
     78  * minor_fini - module cleanup routine
     79  */
     80 int
     81 minor_fini(void)
     82 {
     83 	metarpccloseall();
     84 	return (DEVFSADM_SUCCESS);
     85 }
     86 
     87 /*
     88  * For the admin device:
     89  *	/dev/md/admin -> /devices/pseudo/md@0:admin
     90  *
     91  * For metadevice:
     92  *	/dev/md/dsk/foobar --> /devices/pseudo/md@0:0,100,blk
     93  *	/dev/md/rdsk/foobar --> /devices/pseudo/md@0:0,100,raw
     94  *
     95  * Where 'foobar' is user specified arbitrary name and '100'
     96  * is the minor number returned by MD_IOCMAKE_DEV ioctl
     97  *
     98  */
     99 static int
    100 md_create(di_minor_t minor, di_node_t node)
    101 {
    102 	char mn[MAXNAMELEN + 1];
    103 	char path[PATH_MAX + 1];
    104 	char set_path[PATH_MAX +1];
    105 	char sym_path[PATH_MAX + 1];
    106 	int set = -1, ret;
    107 	char *type, *dir;
    108 	char *device_name;
    109 	dev_t minor_devt = di_minor_devt(minor);
    110 	int key;
    111 	mdsetname_t	*sp = NULL;
    112 	md_error_t ep;
    113 
    114 	/*
    115 	 * Initialize sdssc entry points. Don't worry about the return
    116 	 * value here since the interface functions will get initialized
    117 	 * correctly regardless.
    118 	 */
    119 	(void) sdssc_bind_library();
    120 
    121 	(void) strcpy(mn, di_minor_name(minor));
    122 
    123 	/*
    124 	 * Check whether we are being requested to setup the admin
    125 	 * device link or one of the metadevice links. They need
    126 	 * to be treated differently.
    127 	 */
    128 
    129 	if (strcmp(mn, "admin") == 0) {
    130 		/* there is only one admin link and always in /dev/md/admin */
    131 		(void) devfsadm_mklink("md/admin", node, minor, 0);
    132 	} else {
    133 		/*
    134 		 * Extract out the minor components and create the
    135 		 * appropriate links. The node looks like:
    136 		 * md@<set>,<mdev>,<type>
    137 		 * where the <set> number is the named diskset,
    138 		 * <mdev> is the metadevice number, and <type>
    139 		 * is the trailing "blk" or "raw" indication.
    140 		 *
    141 		 * NOTE: when <set> is non-zero, we need to create
    142 		 * under the "shared" directory entry instead of linking
    143 		 * into the top level dsk/rdsk directories.
    144 		 */
    145 		ret = sscanf(mn, "%d,", &set);
    146 		if (ret == 1 && (type = strrchr(mn, ',')) != NULL) {
    147 			type++;
    148 			if (strcmp(type, "blk") == 0) {
    149 				dir = "dsk";
    150 			} else {
    151 				dir = "rdsk";
    152 			}
    153 
    154 			(void) memset(&ep, '\0', sizeof (ep));
    155 			if ((device_name = meta_getnmentbydev(set,
    156 			    MD_SIDEWILD, minor_devt, NULL, NULL,
    157 			    &key, &ep)) == NULL) {
    158 				(void) close_admin(&ep);
    159 				return (DEVFSADM_CONTINUE);
    160 			}
    161 
    162 			if (set == 0) {
    163 				/* this is a simple md */
    164 				(void) snprintf(path, sizeof (path),
    165 				    "md/%s/%s", dir, basename(device_name));
    166 			} else {
    167 				/* this is a shared md */
    168 				(void) snprintf(path, sizeof (path),
    169 				    "md/shared/%d/%s/%s", set, dir,
    170 				    basename(device_name));
    171 
    172 				/*
    173 				 * flush the caches so the next call to
    174 				 * metasetnosetname will get us the
    175 				 * updated cache.
    176 				 */
    177 				metaflushnames(0);
    178 				if ((sp = metasetnosetname(set, &ep))
    179 				    != NULL) {
    180 					(void) snprintf(set_path,
    181 					    sizeof (set_path), "md/shared/%d",
    182 					    sp->setno);
    183 					(void) snprintf(sym_path,
    184 					    sizeof (sym_path), "md/%s",
    185 					    sp->setname);
    186 				}
    187 			}
    188 			(void) devfsadm_mklink(path, node, minor, 0);
    189 			Free(device_name);
    190 
    191 			if (sp != NULL) {
    192 				(void) devfsadm_secondary_link(sym_path,
    193 				    set_path, 0);
    194 			}
    195 		}
    196 	}
    197 
    198 	(void) close_admin(&ep);
    199 	return (DEVFSADM_CONTINUE);
    200 }
    201