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