xref: /titanic_41/usr/src/cmd/lvm/md_monitord/probedev.c (revision c6d6228cbba828ab5b2b6db6c280a44b2d841653)
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 		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 	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