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