xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_getdevs.c (revision 4af09fced20c437fbdbaf51bb0a234dff4e81405)
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 /*
29  * get dev_t list
30  */
31 
32 #include <meta.h>
33 
34 #include <sys/mhd.h>
35 #include <strings.h>
36 
37 /*
38  * private version of minor(), able to handle 64 bit and 32 bit devices.
39  * print a warning out in case a 32 bit dev is specified.
40  */
41 minor_t
42 meta_getminor(md_dev64_t dev64)
43 {
44 	/* check if it's a real 64 bit dev */
45 	if ((dev64 >> NBITSMAJOR64) > 0) {
46 		return ((minor_t)(dev64 & MAXMIN64));
47 	} else {
48 		if (getenv("META_DEBUG"))
49 			(void) printf(
50 			    "meta_getminor called with 32 bit dev: 0x%llx\n",
51 			    dev64);
52 		return ((minor_t)(dev64 & MAXMIN32));
53 	}
54 }
55 
56 /*
57  * private version of major(), able to handle 64 bit and 32 bit devices.
58  * print a warning out in case a 32 bit dev is specified.
59  */
60 major_t
61 meta_getmajor(md_dev64_t dev64)
62 {
63 	/* check if it's a real 64 bit dev */
64 	if ((dev64 >> NBITSMAJOR64) > 0) {
65 		return ((major_t)((dev64 >> NBITSMINOR64) & MAXMAJ64));
66 	} else {
67 		if (getenv("META_DEBUG"))
68 			(void) printf(
69 			    "meta_getmajor called with 32 bit dev: 0x%llx\n",
70 			    dev64);
71 		return ((major_t)((dev64 >> NBITSMINOR32) & MAXMAJ32));
72 	}
73 }
74 
75 /*
76  * private version of cmpldev(), able to handle 64 bit and 32 bit devices.
77  */
78 dev32_t
79 meta_cmpldev(md_dev64_t dev64)
80 {
81 	minor_t minor;
82 	major_t major;
83 
84 	major = (major_t)(dev64 >> NBITSMAJOR64);
85 	if (major == 0) {
86 		return ((dev32_t)dev64);
87 	}
88 	minor = (dev32_t)dev64 & MAXMIN32;
89 	return ((major << NBITSMINOR32) | minor);
90 }
91 
92 /*
93  * private version of expldev(), able to handle 64 bit and 32 bit devices.
94  */
95 md_dev64_t
96 meta_expldev(md_dev64_t dev64)
97 {
98 	minor_t minor;
99 	major_t major;
100 
101 	major = (major_t)(dev64 >> NBITSMAJOR64);
102 	if (major > 0) { /* a 64 bit device was given, return unchanged */
103 		return (dev64);
104 	}
105 	minor = (minor_t)(dev64) & MAXMIN32;
106 	major = ((major_t)dev64 >> NBITSMINOR32) & MAXMAJ32;
107 	return (((md_dev64_t)major << NBITSMINOR64) | minor);
108 }
109 
110 /*
111  * get underlying devices (recursively)
112  */
113 int
114 meta_getdevs(
115 	mdsetname_t		*sp,
116 	mdname_t		*namep,
117 	mdnamelist_t		**nlpp,
118 	md_error_t		*ep
119 )
120 {
121 	char			*miscname;
122 	md_dev64_t		*mydevs = NULL;
123 	md_getdevs_params_t	mgd;
124 	size_t			i;
125 	int			rval = -1;
126 	md_sys_error_t		*ip;
127 
128 	/* must have local set */
129 	assert(sp != NULL);
130 
131 	/* if no valid name then return an error */
132 	if (namep == NULL)
133 		return (-1);
134 
135 	/* just add regular devices */
136 	if (! metaismeta(namep)) {
137 		mdnamelist_t	*p;
138 
139 		/*
140 		 * If the dev_t is in the array already
141 		 * then let's continue.
142 		 */
143 		for (p = *nlpp; (p != NULL); p = p->next) {
144 			if (strcmp(namep->bname, p->namep->bname) == 0) {
145 				rval = 0;
146 				goto out;
147 			}
148 		}
149 
150 		/* add to list */
151 		(void) metanamelist_append(nlpp, namep);
152 		rval = 0;
153 		goto out;
154 	}
155 
156 	/* get MD misc module */
157 	if ((miscname = metagetmiscname(namep, ep)) == NULL)
158 		goto out;
159 
160 	/* get count of underlying devices */
161 	(void) memset(&mgd, '\0', sizeof (mgd));
162 	MD_SETDRIVERNAME(&mgd, miscname, sp->setno);
163 	mgd.mnum = meta_getminor(namep->dev);
164 	mgd.cnt = 0;
165 	mgd.devs = NULL;
166 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, namep->cname) != 0) {
167 		if (mgd.mde.info.errclass == MDEC_SYS) {
168 			ip = &mgd.mde.info.md_error_info_t_u.sys_error;
169 			if (ip->errnum == ENODEV) {
170 				rval = 0;
171 				goto out;
172 			}
173 		}
174 		(void) mdstealerror(ep, &mgd.mde);
175 		goto out;
176 	} else if (mgd.cnt <= 0) {
177 		assert(mgd.cnt >= 0);
178 		rval = 0;
179 		goto out;
180 	}
181 
182 	/* get underlying devices */
183 	mydevs = Zalloc(sizeof (*mydevs) * mgd.cnt);
184 	mgd.devs = (uintptr_t)mydevs;
185 	if (metaioctl(MD_IOCGET_DEVS, &mgd, &mgd.mde, namep->cname) != 0) {
186 		if (mgd.mde.info.errclass == MDEC_SYS) {
187 			ip = &mgd.mde.info.md_error_info_t_u.sys_error;
188 			if (ip->errnum == ENODEV) {
189 				rval = 0;
190 				goto out;
191 			}
192 		}
193 		(void) mdstealerror(ep, &mgd.mde);
194 		goto out;
195 	} else if (mgd.cnt <= 0) {
196 		assert(mgd.cnt >= 0);
197 		rval = 0;
198 		goto out;
199 	}
200 	/* recurse */
201 	for (i = 0; (i < mgd.cnt); ++i) {
202 		mdname_t	*devnp;
203 
204 		if (mydevs[i] == NODEV64) {
205 			continue;
206 		}
207 		if ((devnp = metadevname(&sp, mydevs[i], ep)) == NULL) {
208 			if (mdissyserror(ep, ENOENT)) {
209 				mdclrerror(ep);
210 				/*
211 				 * If the device doesn't exist, it could be
212 				 * that we have a wrong dev_t/name
213 				 * combination in the namespace, so
214 				 * meta_fix_compnames try to check this
215 				 * with the unit structure and fix this.
216 				 */
217 				if (meta_fix_compnames(sp, namep,
218 				    mydevs[i], ep) == 0)
219 					continue;
220 			}
221 			goto out;
222 		}
223 		if (meta_getdevs(sp, devnp, nlpp, ep) != 0)
224 			goto out;
225 	}
226 
227 	/* success */
228 	rval = 0;
229 
230 	/* cleanup, return error */
231 out:
232 	if (mydevs != NULL)
233 		Free(mydevs);
234 	return (rval);
235 }
236 
237 /*
238  * get all dev_t for a set
239  */
240 int
241 meta_getalldevs(
242 	mdsetname_t		*sp,		/* set to look in */
243 	mdnamelist_t		**nlpp,		/* returned devices */
244 	int			check_db,
245 	md_error_t		*ep
246 )
247 {
248 	md_replicalist_t	*rlp, *rp;
249 	mdnamelist_t		*nlp, *np;
250 	mdhspnamelist_t		*hspnlp, *hspp;
251 	int			rval = 0;
252 
253 	assert(sp != NULL);
254 
255 	/*
256 	 * Get a replica namelist,
257 	 * and then get all the devs within the replicas.
258 	 */
259 	if (check_db == TRUE) {
260 		rlp = NULL;
261 		if (metareplicalist(sp, MD_BASICNAME_OK, &rlp, ep) < 0)
262 			rval = -1;
263 		for (rp = rlp; (rp != NULL); rp = rp->rl_next) {
264 			if (meta_getdevs(sp, rp->rl_repp->r_namep,
265 			    nlpp, ep) != 0)
266 				rval = -1;
267 		}
268 		metafreereplicalist(rlp);
269 	}
270 
271 	/*
272 	 * Get a stripe namelist,
273 	 * and then get all the devs within the stripes.
274 	 */
275 	nlp = NULL;
276 	if (meta_get_stripe_names(sp, &nlp, 0, ep) < 0)
277 		rval = -1;
278 	for (np = nlp; (np != NULL); np = np->next) {
279 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
280 			rval = -1;
281 	}
282 	metafreenamelist(nlp);
283 
284 	/*
285 	 * Get a mirror namelist,
286 	 * and then get all the devs within the mirrors.
287 	 */
288 	nlp = NULL;
289 	if (meta_get_mirror_names(sp, &nlp, 0, ep) < 0)
290 		rval = -1;
291 	for (np = nlp; (np != NULL); np = np->next) {
292 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
293 			rval = -1;
294 	}
295 	metafreenamelist(nlp);
296 
297 	/*
298 	 * Get a trans namelist,
299 	 * and then get all the devs within the trans.
300 	 */
301 	nlp = NULL;
302 
303 	if (meta_get_trans_names(sp, &nlp, 0, ep) < 0)
304 		rval = -1;
305 	for (np = nlp; (np != NULL); np = np->next) {
306 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
307 			rval = -1;
308 	}
309 	metafreenamelist(nlp);
310 
311 	/*
312 	 * Get a hot spare pool namelist,
313 	 * and then get all the devs within the hot spare pools.
314 	 */
315 	hspnlp = NULL;
316 	if (meta_get_hsp_names(sp, &hspnlp, 0, ep) < 0)
317 		rval = -1;
318 	for (hspp = hspnlp; (hspp != NULL); hspp = hspp->next) {
319 		md_hsp_t	*hsp;
320 		uint_t		i;
321 
322 		if ((hsp = meta_get_hsp(sp, hspp->hspnamep, ep)) == NULL)
323 			rval = -1;
324 		else for (i = 0; (i < hsp->hotspares.hotspares_len); ++i) {
325 			md_hs_t	*hs = &hsp->hotspares.hotspares_val[i];
326 
327 			if (meta_getdevs(sp, hs->hsnamep, nlpp, ep) != 0)
328 				rval = -1;
329 		}
330 	}
331 	metafreehspnamelist(hspnlp);
332 
333 	/*
334 	 * Get a raid namelist,
335 	 * and then get all the devs within the raids.
336 	 */
337 	nlp = NULL;
338 	if (meta_get_raid_names(sp, &nlp, 0, ep) < 0)
339 		rval = -1;
340 	for (np = nlp; (np != NULL); np = np->next) {
341 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
342 			rval = -1;
343 	}
344 	metafreenamelist(nlp);
345 
346 	/*
347 	 * Get a soft partition namelist,
348 	 * and then get all the devs within the softpartitions
349 	 */
350 	nlp = NULL;
351 	if (meta_get_sp_names(sp, &nlp, 0, ep) < 0)
352 		rval = -1;
353 	for (np = nlp; (np != NULL); np = np->next) {
354 		if (meta_getdevs(sp, np->namep, nlpp, ep) != 0)
355 			rval = -1;
356 	}
357 	metafreenamelist(nlp);
358 
359 	return (rval);
360 }
361 
362 /*
363  * get vtoc from a device already opened.
364  * returns
365  *	0 on success,
366  *	-1 on error. If the error was  ENOTSUP, partno will be set to
367  *		VT_ENOTSUP if possible.
368  */
369 int
370 meta_getvtoc(
371 	int		fd,		/* fd for named device */
372 	char		*devname,	/* name of device */
373 	struct vtoc	*vtocbufp,	/* vtoc buffer to fill */
374 	int		*partno,	/* return partno here */
375 	md_error_t	*ep
376 )
377 {
378 	int		part;
379 
380 	(void) memset(vtocbufp, 0, sizeof (*vtocbufp));
381 	if ((part = read_vtoc(fd, vtocbufp)) < 0) {
382 		int	err = errno;
383 
384 		if (ioctl(fd, MHIOCSTATUS, NULL) == 1)
385 			err = EACCES;
386 		else if (part == VT_EINVAL)
387 			err = EINVAL;
388 		else if (part == VT_EIO)
389 			err = EIO;
390 		else if (part == VT_ENOTSUP) {
391 			if (partno) {
392 				*partno = VT_ENOTSUP;
393 				return (-1);
394 			}
395 		}
396 		return (mdsyserror(ep, err, devname));
397 	}
398 
399 	/* Slice number for *p0 partition (whole disk on x86) is 16 */
400 	if (part >= V_NUMPAR)
401 		return (mdsyserror(ep, EINVAL, devname));
402 
403 	if (partno)
404 		*partno = part;
405 	return (0);
406 }
407 /*
408  * set mdvtoc for a meta devices
409  */
410 int
411 meta_setmdvtoc(
412 	int		fd,		/* fd for named device */
413 	char		*devname,	/* name of device */
414 	mdvtoc_t	*mdvtocp,	/* mdvtoc buffer to fill */
415 	md_error_t	*ep
416 )
417 {
418 	uint_t i;
419 
420 	/*
421 	 * Sanity-check the mdvtoc
422 	 */
423 
424 	if (mdvtocp->nparts > V_NUMPAR) {
425 		return (-1);
426 	}
427 
428 	/*
429 	 * since many drivers won't allow opening a device make sure
430 	 * all partitions aren't being set to zero. If all are zero then
431 	 * we have no way to set them to something else
432 	 */
433 
434 	for (i = 0; i < mdvtocp->nparts; i++)
435 		if (mdvtocp->parts[i].size > 0)
436 			break;
437 	if (i == mdvtocp->nparts)
438 		return (-1);
439 
440 	/*
441 	 * Write the mdvtoc
442 	 */
443 	if (ioctl(fd, DKIOCSVTOC, (caddr_t)mdvtocp) == -1) {
444 		return (mdsyserror(ep, errno, devname));
445 	}
446 
447 	return (0);
448 }
449 
450 /*
451  * set vtoc
452  */
453 int
454 meta_setvtoc(
455 	int		fd,		/* fd for named device */
456 	char		*devname,	/* name of device */
457 	struct vtoc	*vtocbufp,	/* vtoc buffer to fill */
458 	md_error_t	*ep
459 )
460 {
461 	int		part;
462 	int		err;
463 
464 	if ((part = write_vtoc(fd, vtocbufp)) < 0) {
465 		if (part == VT_EINVAL)
466 			err = EINVAL;
467 		else if (part == VT_EIO)
468 			err = EIO;
469 		else
470 			err = errno;
471 		return (mdsyserror(ep, err, devname));
472 	}
473 
474 	return (0);
475 }
476 
477 /*
478  * FUNCTION:	meta_get_names()
479  * INPUT:	drivername - char string containing the driver name
480  *		sp	- the set name to get soft partitions from
481  *		options	- options from the command line
482  * OUTPUT:	nlpp	- list of all soft partition names
483  *		ep	- return error pointer
484  * RETURNS:	int	- -1 if error, 0 success
485  * PURPOSE:	returns a list of all specified devices in the metadb
486  *		for all devices in the specified set
487  */
488 int
489 meta_get_names(
490 	char		*drivername,
491 	mdsetname_t	*sp,
492 	mdnamelist_t	**nlpp,
493 	mdprtopts_t	options,
494 	md_error_t	*ep
495 )
496 {
497 	md_i_getnum_t	gn;		/* MD_IOCGET_NUM params */
498 	mdnamelist_t	**tailpp = nlpp;
499 	minor_t		*minors = NULL;
500 	minor_t		*m_ptr;
501 	int		i;
502 
503 	(void) memset(&gn, '\0', sizeof (gn));
504 	MD_SETDRIVERNAME(&gn, drivername, sp->setno);
505 
506 	/* get number of devices */
507 	if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
508 		if (mdiserror(&gn.mde, MDE_UNIT_NOT_FOUND)) {
509 			mdclrerror(&gn.mde);
510 		} else {
511 			(void) mdstealerror(ep, &gn.mde);
512 			return (-1);
513 		}
514 	}
515 
516 	if (gn.size > 0) {
517 		/* malloc minor number buffer to be filled by ioctl */
518 		if ((minors = (minor_t *)malloc(
519 		    gn.size * sizeof (minor_t))) == 0) {
520 			return (ENOMEM);
521 		}
522 		gn.minors = (uintptr_t)minors;
523 		if (metaioctl(MD_IOCGET_NUM, &gn, &gn.mde, NULL) != 0) {
524 			(void) mdstealerror(ep, &gn.mde);
525 			free(minors);
526 			return (-1);
527 		}
528 		m_ptr = minors;
529 		for (i = 0; i < gn.size; i++) {
530 			mdname_t	*np;
531 
532 			/* get name */
533 			np = metamnumname(&sp, *m_ptr,
534 			    ((options & PRINT_FAST) ? 1 : 0), ep);
535 
536 			/*
537 			 * np can be NULL if the /dev/md namespace entries
538 			 * do not exist. This could have happened due to
539 			 * devfsadmd not having created them.
540 			 * Therefore assume devfsadmd has not run and tell
541 			 * it to run for the specific device that is missing.
542 			 * Ignore any error return from meta_update_devtree
543 			 * as a failure to create the device nodes will be
544 			 * picked up in the metamnumname() call. Note that
545 			 * the call to meta_update_devtree should not return
546 			 * until the /dev/md links have been created or if
547 			 * there has been a failure of some sort.
548 			 */
549 			if (np == NULL) {
550 				(void) meta_update_devtree(*m_ptr);
551 				np = metamnumname(&sp, *m_ptr,
552 				    ((options & PRINT_FAST) ? 1 : 0), ep);
553 			}
554 
555 			if (np == NULL)
556 				goto out;
557 
558 			tailpp = meta_namelist_append_wrapper(tailpp, np);
559 
560 			/* next device */
561 			m_ptr++;
562 		}
563 		free(minors);
564 	}
565 	return (gn.size);
566 
567 out:
568 	if (minors != NULL)
569 		free(minors);
570 	metafreenamelist(*nlpp);
571 	*nlpp = NULL;
572 	return (-1);
573 }
574 
575 /*
576  * Wrap lib/libdevid/devid_deviceid_to_nmlist.  We want to take the
577  * results from that function and filter out the c[t]dp style names that
578  * we typically see on x86 so that we never see them.
579  */
580 int
581 meta_deviceid_to_nmlist(char *search_path, ddi_devid_t devid, char *minor_name,
582 	devid_nmlist_t	**retlist)
583 {
584 	int		res;
585 	devid_nmlist_t	*dp;
586 	devid_nmlist_t	*tmp_retlist;
587 	int		i = 1;
588 	devid_nmlist_t	*rp;
589 
590 	res = devid_deviceid_to_nmlist(search_path, devid, minor_name, retlist);
591 	if (res != 0) {
592 		return (res);
593 	}
594 
595 
596 	/* first count the number of non c[t]dp items in retlist */
597 	for (dp = *retlist; dp->dev != NODEV; dp++) {
598 		uint_t		s;
599 
600 		/* Check if this is a c[t]dp style name.  */
601 		if (parse_ctd(basename(dp->devname), &s) != 1) {
602 			i++;
603 		}
604 	}
605 
606 	/* create an array to hold the non c[t]dp items */
607 	tmp_retlist = Malloc(sizeof (devid_nmlist_t) * i);
608 	/* copy the non c[t]dp items to the array */
609 	for (dp = *retlist, rp = tmp_retlist; dp->dev != NODEV; dp++) {
610 		uint_t		s;
611 
612 		/* Check if this is a c[t]dp style name.  */
613 		if (parse_ctd(basename(dp->devname), &s) != 1) {
614 			/* nope, so copy and go to the next */
615 			rp->dev = dp->dev;
616 			rp->devname = Strdup(dp->devname);
617 			rp++;
618 		}
619 		/* if it is c[t]dp, just skip the element */
620 	}
621 	/* copy the list terminator */
622 	rp->dev = NODEV;
623 	rp->devname = NULL;
624 	devid_free_nmlist (*retlist);
625 	*retlist = tmp_retlist;
626 	return (res);
627 }
628 
629 /*
630  * Check each real device that makes up a metadevice so that
631  * un_dev entries can be matched against the entries in the
632  * namespace.
633  *
634  * RETURN:
635  *      -1      error
636  *       0      success
637  */
638 int
639 meta_fix_compnames(
640 	mdsetname_t	*sp,
641 	mdname_t	*namep,
642 	md_dev64_t	dev,
643 	md_error_t	*ep
644 )
645 {
646 	int	ret = 0;
647 	char	*miscname;
648 
649 	/* get miscname and unit */
650 	if ((miscname = metagetmiscname(namep, ep)) == NULL)
651 		return (-1);
652 	if (strcmp(miscname, MD_STRIPE) == 0) {
653 		if (meta_stripe_check_component(sp, namep, dev, ep) < 0) {
654 			ret = -1;
655 		}
656 	} else if (strcmp(miscname, MD_SP) == 0) {
657 		if (meta_sp_check_component(sp, namep, ep) < 0) {
658 			ret = -1;
659 		}
660 	} else if (strcmp(miscname, MD_RAID) == 0) {
661 		if (meta_raid_check_component(sp, namep, dev, ep) < 0) {
662 			ret = -1;
663 		}
664 	} else {
665 		(void) mdmderror(ep, MDE_INVAL_UNIT, 0, namep->cname);
666 		return (-1);
667 	}
668 	return (ret);
669 }
670