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