Home | History | Annotate | Download | only in md_monitord
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include "md_monitord.h"
     28 
     29 #define	MD_PROBE_OPEN_T "probe open test"
     30 
     31 /*
     32  * Failure return's a 1
     33  */
     34 int
     35 hotspare_ok(char *bname)
     36 {
     37 	int fd;
     38 	char buf[512];
     39 
     40 	if ((fd = open(bname, O_RDONLY)) < 0)
     41 		return (0);
     42 	if (read(fd, buf, sizeof (buf)) < 0) {
     43 		(void) close(fd);
     44 		return (0);
     45 	}
     46 	(void) close(fd);
     47 	return (1);
     48 }
     49 
     50 void
     51 delete_hotspares_impl(mdhspname_t *hspnp, md_hsp_t *hspp, boolean_e verbose)
     52 {
     53 	md_hs_t *hsp;
     54 	uint_t		hsi;
     55 	char    *cname, *bname, *hs_state;
     56 	md_error_t e = mdnullerror;
     57 	int deleted_hs = 0;
     58 
     59 	for (hsi = 0; (hsi < hspp->hotspares.hotspares_len); ++hsi) {
     60 		mdnamelist_t *nlp;
     61 
     62 		hsp = &hspp->hotspares.hotspares_val[hsi];
     63 		if (verbose == True)
     64 			monitord_print(6, "hsi %d\n", hsi);
     65 		cname = hsp->hsnamep->cname;
     66 		bname = hsp->hsnamep->bname;
     67 		nlp = NULL;
     68 		(void) metanamelist_append(&nlp, hsp->hsnamep);
     69 		hs_state = hs_state_to_name(hsp, NULL);
     70 		/* print hotspare */
     71 		if (verbose == True)
     72 			monitord_print(6, "\t%-19s\t%-19s\t%-12s\n",
     73 			    cname, bname, hs_state);
     74 		if (hsp->state == HSS_AVAILABLE) {
     75 			if (hotspare_ok(bname))
     76 				continue;
     77 
     78 			monitord_print(6, gettext(
     79 			    "NOTICE: Hotspare %s in %s has failed.\n"
     80 			    "\tDeleting %s since it is not in use\n\n"),
     81 			    bname, hspnp->hspname, bname);
     82 
     83 			if (meta_hs_delete(sp, hspnp, nlp, 0, &e) != NULL) {
     84 				mde_perror(&e, "");
     85 				mdclrerror(&e);
     86 			} else {
     87 				deleted_hs++;
     88 			}
     89 		} else {
     90 			if (verbose == True)
     91 				monitord_print(6, gettext(
     92 				    "%s in use - skipping\n"), cname);
     93 		}
     94 	}
     95 }
     96 
     97 
     98 
     99 /*
    100  * Generic routine to issue probe ioctls
    101  */
    102 
    103 int
    104 md_probe_ioctl(mdnamelist_t *nlp, int ndevs, char *drvname, boolean_e verbose)
    105 {
    106 	mdnamelist_t	*p;
    107 	mdname_t	*np;
    108 	md_probedev_t	probe_ioc, *iocp;
    109 	int		i, retval = 0;
    110 	/*
    111 	 * Allocate space for all the metadevices and fill in
    112 	 * the minor numbers.
    113 	 */
    114 
    115 	(void) memset(&probe_ioc, 0, sizeof (probe_ioc));
    116 	iocp = &probe_ioc;
    117 
    118 	if ((iocp->mnum_list = (uintptr_t)calloc(ndevs, sizeof (minor_t)))
    119 	    == 0) {
    120 		monitord_print(0, "md_probe_ioctl: calloc");
    121 		return (-1);
    122 	}
    123 
    124 	(void) strcpy(iocp->test_name, MD_PROBE_OPEN_T);
    125 	MD_SETDRIVERNAME(&probe_ioc, drvname, sp->setno);
    126 
    127 	if (verbose == True) {
    128 		monitord_print(6, "\n\nmd_probe_ioctl: %s: %s\n",
    129 		    (strcmp(sp->setname, MD_LOCAL_NAME) == 0) ?
    130 		    gettext("local_set") :
    131 		    sp->setname, iocp->md_driver.md_drivername);
    132 	}
    133 
    134 	iocp->nmdevs = ndevs;
    135 	if (verbose == True)
    136 		monitord_print(6, "...ndevs 0x%x\n", ndevs);
    137 
    138 	for (p = nlp, i = 0; p; p = p->next, i++) {
    139 		np = p->namep;
    140 		((minor_t *)(uintptr_t)iocp->mnum_list)[i] =
    141 		    meta_getminor(np->dev);
    142 		if (verbose == True)
    143 			monitord_print(6, "...%s 0x%lx\n", np->cname,
    144 			    ((minor_t *)(uintptr_t)iocp->mnum_list)[i]);
    145 	}
    146 
    147 
    148 	if (issue_ioctl == True) {
    149 		if (metaioctl(MD_IOCPROBE_DEV, iocp, &(iocp->mde), NULL) != 0)
    150 			retval = -1;
    151 	}
    152 
    153 	Free((void *)(uintptr_t)iocp->mnum_list);
    154 	return (retval);
    155 }
    156 /*
    157  *
    158  *  - remove p from nlp list
    159  *  - put it on the toplp list.
    160  *  - update the p to the next element
    161  */
    162 
    163 void
    164 add_to_list(mdnamelist_t **curpp, mdnamelist_t **prevpp,
    165 		mdnamelist_t **newlpp)
    166 {
    167 	mdnamelist_t	*p, *prevp, *nlp;
    168 
    169 	p = *curpp;
    170 	prevp = *prevpp;
    171 	nlp = *newlpp;
    172 
    173 	if (prevp == p) {
    174 		/* if first element reset prevp */
    175 			prevp = p->next;
    176 			p->next = nlp;
    177 			nlp = p;
    178 			p = prevp;
    179 	} else {
    180 		prevp->next = p->next;
    181 		p->next = nlp;
    182 		nlp = p;
    183 		p = prevp->next;
    184 	}
    185 	*curpp = p;
    186 	*prevpp = prevp;
    187 	*newlpp = nlp;
    188 }
    189 /*
    190  * Scans the given list of metadeivces and returns a list of top level
    191  * metadevices.
    192  * Note: The orignal list is not valid at the end and is set to NULL.
    193  */
    194 
    195 int
    196 get_toplevel_mds(mdnamelist_t **lpp, mdnamelist_t **top_pp, boolean_e verbose)
    197 {
    198 	mdnamelist_t	*p, *prevp, *toplp;
    199 	int		ntopmd, i;
    200 	md_common_t	*mdp;
    201 	md_error_t	e = mdnullerror;
    202 
    203 	i = ntopmd = 0;
    204 	prevp = p = *lpp;
    205 	toplp = NULL;
    206 
    207 	while (p) {
    208 		if ((mdp = meta_get_unit(sp, p->namep, &e)) == NULL) {
    209 			mdclrerror(&e);
    210 			if (verbose == True)
    211 				monitord_print(6, gettext(
    212 				    "......error on (%d)%s\n"), i,
    213 				    p->namep->devicesname);
    214 				prevp = p;
    215 				p = p->next;
    216 				continue;
    217 		}
    218 
    219 		if (mdp->parent == MD_NO_PARENT) {
    220 			/* increment the top level md count. */
    221 			ntopmd++;
    222 			add_to_list(&p, &prevp, &toplp);
    223 		} else {
    224 			prevp = p;
    225 			p = p->next;
    226 		}
    227 		i++;
    228 	}
    229 
    230 	*lpp = NULL;
    231 	*top_pp = toplp;
    232 
    233 	return (ntopmd);
    234 }
    235 
    236 int
    237 get_namelist(mdnamelist_t **transdevlist, mdnamelist_t **devlist,
    238 					char *dev_type)
    239 {
    240 	mdnamelist_t *np, *prevp;
    241 	md_error_t	e = mdnullerror;
    242 	char		*type_name;
    243 	int		i = 0;
    244 
    245 	prevp = np = *transdevlist;
    246 	while (np) {
    247 		if ((type_name = metagetmiscname(np->namep, &e)) == NULL) {
    248 			*devlist = NULL;
    249 			mdclrerror(&e);
    250 			return (-1);
    251 		}
    252 		if (strcmp(type_name, dev_type) == 0) {
    253 			/* move it to the devlist */
    254 			add_to_list(&np, &prevp, devlist);
    255 			i++;
    256 		} else {
    257 			prevp = np;
    258 			np = np->next;
    259 		}
    260 	}
    261 	return (i);
    262 }
    263 
    264 
    265 mdnamelist_t *
    266 create_nlp()
    267 {
    268 	mdnamelist_t *np;
    269 
    270 	if (np = (mdnamelist_t *)malloc(sizeof (mdnamelist_t))) {
    271 		np->next = NULL;
    272 		return (np);
    273 	} else {
    274 		/* error condition below */
    275 		monitord_print(0, gettext(
    276 		    "create_nlp: malloc failed\n"));
    277 		monitord_exit(errno);
    278 	}
    279 	return (0);
    280 }
    281 
    282 /*
    283  * Create a list of metadevices associated with trans. top_pp points to
    284  * this list. The number of components in the list are also returned.
    285  */
    286 int
    287 create_trans_compslist(mdnamelist_t **lpp, mdnamelist_t **top_pp,
    288 							boolean_e verbose)
    289 {
    290 	mdnamelist_t	*p, *tailp, *toplp, *newlp;
    291 	int		ntoptrans;
    292 	md_error_t	e = mdnullerror;
    293 	md_trans_t	*tp;
    294 
    295 	ntoptrans = 0;
    296 	p = *lpp;
    297 	tailp = toplp = NULL;
    298 	/*
    299 	 * Scan the current list of trans devices. From that
    300 	 * extract all the lower level metadevices and put them on
    301 	 * toplp list.
    302 	 */
    303 
    304 	while (p) {
    305 		if (tp = meta_get_trans(sp, p->namep, &e)) {
    306 			/*
    307 			 * Check the master and log devices to see if they
    308 			 * are metadevices
    309 			 */
    310 			if (metaismeta(tp->masternamep)) {
    311 				if (verbose == True)
    312 					monitord_print(6, gettext(
    313 					    "master metadevice\n"));
    314 				/* get a mdnamelist_t. */
    315 				newlp = create_nlp();
    316 				newlp->namep = tp->masternamep;
    317 				if (toplp == NULL) {
    318 					toplp = tailp = newlp;
    319 				} else {
    320 					tailp->next = newlp;
    321 					tailp = newlp;
    322 				}
    323 				ntoptrans++;
    324 			}
    325 
    326 			if (tp->lognamep && metaismeta(tp->lognamep)) {
    327 				if (verbose == True)
    328 					monitord_print(6, gettext(
    329 					    "log metadevice\n"));
    330 				newlp = create_nlp();
    331 				newlp->namep = tp->lognamep;
    332 				if (toplp == NULL) {
    333 					toplp = tailp = newlp;
    334 				} else {
    335 					tailp->next = newlp;
    336 					tailp = newlp;
    337 				}
    338 				ntoptrans++;
    339 			}
    340 			p = p->next;
    341 		} else {
    342 			mdclrerror(&e);
    343 		}
    344 	}
    345 	*top_pp = toplp;
    346 	return (ntoptrans);
    347 }
    348 
    349 void
    350 probe_mirror_devs(boolean_e verbose)
    351 {
    352 	mdnamelist_t	*nlp, *toplp;
    353 	int		cnt;
    354 	md_error_t	e = mdnullerror;
    355 
    356 	nlp = toplp = NULL;
    357 
    358 	if (meta_get_mirror_names(sp, &nlp, 0, &e) > 0) {
    359 		/*
    360 		 * We have some mirrors to probe
    361 		 * get a list of top-level mirrors
    362 		 */
    363 
    364 		cnt = get_toplevel_mds(&nlp, &toplp, verbose);
    365 		if (cnt && (md_probe_ioctl(toplp, cnt,
    366 		    MD_MIRROR, verbose) < 0))
    367 			monitord_print(0, gettext(
    368 			    "probe_mirror_devs: "
    369 			    "mirror components %d ioctl error\n"),
    370 			    cnt);
    371 
    372 	} else {
    373 		mdclrerror(&e);
    374 	}
    375 
    376 	metafreenamelist(nlp);
    377 	metafreenamelist(toplp);
    378 }
    379 
    380 void
    381 probe_raid_devs(boolean_e verbose)
    382 {
    383 	mdnamelist_t	*nlp, *toplp;
    384 	int		cnt;
    385 	md_error_t	e = mdnullerror;
    386 
    387 	nlp = toplp = NULL;
    388 
    389 	if (meta_get_raid_names(sp, &nlp, 0, &e) > 0) {
    390 		/*
    391 		 * We have some mirrors to probe
    392 		 * get a list of top-level mirrors
    393 		 */
    394 
    395 		cnt = get_toplevel_mds(&nlp, &toplp, verbose);
    396 
    397 		if (cnt && (md_probe_ioctl(toplp, cnt,
    398 		    MD_RAID, verbose) < 0))
    399 			monitord_print(0, gettext(
    400 			    "probe_raid_devs: "
    401 			    "RAID-5 components %d ioctl error\n"),
    402 			    cnt);
    403 	} else {
    404 		mdclrerror(&e);
    405 	}
    406 
    407 	metafreenamelist(nlp);
    408 	metafreenamelist(toplp);
    409 }
    410 
    411 /*
    412  * Trans probes are different. -- so whats new.
    413  * we separate out the master and log device and then issue the
    414  * probe calls.
    415  * Since the underlying device could be disk, stripe, RAID or miror,
    416  * we have to sort them out and then call the ioctl for each.
    417  */
    418 
    419 void
    420 probe_trans_devs(boolean_e verbose)
    421 {
    422 	mdnamelist_t	*nlp, *toplp;
    423 	mdnamelist_t	*trans_raidlp, *trans_mmlp, *trans_stripelp;
    424 	int		cnt;
    425 	md_error_t	e = mdnullerror;
    426 
    427 	nlp = toplp = NULL;
    428 	trans_raidlp = trans_mmlp = trans_stripelp = NULL;
    429 
    430 	if (meta_get_trans_names(sp, &nlp, 0, &e) > 0) {
    431 		/*
    432 		 * get a list of master and log metadevices.
    433 		 */
    434 
    435 		cnt = create_trans_compslist(&nlp, &toplp, verbose);
    436 		if (verbose == True) {
    437 			int i;
    438 
    439 			for (i = 0, nlp = toplp; i < cnt; i++) {
    440 				monitord_print(6, gettext(
    441 				    "tran: underlying drv %s\n"),
    442 				    (nlp->namep)->cname);
    443 				nlp = nlp->next;
    444 			}
    445 		}
    446 
    447 		/* underlying RAID-5 components */
    448 
    449 		cnt = get_namelist(&toplp, &trans_raidlp, MD_RAID);
    450 		if ((cnt > 0) && (md_probe_ioctl(trans_raidlp, cnt,
    451 		    MD_RAID, verbose) < 0))
    452 			monitord_print(0, gettext(
    453 			    "probe_trans_devs: "
    454 			    "RAID-5 components %d ioctl error\n"),
    455 			    cnt);
    456 		metafreenamelist(trans_raidlp);
    457 
    458 		/* underlying mirror components */
    459 
    460 		cnt = get_namelist(&toplp, &trans_mmlp, MD_MIRROR);
    461 
    462 		if ((cnt > 0) && (md_probe_ioctl(trans_mmlp, cnt,
    463 		    MD_MIRROR, verbose) < 0))
    464 			monitord_print(0, gettext(
    465 			    "probe_trans_devs: "
    466 			    "mirror components %d ioctl error\n"),
    467 			    cnt);
    468 		metafreenamelist(trans_mmlp);
    469 
    470 		/* underlying stripe components */
    471 
    472 		cnt = get_namelist(&toplp, &trans_stripelp, MD_STRIPE);
    473 		if ((cnt > 0) && (md_probe_ioctl(trans_stripelp, cnt,
    474 		    MD_STRIPE, verbose) < 0))
    475 			monitord_print(0, gettext(
    476 			    "probe_trans_devs: "
    477 			    "stripe components %d ioctl error\n"),
    478 			    cnt);
    479 
    480 		metafreenamelist(trans_stripelp);
    481 		metafreenamelist(nlp);
    482 	} else {
    483 		mdclrerror(&e);
    484 	}
    485 }
    486 
    487 /*
    488  * probe hot spares. This is differs from other approaches since
    489  * there are no read/write routines through md. We check at the physical
    490  * component level and then delete it if its bad.
    491  */
    492 
    493 void
    494 probe_hotspare_devs(boolean_e verbose)
    495 {
    496 	mdhspnamelist_t *hspnlp = NULL;
    497 	mdhspnamelist_t	*p;
    498 	md_hsp_t	*hspp;
    499 	md_error_t	e = mdnullerror;
    500 
    501 	if (meta_get_hsp_names(sp, &hspnlp, 0, &e) <= 0) {
    502 		mdclrerror(&e);
    503 		return;
    504 	}
    505 
    506 	for (p = hspnlp; (p != NULL); p = p->next) {
    507 		mdhspname_t	*hspnp = p->hspnamep;
    508 
    509 		if (verbose == True)
    510 			monitord_print(6, "%s %s\n", gettext("name"),
    511 			    hspnp->hspname);
    512 
    513 		if ((hspp = meta_get_hsp(sp, hspnp, &e)) == NULL)
    514 			continue;
    515 
    516 		if (hspp->hotspares.hotspares_len != 0) {
    517 			if (verbose == True)
    518 				monitord_print(6, " %u hotspares\n",
    519 				    hspp->hotspares.hotspares_len);
    520 			delete_hotspares_impl(hspnp, hspp, verbose);
    521 		}
    522 	}
    523 	mdclrerror(&e);
    524 	metafreehspnamelist(hspnlp);
    525 }
    526