xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_init.c (revision fd9cb95cbb2f626355a60efb9d02c5f0a33c10e6)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 /*
31  * initialize metadevices
32  */
33 
34 #include <meta.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
213  *		-1	Error. <ep> contains error reason
214  */
215 int
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 	int			rval = 0;
225 	char			*p, *e = uname;
226 	size_t			len = strlen(uname);
227 
228 	e += len;
229 	(void) memset(&params, 0, sizeof (params));
230 	MD_SETDRIVERNAME(&params, "md", (*spp)->setno);
231 
232 	/*
233 	 * Find the start of the unit within <uname>.
234 	 */
235 	p = strrchr(uname, '/');
236 	if (p == NULL) {
237 		/* Relative name (e.g. d80) */
238 		p = &uname[1];
239 	} else {
240 		/* qualified name (e.g. /dev/md/dsk/d80) */
241 		p += 2;
242 		if (p >= e) {
243 			/* Invalid drive name */
244 			p = Malloc(len + 3);
245 			(void) snprintf(p, len + 3, "\"%s\"", uname);
246 			rval = mderror(ep, MDE_NOT_DRIVENAME, p);
247 			Free(p);
248 			return (rval);
249 		}
250 	}
251 	e = NULL;
252 	params.mnum = strtoul(p, &e, 10);
253 	if (e == p) {
254 		/* Invalid drive name */
255 		p = Malloc(len + 3);
256 		(void) snprintf(p, len + 3, "\"%s\"", uname);
257 		rval = mderror(ep, MDE_NOT_DRIVENAME, p);
258 		Free(p);
259 		return (rval);
260 	}
261 
262 	if (metaioctl(MD_IOCMAKE_DEV, &params, &params.mde, NULL) != 0) {
263 		return (mdstealerror(ep, &params.mde));
264 	}
265 	/*
266 	 * Wait until device appears in namespace. di_devlink_init() returns
267 	 * once the /dev links have been created. If NULL is returned the
268 	 * link operation failed and we haven't got a device to use.
269 	 * NOTE: This will take a _long_ time for large numbers of metadevices.
270 	 *	 Change to use the enhanced di_devlink_init() interface when
271 	 *	 available.
272 	 */
273 	hdl = di_devlink_init("md", DI_MAKE_LINK);
274 	if (hdl != NULL) {
275 		(void) di_devlink_fini(&hdl);
276 	} else {
277 		p = Malloc(len + 3);
278 		(void) snprintf(p, len + 3, "\"%s\"", uname);
279 		rval = mderror(ep, MDE_UNIT_NOT_FOUND, p);
280 		Free(p);
281 	}
282 	return (rval);
283 }
284 
285 /*
286  * FUNCTION:	is_metadb_cmd()
287  * INPUT:	argc	- number of command line arguments
288  *		argv	- pointer to array of command line arguments
289  * OUTPUT:	none
290  * RETURNS:	TRUE if a metadb is to be created, FALSE otherwise
291  * PURPOSE:	parses enough of the command line to determine if a metadb
292  *		create is being attempted
293  */
294 static boolean_t
295 is_metadb_cmd(
296 	int	argc,
297 	char	*argv[]
298 )
299 {
300 	ulong_t	num;
301 	int	len;
302 
303 	/* look for match */
304 	if (argc > 0 && (sscanf(argv[0], "mddb%lu%n", &num, &len) == 1) &&
305 		    (strlen(argv[0]) == len) && ((long)num >= 0)) {
306 		return (B_TRUE);
307 	}
308 
309 	return (B_FALSE);
310 }
311 
312 /*
313  * FUNCTION:	is_stripe_cmd()
314  * INPUT:	argc	- number of command line arguments
315  *		argv	- pointer to array of command line arguments
316  * OUTPUT:	none
317  * RETURNS:	TRUE if a stripe is to be created, FALSE otherwise
318  * PURPOSE:	parses enough of the command line to determine if a stripe
319  *		create is being attempted
320  */
321 static boolean_t
322 is_stripe_cmd(
323 	int	argc,
324 	char	*argv[]
325 )
326 {
327 	uint_t	nrow;
328 
329 	if (argc > 1 && (sscanf(argv[1], "%u", &nrow) != 1) || ((int)nrow < 0))
330 		return (B_FALSE);
331 
332 	return (B_TRUE);
333 }
334 
335 /*
336  * FUNCTION:	meta_get_init_type()
337  * INPUT:	argc	- number of command line arguments
338  *		argv	- pointer to array of command line arguments
339  * OUTPUT:	none
340  * RETURNS:	type of metadevice or hot spare pools being initialized
341  * PURPOSE:	parses enough of the command line to determine what type
342  *		of metainit is being attempted
343  */
344 mdinittypes_t
345 meta_get_init_type(
346 	int 	argc,
347 	char	*argv[]
348 )
349 {
350 	char		*arg = argv[1];
351 	mdinittypes_t	init_type;
352 
353 	if (argc == 1) /* must be a hot spare pool w/o devices */
354 		return (TAB_HSP);
355 
356 	init_type = TAB_UNKNOWN;
357 	if (arg != NULL) {
358 		if (strcmp(arg, "-m") == 0) {
359 			init_type = TAB_MIRROR;
360 		} else if (strcmp(arg, "-r") == 0) {
361 			init_type = TAB_RAID;
362 		} else if (strcmp(arg, "-p") == 0) {
363 			init_type = TAB_SP;
364 		} else if (strcmp(arg, "-t") == 0) {
365 			init_type = TAB_TRANS;
366 		} else if (is_metadb_cmd(argc, argv)) {
367 			init_type = TAB_MDDB;
368 		} else if (is_stripe_cmd(argc, argv)) {
369 			init_type = TAB_STRIPE;
370 		} else { /* assume that it is a hsp */
371 			init_type = TAB_HSP;
372 		}
373 	}
374 	return (init_type);
375 }
376 
377 /*
378  * initialize named device or hotspare pool
379  */
380 int
381 meta_init_name(
382 	mdsetname_t	**spp,
383 	int		argc,
384 	char		*argv[],
385 	mdcmdopts_t	options,
386 	md_error_t	*ep
387 )
388 {
389 	mdinittypes_t	init_type;
390 	char		*p;
391 	int		rval;
392 	char		*uname = argv[0];
393 
394 	assert(argc > 0);
395 
396 	/* determine type of metadevice or hot spare pool being created */
397 	init_type = meta_get_init_type(argc, argv);
398 
399 	/* hotspare pool */
400 	if (init_type == TAB_HSP)
401 		return (meta_init_hsp(spp, argc, argv, options, ep));
402 
403 	/* metadevice */
404 	if (argc >= 2 && init_type != TAB_UNKNOWN) {
405 		md_error_t	t_e = mdnullerror;
406 		char	*cname;
407 
408 		/*
409 		 * We need to create the device node if the specified metadevice
410 		 * does not already exist in the database. The actual creation
411 		 * is undertaken by the md driver and the links propagated by
412 		 * devfsadm.
413 		 */
414 
415 		/* initialize the spp properly */
416 		if ((cname = meta_name_getname(spp, uname, &t_e)) != NULL)
417 			Free(cname);
418 		if (! mdisok(&t_e))
419 			return (mdstealerror(ep, &t_e));
420 
421 		/* Create device node */
422 		if (meta_init_make_device(spp, uname, &t_e) != 0) {
423 			return (mdstealerror(ep, &t_e));
424 		}
425 
426 		switch (init_type) {
427 		case TAB_MIRROR:
428 			return (meta_init_mirror(spp, argc, argv, options, ep));
429 			break;
430 		case TAB_RAID:
431 			return (meta_init_raid(spp, argc, argv, options, ep));
432 			break;
433 		case TAB_SP:
434 			return (meta_init_sp(spp, argc, argv, options, ep));
435 			break;
436 		case TAB_TRANS:
437 			return (mderror(ep, MDE_EOF_TRANS, NULL));
438 			break;
439 		case TAB_STRIPE:
440 			return (meta_init_stripe(spp, argc, argv, options, ep));
441 			break;
442 		}
443 	}
444 
445 	/* unknown type */
446 	p = Malloc(1 + strlen(uname) + 1 + 1);
447 	(void) strcpy(p, "\"");
448 	(void) strcat(p, uname);
449 	(void) strcat(p, "\"");
450 	rval = mderror(ep, MDE_SYNTAX, p);
451 	Free(p);
452 	return (rval);
453 }
454