xref: /onnv-gate/usr/src/lib/lvm/libpreen/common/mdpreen.c (revision 3149:112750a9ab02)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51207Sachimm  * Common Development and Distribution License (the "License").
61207Sachimm  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221207Sachimm  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * preenlib interface for SVM.
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * On startup fsck attempts to check filesystems in parallel. However
320Sstevel@tonic-gate  * running mutiple fscks on the same disk at the same time
330Sstevel@tonic-gate  * significantly degrades the performance. fsck code avoids such
340Sstevel@tonic-gate  * behavior. To analyse such patterns it needs the physical disk
350Sstevel@tonic-gate  * instance. preen_build_devs provides that information for
360Sstevel@tonic-gate  * filesystems that are on top of metadevices.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
392805Seota #include <ctype.h>
400Sstevel@tonic-gate #include <meta.h>
410Sstevel@tonic-gate #include <limits.h>
420Sstevel@tonic-gate #include <sys/types.h>
430Sstevel@tonic-gate #include <sys/stat.h>
44645Sgjelinek #include <zone.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #include <sdssc.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #define	MAX_N2M_ALIAS_LINE	(2*FILENAME_MAX + 1)
490Sstevel@tonic-gate #define	NAME_TO_MAJOR		"/etc/name_to_major"
500Sstevel@tonic-gate #define	MD_MODULE		"md"
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  *	Macros to produce a quoted string containing the value of a
540Sstevel@tonic-gate  *	preprocessor macro. For example, if SIZE is defined to be 256,
550Sstevel@tonic-gate  *	VAL2STR(SIZE) is "256". This is used to construct format
560Sstevel@tonic-gate  *	strings for scanf-family functions below.
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate #define	QUOTE(x)	#x
590Sstevel@tonic-gate #define	VAL2STR(x)	QUOTE(x)
600Sstevel@tonic-gate 
610Sstevel@tonic-gate extern	void	preen_addunit(void *cookie, char *dname, int (*cf)(),
620Sstevel@tonic-gate 		    void *datap, uint_t unit);
630Sstevel@tonic-gate extern	int	preen_subdev(char *name, struct dk_cinfo *dkiop, void *dp);
640Sstevel@tonic-gate 
652805Seota static	int	is_blank(char *);
662805Seota 
672805Seota /*
682805Seota  * is_blank() returns 1 (true) if a line specified is composed of
692805Seota  * whitespace characters only. otherwise, it returns 0 (false).
702805Seota  *
712805Seota  * Note. the argument (line) must be null-terminated.
722805Seota  */
732805Seota static int
is_blank(char * line)742805Seota is_blank(char *line)
752805Seota {
762805Seota 	for (/* nothing */; *line != '\0'; line++)
772805Seota 		if (!isspace(*line))
782805Seota 			return (0);
792805Seota 	return (1);
802805Seota }
812805Seota 
820Sstevel@tonic-gate static int
get_major_from_n2m(char * modname,int * major)830Sstevel@tonic-gate get_major_from_n2m(char *modname, int *major)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	FILE *fp;
860Sstevel@tonic-gate 	char drv[FILENAME_MAX + 1];
870Sstevel@tonic-gate 	int entry;
880Sstevel@tonic-gate 	int found = 0;
892805Seota 	char line[MAX_N2M_ALIAS_LINE], *cp;
900Sstevel@tonic-gate 	int status = 0;
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	if ((fp = fopen(NAME_TO_MAJOR, "r")) == NULL) {
930Sstevel@tonic-gate 		return (-1);
940Sstevel@tonic-gate 	}
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	while ((fgets(line, sizeof (line), fp) != NULL) &&
970Sstevel@tonic-gate 						status == 0) {
982805Seota 		/* cut off comments starting with '#' */
992805Seota 		if ((cp = strchr(line, '#')) != NULL)
1002805Seota 			*cp = '\0';
1012805Seota 		/* ignore comment or blank lines */
1022805Seota 		if (is_blank(line))
1032805Seota 			continue;
1042805Seota 		/* sanity-check */
1050Sstevel@tonic-gate 		if (sscanf(line, "%" VAL2STR(FILENAME_MAX) "s %d",
1060Sstevel@tonic-gate 		    drv, &entry) != 2) {
1070Sstevel@tonic-gate 			status = -1;
1080Sstevel@tonic-gate 		}
1090Sstevel@tonic-gate 		if (strcmp(drv, modname) == 0) {
1100Sstevel@tonic-gate 			*major = entry;
1110Sstevel@tonic-gate 			found = 1;
1120Sstevel@tonic-gate 			break;
1130Sstevel@tonic-gate 		}
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	/*
1170Sstevel@tonic-gate 	 * if no match is found return -1
1180Sstevel@tonic-gate 	 */
1190Sstevel@tonic-gate 	if (found == 0)
1200Sstevel@tonic-gate 		status = -1;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate 	(void) fclose(fp);
1230Sstevel@tonic-gate 	return (status);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * This routine is called from preenlib the first time. It is then
1280Sstevel@tonic-gate  * recursively called through preen_subdev.
1290Sstevel@tonic-gate  *
1300Sstevel@tonic-gate  * The argument passed in (uname) starts with the special device from
1310Sstevel@tonic-gate  * /etc/vfstab. Recursive calls pass in the underlying physical device
1320Sstevel@tonic-gate  * names.
1330Sstevel@tonic-gate  */
1340Sstevel@tonic-gate void
preen_build_devs(char * uname,struct dk_cinfo * dkiop,void * dp)1350Sstevel@tonic-gate preen_build_devs(
1360Sstevel@tonic-gate 	char		*uname,		/* name of metadevice */
1370Sstevel@tonic-gate 	struct dk_cinfo	*dkiop,		/* associated controller info */
1380Sstevel@tonic-gate 	void		*dp		/* magic info */
1390Sstevel@tonic-gate )
1400Sstevel@tonic-gate {
1410Sstevel@tonic-gate 	char		*setname = NULL;
142*3149Spetede 	char		*tname = NULL;
1430Sstevel@tonic-gate 	mdsetname_t	*sp;
1440Sstevel@tonic-gate 	mdname_t	*namep;		/* metadevice name */
1450Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;	/* list of real devices */
1460Sstevel@tonic-gate 	mdnamelist_t	*p;
1470Sstevel@tonic-gate 	devid_nmlist_t	*nm_list = NULL;
1480Sstevel@tonic-gate 	md_error_t	status = mdnullerror;
1490Sstevel@tonic-gate 	md_error_t	*ep = &status;
1500Sstevel@tonic-gate 	int		ep_valid = 0;	/* does ep contain a real error */
1510Sstevel@tonic-gate 	struct stat	statb;
1520Sstevel@tonic-gate 	static int	md_major = -1;
1530Sstevel@tonic-gate 	side_t		sideno;
1540Sstevel@tonic-gate 
155645Sgjelinek 	/*
156645Sgjelinek 	 * The rest of the code in this library can't work within a
157645Sgjelinek 	 * non-global zone so we just return the top level metadevice back
158645Sgjelinek 	 * to be fscked.
159645Sgjelinek 	 */
160645Sgjelinek 	if (getzoneid() != GLOBAL_ZONEID) {
161645Sgjelinek 		preen_addunit(dp, dkiop->dki_dname, NULL, NULL,
162645Sgjelinek 		    dkiop->dki_unit);
163645Sgjelinek 		return;
164645Sgjelinek 	}
165645Sgjelinek 
1660Sstevel@tonic-gate 	if (stat(uname, &statb) != 0)
1670Sstevel@tonic-gate 		return;
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	if (md_major == -1 &&
1700Sstevel@tonic-gate 		get_major_from_n2m(MD_MODULE, &md_major) != 0)
1710Sstevel@tonic-gate 		return;
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	/*
1740Sstevel@tonic-gate 	 * If the path passed in is not a metadevice, then add that
1750Sstevel@tonic-gate 	 * device to the list (preen_addunit) since it has to be a
1760Sstevel@tonic-gate 	 * physical device.
1770Sstevel@tonic-gate 	 */
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if (major(statb.st_rdev) != md_major) {
1800Sstevel@tonic-gate 		preen_addunit(dp, dkiop->dki_dname, NULL, NULL,
1810Sstevel@tonic-gate 		    dkiop->dki_unit);
1820Sstevel@tonic-gate 		return;
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 	/*
1850Sstevel@tonic-gate 	 * Bind to the cluster library
1860Sstevel@tonic-gate 	 */
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	if (sdssc_bind_library() == SDSSC_ERROR)
1890Sstevel@tonic-gate 		return;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	if (md_init_daemon("fsck", ep) != 0) {
1920Sstevel@tonic-gate 		ep_valid = 1;
1930Sstevel@tonic-gate 		goto out;
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 
1960Sstevel@tonic-gate 	/*
1970Sstevel@tonic-gate 	 * parse the path name to get the diskset name.
1980Sstevel@tonic-gate 	 */
199*3149Spetede 	parse_device(NULL, uname, &tname, &setname);
200*3149Spetede 	Free(tname);
2010Sstevel@tonic-gate 	if ((sp = metasetname(setname, ep)) == NULL) {
2020Sstevel@tonic-gate 		ep_valid = 1;
2030Sstevel@tonic-gate 		goto out;
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	/* check for ownership */
2070Sstevel@tonic-gate 	if (meta_check_ownership(sp, ep) != 0) {
2080Sstevel@tonic-gate 		/*
2090Sstevel@tonic-gate 		 * Don't own the set but we are here implies
2100Sstevel@tonic-gate 		 * that this is a clustered proxy device. Simply add
2110Sstevel@tonic-gate 		 * the unit.
2120Sstevel@tonic-gate 		 */
2130Sstevel@tonic-gate 		preen_addunit(dp, dkiop->dki_dname, NULL, NULL,
2140Sstevel@tonic-gate 		    dkiop->dki_unit);
2150Sstevel@tonic-gate 		ep_valid = 1;
2160Sstevel@tonic-gate 		goto out;
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * get list of underlying physical devices.
2210Sstevel@tonic-gate 	 */
2221623Stw21770 	if ((namep = metaname(&sp, uname, UNKNOWN, ep)) == NULL) {
2230Sstevel@tonic-gate 		ep_valid = 1;
2240Sstevel@tonic-gate 		goto out;
2250Sstevel@tonic-gate 	}
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	if (namep->dev == NODEV64) {
2280Sstevel@tonic-gate 		goto out;
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	if (meta_getdevs(sp, namep, &nlp, ep) != 0) {
2320Sstevel@tonic-gate 		ep_valid = 1;
2330Sstevel@tonic-gate 		goto out;
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	if ((sideno = getmyside(sp, ep)) == MD_SIDEWILD) {
2370Sstevel@tonic-gate 		ep_valid = 1;
2380Sstevel@tonic-gate 		goto out;
2390Sstevel@tonic-gate 	}
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	/* gather and add the underlying devs */
2420Sstevel@tonic-gate 	for (p = nlp; (p != NULL); p = p->next) {
2430Sstevel@tonic-gate 		mdname_t	*devnp = p->namep;
2440Sstevel@tonic-gate 		int		fd;
2450Sstevel@tonic-gate 		struct dk_cinfo	cinfo;
2460Sstevel@tonic-gate 		ddi_devid_t	md_did;
2470Sstevel@tonic-gate 		char		*devname;
2480Sstevel@tonic-gate 		char		*minor_name = NULL;
2490Sstevel@tonic-gate 		char		mname[MAXPATHLEN];
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		/*
2520Sstevel@tonic-gate 		 * we don't want to use the rname anymore because
2530Sstevel@tonic-gate 		 * that may have changed. Use the device id information
2540Sstevel@tonic-gate 		 * to find the correct ctd name and open based on that.
2550Sstevel@tonic-gate 		 * If there isn't a devid or we have a did device, then
2560Sstevel@tonic-gate 		 * use the rname. In clustering, it's corrected for us.
2570Sstevel@tonic-gate 		 * If no devid it's at least worth a try.
2580Sstevel@tonic-gate 		 */
2590Sstevel@tonic-gate 		if (((md_did = meta_getdidbykey(sp->setno, sideno,
2600Sstevel@tonic-gate 		    devnp->key, ep)) == NULL) || ((minor_name =
2610Sstevel@tonic-gate 		    meta_getdidminorbykey(sp->setno, sideno,
2620Sstevel@tonic-gate 		    devnp->key, ep)) == NULL)) {
2630Sstevel@tonic-gate 			devname = devnp->rname;
2640Sstevel@tonic-gate 			if (md_did)
2650Sstevel@tonic-gate 				Free(md_did);
2660Sstevel@tonic-gate 		} else {
2670Sstevel@tonic-gate 			if (strstr(minor_name, ",raw") == NULL) {
2680Sstevel@tonic-gate 				(void) snprintf(mname, MAXPATHLEN, "%s,raw",
2690Sstevel@tonic-gate 				    minor_name);
2700Sstevel@tonic-gate 			} else {
2710Sstevel@tonic-gate 				(void) snprintf(mname, MAXPATHLEN, "%s",
2720Sstevel@tonic-gate 				    minor_name);
2730Sstevel@tonic-gate 			}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 			/*
2760Sstevel@tonic-gate 			 * We need to make sure we call this with a specific
2770Sstevel@tonic-gate 			 * mname (raw mname) so that we get the exact slice
2780Sstevel@tonic-gate 			 * with the given device id. Otherwise we could try
2790Sstevel@tonic-gate 			 * to open a slice that doesn't really exist.
2800Sstevel@tonic-gate 			 */
2810Sstevel@tonic-gate 			if (meta_deviceid_to_nmlist("/dev", md_did,
2820Sstevel@tonic-gate 			    mname, &nm_list) != 0) {
2830Sstevel@tonic-gate 				(void) mdsyserror(ep, errno, devnp->rname);
2840Sstevel@tonic-gate 				ep_valid = 1;
2850Sstevel@tonic-gate 				Free(md_did);
2860Sstevel@tonic-gate 				Free(minor_name);
2870Sstevel@tonic-gate 				goto out;
2880Sstevel@tonic-gate 			}
2890Sstevel@tonic-gate 			devname = Strdup(nm_list->devname);
2900Sstevel@tonic-gate 			Free(md_did);
2910Sstevel@tonic-gate 			Free(minor_name);
2920Sstevel@tonic-gate 			devid_free_nmlist(nm_list);
2930Sstevel@tonic-gate 		}
2940Sstevel@tonic-gate 		/* get device name and (real) cinfo */
2950Sstevel@tonic-gate 		if ((fd = open(devname, O_RDONLY, 0)) < 0) {
2960Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, devname);
2970Sstevel@tonic-gate 			ep_valid = 1;
2981207Sachimm 			/*
2991207Sachimm 			 * We need to scan all sub devices even if some fail
3001207Sachimm 			 * since exit here would end up in not finishing fsck
3011207Sachimm 			 * on all devices and prevent us from going into
3021207Sachimm 			 * multiuser mode.
3031207Sachimm 			 */
3041207Sachimm 			continue;
3050Sstevel@tonic-gate 		}
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 		if (ioctl(fd, DKIOCINFO, &cinfo) != 0) {
3080Sstevel@tonic-gate 			(void) mdsyserror(ep, errno, devname);
3090Sstevel@tonic-gate 			(void) close(fd);
3100Sstevel@tonic-gate 			ep_valid = 1;
3111207Sachimm 			/* Continue here too. See comment from before */
3121207Sachimm 			continue;
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 		(void) close(fd);	/* sd/ssd bug */
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 		/*
3170Sstevel@tonic-gate 		 * preen_subdev fails when the device name has been
3180Sstevel@tonic-gate 		 * resolved to the physical layer. Hence it is added
3190Sstevel@tonic-gate 		 * to preen_addunit.
3200Sstevel@tonic-gate 		 */
3210Sstevel@tonic-gate 		if (preen_subdev(devname, &cinfo, dp) != 0) {
3220Sstevel@tonic-gate 			preen_addunit(dp, cinfo.dki_dname, NULL, NULL,
3230Sstevel@tonic-gate 			    cinfo.dki_unit);
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 	}
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	/* cleanup, if we fail, just add this composite device to the list */
3280Sstevel@tonic-gate out:
3290Sstevel@tonic-gate 	if (setname != NULL)
3300Sstevel@tonic-gate 		Free(setname);
3310Sstevel@tonic-gate 	if (ep_valid != 0) {
3320Sstevel@tonic-gate 		mde_perror(&status, "");
3330Sstevel@tonic-gate 		mdclrerror(&status);
3340Sstevel@tonic-gate 	}
3350Sstevel@tonic-gate 	metafreenamelist(nlp);
3360Sstevel@tonic-gate }
337