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 2007 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 #include "libdevinfo.h" 29 #include "devinfo_devlink.h" 30 #include "device_info.h" 31 32 #undef DEBUG 33 #ifndef DEBUG 34 #define NDEBUG 1 35 #else 36 #undef NDEBUG 37 #endif 38 39 #include <assert.h> 40 41 static mutex_t update_mutex = DEFAULTMUTEX; /* Protects update record lock */ 42 static mutex_t temp_file_mutex = DEFAULTMUTEX; /* for file creation tests */ 43 44 static const size_t elem_sizes[DB_TYPES] = { 45 sizeof (struct db_node), 46 sizeof (struct db_minor), 47 sizeof (struct db_link), 48 sizeof (char) 49 }; 50 51 /* 52 * List of directories/files skipped while physically walking /dev 53 * Paths are relative to "<root>/dev/" 54 */ 55 static const char *skip_dirs[] = {"fd"}; 56 static const char *skip_files[] = { 57 "stdout", 58 "stdin", 59 "stderr" 60 }; 61 62 #define N_SKIP_DIRS (sizeof (skip_dirs) / sizeof (skip_dirs[0])) 63 #define N_SKIP_FILES (sizeof (skip_files) / sizeof (skip_files[0])) 64 65 #define DI_TEST_DB ETCDEV "di_test_db" 66 67 /* 68 * 69 * This file contains two sets of interfaces which operate on the reverse 70 * links database. One set (which includes di_devlink_open()/_close()) 71 * allows link generators like devfsadm(1M) and ucblinks(1B) (writers) to 72 * populate the database with /devices -> /dev mappings. Another set 73 * of interfaces (which includes di_devlink_init()/_fini()) allows 74 * applications (readers) to lookup the database for /dev links corresponding 75 * to a given minor. 76 * 77 * Writers operate on a cached version of the database. The cache is created 78 * when di_devlink_open() is called. As links in /dev are created and removed, 79 * the cache is updated to keep it in synch with /dev. When the /dev updates 80 * are complete, the link generator calls di_devlink_close() which writes 81 * out the cache to the database. 82 * 83 * Applications which need to lookup the database, call di_devlink_init(). 84 * di_devlink_init() checks the database file (if one exists). If the 85 * database is valid, it is mapped into the address space of the 86 * application. The database file consists of several segments. Each 87 * segment can be mapped in independently and is mapped on demand. 88 * 89 * Database Layout 90 * 91 * --------------------- 92 * | Magic # | 93 * | ----------------- | 94 * | Version | HEADER 95 * | ----------------- | 96 * | ... | 97 * --------------------- 98 * | | 99 * | | NODES 100 * | | 101 * | | 102 * --------------------- 103 * | | 104 * | | MINORS 105 * | | 106 * | | 107 * --------------------- 108 * | | 109 * | | LINKS 110 * | | 111 * | | 112 * --------------------- 113 * | | 114 * | | STRINGS 115 * | | 116 * | | 117 * --------------------- 118 * 119 * Readers can lookup /dev links for a specific minor or 120 * lookup all /dev links. In the latter case, the node 121 * and minor segments are not mapped in and the reader 122 * walks through every link in the link segment. 123 * 124 */ 125 di_devlink_handle_t 126 di_devlink_open(const char *root_dir, uint_t flags) 127 { 128 int err; 129 char path[PATH_MAX]; 130 struct di_devlink_handle *hdp; 131 int retried = 0; 132 133 retry: 134 /* 135 * Allocate a read-write handle but open the DB in readonly 136 * mode. We do writes only to a temporary copy of the database. 137 */ 138 if ((hdp = handle_alloc(root_dir, OPEN_RDWR)) == NULL) { 139 return (NULL); 140 } 141 142 err = open_db(hdp, OPEN_RDONLY); 143 144 /* 145 * We don't want to unlink the db at this point - if we did we 146 * would be creating a window where consumers would take a slow 147 * code path (and those consumers might also trigger requests for 148 * db creation, which we are already in the process of doing). 149 * When we are done with our update, we use rename to install the 150 * latest version of the db file. 151 */ 152 get_db_path(hdp, DB_FILE, path, sizeof (path)); 153 154 /* 155 * The flags argument is reserved for future use. 156 */ 157 if (flags != 0) { 158 handle_free(&hdp); /* also closes the DB */ 159 errno = EINVAL; 160 return (NULL); 161 } 162 163 if (cache_alloc(hdp) != 0) { 164 handle_free(&hdp); 165 return (NULL); 166 } 167 168 if (err) { 169 /* 170 * Failed to open DB. 171 * The most likely cause is that DB file did not exist. 172 * Call di_devlink_close() to recreate the DB file and 173 * retry di_devlink_open(). 174 */ 175 if (retried == 0) { 176 (void) di_devlink_close(&hdp, 0); 177 retried = 1; 178 goto retry; 179 } 180 181 /* 182 * DB cannot be opened, just return the 183 * handle. We will recreate the DB later. 184 */ 185 return (hdp); 186 } 187 188 /* Read the database into the cache */ 189 CACHE(hdp)->update_count = DB_HDR(hdp)->update_count; 190 (void) read_nodes(hdp, NULL, DB_HDR(hdp)->root_idx); 191 (void) read_links(hdp, NULL, DB_HDR(hdp)->dngl_idx); 192 193 (void) close_db(hdp); 194 195 return (hdp); 196 } 197 198 static void 199 get_db_path( 200 struct di_devlink_handle *hdp, 201 const char *fname, 202 char *buf, 203 size_t blen) 204 { 205 char *dir = NULL; 206 207 #ifdef DEBUG 208 if (dir = getenv(ALT_DB_DIR)) { 209 (void) dprintf(DBG_INFO, "get_db_path: alternate db dir: %s\n", 210 dir); 211 } 212 #endif 213 if (dir == NULL) { 214 dir = hdp->db_dir; 215 } 216 217 (void) snprintf(buf, blen, "%s/%s", dir, fname); 218 } 219 220 static int 221 open_db(struct di_devlink_handle *hdp, int flags) 222 { 223 size_t sz; 224 long page_sz; 225 int fd, rv, flg; 226 struct stat sbuf; 227 uint32_t count[DB_TYPES] = {0}; 228 char path[PATH_MAX]; 229 void *cp; 230 231 assert(!DB_OPEN(hdp)); 232 233 #ifdef DEBUG 234 if (getenv(SKIP_DB)) { 235 (void) dprintf(DBG_INFO, "open_db: skipping database\n"); 236 return (-1); 237 } 238 #endif 239 if ((page_sz = sysconf(_SC_PAGE_SIZE)) == -1) { 240 return (-1); 241 } 242 243 /* 244 * Use O_TRUNC flag for write access, so that the subsequent ftruncate() 245 * call will zero-fill the entire file 246 */ 247 if (IS_RDONLY(flags)) { 248 flg = O_RDONLY; 249 get_db_path(hdp, DB_FILE, path, sizeof (path)); 250 } else { 251 flg = O_RDWR|O_CREAT|O_TRUNC; 252 get_db_path(hdp, DB_TMP, path, sizeof (path)); 253 } 254 255 /* 256 * Avoid triggering /dev reconfigure for read when not present 257 */ 258 if (IS_RDONLY(flags) && 259 (strncmp(path, "/dev/", 5) == 0) && !device_exists(path)) { 260 return (-1); 261 } 262 263 if ((fd = open(path, flg, DB_PERMS)) == -1) { 264 return (-1); 265 } 266 267 if (IS_RDONLY(flags)) { 268 flg = PROT_READ; 269 rv = fstat(fd, &sbuf); 270 sz = sbuf.st_size; 271 } else { 272 flg = PROT_READ | PROT_WRITE; 273 sz = size_db(hdp, page_sz, count); 274 rv = ftruncate(fd, sz); 275 } 276 277 if (rv == -1 || sz < HDR_LEN) { 278 if (rv != -1) 279 errno = EINVAL; 280 (void) close(fd); 281 return (-1); 282 } 283 284 cp = mmap(0, HDR_LEN, flg, MAP_SHARED, fd, 0); 285 if (cp == MAP_FAILED) { 286 (void) close(fd); 287 return (-1); 288 } 289 DB(hdp)->hdr = (struct db_hdr *)cp; 290 DB(hdp)->db_fd = fd; 291 DB(hdp)->flags = flags; 292 293 if (IS_RDONLY(flags)) { 294 rv = invalid_db(hdp, sz, page_sz); 295 } else { 296 rv = init_hdr(hdp, page_sz, count); 297 } 298 299 if (rv) { 300 (void) dprintf(DBG_ERR, "open_db: invalid DB(%s)\n", path); 301 (void) close_db(hdp); 302 return (-1); 303 } else { 304 (void) dprintf(DBG_STEP, "open_db: DB(%s): opened\n", path); 305 return (0); 306 } 307 } 308 309 /* 310 * A handle can be allocated for read-only or read-write access 311 */ 312 static struct di_devlink_handle * 313 handle_alloc(const char *root_dir, uint_t flags) 314 { 315 char dev_dir[PATH_MAX], path[PATH_MAX], db_dir[PATH_MAX]; 316 struct di_devlink_handle *hdp, proto = {0}; 317 int install = 0; 318 int isroot = 0; 319 struct stat sb; 320 char can_path[PATH_MAX]; 321 322 assert(flags == OPEN_RDWR || flags == OPEN_RDONLY); 323 324 dev_dir[0] = '\0'; 325 db_dir[0] = '\0'; 326 327 /* 328 * NULL and the empty string are equivalent to "/" 329 */ 330 if (root_dir && root_dir[0] != '\0') { 331 332 if (root_dir[0] != '/') { 333 errno = EINVAL; 334 return (NULL); 335 } 336 337 #ifdef DEBUG 338 /*LINTED*/ 339 assert(sizeof (dev_dir) >= PATH_MAX); 340 #endif 341 if ((realpath(root_dir, dev_dir) == NULL) || 342 (realpath(root_dir, db_dir) == NULL)) { 343 return (NULL); 344 } 345 } else { 346 /* 347 * The dev dir is at /dev i.e. we are not doing a -r /altroot 348 */ 349 isroot = 1; 350 } 351 352 if (strcmp(dev_dir, "/") == 0) { 353 dev_dir[0] = 0; 354 db_dir[0] = 0; 355 } else { 356 (void) strlcpy(db_dir, dev_dir, sizeof (db_dir)); 357 } 358 359 (void) strlcat(dev_dir, DEV, sizeof (dev_dir)); 360 (void) strlcat(db_dir, ETCDEV, sizeof (db_dir)); 361 362 /* 363 * The following code is for install. Readers and writers need 364 * to be redirected to /tmp/etc/dev for the database file. 365 * Note that we test for readonly /etc by actually creating a 366 * file since statvfs is not a reliable method for determining 367 * readonly filesystems. 368 */ 369 install = 0; 370 (void) snprintf(can_path, sizeof (can_path), "%s/%s", ETCDEV, DB_FILE); 371 if (flags == OPEN_RDWR && isroot) { 372 char di_test_db[PATH_MAX]; 373 int fd; 374 (void) mutex_lock(&temp_file_mutex); 375 (void) snprintf(di_test_db, sizeof (di_test_db), "%s.%d", 376 DI_TEST_DB, getpid()); 377 fd = open(di_test_db, O_CREAT|O_RDWR|O_EXCL, 0644); 378 if (fd == -1 && errno == EROFS && stat(can_path, &sb) == -1) 379 install = 1; 380 if (fd != -1) { 381 (void) close(fd); 382 (void) unlink(di_test_db); 383 } 384 (void) mutex_unlock(&temp_file_mutex); 385 } else if (isroot) { 386 /* 387 * Readers can be non-privileged so we cannot test by creating 388 * a file in /etc/dev. Instead we check if the database 389 * file is missing in /etc/dev and is present in /tmp/etc/dev 390 * and is owned by root. 391 */ 392 char install_path[PATH_MAX]; 393 394 (void) snprintf(install_path, sizeof (install_path), 395 "/tmp%s/%s", ETCDEV, DB_FILE); 396 if (stat(can_path, &sb) == -1 && stat(install_path, &sb) 397 != -1 && sb.st_uid == 0) { 398 install = 1; 399 } 400 } 401 402 /* 403 * Check if we are in install. If we are, the database will be in 404 * /tmp/etc/dev 405 */ 406 if (install) 407 (void) snprintf(db_dir, sizeof (db_dir), "/tmp%s", ETCDEV); 408 409 proto.dev_dir = dev_dir; 410 proto.db_dir = db_dir; 411 proto.flags = flags; 412 proto.lock_fd = -1; 413 414 /* 415 * Lock database if a read-write handle is being allocated. 416 * Locks are needed to protect against multiple writers. 417 * Readers don't need locks. 418 */ 419 if (HDL_RDWR(&proto)) { 420 if (enter_db_lock(&proto, root_dir) != 1) { 421 return (NULL); 422 } 423 } 424 425 DB(&proto)->db_fd = -1; 426 427 hdp = calloc(1, sizeof (struct di_devlink_handle)); 428 if (hdp == NULL) { 429 goto error; 430 } 431 432 *hdp = proto; 433 434 /* 435 * The handle hdp now contains a pointer to local storage 436 * in the dev_dir field (obtained from the proto handle). 437 * In the following line, a dynamically allocated version 438 * is substituted. 439 */ 440 441 if ((hdp->dev_dir = strdup(proto.dev_dir)) == NULL) { 442 free(hdp); 443 goto error; 444 } 445 446 if ((hdp->db_dir = strdup(proto.db_dir)) == NULL) { 447 free(hdp->dev_dir); 448 free(hdp); 449 goto error; 450 } 451 452 return (hdp); 453 454 error: 455 if (HDL_RDWR(&proto)) { 456 /* Unlink DB file on error */ 457 get_db_path(&proto, DB_FILE, path, sizeof (path)); 458 (void) unlink(path); 459 exit_db_lock(&proto); 460 } 461 return (NULL); 462 } 463 464 465 static int 466 cache_alloc(struct di_devlink_handle *hdp) 467 { 468 size_t hash_sz = 0; 469 470 assert(HDL_RDWR(hdp)); 471 472 if (DB_OPEN(hdp)) { 473 hash_sz = DB_NUM(hdp, DB_LINK) / AVG_CHAIN_SIZE; 474 } 475 hash_sz = (hash_sz >= MIN_HASH_SIZE) ? hash_sz : MIN_HASH_SIZE; 476 477 CACHE(hdp)->hash = calloc(hash_sz, sizeof (cache_link_t *)); 478 if (CACHE(hdp)->hash == NULL) { 479 return (-1); 480 } 481 CACHE(hdp)->hash_sz = hash_sz; 482 483 return (0); 484 } 485 486 487 static int 488 invalid_db(struct di_devlink_handle *hdp, size_t fsize, long page_sz) 489 { 490 int i; 491 char *cp; 492 size_t sz; 493 494 if (DB_HDR(hdp)->magic != DB_MAGIC || DB_HDR(hdp)->vers != DB_VERSION) { 495 return (1); 496 } 497 498 if (DB_HDR(hdp)->page_sz == 0 || DB_HDR(hdp)->page_sz != page_sz) { 499 return (1); 500 } 501 502 sz = seg_size(hdp, DB_HEADER); 503 for (i = 0; i < DB_TYPES; i++) { 504 (void) dprintf(DBG_INFO, "N[%u] = %u\n", i, DB_NUM(hdp, i)); 505 /* There must be at least 1 element of each type */ 506 if (DB_NUM(hdp, i) < 1) { 507 return (1); 508 } 509 sz += seg_size(hdp, i); 510 assert(sz % page_sz == 0); 511 } 512 513 if (sz != fsize) { 514 return (1); 515 } 516 517 if (!VALID_INDEX(hdp, DB_NODE, DB_HDR(hdp)->root_idx)) { 518 return (1); 519 } 520 521 if (!VALID_INDEX(hdp, DB_LINK, DB_HDR(hdp)->dngl_idx)) { 522 return (1); 523 } 524 525 if (DB_EMPTY(hdp)) { 526 return (1); 527 } 528 529 /* 530 * The last character in the string segment must be a NUL char. 531 */ 532 cp = get_string(hdp, DB_NUM(hdp, DB_STR) - 1); 533 if (cp == NULL || *cp != '\0') { 534 return (1); 535 } 536 537 return (0); 538 } 539 540 static int 541 read_nodes(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx) 542 { 543 char *path; 544 cache_node_t *cnp; 545 struct db_node *dnp; 546 const char *fcn = "read_nodes"; 547 548 assert(HDL_RDWR(hdp)); 549 550 /* 551 * parent node should be NULL only for the root node 552 */ 553 if ((pcnp == NULL) ^ (nidx == DB_HDR(hdp)->root_idx)) { 554 (void) dprintf(DBG_ERR, "%s: invalid parent or index(%u)\n", 555 fcn, nidx); 556 SET_DB_ERR(hdp); 557 return (-1); 558 } 559 560 for (; dnp = get_node(hdp, nidx); nidx = dnp->sib) { 561 562 path = get_string(hdp, dnp->path); 563 564 /* 565 * Insert at head of list to recreate original order 566 */ 567 cnp = node_insert(hdp, pcnp, path, INSERT_HEAD); 568 if (cnp == NULL) { 569 SET_DB_ERR(hdp); 570 break; 571 } 572 573 assert(strcmp(path, "/") ^ (nidx == DB_HDR(hdp)->root_idx)); 574 assert(strcmp(path, "/") != 0 || dnp->sib == DB_NIL); 575 576 if (read_minors(hdp, cnp, dnp->minor) != 0 || 577 read_nodes(hdp, cnp, dnp->child) != 0) { 578 break; 579 } 580 581 (void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, nidx, 582 cnp->path); 583 } 584 585 return (dnp ? -1 : 0); 586 } 587 588 static int 589 read_minors(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx) 590 { 591 cache_minor_t *cmnp; 592 struct db_minor *dmp; 593 char *name, *nodetype; 594 const char *fcn = "read_minors"; 595 596 assert(HDL_RDWR(hdp)); 597 598 if (pcnp == NULL) { 599 (void) dprintf(DBG_ERR, "%s: minor[%u]: orphan minor\n", fcn, 600 nidx); 601 SET_DB_ERR(hdp); 602 return (-1); 603 } 604 605 for (; dmp = get_minor(hdp, nidx); nidx = dmp->sib) { 606 607 name = get_string(hdp, dmp->name); 608 nodetype = get_string(hdp, dmp->nodetype); 609 610 cmnp = minor_insert(hdp, pcnp, name, nodetype, NULL); 611 if (cmnp == NULL) { 612 SET_DB_ERR(hdp); 613 break; 614 } 615 616 (void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, nidx, 617 cmnp->name); 618 619 if (read_links(hdp, cmnp, dmp->link) != 0) { 620 break; 621 } 622 } 623 624 return (dmp ? -1 : 0); 625 } 626 627 /* 628 * If the link is dangling the corresponding minor will be absent. 629 */ 630 static int 631 read_links(struct di_devlink_handle *hdp, cache_minor_t *pcmp, uint32_t nidx) 632 { 633 cache_link_t *clp; 634 struct db_link *dlp; 635 char *path, *content; 636 637 assert(HDL_RDWR(hdp)); 638 639 if (nidx != DB_NIL && 640 ((pcmp == NULL) ^ (nidx == DB_HDR(hdp)->dngl_idx))) { 641 (void) dprintf(DBG_ERR, "read_links: invalid minor or" 642 " index(%u)\n", nidx); 643 SET_DB_ERR(hdp); 644 return (-1); 645 } 646 647 for (; dlp = get_link(hdp, nidx); nidx = dlp->sib) { 648 649 path = get_string(hdp, dlp->path); 650 content = get_string(hdp, dlp->content); 651 652 clp = link_insert(hdp, pcmp, path, content, dlp->attr); 653 if (clp == NULL) { 654 SET_DB_ERR(hdp); 655 break; 656 } 657 658 (void) dprintf(DBG_STEP, "read_links: link[%u]: %s%s\n", 659 nidx, clp->path, pcmp == NULL ? "(DANGLING)" : ""); 660 } 661 662 return (dlp ? -1 : 0); 663 } 664 665 int 666 di_devlink_close(di_devlink_handle_t *pp, int flag) 667 { 668 int i, rv; 669 char tmp[PATH_MAX]; 670 char file[PATH_MAX]; 671 uint32_t next[DB_TYPES] = {0}; 672 struct di_devlink_handle *hdp; 673 674 if (pp == NULL || *pp == NULL || !HDL_RDWR(*pp)) { 675 errno = EINVAL; 676 return (-1); 677 } 678 679 hdp = *pp; 680 *pp = NULL; 681 682 /* 683 * The caller encountered some error in their processing. 684 * so handle isn't valid. Discard it and return success. 685 */ 686 if (flag == DI_LINK_ERROR) { 687 handle_free(&hdp); 688 return (0); 689 } 690 691 if (DB_ERR(hdp)) { 692 handle_free(&hdp); 693 errno = EINVAL; 694 return (-1); 695 } 696 697 /* 698 * Extract the DB path before the handle is freed. 699 */ 700 get_db_path(hdp, DB_FILE, file, sizeof (file)); 701 get_db_path(hdp, DB_TMP, tmp, sizeof (tmp)); 702 703 /* 704 * update database with actual contents of /dev 705 */ 706 (void) dprintf(DBG_INFO, "di_devlink_close: update_count = %u\n", 707 CACHE(hdp)->update_count); 708 709 /* 710 * For performance reasons, synchronization of the database 711 * with /dev is turned off by default. However, applications 712 * with appropriate permissions can request a "sync" by 713 * calling di_devlink_update(). 714 */ 715 if (CACHE(hdp)->update_count == 0) { 716 CACHE(hdp)->update_count = 1; 717 (void) dprintf(DBG_INFO, 718 "di_devlink_close: synchronizing DB\n"); 719 (void) synchronize_db(hdp); 720 } 721 722 /* 723 * Resolve dangling links AFTER synchronizing DB with /dev as the 724 * synchronization process may create dangling links. 725 */ 726 resolve_dangling_links(hdp); 727 728 /* 729 * All changes to the cache are complete. Write out the cache 730 * to the database only if it is not empty. 731 */ 732 if (CACHE_EMPTY(hdp)) { 733 (void) dprintf(DBG_INFO, "di_devlink_close: skipping write\n"); 734 (void) unlink(file); 735 handle_free(&hdp); 736 return (0); 737 } 738 739 if (open_db(hdp, OPEN_RDWR) != 0) { 740 handle_free(&hdp); 741 return (-1); 742 } 743 744 /* 745 * Keep track of array assignments. There is at least 746 * 1 element (the "NIL" element) per type. 747 */ 748 for (i = 0; i < DB_TYPES; i++) { 749 next[i] = 1; 750 } 751 752 (void) write_nodes(hdp, NULL, CACHE_ROOT(hdp), next); 753 (void) write_links(hdp, NULL, CACHE(hdp)->dngl, next); 754 DB_HDR(hdp)->update_count = CACHE(hdp)->update_count; 755 756 rv = close_db(hdp); 757 758 if (rv != 0 || DB_ERR(hdp) || rename(tmp, file) != 0) { 759 (void) dprintf(DBG_ERR, "di_devlink_close: %s error: %s\n", 760 rv ? "close_db" : "DB or rename", strerror(errno)); 761 (void) unlink(tmp); 762 (void) unlink(file); 763 handle_free(&hdp); 764 return (-1); 765 } 766 767 handle_free(&hdp); 768 769 (void) dprintf(DBG_INFO, "di_devlink_close: wrote DB(%s)\n", file); 770 771 return (0); 772 } 773 774 /* 775 * Inits the database header. 776 */ 777 static int 778 init_hdr(struct di_devlink_handle *hdp, long page_sz, uint32_t *count) 779 { 780 int i; 781 782 DB_HDR(hdp)->magic = DB_MAGIC; 783 DB_HDR(hdp)->vers = DB_VERSION; 784 DB_HDR(hdp)->root_idx = DB_NIL; 785 DB_HDR(hdp)->dngl_idx = DB_NIL; 786 DB_HDR(hdp)->page_sz = (uint32_t)page_sz; 787 788 for (i = 0; i < DB_TYPES; i++) { 789 assert(count[i] >= 1); 790 DB_NUM(hdp, i) = count[i]; 791 } 792 793 return (0); 794 } 795 796 static int 797 write_nodes( 798 struct di_devlink_handle *hdp, 799 struct db_node *pdnp, 800 cache_node_t *cnp, 801 uint32_t *next) 802 { 803 uint32_t idx; 804 struct db_node *dnp; 805 const char *fcn = "write_nodes"; 806 807 assert(HDL_RDWR(hdp)); 808 809 for (; cnp != NULL; cnp = cnp->sib) { 810 811 assert(cnp->path != NULL); 812 813 /* parent node should only be NULL for root node */ 814 if ((pdnp == NULL) ^ (cnp == CACHE_ROOT(hdp))) { 815 (void) dprintf(DBG_ERR, "%s: invalid parent for: %s\n", 816 fcn, cnp->path); 817 SET_DB_ERR(hdp); 818 break; 819 } 820 821 assert((strcmp(cnp->path, "/") != 0) ^ 822 (cnp == CACHE_ROOT(hdp))); 823 824 idx = next[DB_NODE]; 825 if ((dnp = set_node(hdp, idx)) == NULL) { 826 SET_DB_ERR(hdp); 827 break; 828 } 829 830 dnp->path = write_string(hdp, cnp->path, next); 831 if (dnp->path == DB_NIL) { 832 SET_DB_ERR(hdp); 833 break; 834 } 835 /* commit write for this node */ 836 next[DB_NODE]++; 837 838 if (pdnp == NULL) { 839 assert(DB_HDR(hdp)->root_idx == DB_NIL); 840 DB_HDR(hdp)->root_idx = idx; 841 } else { 842 dnp->sib = pdnp->child; 843 pdnp->child = idx; 844 } 845 846 (void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, idx, 847 cnp->path); 848 849 if (write_minors(hdp, dnp, cnp->minor, next) != 0 || 850 write_nodes(hdp, dnp, cnp->child, next) != 0) { 851 break; 852 } 853 } 854 855 return (cnp ? -1 : 0); 856 } 857 858 static int 859 write_minors( 860 struct di_devlink_handle *hdp, 861 struct db_node *pdnp, 862 cache_minor_t *cmnp, 863 uint32_t *next) 864 { 865 uint32_t idx; 866 struct db_minor *dmp; 867 const char *fcn = "write_minors"; 868 869 assert(HDL_RDWR(hdp)); 870 871 if (pdnp == NULL) { 872 (void) dprintf(DBG_ERR, "%s: no node for minor: %s\n", fcn, 873 cmnp ? cmnp->name : "<NULL>"); 874 SET_DB_ERR(hdp); 875 return (-1); 876 } 877 878 for (; cmnp != NULL; cmnp = cmnp->sib) { 879 880 assert(cmnp->name != NULL); 881 882 idx = next[DB_MINOR]; 883 if ((dmp = set_minor(hdp, idx)) == NULL) { 884 SET_DB_ERR(hdp); 885 break; 886 } 887 888 dmp->name = write_string(hdp, cmnp->name, next); 889 dmp->nodetype = write_string(hdp, cmnp->nodetype, next); 890 if (dmp->name == DB_NIL || dmp->nodetype == DB_NIL) { 891 dmp->name = dmp->nodetype = DB_NIL; 892 SET_DB_ERR(hdp); 893 break; 894 } 895 896 /* Commit writes to this minor */ 897 next[DB_MINOR]++; 898 899 dmp->sib = pdnp->minor; 900 pdnp->minor = idx; 901 902 (void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, idx, 903 cmnp->name); 904 905 if (write_links(hdp, dmp, cmnp->link, next) != 0) { 906 break; 907 } 908 } 909 910 return (cmnp ? -1 : 0); 911 } 912 913 static int 914 write_links( 915 struct di_devlink_handle *hdp, 916 struct db_minor *pdmp, 917 cache_link_t *clp, 918 uint32_t *next) 919 { 920 uint32_t idx; 921 struct db_link *dlp; 922 const char *fcn = "write_links"; 923 924 assert(HDL_RDWR(hdp)); 925 926 /* A NULL minor if and only if the links are dangling */ 927 if (clp != NULL && ((pdmp == NULL) ^ (clp == CACHE(hdp)->dngl))) { 928 (void) dprintf(DBG_ERR, "%s: invalid minor for link\n", fcn); 929 SET_DB_ERR(hdp); 930 return (-1); 931 } 932 933 for (; clp != NULL; clp = clp->sib) { 934 935 assert(clp->path != NULL); 936 937 if ((pdmp == NULL) ^ (clp->minor == NULL)) { 938 (void) dprintf(DBG_ERR, "%s: invalid minor for link" 939 "(%s)\n", fcn, clp->path); 940 SET_DB_ERR(hdp); 941 break; 942 } 943 944 idx = next[DB_LINK]; 945 if ((dlp = set_link(hdp, idx)) == NULL) { 946 SET_DB_ERR(hdp); 947 break; 948 } 949 950 dlp->path = write_string(hdp, clp->path, next); 951 dlp->content = write_string(hdp, clp->content, next); 952 if (dlp->path == DB_NIL || dlp->content == DB_NIL) { 953 dlp->path = dlp->content = DB_NIL; 954 SET_DB_ERR(hdp); 955 break; 956 } 957 958 dlp->attr = clp->attr; 959 960 /* Commit writes to this link */ 961 next[DB_LINK]++; 962 963 if (pdmp != NULL) { 964 dlp->sib = pdmp->link; 965 pdmp->link = idx; 966 } else { 967 dlp->sib = DB_HDR(hdp)->dngl_idx; 968 DB_HDR(hdp)->dngl_idx = idx; 969 } 970 971 (void) dprintf(DBG_STEP, "%s: link[%u]: %s%s\n", fcn, idx, 972 clp->path, pdmp == NULL ? "(DANGLING)" : ""); 973 } 974 975 return (clp ? -1 : 0); 976 } 977 978 979 static uint32_t 980 write_string(struct di_devlink_handle *hdp, const char *str, uint32_t *next) 981 { 982 char *dstr; 983 uint32_t idx; 984 985 assert(HDL_RDWR(hdp)); 986 987 if (str == NULL) { 988 (void) dprintf(DBG_ERR, "write_string: NULL argument\n"); 989 return (DB_NIL); 990 } 991 992 idx = next[DB_STR]; 993 if (!VALID_STR(hdp, idx, str)) { 994 (void) dprintf(DBG_ERR, "write_string: invalid index[%u]," 995 " string(%s)\n", idx, str); 996 return (DB_NIL); 997 } 998 999 if ((dstr = set_string(hdp, idx)) == NULL) { 1000 return (DB_NIL); 1001 } 1002 1003 (void) strcpy(dstr, str); 1004 1005 next[DB_STR] += strlen(dstr) + 1; 1006 1007 return (idx); 1008 } 1009 1010 static int 1011 close_db(struct di_devlink_handle *hdp) 1012 { 1013 int i, rv = 0; 1014 size_t sz; 1015 1016 if (!DB_OPEN(hdp)) { 1017 #ifdef DEBUG 1018 assert(DB(hdp)->db_fd == -1); 1019 assert(DB(hdp)->flags == 0); 1020 for (i = 0; i < DB_TYPES; i++) { 1021 assert(DB_SEG(hdp, i) == NULL); 1022 assert(DB_SEG_PROT(hdp, i) == 0); 1023 } 1024 #endif 1025 return (0); 1026 } 1027 1028 /* Unmap header after unmapping all other mapped segments */ 1029 for (i = 0; i < DB_TYPES; i++) { 1030 if (DB_SEG(hdp, i)) { 1031 sz = seg_size(hdp, i); 1032 if (DB_RDWR(hdp)) 1033 rv += msync(DB_SEG(hdp, i), sz, MS_SYNC); 1034 (void) munmap(DB_SEG(hdp, i), sz); 1035 DB_SEG(hdp, i) = NULL; 1036 DB_SEG_PROT(hdp, i) = 0; 1037 } 1038 } 1039 1040 if (DB_RDWR(hdp)) 1041 rv += msync((caddr_t)DB_HDR(hdp), HDR_LEN, MS_SYNC); 1042 (void) munmap((caddr_t)DB_HDR(hdp), HDR_LEN); 1043 DB(hdp)->hdr = NULL; 1044 1045 (void) close(DB(hdp)->db_fd); 1046 DB(hdp)->db_fd = -1; 1047 DB(hdp)->flags = 0; 1048 1049 return (rv ? -1 : 0); 1050 } 1051 1052 1053 static void 1054 cache_free(struct di_devlink_handle *hdp) 1055 { 1056 cache_link_t *clp; 1057 1058 subtree_free(hdp, &(CACHE_ROOT(hdp))); 1059 assert(CACHE_LAST(hdp) == NULL); 1060 1061 /* 1062 * Don't bother removing links from hash table chains, 1063 * as we are freeing the hash table itself. 1064 */ 1065 while (CACHE(hdp)->dngl != NULL) { 1066 clp = CACHE(hdp)->dngl; 1067 CACHE(hdp)->dngl = clp->sib; 1068 assert(clp->minor == NULL); 1069 link_free(&clp); 1070 } 1071 1072 assert((CACHE(hdp)->hash == NULL) ^ (CACHE(hdp)->hash_sz != 0)); 1073 1074 free(CACHE(hdp)->hash); 1075 CACHE(hdp)->hash = NULL; 1076 CACHE(hdp)->hash_sz = 0; 1077 } 1078 1079 static void 1080 handle_free(struct di_devlink_handle **pp) 1081 { 1082 struct di_devlink_handle *hdp = *pp; 1083 1084 *pp = NULL; 1085 1086 if (hdp == NULL) 1087 return; 1088 1089 (void) close_db(hdp); 1090 cache_free(hdp); 1091 1092 if (HDL_RDWR(hdp)) 1093 exit_db_lock(hdp); 1094 assert(hdp->lock_fd == -1); 1095 1096 free(hdp->dev_dir); 1097 free(hdp->db_dir); 1098 free(hdp); 1099 } 1100 1101 /* 1102 * Frees the tree rooted at a node. Siblings of the subtree root 1103 * have to be handled by the caller. 1104 */ 1105 static void 1106 subtree_free(struct di_devlink_handle *hdp, cache_node_t **pp) 1107 { 1108 cache_node_t *np; 1109 cache_link_t *clp; 1110 cache_minor_t *cmnp; 1111 1112 if (pp == NULL || *pp == NULL) 1113 return; 1114 1115 while ((*pp)->child != NULL) { 1116 np = (*pp)->child; 1117 (*pp)->child = np->sib; 1118 subtree_free(hdp, &np); 1119 } 1120 1121 while ((*pp)->minor != NULL) { 1122 cmnp = (*pp)->minor; 1123 (*pp)->minor = cmnp->sib; 1124 1125 while (cmnp->link != NULL) { 1126 clp = cmnp->link; 1127 cmnp->link = clp->sib; 1128 rm_link_from_hash(hdp, clp); 1129 link_free(&clp); 1130 } 1131 minor_free(hdp, &cmnp); 1132 } 1133 1134 node_free(pp); 1135 } 1136 1137 static void 1138 rm_link_from_hash(struct