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