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 1995-2003 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 * Just in case we're not in a build environment, make sure that
31 * TEXT_DOMAIN gets set to something.
32 */
33 #if !defined(TEXT_DOMAIN)
34 #define TEXT_DOMAIN "SYS_TEST"
35 #endif
36
37 /*
38 * libmeta wrappers for event notification
39 */
40
41 #include <meta.h>
42 #include <sys/lvm/md_notify.h>
43
44 #if defined(DEBUG)
45 #include <assert.h>
46 #endif /* DEBUG */
47
48 struct tag2obj_type {
49 md_tags_t tag;
50 ev_obj_t obj;
51 } tag2obj_typetab[] =
52 {
53 { TAG_EMPTY, EVO_EMPTY },
54 { TAG_METADEVICE, EVO_METADEV },
55 { TAG_REPLICA, EVO_REPLICA },
56 { TAG_HSP, EVO_HSP },
57 { TAG_HS, EVO_HS },
58 { TAG_SET, EVO_SET },
59 { TAG_DRIVE, EVO_DRIVE },
60 { TAG_HOST, EVO_HOST },
61 { TAG_MEDIATOR, EVO_MEDIATOR },
62 { TAG_UNK, EVO_UNSPECIFIED },
63
64 { TAG_LAST, EVO_LAST }
65 };
66
67 struct evdrv2evlib_type {
68 md_event_type_t drv;
69 evid_t lib;
70 } evdrv2evlib_typetab[] =
71 {
72 { EQ_EMPTY, EV_EMPTY },
73 { EQ_CREATE, EV_CREATE },
74 { EQ_DELETE, EV_DELETE },
75 { EQ_ADD, EV_ADD },
76 { EQ_REMOVE, EV_REMOVE },
77 { EQ_REPLACE, EV_REPLACE },
78 { EQ_MEDIATOR_ADD, EV_MEDIATOR_ADD },
79 { EQ_MEDIATOR_DELETE, EV_MEDIATOR_DELETE },
80 { EQ_HOST_ADD, EV_HOST_ADD },
81 { EQ_HOST_DELETE, EV_HOST_DELETE },
82 { EQ_DRIVE_ADD, EV_DRIVE_ADD },
83 { EQ_DRIVE_DELETE, EV_DRIVE_DELETE },
84 { EQ_RENAME_SRC, EV_RENAME_SRC },
85 { EQ_RENAME_DST, EV_RENAME_DST },
86 { EQ_INIT_START, EV_INIT_START },
87 { EQ_INIT_FAILED, EV_INIT_FAILED },
88 { EQ_INIT_FATAL, EV_INIT_FATAL },
89 { EQ_INIT_SUCCESS, EV_INIT_SUCCESS },
90 { EQ_IOERR, EV_IOERR },
91 { EQ_ERRED, EV_ERRED },
92 { EQ_LASTERRED, EV_LASTERRED },
93 { EQ_OK, EV_OK },
94 { EQ_ENABLE, EV_ENABLE },
95 { EQ_RESYNC_START, EV_RESYNC_START },
96 { EQ_RESYNC_FAILED, EV_RESYNC_FAILED },
97 { EQ_RESYNC_SUCCESS, EV_RESYNC_SUCCESS },
98 { EQ_RESYNC_DONE, EV_RESYNC_DONE },
99 { EQ_HOTSPARED, EV_HOTSPARED },
100 { EQ_HS_FREED, EV_HS_FREED },
101 { EQ_TAKEOVER, EV_TAKEOVER },
102 { EQ_RELEASE, EV_RELEASE },
103 { EQ_OPEN_FAIL, EV_OPEN_FAIL },
104 { EQ_OFFLINE, EV_OFFLINE },
105 { EQ_ONLINE, EV_ONLINE },
106 { EQ_GROW, EV_GROW },
107 { EQ_DETACH, EV_DETACH },
108 { EQ_DETACHING, EV_DETACHING },
109 { EQ_ATTACH, EV_ATTACH },
110 { EQ_ATTACHING, EV_ATTACHING },
111 { EQ_CHANGE, EV_CHANGE },
112 { EQ_EXCHANGE, EV_EXCHANGE },
113 { EQ_REGEN_START, EV_REGEN_START },
114 { EQ_REGEN_DONE, EV_REGEN_DONE },
115 { EQ_REGEN_FAILED, EV_REGEN_FAILED },
116 { EQ_USER, EV_USER },
117 { EQ_NOTIFY_LOST, EV_NOTIFY_LOST },
118
119 { EQ_LAST, EV_LAST }
120 };
121
122 static ev_obj_t
dev2tag(md_dev64_t dev,set_t setno,md_error_t * ep)123 dev2tag(md_dev64_t dev, set_t setno, md_error_t *ep)
124 {
125 mdname_t *np = NULL;
126 mdsetname_t *sp = NULL;
127 ev_obj_t obj = EVO_METADEV;
128 char *miscname;
129
130 if ((sp = metasetnosetname(setno, ep)) == NULL) {
131 goto out;
132 }
133 if (!(np = metamnumname(&sp, meta_getminor(dev), 0, ep))) {
134 goto out;
135 }
136
137 /* need to invalidate name in case rename or delete/create done */
138 meta_invalidate_name(np);
139
140 if (!(miscname = metagetmiscname(np, ep))) {
141 goto out;
142 }
143 if (strcmp(miscname, MD_STRIPE) == 0) {
144 obj = EVO_STRIPE;
145 } else if (strcmp(miscname, MD_MIRROR) == 0) {
146 obj = EVO_MIRROR;
147 } else if (strcmp(miscname, MD_RAID) == 0) {
148 obj = EVO_RAID5;
149 } else if (strcmp(miscname, MD_TRANS) == 0) {
150 obj = EVO_TRANS;
151 }
152 out:
153 return (obj);
154 }
155
156 static ev_obj_t
tagdrv_2_objlib(md_tags_t tag)157 tagdrv_2_objlib(md_tags_t tag)
158 {
159 int i;
160
161 for (i = 0; tag2obj_typetab[i].tag != TAG_LAST; i++) {
162 if (tag2obj_typetab[i].tag == tag)
163 return (tag2obj_typetab[i].obj);
164 }
165 return (EVO_UNSPECIFIED);
166 }
167
168 static md_tags_t
objlib_2_tagdrv(ev_obj_t obj)169 objlib_2_tagdrv(ev_obj_t obj)
170 {
171 int i;
172
173 for (i = 0; tag2obj_typetab[i].tag != TAG_LAST; i++) {
174 if (tag2obj_typetab[i].obj == obj)
175 return (tag2obj_typetab[i].tag);
176 }
177 return (TAG_UNK);
178 }
179
180
181 static evid_t
evdrv_2_evlib(md_event_type_t drv_ev)182 evdrv_2_evlib(md_event_type_t drv_ev)
183 {
184 int i;
185
186 for (i = 0; evdrv2evlib_typetab[i].drv != EQ_LAST; i++) {
187 if (evdrv2evlib_typetab[i].drv == drv_ev)
188 return (evdrv2evlib_typetab[i].lib);
189 }
190 return (EV_UNK);
191 }
192
193 static md_event_type_t
evlib_2_evdrv(evid_t lib_ev)194 evlib_2_evdrv(evid_t lib_ev)
195 {
196 int i;
197
198 for (i = 0; evdrv2evlib_typetab[i].drv != EQ_LAST; i++) {
199 if (evdrv2evlib_typetab[i].lib == lib_ev)
200 return (evdrv2evlib_typetab[i].drv);
201 }
202 return (EQ_EMPTY);
203 }
204
205
206 /*
207 * meta_event
208 * returns 0 on succcess or < 0 to indicate error.
209 * abs(return code) = errno
210 */
211 static int
meta_event(md_event_ioctl_t * evctl,md_error_t * ep)212 meta_event(md_event_ioctl_t *evctl, md_error_t *ep)
213 {
214 int l;
215
216 if (!evctl || !ep)
217 return (-EINVAL);
218
219 l = strlen(evctl->mdn_name);
220 if ((l == 0 && evctl->mdn_cmd != EQ_PUT) || l >= MD_NOTIFY_NAME_SIZE) {
221 return (-EINVAL);
222 }
223
224 MD_SETDRIVERNAME(evctl, MD_NOTIFY, 0);
225 mdclrerror(ep);
226 errno = 0;
227
228 if (metaioctl(MD_IOCNOTIFY, evctl, ep, evctl->mdn_name) != 0) {
229 if (errno == 0) {
230 errno = EINVAL;
231 }
232 if (mdisok(ep)) {
233 (void) mdsyserror(ep, errno, evctl->mdn_name);
234 }
235 return (-errno);
236 }
237
238 return (0);
239 }
240
241 static void
init_evctl(char * qname,md_tags_t tag,md_event_type_t ev,uint_t flags,set_t set,md_dev64_t dev,md_event_cmds_t cmd,u_longlong_t udata,md_event_ioctl_t * evctlp)242 init_evctl(char *qname,
243 md_tags_t tag,
244 md_event_type_t ev,
245 uint_t flags,
246 set_t set,
247 md_dev64_t dev,
248 md_event_cmds_t cmd,
249 u_longlong_t udata,
250 md_event_ioctl_t *evctlp)
251 {
252
253 assert(evctlp);
254
255 (void) memset(evctlp, 0, sizeof (md_event_ioctl_t));
256
257 evctlp->mdn_magic = MD_EVENT_ID;
258 evctlp->mdn_rev = MD_NOTIFY_REVISION;
259
260 if (qname)
261 (void) strncpy(evctlp->mdn_name, qname, MD_NOTIFY_NAME_SIZE-1);
262 else
263 (void) memset(evctlp->mdn_name, 0, MD_NOTIFY_NAME_SIZE);
264
265 evctlp->mdn_tag = tag;
266 evctlp->mdn_event = ev;
267 evctlp->mdn_flags = flags;
268 evctlp->mdn_set = set;
269 evctlp->mdn_dev = dev;
270 evctlp->mdn_cmd = cmd;
271 evctlp->mdn_user = udata;
272 }
273
274 /*
275 * meta_notify_createq
276 * - creates an eventq
277 * - returns 0 on success or errno and sets ep
278 */
279 int
meta_notify_createq(char * qname,ulong_t flags,md_error_t * ep)280 meta_notify_createq(char *qname, ulong_t flags, md_error_t *ep)
281 {
282 md_event_ioctl_t evctl;
283 int err = 0;
284
285 mdclrerror(ep);
286 if (!qname || strlen(qname) == 0) {
287 (void) mdsyserror(ep, EINVAL,
288 dgettext(TEXT_DOMAIN,
289 "null or zero-length queue name"));
290 return (EINVAL);
291 }
292
293 init_evctl(qname,
294 TAG_EMPTY,
295 EQ_EMPTY,
296 (flags & EVFLG_PERMANENT) != 0? EQ_Q_PERM: 0,
297 /* set */ 0,
298 /* dev */ 0,
299 EQ_ON,
300 /* user-defined event data */ 0,
301 &evctl);
302
303 err = meta_event(&evctl, ep);
304
305 if (err == -EEXIST && !(flags & EVFLG_EXISTERR)) {
306 err = 0;
307 mdclrerror(ep);
308 }
309 if (!mdisok(ep) && mdanysyserror(ep)) {
310 err = (ep)->info.md_error_info_t_u.ds_error.errnum;
311 }
312 return (-err);
313 }
314
315 /*
316 * meta_notify_deleteq
317 * - deletes an eventq
318 * - free's any underlying resources
319 * - returns 0 on success or errno and sets ep
320 */
321 int
meta_notify_deleteq(char * qname,md_error_t * ep)322 meta_notify_deleteq(char *qname, md_error_t *ep)
323 {
324 md_event_ioctl_t evctl;
325 int err;
326
327 init_evctl(qname,
328 TAG_EMPTY,
329 EQ_EMPTY,
330 /* flags */ 0,
331 /* set */ 0,
332 /* dev */ 0,
333 EQ_OFF,
334 /* user-defined event data */ 0,
335 &evctl);
336
337 err = meta_event(&evctl, ep);
338 return (-err);
339 }
340
341 /*
342 * meta_notify_validq
343 * - verifies that the queue exists
344 * - returns true or false, ep may be changed as a side-effect
345 */
346 bool_t
meta_notify_validq(char * qname,md_error_t * ep)347 meta_notify_validq(char *qname, md_error_t *ep)
348 {
349 md_event_ioctl_t evctl;
350
351 init_evctl(qname,
352 TAG_EMPTY,
353 EQ_EMPTY,
354 /* flags */ 0,
355 /* set */ 0,
356 /* dev */ 0,
357 EQ_ON,
358 /* user-defined event data */ 0,
359 &evctl);
360
361 return (meta_event(&evctl, ep) == -EEXIST);
362 }
363
364 /*
365 * meta_notify_listq
366 * - returns number of (currently) active queus or -errno
367 * - allocates qnames array and sets user's pointer to it,
368 * fills in array with vector of qnames
369 */
370 int
meta_notify_listq(char *** qnames,md_error_t * ep)371 meta_notify_listq(char ***qnames, md_error_t *ep)
372 {
373
374 #ifdef lint
375 qnames = qnames;
376 #endif /* lint */
377
378 mdclrerror(ep);
379 (void) mdsyserror(ep, EOPNOTSUPP, "EOPNOTSUPP");
380 return (-EOPNOTSUPP);
381 }
382
383 /*
384 * meta_notify_flushq
385 * - calls the underlying notify driver to flush all events
386 * from the named queue
387 * - returns 0 on success or errno and sets ep as necessary
388 */
389 int
meta_notify_flushq(char * qname,md_error_t * ep)390 meta_notify_flushq(char *qname, md_error_t *ep)
391 {
392
393 #ifdef lint
394 qname = qname;
395 #endif /* lint */
396
397 mdclrerror(ep);
398 (void) mdsyserror(ep, EOPNOTSUPP, "EOPNOTSUPP");
399 return (EOPNOTSUPP);
400 }
401
402 static void
cook_ev(md_event_ioctl_t * evctlp,md_ev_t * evp,md_error_t * ep)403 cook_ev(md_event_ioctl_t *evctlp, md_ev_t *evp, md_error_t *ep)
404 {
405 assert(evctlp);
406 assert(evp);
407
408 evp->obj_type = tagdrv_2_objlib(evctlp->mdn_tag);
409
410 if (evp->obj_type == EVO_METADEV) {
411 evp->obj_type = dev2tag(evctlp->mdn_dev, evctlp->mdn_set, ep);
412 }
413
414 evp->setno = evctlp->mdn_set;
415 evp->ev = evdrv_2_evlib(evctlp->mdn_event);
416 evp->obj = evctlp->mdn_dev;
417 evp->uev = evctlp->mdn_user;
418 }
419
420 /*
421 * meta_notify_getev
422 * - collects up to 1 event and stores it into md_ev_t
423 * - returns number of events found (0 or 1) on success or -errno
424 * - flags governs whether an empty queue is waited upon (EVFLG_WAIT)
425 */
426 int
meta_notify_getev(char * qname,ulong_t flags,md_ev_t * evp,md_error_t * ep)427 meta_notify_getev(char *qname, ulong_t flags, md_ev_t *evp, md_error_t *ep)
428 {
429 md_event_ioctl_t evctl;
430 int n_ev;
431 int err = -EINVAL;
432
433 if (!evp) {
434 goto out;
435 }
436
437 init_evctl(qname,
438 TAG_EMPTY,
439 EQ_EMPTY,
440 /* flags (unused in get) */ 0,
441 (evp->setno == EV_ALLSETS)? MD_ALLSETS: evp->setno,
442 (evp->obj == EV_ALLOBJS)? MD_ALLDEVS: evp->obj,
443 (flags & EVFLG_WAIT) != 0? EQ_GET_WAIT: EQ_GET_NOWAIT,
444 /* user-defined event data */ 0,
445 &evctl);
446
447 err = meta_event(&evctl, ep);
448
449 /*
450 * trap EAGAIN so that EV_EMPTY events get returned, but
451 * be sure n_ev = 0 so that users who just watch the count
452 * will also work
453 */
454 switch (err) {
455 case -EAGAIN:
456 err = n_ev = 0;
457 cook_ev(&evctl, evp, ep);
458 break;
459 case 0:
460 n_ev = 1;
461 cook_ev(&evctl, evp, ep);
462 break;
463 }
464 out:
465 return (err == 0? n_ev: err);
466 }
467
468
469 /*
470 * meta_notify_getevlist
471 * - collects all pending events in the named queue and allocates
472 * an md_evlist_t * to return them
473 * - returns the number of events found (may be 0 if !WAIT) on success
474 * or -errno and sets ep as necessary
475 */
476 int
meta_notify_getevlist(char * qname,ulong_t flags,md_evlist_t ** evpp_arg,md_error_t * ep)477 meta_notify_getevlist(char *qname,
478 ulong_t flags,
479 md_evlist_t **evpp_arg,
480 md_error_t *ep)
481 {
482 md_ev_t *evp = NULL;
483 md_evlist_t *evlp = NULL;
484 md_evlist_t *evlp_head = NULL;
485 md_evlist_t *new = NULL;
486 int n_ev = 0;
487 int err = -EINVAL;
488
489 mdclrerror(ep);
490 if (!evpp_arg) {
491 (void) mdsyserror(ep, EINVAL, dgettext(TEXT_DOMAIN,
492 "No event list pointer"));
493 goto out;
494 }
495
496 if (!qname || strlen(qname) == 0) {
497 (void) mdsyserror(ep, EINVAL, dgettext(TEXT_DOMAIN,
498 "Null or zero-length queue name"));
499 goto out;
500 }
501
502 do {
503 if (!(evp = (md_ev_t *)Malloc(sizeof (md_ev_t)))) {
504 (void) mdsyserror(ep, ENOMEM, qname);
505 continue;
506 }
507 evp->obj_type = EVO_EMPTY;
508 evp->setno = EV_ALLSETS;
509 evp->ev = EV_EMPTY;
510 evp->obj = EV_ALLOBJS;
511 evp->uev = 0ULL;
512
513 err = meta_notify_getev(qname, flags, evp, ep);
514
515 if (evp->ev != EV_EMPTY) {
516 new = (md_evlist_t *)Zalloc(sizeof (md_evlist_t));
517 if (evlp_head == NULL) {
518 evlp = evlp_head = new;
519 } else {
520 evlp->next = new;
521 evlp = new;
522 }
523 evlp->evp = evp;
524 n_ev++;
525 }
526
527 } while (err >= 0 && evp && evp->ev != EV_EMPTY);
528 out:
529 if (err == -EAGAIN) {
530 err = 0;
531 }
532
533 if (err < 0) {
534 meta_notify_freeevlist(evlp_head);
535 evlp_head = NULL;
536 return (err);
537 } else if ((err == 0) && (evp->ev == EV_EMPTY)) {
538 Free(evp);
539 evp = NULL;
540 }
541
542 if (evpp_arg) {
543 *evpp_arg = evlp_head;
544 }
545
546 return (n_ev);
547 }
548
549
550 /*
551 * the guts of meta_notify_putev() and meta_notify_sendev()
552 * are within this function.
553 *
554 * meta_notify_putev() is intended for general use by user-level code,
555 * such as the GUI, to send user-defined events.
556 *
557 * meta_notify_sendev() is for "user-level driver" code, such as
558 * set manipulation and the multi-host daemon to generate events.
559 *
560 * Note- only convention enforces this usage.
561 */
562 int
meta_notify_doputev(md_ev_t * evp,md_error_t * ep)563 meta_notify_doputev(md_ev_t *evp, md_error_t *ep)
564 {
565 md_event_ioctl_t evctl;
566
567 if (!evp || !ep) {
568 return (EINVAL);
569 }
570
571 /*
572 * users may only put events of type EQ_USER
573 */
574 init_evctl(/* qname (unused in put) */ NULL,
575 TAG_EMPTY,
576 EQ_EMPTY,
577 /* flags (unused in put) */ 0,
578 (evp->setno == EV_ALLSETS)? MD_ALLSETS: evp->setno,
579 (evp->obj == EV_ALLOBJS)? MD_ALLDEVS: evp->obj,
580 EQ_PUT,
581 evp->uev,
582 &evctl);
583
584 evctl.mdn_tag = objlib_2_tagdrv(evp->obj_type);
585 evctl.mdn_event = evlib_2_evdrv(evp->ev);
586
587 return (-meta_event(&evctl, ep));
588 }
589
590 /*
591 * meta_notify_putev
592 * - sends an event down to the notify driver (hence, all queues)
593 * - returns 0 on success or errno
594 */
595 int
meta_notify_putev(md_ev_t * evp,md_error_t * ep)596 meta_notify_putev(md_ev_t *evp, md_error_t *ep)
597 {
598 if (!evp || !ep) {
599 return (EINVAL);
600 }
601
602 evp->ev = EV_USER; /* by definition */
603
604 return (meta_notify_doputev(evp, ep));
605 }
606
607 /*
608 * alternate put event entry point which allows
609 * more control of event innards (for use by md "user-level drivers")
610 *
611 * Since this routine isn't for use by clients, the user event data
612 * is always forced to be 0. That is only meaningful for events
613 * of type EQ_USER (and those go through meta_notify_putev()), so
614 * this is consistent.
615 */
616 int
meta_notify_sendev(ev_obj_t tag,set_t set,md_dev64_t dev,evid_t ev)617 meta_notify_sendev(
618 ev_obj_t tag,
619 set_t set,
620 md_dev64_t dev,
621 evid_t ev)
622 {
623 md_error_t status = mdnullerror;
624 md_error_t *ep = &status;
625 md_ev_t ev_packet;
626 int rc;
627
628 ev_packet.obj_type = tag;
629 ev_packet.setno = set;
630 ev_packet.obj = dev;
631 ev_packet.ev = ev;
632 ev_packet.uev = 0ULL;
633
634 rc = meta_notify_doputev(&ev_packet, ep);
635
636 if (0 == rc && !mdisok(ep)) {
637 rc = EINVAL;
638 mdclrerror(ep);
639 }
640 return (rc);
641 }
642
643 /*
644 * meta_notify_putevlist
645 * - sends all of the events in the event list
646 * - returns number of events sent (>= 0) on success or -errno
647 */
648 int
meta_notify_putevlist(md_evlist_t * evlp,md_error_t * ep)649 meta_notify_putevlist(md_evlist_t *evlp, md_error_t *ep)
650 {
651 md_evlist_t *evlpi;
652 int n_ev = 0;
653 int err;
654
655 if (!evlp) {
656 err = 0;
657 goto out; /* that was easy */
658 }
659
660 for (n_ev = 0, evlpi = evlp; evlpi; evlpi = evlpi->next) {
661 if ((err = meta_notify_putev(evlpi->evp, ep)) < 0) {
662 goto out;
663 }
664 n_ev++;
665 }
666 out:
667 return (err != 0? err: n_ev);
668 }
669
670 /*
671 * meta_notify_freevlist
672 * - frees any memory allocated within the event list
673 * - returns 0 on success or errno and sets ep as necessary
674 */
675 void
meta_notify_freeevlist(md_evlist_t * evlp)676 meta_notify_freeevlist(md_evlist_t *evlp)
677 {
678 md_evlist_t *i;
679 md_evlist_t *next;
680
681 for (i = evlp; i; i = i->next) {
682 if (i && i->evp) {
683 Free(i->evp);
684 i->evp = NULL;
685 }
686 }
687 for (i = evlp; i; /* NULL */) {
688 next = i->next;
689 Free(i);
690 i = next;
691 }
692 }
693