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