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