xref: /titanic_41/usr/src/lib/libdiskmgt/common/inuse_svm.c (revision fb9f9b975cb9214fec5dab37d461199adab9b964)
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 /*
30  * Creates and maintains a cache of slices used by SVM.
31  */
32 
33 #include <meta.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <libintl.h>
38 #include <synch.h>
39 #include <thread.h>
40 #include <dlfcn.h>
41 #include <link.h>
42 #include <libsysevent.h>
43 #include <syslog.h>
44 #include <sys/types.h>
45 #include <sys/sysevent/eventdefs.h>
46 
47 #include "libdiskmgt.h"
48 #include "disks_private.h"
49 
50 /*
51  * The list of SVM slices in use.
52  */
53 
54 struct svm_list {
55 	struct svm_list	*next;
56 	char		*slice;
57 	char		*name;
58 	char		*type;
59 };
60 
61 static struct svm_list	*svm_listp = NULL;
62 static rwlock_t		svm_lock = DEFAULTRWLOCK;
63 static int		initialized = 0;
64 static mutex_t		init_lock = DEFAULTMUTEX;
65 
66 static int	add_use_record(char *devname, char *type, char *mname);
67 static int	diskset_info(mdsetname_t *sp);
68 static int	drive_in_diskset(char *dpath, char *setname);
69 static void	event_handler();
70 static void	free_names(mdnamelist_t *nlp);
71 static void	free_svm(struct svm_list *listp);
72 static int	init_svm();
73 static int	load_svm();
74 static int	new_entry(char *sname, char *type, char *mname,
75 			    mdsetname_t *sp);
76 
77 /*
78  * Pointers to libmeta functions that we dynamically resolve.
79  */
80 static set_t		(*mdl_get_max_sets)(md_error_t *ep);
81 static void		(*mdl_mdclrerror)(md_error_t *ep);
82 static md_error_t	*mdl_mdnullerror;
83 static void		(*mdl_metaflushnames)(int flush_sr_cache);
84 static void		(*mdl_metaflushsetname)(mdsetname_t *sp);
85 static void		(*mdl_metafreenamelist)(mdnamelist_t *nlp);
86 static void		(*mdl_metafreereplicalist)(md_replicalist_t *rlp);
87 static md_drive_desc	*(*mdl_metaget_drivedesc)(mdsetname_t *sp, int flags,
88 			    md_error_t *ep);
89 static mdname_t		*(*mdl_metaname)(mdsetname_t **spp, char *uname,
90 			    md_error_t *ep);
91 static int		(*mdl_metareplicalist)(mdsetname_t *sp, int flags,
92 			    md_replicalist_t **rlpp, md_error_t *ep);
93 static mdsetname_t	*(*mdl_metasetnosetname)(set_t setno, md_error_t *ep);
94 static int		(*mdl_meta_get_hotspare_names)(mdsetname_t *sp,
95 			    mdnamelist_t **nlpp, int options, md_error_t *ep);
96 static md_raid_t	*(*mdl_meta_get_raid)(mdsetname_t *sp, mdname_t *raidnp,
97 			    md_error_t *ep);
98 static int		(*mdl_meta_get_raid_names)(mdsetname_t *sp,
99 			    mdnamelist_t **nlpp, int options, md_error_t *ep);
100 static md_sp_t		*(*mdl_meta_get_sp)(mdsetname_t *sp, mdname_t *np,
101 			    md_error_t *ep);
102 static int		(*mdl_meta_get_sp_names)(mdsetname_t *sp,
103 			    mdnamelist_t **nlpp, int options, md_error_t *ep);
104 static md_stripe_t	*(*mdl_meta_get_stripe)(mdsetname_t *sp,
105 			    mdname_t *stripenp, md_error_t *ep);
106 static int		(*mdl_meta_get_stripe_names)(mdsetname_t *sp,
107 			    mdnamelist_t **nlpp, int options, md_error_t *ep);
108 static int		(*mdl_meta_get_trans_names)(mdsetname_t *sp,
109 			    mdnamelist_t **nlpp, int options, md_error_t *ep);
110 static void		(*mdl_meta_invalidate_name)(mdname_t *np);
111 static void		(*mdl_sdssc_bind_library)();
112 
113 /*
114  * Search the list of devices under SVM for the specified device.
115  */
116 int
117 inuse_svm(char *slice, nvlist_t *attrs, int *errp)
118 {
119 	struct svm_list	*listp;
120 	int		found = 0;
121 
122 	*errp = 0;
123 	if (slice == NULL) {
124 	    return (found);
125 	}
126 
127 	(void) mutex_lock(&init_lock);
128 	if (!initialized) {
129 		/* dynamically load libmeta */
130 		if (init_svm()) {
131 			/*
132 			 * need to initialize the cluster library to
133 			 * avoid seg faults
134 			 */
135 			(mdl_sdssc_bind_library)();
136 
137 			/* load the SVM cache */
138 			*errp = load_svm();
139 
140 			if (*errp == 0) {
141 				/* start a thread to monitor the svm config */
142 				sysevent_handle_t *shp;
143 				const char *subclass_list[1];
144 				/*
145 				 * Only start the svmevent thread if
146 				 * we are not doing an install
147 				 */
148 
149 				if (getenv("_LIBDISKMGT_INSTALL") == NULL) {
150 					shp = sysevent_bind_handle(
151 					    event_handler);
152 					if (shp != NULL) {
153 						subclass_list[0] = EC_SUB_ALL;
154 						if (sysevent_subscribe_event(
155 						    shp, EC_SVM_CONFIG,
156 						    subclass_list, 1) != 0) {
157 							*errp = errno;
158 						}
159 					} else {
160 						*errp = errno;
161 					}
162 					if (*errp) {
163 						/*
164 						 * If the sysevent thread fails,
165 						 * log the error but continue
166 						 * on. This failing to start
167 						 * is not catastrophic in
168 						 * particular for short lived
169 						 * consumers of libdiskmgt.
170 						 */
171 						syslog(LOG_WARNING,
172 						    dgettext(TEXT_DOMAIN,
173 						    "libdiskmgt: sysevent "
174 						    "thread for SVM failed "
175 						    "to start\n"));
176 						*errp = 0;
177 					}
178 				}
179 			}
180 		}
181 
182 		if (*errp == 0) {
183 			initialized = 1;
184 		}
185 	}
186 	(void) mutex_unlock(&init_lock);
187 
188 	(void) rw_rdlock(&svm_lock);
189 	listp = svm_listp;
190 	while (listp != NULL) {
191 	    if (strcmp(slice, listp->slice) == 0) {
192 		libdiskmgt_add_str(attrs, DM_USED_BY, DM_USE_SVM, errp);
193 		if (strcmp(listp->type, "mdb") == 0 ||
194 		    strcmp(listp->type, "hs") == 0) {
195 
196 		    libdiskmgt_add_str(attrs, DM_USED_NAME, listp->type, errp);
197 		} else {
198 		    char name[MAXPATHLEN];
199 		    (void) snprintf(name, MAXPATHLEN, "%s:%s", listp->type,
200 			listp->name);
201 		    libdiskmgt_add_str(attrs, DM_USED_NAME, name, errp);
202 		}
203 		found = 1;
204 		break;
205 	    }
206 	    listp = listp->next;
207 	}
208 	(void) rw_unlock(&svm_lock);
209 
210 	return (found);
211 }
212 
213 static int
214 add_use_record(char *devname, char *type, char *mname)
215 {
216 	struct svm_list *sp;
217 
218 	/* If prev. record is a dup, skip it. */
219 	if (svm_listp != NULL && strcmp(svm_listp->slice, devname) == 0 &&
220 	    strcmp(svm_listp->type, type) == 0) {
221 	    return (0);
222 	}
223 
224 	sp = (struct svm_list *)malloc(sizeof (struct svm_list));
225 	if (sp == NULL) {
226 	    return (ENOMEM);
227 	}
228 
229 	if ((sp->slice = strdup(devname)) == NULL) {
230 	    free(sp);
231 	    return (ENOMEM);
232 	}
233 
234 	if ((sp->name = strdup(mname)) == NULL) {
235 	    free(sp->slice);
236 	    free(sp);
237 	    return (ENOMEM);
238 	}
239 
240 	if ((sp->type = strdup(type)) == NULL) {
241 	    free(sp->slice);
242 	    free(sp->name);
243 	    free(sp);
244 	    return (ENOMEM);
245 	}
246 
247 	sp->next = svm_listp;
248 	svm_listp = sp;
249 
250 	return (0);
251 }
252 
253 static int
254 diskset_info(mdsetname_t *sp)
255 {
256 	md_error_t		error = *mdl_mdnullerror;
257 	md_replicalist_t	*replica_list = NULL;
258 	mdnamelist_t		*trans_list = NULL;
259 	mdnamelist_t		*raid_list = NULL;
260 	mdnamelist_t		*stripe_list = NULL;
261 	mdnamelist_t		*sp_list = NULL;
262 	mdnamelist_t		*spare_list = NULL;
263 
264 	if ((mdl_metareplicalist)(sp, MD_BASICNAME_OK, &replica_list, &error)
265 	    >= 0) {
266 	    md_replicalist_t	*nlp;
267 
268 	    for (nlp = replica_list; nlp != NULL; nlp = nlp->rl_next) {
269 		if (new_entry(nlp->rl_repp->r_namep->bname, "mdb",
270 		    nlp->rl_repp->r_namep->cname, sp)) {
271 		    (mdl_metafreereplicalist)(replica_list);
272 		    return (ENOMEM);
273 		}
274 	    }
275 	    (mdl_metafreereplicalist)(replica_list);
276 
277 	} else {
278 	    (mdl_mdclrerror)(&error);
279 	    /* there are no metadb's; that is ok, no need to check the rest */
280 	    return (0);
281 	}
282 	(mdl_mdclrerror)(&error);
283 
284 	if ((mdl_meta_get_trans_names)(sp, &trans_list, 0, &error) >= 0) {
285 	    mdnamelist_t *nlp;
286 
287 	    for (nlp = trans_list; nlp != NULL; nlp = nlp->next) {
288 		if (new_entry(nlp->namep->bname, "trans", nlp->namep->cname,
289 		    sp)) {
290 		    free_names(trans_list);
291 		    return (ENOMEM);
292 		}
293 	    }
294 
295 	    free_names(trans_list);
296 	}
297 	(mdl_mdclrerror)(&error);
298 
299 	if ((mdl_meta_get_raid_names)(sp, &raid_list, 0, &error) >= 0) {
300 	    mdnamelist_t *nlp;
301 
302 	    for (nlp = raid_list; nlp != NULL; nlp = nlp->next) {
303 		mdname_t	*mdn;
304 		md_raid_t	*raid;
305 
306 		mdn = (mdl_metaname)(&sp, nlp->namep->cname, &error);
307 		(mdl_mdclrerror)(&error);
308 		if (mdn == NULL) {
309 		    continue;
310 		}
311 
312 		raid = (mdl_meta_get_raid)(sp, mdn, &error);
313 		(mdl_mdclrerror)(&error);
314 
315 		if (raid != NULL) {
316 		    int i;
317 
318 		    for (i = 0; i < raid->cols.cols_len; i++) {
319 			if (new_entry(raid->cols.cols_val[i].colnamep->bname,
320 			    "raid", nlp->namep->cname, sp)) {
321 			    free_names(raid_list);
322 			    return (ENOMEM);
323 			}
324 		    }
325 		}
326 	    }
327 
328 	    free_names(raid_list);
329 	}
330 	(mdl_mdclrerror)(&error);
331 
332 	if ((mdl_meta_get_stripe_names)(sp, &stripe_list, 0, &error) >= 0) {
333 	    mdnamelist_t *nlp;
334 
335 	    for (nlp = stripe_list; nlp != NULL; nlp = nlp->next) {
336 		mdname_t	*mdn;
337 		md_stripe_t	*stripe;
338 
339 		mdn = (mdl_metaname)(&sp, nlp->namep->cname, &error);
340 		(mdl_mdclrerror)(&error);
341 		if (mdn == NULL) {
342 		    continue;
343 		}
344 
345 		stripe = (mdl_meta_get_stripe)(sp, mdn, &error);
346 		(mdl_mdclrerror)(&error);
347 
348 		if (stripe != NULL) {
349 		    int i;
350 
351 		    for (i = 0; i < stripe->rows.rows_len; i++) {
352 			md_row_t	*rowp;
353 			int		j;
354 
355 			rowp = &stripe->rows.rows_val[i];
356 
357 			for (j = 0; j < rowp->comps.comps_len; j++) {
358 			    md_comp_t	*component;
359 
360 			    component = &rowp->comps.comps_val[j];
361 			    if (new_entry(component->compnamep->bname, "stripe",
362 				nlp->namep->cname, sp)) {
363 				free_names(stripe_list);
364 				return (ENOMEM);
365 			    }
366 			}
367 		    }
368 		}
369 	    }
370 
371 	    free_names(stripe_list);
372 	}
373 	(mdl_mdclrerror)(&error);
374 
375 	if ((mdl_meta_get_sp_names)(sp, &sp_list, 0, &error) >= 0) {
376 	    mdnamelist_t *nlp;
377 
378 	    for (nlp = sp_list; nlp != NULL; nlp = nlp->next) {
379 		mdname_t	*mdn;
380 		md_sp_t		*soft_part;
381 
382 		mdn = (mdl_metaname)(&sp, nlp->namep->cname, &error);
383 		(mdl_mdclrerror)(&error);
384 		if (mdn == NULL) {
385 		    continue;
386 		}
387 
388 		soft_part = (mdl_meta_get_sp)(sp, mdn, &error);
389 		(mdl_mdclrerror)(&error);
390 
391 		if (soft_part != NULL) {
392 		    if (new_entry(soft_part->compnamep->bname, "sp",
393 			nlp->namep->cname, sp)) {
394 			free_names(sp_list);
395 			return (ENOMEM);
396 		    }
397 		}
398 	    }
399 
400 	    free_names(sp_list);
401 	}
402 	(mdl_mdclrerror)(&error);
403 
404 	if ((mdl_meta_get_hotspare_names)(sp, &spare_list, 0, &error) >= 0) {
405 	    mdnamelist_t *nlp;
406 
407 	    for (nlp = spare_list; nlp != NULL; nlp = nlp->next) {
408 		if (new_entry(nlp->namep->bname, "hs", nlp->namep->cname, sp)) {
409 		    free_names(spare_list);
410 		    return (ENOMEM);
411 		}
412 	    }
413 
414 	    free_names(spare_list);
415 	}
416 
417 	(mdl_mdclrerror)(&error);
418 
419 	return (0);
420 }
421 
422 /*
423  * SVM uses "drive names" (ctd name without trailing slice) for drives
424  * in disksets.  Since it massages these names there is no direct correspondence
425  * with the slice device names in /dev.  So, we need to massage these names
426  * back to something we can match on when a slice comes in.  We create an
427  * entry for each possible slice since we don't know what slices actually
428  * exist.  Slice 0 & 7 are probably enough, but the user could have
429  * repartitioned the drive after they added it to the diskset and removed the
430  * mdb.
431  */
432 static int
433 drive_in_diskset(char *dpath, char *setname)
434 {
435 	int i;
436 	char path[MAXPATHLEN];
437 
438 	(void) strlcpy(path, dpath, sizeof (path));
439 	if (strncmp(path, "/dev/rdsk/", 10) == 0) {
440 	    /* change rdsk to dsk */
441 	    char *p;
442 
443 	    /* start p pointing to r in rdsk */
444 	    for (p = path + 5; *p; p++) {
445 		*p = *(p + 1);
446 	    }
447 	} else if (strncmp(path, "/dev/did/rdsk/", 14) == 0) {
448 	    /* change rdsk to dsk */
449 	    char *p;
450 
451 	    /* start p pointing to r in rdsk */
452 	    for (p = path + 9; *p; p++) {
453 		*p = *(p + 1);
454 	    }
455 	}
456 
457 	for (i = 0; i < 8; i++) {
458 	    char slice[MAXPATHLEN];
459 
460 	    (void) snprintf(slice, sizeof (slice), "%ss%d", path, i);
461 	    if (add_use_record(slice, "diskset", setname)) {
462 		return (ENOMEM);
463 	    }
464 	}
465 
466 	return (0);
467 }
468 
469 static void
470 event_handler()
471 {
472 	(void) rw_wrlock(&svm_lock);
473 	free_svm(svm_listp);
474 	svm_listp = NULL;
475 	(mdl_metaflushnames)(0);
476 	(void) load_svm();
477 	(void) rw_unlock(&svm_lock);
478 }
479 
480 static void
481 free_names(mdnamelist_t *nlp)
482 {
483 	mdnamelist_t *p;
484 
485 	for (p = nlp; p != NULL; p = p->next) {
486 	    (mdl_meta_invalidate_name)(p->namep);
487 	    p->namep = NULL;
488 	}
489 	(mdl_metafreenamelist)(nlp);
490 }
491 
492 /*
493  * Free the list of SVM entries.
494  */
495 static void
496 free_svm(struct svm_list *listp) {
497 
498 	struct svm_list	*nextp;
499 
500 	while (listp != NULL) {
501 	    nextp = listp->next;
502 	    free((void *)listp->slice);
503 	    free((void *)listp->name);
504 	    free((void *)listp->type);
505 	    free((void *)listp);
506 	    listp = nextp;
507 	}
508 }
509 
510 /*
511  * Try to dynamically link the libmeta functions we need.
512  */
513 static int
514 init_svm()
515 {
516 	void	*lh;
517 
518 	if ((lh = dlopen("/usr/lib/libmeta.so", RTLD_NOW)) == NULL) {
519 	    return (0);
520 	}
521 
522 	mdl_get_max_sets = (set_t (*)(md_error_t *))dlsym(lh, "get_max_sets");
523 
524 	mdl_mdclrerror = (void(*)(md_error_t *))dlsym(lh, "mdclrerror");
525 
526 	mdl_mdnullerror = (md_error_t *)dlsym(lh, "mdnullerror");
527 
528 	mdl_metaflushnames = (void (*)(int))dlsym(lh, "metaflushnames");
529 
530 	mdl_metaflushsetname = (void (*)(mdsetname_t *))dlsym(lh,
531 	    "metaflushsetname");
532 
533 	mdl_metafreenamelist = (void (*)(mdnamelist_t *))dlsym(lh,
534 	    "metafreenamelist");
535 
536 	mdl_metafreereplicalist = (void (*)(md_replicalist_t *))dlsym(lh,
537 	    "metafreereplicalist");
538 
539 	mdl_metaget_drivedesc = (md_drive_desc *(*)(mdsetname_t *, int,
540 	    md_error_t *))dlsym(lh, "metaget_drivedesc");
541 
542 	mdl_metaname = (mdname_t *(*)(mdsetname_t **, char *, md_error_t *))
543 	    dlsym(lh, "metaname");
544 
545 	mdl_metareplicalist = (int (*)(mdsetname_t *, int, md_replicalist_t **,
546 	    md_error_t *))dlsym(lh, "metareplicalist");
547 
548 	mdl_metasetnosetname = (mdsetname_t *(*)(set_t, md_error_t *))dlsym(lh,
549 	    "metasetnosetname");
550 
551 	mdl_meta_get_hotspare_names = (int (*)(mdsetname_t *, mdnamelist_t **,
552 	    int, md_error_t *))dlsym(lh, "meta_get_hotspare_names");
553 
554 	mdl_meta_get_raid = (md_raid_t *(*)(mdsetname_t *, mdname_t *,
555 	    md_error_t *))dlsym(lh, "meta_get_raid");
556 
557 	mdl_meta_get_raid_names = (int (*)(mdsetname_t *, mdnamelist_t **,
558 	    int, md_error_t *))dlsym(lh, "meta_get_raid_names");
559 
560 	mdl_meta_get_sp = (md_sp_t *(*)(mdsetname_t *, mdname_t *,
561 	    md_error_t *))dlsym(lh, "meta_get_sp");
562 
563 	mdl_meta_get_sp_names = (int (*)(mdsetname_t *, mdnamelist_t **,
564 	    int, md_error_t *))dlsym(lh, "meta_get_sp_names");
565 
566 	mdl_meta_get_stripe = (md_stripe_t *(*)(mdsetname_t *, mdname_t *,
567 	    md_error_t *))dlsym(lh, "meta_get_stripe");
568 
569 	mdl_meta_get_stripe_names = (int (*)(mdsetname_t *, mdnamelist_t **,
570 	    int, md_error_t *))dlsym(lh, "meta_get_stripe_names");
571 
572 	mdl_meta_get_trans_names = (int (*)(mdsetname_t *, mdnamelist_t **,
573 	    int, md_error_t *))dlsym(lh, "meta_get_trans_names");
574 
575 	mdl_meta_invalidate_name = (void (*)(mdname_t *))dlsym(lh,
576 	    "meta_invalidate_name");
577 
578 	mdl_sdssc_bind_library = (void (*)())dlsym(lh, "sdssc_bind_library");
579 
580 	return (1);
581 }
582 
583 /*
584  * Create a list of SVM devices
585  */
586 static int
587 load_svm()
588 {
589 	int		max_sets;
590 	md_error_t	error = *mdl_mdnullerror;
591 	int		i;
592 
593 	if ((max_sets = (mdl_get_max_sets)(&error)) == 0) {
594 	    return (0);
595 	}
596 
597 	if (!mdisok(&error)) {
598 	    (mdl_mdclrerror)(&error);
599 	    return (0);
600 	}
601 
602 	/* for each possible set number, see if we really have a diskset */
603 	for (i = 0; i < max_sets; i++) {
604 	    mdsetname_t	*sp;
605 
606 	    if ((sp = (mdl_metasetnosetname)(i, &error)) == NULL) {
607 
608 		if (!mdisok(&error) &&
609 		    mdisrpcerror(&error, RPC_PROGNOTREGISTERED)) {
610 		    /* metad rpc program not registered - no metasets */
611 		    break;
612 		}
613 
614 		(mdl_mdclrerror)(&error);
615 		continue;
616 	    }
617 	    (mdl_mdclrerror)(&error);
618 
619 	    /* pick up drives in disksets with no mdbs/metadevices */
620 	    if (sp->setno != 0) {
621 		md_drive_desc	*dd;
622 
623 		dd = (mdl_metaget_drivedesc)(sp, MD_BASICNAME_OK | PRINT_FAST,
624 		    &error);
625 		(mdl_mdclrerror)(&error);
626 		for (; dd != NULL; dd = dd->dd_next) {
627 		    if (drive_in_diskset(dd->dd_dnp->rname, sp->setname)) {
628 			(mdl_metaflushsetname)(sp);
629 			return (ENOMEM);
630 		    }
631 		}
632 	    }
633 
634 	    if (diskset_info(sp)) {
635 		(mdl_metaflushsetname)(sp);
636 		return (ENOMEM);
637 	    }
638 
639 	    (mdl_metaflushsetname)(sp);
640 	}
641 
642 	(mdl_mdclrerror)(&error);
643 
644 	return (0);
645 }
646 
647 static int
648 new_entry(char *sname, char *type, char *mname, mdsetname_t *sp)
649 {
650 	mdname_t	*mdn;
651 	md_error_t	 error = *mdl_mdnullerror;
652 
653 	mdn = (mdl_metaname)(&sp, sname, &error);
654 	if (!mdisok(&error)) {
655 	    (mdl_mdclrerror)(&error);
656 	    return (0);
657 	}
658 
659 	if (mdn != NULL && (
660 	    mdn->drivenamep->type == MDT_ACCES ||
661 	    mdn->drivenamep->type == MDT_COMP ||
662 	    mdn->drivenamep->type == MDT_FAST_COMP)) {
663 
664 	    return (add_use_record(mdn->bname, type, mname));
665 	}
666 
667 	return (0);
668 }
669