xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_init.c (revision 3ee0e49223f178da635734759b9167f924321ff0)
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 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * initialize metadevices
31  */
32 
33 #include <meta.h>
34 #include <sys/lvm/mdio.h>
35 #include <libdevinfo.h>
36 
37 
38 int
39 parse_interlace(
40 	char		*uname,		/* Meta Device name (eg d0) */
41 	char		*str,		/* String to Parse		 */
42 	diskaddr_t	*interlacep,
43 	md_error_t	*ep
44 )
45 {
46 	diskaddr_t	num;
47 	char		c;
48 	int		cnt;
49 
50 	/* parse interlace */
51 	if ((cnt = sscanf(str, "%llu%c", &num, &c)) < 1) {
52 		return (meta_cook_syntax(ep, MDE_BAD_INTERLACE,
53 		    uname, 1, &str));
54 	} else if (cnt == 1) {
55 		if (num & (DEV_BSIZE - 1)) {
56 			return (meta_cook_syntax(ep, MDE_BAD_INTERLACE,
57 			    uname, 1, &str));
58 		}
59 		num = lbtodb(num);
60 	} else switch (c) {
61 	case 'b':
62 	case 'B':
63 		num *= DEV_BSIZE / DEV_BSIZE;
64 		break;
65 	case 'k':
66 	case 'K':
67 		num *= 1024 / DEV_BSIZE;
68 		break;
69 	case 'm':
70 	case 'M':
71 		num *= 1024 * 1024 / DEV_BSIZE;
72 		break;
73 	default:
74 		return (meta_cook_syntax(ep, MDE_BAD_INTERLACE,
75 		    NULL, 1, &str));
76 	}
77 
78 	/* return success */
79 	*interlacep = num;
80 	return (0);
81 }
82 
83 /*
84  * cook up syntax error
85  */
86 int
87 meta_cook_syntax(
88 	md_error_t	*ep,
89 	md_void_errno_t	errcode,
90 	char		*uname,
91 	int		argc,
92 	char		*argv[]
93 )
94 {
95 	int		rval;
96 
97 	/* if we have a token, concat it to uname */
98 	if ((argc > 0) && (argv[0] != NULL) && (argv[0][0] != '\0')) {
99 		char	*p;
100 
101 		if ((uname != NULL) && (uname[0] != '\0')) {
102 			p = Malloc(strlen(uname) + 2
103 			    + 1 + strlen(argv[0]) + 1 + 1);
104 			(void) strcpy(p, uname);
105 			(void) strcat(p, ": ");
106 		} else {
107 			p = Malloc(1 + strlen(argv[0]) + 1 + 1);
108 			p[0] = '\0';
109 		}
110 		(void) strcat(p, "\"");
111 		(void) strcat(p, argv[0]);
112 		(void) strcat(p, "\"");
113 		rval = mderror(ep, errcode, p);
114 		Free(p);
115 	} else {
116 		rval = mderror(ep, errcode, uname);
117 	}
118 
119 	return (rval);
120 }
121 
122 int
123 meta_check_devicesize(
124 	diskaddr_t	total_blocks
125 )
126 {
127 	int	rval = MD_CRO_32BIT;
128 
129 
130 	if (total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) {
131 		rval = MD_CRO_64BIT;
132 	}
133 	return (rval);
134 }
135 
136 
137 /*
138  * setup metadevice geometry
139  */
140 /*ARGSUSED*/
141 int
142 meta_setup_geom(
143 	md_unit_t	*md,
144 	mdname_t	*np,
145 	mdgeom_t	*geomp,
146 	uint_t		write_reinstruct,
147 	uint_t		read_reinstruct,
148 	uint_t		round_cyl,
149 	md_error_t	*ep
150 )
151 {
152 	diskaddr_t	cylsize = geomp->nhead * geomp->nsect;
153 	diskaddr_t	total_blocks;
154 
155 	if (round_cyl) {
156 		total_blocks = rounddown(md->c.un_actual_tb, cylsize);
157 	} else {
158 		total_blocks = md->c.un_actual_tb;
159 	}
160 
161 	md->c.un_total_blocks = total_blocks;
162 	md->c.un_nhead = geomp->nhead;
163 	md->c.un_nsect = geomp->nsect;
164 	md->c.un_rpm = geomp->rpm;
165 	md->c.un_wr_reinstruct = write_reinstruct;
166 	md->c.un_rd_reinstruct = read_reinstruct;
167 	return (0);
168 }
169 
170 /*
171  * adjust metadevice geometry
172  */
173 /*ARGSUSED*/
174 int
175 meta_adjust_geom(
176 	md_unit_t	*md,
177 	mdname_t	*np,
178 	uint_t		write_reinstruct,
179 	uint_t		read_reinstruct,
180 	uint_t		round_cyl,
181 	md_error_t	*ep
182 )
183 {
184 	diskaddr_t	cylsize = md->c.un_nhead * md->c.un_nsect;
185 	diskaddr_t	total_blocks;
186 
187 	if (round_cyl) {
188 		total_blocks = rounddown(md->c.un_actual_tb, cylsize);
189 	} else {
190 		total_blocks = md->c.un_actual_tb;
191 	}
192 
193 	md->c.un_total_blocks = total_blocks;
194 	if (write_reinstruct > md->c.un_wr_reinstruct)
195 		md->c.un_wr_reinstruct = write_reinstruct;
196 	if (read_reinstruct > md->c.un_rd_reinstruct)
197 		md->c.un_rd_reinstruct = read_reinstruct;
198 	return (0);
199 }
200 
201 /*
202  * Function: meta_init_make_device
203  * Purpose:
204  * 	Create the device node <uname> by constructing the necessary
205  * 	md_mkdev_params_t structure. We have to handle relative names
206  *	(e.g. "d80") and fully-qualified names (e.g. "/dev/md/red/dsk/d80").
207  *	The field that we need is the unit number of the metadevice (80 in
208  *	the above examples).
209  * Input:	spp	set structure
210  *		uname	unit-name (fully qualified or relative)
211  * Output:	ep	error return structure
212  * Returns:	> 0	success and return 'key'
213  *		-1	Error. <ep> contains error reason
214  */
215 mdkey_t
216 meta_init_make_device(
217 	mdsetname_t	**spp,
218 	char		*uname,
219 	md_error_t	*ep
220 )
221 {
222 	di_devlink_handle_t	hdl;
223 	md_mkdev_params_t	params;
224 	mdkey_t			rval = 0;
225 	char			*p;
226 	int			len = strlen(uname);
227 
228 	(void) memset(&params, 0, sizeof (params));
229 	MD_SETDRIVERNAME(&params, "md", (*spp)->setno);
230 
231 	/*
232 	 * This ioctl call causes kernel to allocate a unit number
233 	 * and populate /devices for the named metadevice
234 	 */
235 	if (metaioctl(MD_IOCMAKE_DEV, &params, &params.mde, NULL) != 0) {
236 		return (mdstealerror(ep, &params.mde));
237 	}
238 
239 	/*
240 	 * Now we have minor number so add it to the namespace
241 	 * and return the key
242 	 */
243 	if ((rval = add_self_name(*spp, uname, &params, ep)) <= 0) {
244 		if (mdisok(ep))
245 			(void) mderror(ep, MDE_UNIT_NOT_FOUND, NULL);
246 
247 		return (-1);
248 	}
249 
250 	/*
251 	 * Wait until device appears in namespace. di_devlink_init() returns
252 	 * once the /dev links have been created. If NULL is returned the
253 	 * link operation failed and we haven't got a device to use.
254 	 * NOTE: This will take a _long_ time for large numbers of metadevices.
255 	 *	 Change to use the enhanced di_devlink_init() interface when
256 	 *	 available.
257 	 */
258 	hdl = di_devlink_init("md", DI_MAKE_LINK);
259 	if (hdl != NULL) {
260 		(void) di_devlink_fini(&hdl);
261 	} else {
262 		/*
263 		 * Delete name entry we just created
264 		 */
265 		(void) del_self_name(*spp, rval, ep);
266 		p = Malloc(len + 3);
267 		(void) snprintf(p, len + 3, "\"%s\"", uname);
268 		rval = mderror(ep, MDE_UNIT_NOT_FOUND, p);
269 		Free(p);
270 	}
271 	return (rval);
272 }
273 
274 /*
275  * FUNCTION:	is_metadb_cmd()
276  * INPUT:	argc	- number of command line arguments
277  *		argv	- pointer to array of command line arguments
278  * OUTPUT:	none
279  * RETURNS:	TRUE if a metadb is to be created, FALSE otherwise
280  * PURPOSE:	parses enough of the command line to determine if a metadb
281  *		create is being attempted
282  */
283 static boolean_t
284 is_metadb_cmd(
285 	int	argc,
286 	char	*argv[]
287 )
288 {
289 	ulong_t	num;
290 	int	len;
291 
292 	/* look for match */
293 	if (argc > 0 && (sscanf(argv[0], "mddb%lu%n", &num, &len) == 1) &&
294 		    (strlen(argv[0]) == len) && ((long)num >= 0)) {
295 		return (B_TRUE);
296 	}
297 
298 	return (B_FALSE);
299 }
300 
301 /*
302  * FUNCTION:	is_stripe_cmd()
303  * INPUT:	argc	- number of command line arguments
304  *		argv	- pointer to array of command line arguments
305  * OUTPUT:	none
306  * RETURNS:	TRUE if a stripe is to be created, FALSE otherwise
307  * PURPOSE:	parses enough of the command line to determine if a stripe
308  *		create is being attempted
309  */
310 static boolean_t
311 is_stripe_cmd(
312 	int	argc,
313 	char	*argv[]
314 )
315 {
316 	uint_t	nrow;
317 
318 	if (argc > 1 && (sscanf(argv[1], "%u", &nrow) != 1) || ((int)nrow < 0))
319 		return (B_FALSE);
320 
321 	return (B_TRUE);
322 }
323 
324 /*
325  * FUNCTION:	meta_get_init_type()
326  * INPUT:	argc	- number of command line arguments
327  *		argv	- pointer to array of command line arguments
328  * OUTPUT:	none
329  * RETURNS:	type of metadevice or hot spare pools being initialized
330  * PURPOSE:	parses enough of the command line to determine what type
331  *		of metainit is being attempted
332  */
333 mdinittypes_t
334 meta_get_init_type(
335 	int 	argc,
336 	char	*argv[]
337 )
338 {
339 	char		*arg = argv[1];
340 	mdinittypes_t	init_type;
341 
342 	if (argc == 1) /* must be a hot spare pool w/o devices */
343 		return (TAB_HSP);
344 
345 	init_type = TAB_UNKNOWN;
346 	if (arg != NULL) {
347 		if (strcmp(arg, "-m") == 0) {
348 			init_type = TAB_MIRROR;
349 		} else if (strcmp(arg, "-r") == 0) {
350 			init_type = TAB_RAID;
351 		} else if (strcmp(arg, "-p") == 0) {
352 			init_type = TAB_SP;
353 		} else if (strcmp(arg, "-t") == 0) {
354 			init_type = TAB_TRANS;
355 		} else if (is_metadb_cmd(argc, argv)) {
356 			init_type = TAB_MDDB;
357 		} else if (is_stripe_cmd(argc, argv)) {
358 			init_type = TAB_STRIPE;
359 		} else { /* assume that it is a hsp */
360 			init_type = TAB_HSP;
361 		}
362 	}
363 	return (init_type);
364 }
365 
366 /*
367  * initialize named device or hotspare pool
368  */
369 int
370 meta_init_name(
371 	mdsetname_t	**spp,
372 	int		argc,
373 	char		*argv[],
374 	char		*cname, /* canonical name */
375 	mdcmdopts_t	options,
376 	md_error_t	*ep
377 )
378 {
379 	mdinittypes_t	init_type;
380 	char		*p;
381 	int		rval;
382 	char		*uname = argv[0];
383 	mdkey_t		key = MD_KEYWILD;
384 	minor_t		mnum;
385 	md_error_t	t_e = mdnullerror;
386 
387 	assert(argc > 0);
388 	assert(*spp != NULL);
389 
390 	/* determine type of metadevice or hot spare pool being created */
391 	init_type = meta_get_init_type(argc, argv);
392 
393 	/*
394 	 * Metatrans is eof
395 	 */
396 	if (init_type == TAB_TRANS)
397 		return (mderror(ep, MDE_EOF_TRANS, NULL));
398 
399 	/* hotspare pool */
400 	if (init_type == TAB_HSP)
401 		return (meta_init_hsp(spp, argc, argv, options, ep));
402 
403 	/*
404 	 * We are creating metadevice so make sure the name
405 	 * has not been used
406 	 */
407 	if (is_existing_meta_hsp(*spp, cname)) {
408 		/*
409 		 * The name has been used by hsp
410 		 */
411 		if (is_existing_hsp(*spp, cname)) {
412 			return (mderror(ep, MDE_NAME_IN_USE, cname));
413 		}
414 
415 		/*
416 		 * If path exists but unit is not created
417 		 * then meta_init_make_device will correct
418 		 * that.  If unit also exists then it
419 		 * will return a conflict error
420 		 */
421 		if (init_type != TAB_UNKNOWN) {
422 		    /* Create device node */
423 		    if ((key = meta_init_make_device(spp, uname,
424 			&t_e)) <= 0) {
425 			return (mdstealerror(ep, &t_e));
426 		    }
427 		}
428 	}
429 
430 	/* metadevice */
431 	if (argc >= 2 && init_type != TAB_UNKNOWN) {
432 		/*
433 		 * We need to create the device node if the specified metadevice
434 		 * does not already exist in the database. The actual creation
435 		 * is undertaken by the md driver and the links propagated by
436 		 * devfsadm.
437 		 */
438 		if (key == MD_KEYWILD) {
439 			if ((key = meta_init_make_device(spp, uname,
440 			    &t_e)) <= 0)
441 				return (mdstealerror(ep, &t_e));
442 		}
443 
444 		switch (init_type) {
445 		case TAB_MIRROR:
446 			rval = meta_init_mirror(spp, argc, argv, options, ep);
447 			break;
448 		case TAB_RAID:
449 			rval = meta_init_raid(spp, argc, argv, options, ep);
450 			break;
451 		case TAB_SP:
452 			rval = meta_init_sp(spp, argc, argv, options, ep);
453 			break;
454 		case TAB_STRIPE:
455 			rval = meta_init_stripe(spp, argc, argv, options, ep);
456 			break;
457 		}
458 
459 		if (rval == -1 || !(options & MDCMD_DOIT)) {
460 			/*
461 			 * Remove the device node created before
462 			 */
463 			if ((meta_getnmentbykey((*spp)->setno, MD_SIDEWILD,
464 			    key, NULL, &mnum, NULL, ep) != NULL) &&
465 			    MD_MIN2UNIT(mnum) < MD_MAXUNITS) {
466 			    (void) metaioctl(MD_IOCREM_DEV, &mnum, &t_e, NULL);
467 			}
468 
469 			/*
470 			 * Del what we added before
471 			 */
472 			(void) del_self_name(*spp, key, &t_e);
473 		}
474 		return (rval);
475 	}
476 
477 	/* unknown type */
478 	p = Malloc(1 + strlen(uname) + 1 + 1);
479 	(void) strcpy(p, "\"");
480 	(void) strcat(p, uname);
481 	(void) strcat(p, "\"");
482 	rval = mderror(ep, MDE_SYNTAX, p);
483 	Free(p);
484 	return (rval);
485 }
486