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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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