xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_init.c (revision d89fccd8788afe1e920f842edd883fe192a1b8fe)
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 		return (mderror(ep, MDE_UNIT_NOT_FOUND, NULL));
245 	}
246 
247 	/*
248 	 * Wait until device appears in namespace. di_devlink_init() returns
249 	 * once the /dev links have been created. If NULL is returned the
250 	 * link operation failed and we haven't got a device to use.
251 	 * NOTE: This will take a _long_ time for large numbers of metadevices.
252 	 *	 Change to use the enhanced di_devlink_init() interface when
253 	 *	 available.
254 	 */
255 	hdl = di_devlink_init("md", DI_MAKE_LINK);
256 	if (hdl != NULL) {
257 		(void) di_devlink_fini(&hdl);
258 	} else {
259 		/*
260 		 * Delete name entry we just created
261 		 */
262 		(void) del_self_name(*spp, rval, ep);
263 		p = Malloc(len + 3);
264 		(void) snprintf(p, len + 3, "\"%s\"", uname);
265 		rval = mderror(ep, MDE_UNIT_NOT_FOUND, p);
266 		Free(p);
267 	}
268 	return (rval);
269 }
270 
271 /*
272  * FUNCTION:	is_metadb_cmd()
273  * INPUT:	argc	- number of command line arguments
274  *		argv	- pointer to array of command line arguments
275  * OUTPUT:	none
276  * RETURNS:	TRUE if a metadb is to be created, FALSE otherwise
277  * PURPOSE:	parses enough of the command line to determine if a metadb
278  *		create is being attempted
279  */
280 static boolean_t
281 is_metadb_cmd(
282 	int	argc,
283 	char	*argv[]
284 )
285 {
286 	ulong_t	num;
287 	int	len;
288 
289 	/* look for match */
290 	if (argc > 0 && (sscanf(argv[0], "mddb%lu%n", &num, &len) == 1) &&
291 		    (strlen(argv[0]) == len) && ((long)num >= 0)) {
292 		return (B_TRUE);
293 	}
294 
295 	return (B_FALSE);
296 }
297 
298 /*
299  * FUNCTION:	is_stripe_cmd()
300  * INPUT:	argc	- number of command line arguments
301  *		argv	- pointer to array of command line arguments
302  * OUTPUT:	none
303  * RETURNS:	TRUE if a stripe is to be created, FALSE otherwise
304  * PURPOSE:	parses enough of the command line to determine if a stripe
305  *		create is being attempted
306  */
307 static boolean_t
308 is_stripe_cmd(
309 	int	argc,
310 	char	*argv[]
311 )
312 {
313 	uint_t	nrow;
314 
315 	if (argc > 1 && (sscanf(argv[1], "%u", &nrow) != 1) || ((int)nrow < 0))
316 		return (B_FALSE);
317 
318 	return (B_TRUE);
319 }
320 
321 /*
322  * FUNCTION:	meta_get_init_type()
323  * INPUT:	argc	- number of command line arguments
324  *		argv	- pointer to array of command line arguments
325  * OUTPUT:	none
326  * RETURNS:	type of metadevice or hot spare pools being initialized
327  * PURPOSE:	parses enough of the command line to determine what type
328  *		of metainit is being attempted
329  */
330 mdinittypes_t
331 meta_get_init_type(
332 	int 	argc,
333 	char	*argv[]
334 )
335 {
336 	char		*arg = argv[1];
337 	mdinittypes_t	init_type;
338 
339 	if (argc == 1) /* must be a hot spare pool w/o devices */
340 		return (TAB_HSP);
341 
342 	init_type = TAB_UNKNOWN;
343 	if (arg != NULL) {
344 		if (strcmp(arg, "-m") == 0) {
345 			init_type = TAB_MIRROR;
346 		} else if (strcmp(arg, "-r") == 0) {
347 			init_type = TAB_RAID;
348 		} else if (strcmp(arg, "-p") == 0) {
349 			init_type = TAB_SP;
350 		} else if (strcmp(arg, "-t") == 0) {
351 			init_type = TAB_TRANS;
352 		} else if (is_metadb_cmd(argc, argv)) {
353 			init_type = TAB_MDDB;
354 		} else if (is_stripe_cmd(argc, argv)) {
355 			init_type = TAB_STRIPE;
356 		} else { /* assume that it is a hsp */
357 			init_type = TAB_HSP;
358 		}
359 	}
360 	return (init_type);
361 }
362 
363 /*
364  * initialize named device or hotspare pool
365  */
366 int
367 meta_init_name(
368 	mdsetname_t	**spp,
369 	int		argc,
370 	char		*argv[],
371 	char		*cname, /* canonical name */
372 	mdcmdopts_t	options,
373 	md_error_t	*ep
374 )
375 {
376 	mdinittypes_t	init_type;
377 	char		*p;
378 	int		rval;
379 	char		*uname = argv[0];
380 	mdkey_t		key = MD_KEYWILD;
381 	minor_t		mnum;
382 	md_error_t	t_e = mdnullerror;
383 
384 	assert(argc > 0);
385 	assert(*spp != NULL);
386 
387 	/* determine type of metadevice or hot spare pool being created */
388 	init_type = meta_get_init_type(argc, argv);
389 
390 	/*
391 	 * Metatrans is eof
392 	 */
393 	if (init_type == TAB_TRANS)
394 		return (mderror(ep, MDE_EOF_TRANS, NULL));
395 
396 	/* hotspare pool */
397 	if (init_type == TAB_HSP)
398 		return (meta_init_hsp(spp, argc, argv, options, ep));
399 
400 	/*
401 	 * We are creating metadevice so make sure the name
402 	 * has not been used
403 	 */
404 	if (is_existing_meta_hsp(*spp, cname)) {
405 		/*
406 		 * The name has been used by hsp
407 		 */
408 		if (is_existing_hsp(*spp, cname)) {
409 			return (mderror(ep, MDE_NAME_IN_USE, cname));
410 		}
411 
412 		/*
413 		 * If path exists but unit is not created
414 		 * then meta_init_make_device will correct
415 		 * that.  If unit also exists then it
416 		 * will return a conflict error
417 		 */
418 		if (init_type != TAB_UNKNOWN) {
419 		    /* Create device node */
420 		    if ((key = meta_init_make_device(spp, uname,
421 			&t_e)) <= 0) {
422 			return (mdstealerror(ep, &t_e));
423 		    }
424 		}
425 	}
426 
427 	/* metadevice */
428 	if (argc >= 2 && init_type != TAB_UNKNOWN) {
429 		/*
430 		 * We need to create the device node if the specified metadevice
431 		 * does not already exist in the database. The actual creation
432 		 * is undertaken by the md driver and the links propagated by
433 		 * devfsadm.
434 		 */
435 		if (key == MD_KEYWILD) {
436 			if ((key = meta_init_make_device(spp, uname,
437 			    &t_e)) <= 0)
438 				return (mdstealerror(ep, &t_e));
439 		}
440 
441 		switch (init_type) {
442 		case TAB_MIRROR:
443 			rval = meta_init_mirror(spp, argc, argv, options, ep);
444 			break;
445 		case TAB_RAID:
446 			rval = meta_init_raid(spp, argc, argv, options, ep);
447 			break;
448 		case TAB_SP:
449 			rval = meta_init_sp(spp, argc, argv, options, ep);
450 			break;
451 		case TAB_STRIPE:
452 			rval = meta_init_stripe(spp, argc, argv, options, ep);
453 			break;
454 		}
455 
456 		if (rval == -1 || !(options & MDCMD_DOIT)) {
457 			/*
458 			 * Remove the device node created before
459 			 */
460 			if ((meta_getnmentbykey((*spp)->setno, MD_SIDEWILD,
461 			    key, NULL, &mnum, NULL, ep) != NULL) &&
462 			    MD_MIN2UNIT(mnum) < MD_MAXUNITS) {
463 			    (void) metaioctl(MD_IOCREM_DEV, &mnum, &t_e, NULL);
464 			}
465 
466 			/*
467 			 * Del what we added before
468 			 */
469 			(void) del_self_name(*spp, key, &t_e);
470 		}
471 		return (rval);
472 	}
473 
474 	/* unknown type */
475 	p = Malloc(1 + strlen(uname) + 1 + 1);
476 	(void) strcpy(p, "\"");
477 	(void) strcat(p, uname);
478 	(void) strcat(p, "\"");
479 	rval = mderror(ep, MDE_SYNTAX, p);
480 	Free(p);
481 	return (rval);
482 }
483