17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5facf4a8dSllai * Common Development and Distribution License (the "License").
6facf4a8dSllai * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
217c478bd9Sstevel@tonic-gate /*
2274ceea2dSVikram Hegde * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237c478bd9Sstevel@tonic-gate * Use is subject to license terms.
2448bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
27facf4a8dSllai #include "libdevinfo.h"
287c478bd9Sstevel@tonic-gate #include "devinfo_devlink.h"
29ff2aee48Scth #include "device_info.h"
307c478bd9Sstevel@tonic-gate
31ff2aee48Scth #undef DEBUG
32ff2aee48Scth #ifndef DEBUG
337c478bd9Sstevel@tonic-gate #define NDEBUG 1
347c478bd9Sstevel@tonic-gate #else
357c478bd9Sstevel@tonic-gate #undef NDEBUG
367c478bd9Sstevel@tonic-gate #endif
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #include <assert.h>
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate static mutex_t update_mutex = DEFAULTMUTEX; /* Protects update record lock */
41568e756aSvikram static mutex_t temp_file_mutex = DEFAULTMUTEX; /* for file creation tests */
427c478bd9Sstevel@tonic-gate
437c478bd9Sstevel@tonic-gate static const size_t elem_sizes[DB_TYPES] = {
447c478bd9Sstevel@tonic-gate sizeof (struct db_node),
457c478bd9Sstevel@tonic-gate sizeof (struct db_minor),
467c478bd9Sstevel@tonic-gate sizeof (struct db_link),
477c478bd9Sstevel@tonic-gate sizeof (char)
487c478bd9Sstevel@tonic-gate };
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate * List of directories/files skipped while physically walking /dev
527c478bd9Sstevel@tonic-gate * Paths are relative to "<root>/dev/"
537c478bd9Sstevel@tonic-gate */
547c478bd9Sstevel@tonic-gate static const char *skip_dirs[] = {"fd"};
557c478bd9Sstevel@tonic-gate static const char *skip_files[] = {
567c478bd9Sstevel@tonic-gate "stdout",
577c478bd9Sstevel@tonic-gate "stdin",
587c478bd9Sstevel@tonic-gate "stderr"
597c478bd9Sstevel@tonic-gate };
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate #define N_SKIP_DIRS (sizeof (skip_dirs) / sizeof (skip_dirs[0]))
627c478bd9Sstevel@tonic-gate #define N_SKIP_FILES (sizeof (skip_files) / sizeof (skip_files[0]))
637c478bd9Sstevel@tonic-gate
64568e756aSvikram #define DI_TEST_DB ETCDEV "di_test_db"
65568e756aSvikram
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate *
687c478bd9Sstevel@tonic-gate * This file contains two sets of interfaces which operate on the reverse
697c478bd9Sstevel@tonic-gate * links database. One set (which includes di_devlink_open()/_close())
70*bbf21555SRichard Lowe * allows link generators like devfsadm(8) and ucblinks(1B) (writers) to
717c478bd9Sstevel@tonic-gate * populate the database with /devices -> /dev mappings. Another set
727c478bd9Sstevel@tonic-gate * of interfaces (which includes di_devlink_init()/_fini()) allows
737c478bd9Sstevel@tonic-gate * applications (readers) to lookup the database for /dev links corresponding
747c478bd9Sstevel@tonic-gate * to a given minor.
757c478bd9Sstevel@tonic-gate *
767c478bd9Sstevel@tonic-gate * Writers operate on a cached version of the database. The cache is created
777c478bd9Sstevel@tonic-gate * when di_devlink_open() is called. As links in /dev are created and removed,
787c478bd9Sstevel@tonic-gate * the cache is updated to keep it in synch with /dev. When the /dev updates
797c478bd9Sstevel@tonic-gate * are complete, the link generator calls di_devlink_close() which writes
807c478bd9Sstevel@tonic-gate * out the cache to the database.
817c478bd9Sstevel@tonic-gate *
827c478bd9Sstevel@tonic-gate * Applications which need to lookup the database, call di_devlink_init().
837c478bd9Sstevel@tonic-gate * di_devlink_init() checks the database file (if one exists). If the
847c478bd9Sstevel@tonic-gate * database is valid, it is mapped into the address space of the
857c478bd9Sstevel@tonic-gate * application. The database file consists of several segments. Each
867c478bd9Sstevel@tonic-gate * segment can be mapped in independently and is mapped on demand.
877c478bd9Sstevel@tonic-gate *
887c478bd9Sstevel@tonic-gate * Database Layout
897c478bd9Sstevel@tonic-gate *
907c478bd9Sstevel@tonic-gate * ---------------------
917c478bd9Sstevel@tonic-gate * | Magic # |
927c478bd9Sstevel@tonic-gate * | ----------------- |
937c478bd9Sstevel@tonic-gate * | Version | HEADER
947c478bd9Sstevel@tonic-gate * | ----------------- |
957c478bd9Sstevel@tonic-gate * | ... |
967c478bd9Sstevel@tonic-gate * ---------------------
977c478bd9Sstevel@tonic-gate * | |
987c478bd9Sstevel@tonic-gate * | | NODES
997c478bd9Sstevel@tonic-gate * | |
1007c478bd9Sstevel@tonic-gate * | |
1017c478bd9Sstevel@tonic-gate * ---------------------
1027c478bd9Sstevel@tonic-gate * | |
1037c478bd9Sstevel@tonic-gate * | | MINORS
1047c478bd9Sstevel@tonic-gate * | |
1057c478bd9Sstevel@tonic-gate * | |
1067c478bd9Sstevel@tonic-gate * ---------------------
1077c478bd9Sstevel@tonic-gate * | |
1087c478bd9Sstevel@tonic-gate * | | LINKS
1097c478bd9Sstevel@tonic-gate * | |
1107c478bd9Sstevel@tonic-gate * | |
1117c478bd9Sstevel@tonic-gate * ---------------------
1127c478bd9Sstevel@tonic-gate * | |
1137c478bd9Sstevel@tonic-gate * | | STRINGS
1147c478bd9Sstevel@tonic-gate * | |
1157c478bd9Sstevel@tonic-gate * | |
1167c478bd9Sstevel@tonic-gate * ---------------------
1177c478bd9Sstevel@tonic-gate *
1187c478bd9Sstevel@tonic-gate * Readers can lookup /dev links for a specific minor or
1197c478bd9Sstevel@tonic-gate * lookup all /dev links. In the latter case, the node
1207c478bd9Sstevel@tonic-gate * and minor segments are not mapped in and the reader
1217c478bd9Sstevel@tonic-gate * walks through every link in the link segment.
1227c478bd9Sstevel@tonic-gate *
1237c478bd9Sstevel@tonic-gate */
1247c478bd9Sstevel@tonic-gate di_devlink_handle_t
di_devlink_open(const char * root_dir,uint_t flags)1257c478bd9Sstevel@tonic-gate di_devlink_open(const char *root_dir, uint_t flags)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate int err;
1287c478bd9Sstevel@tonic-gate char path[PATH_MAX];
1297c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp;
1307c478bd9Sstevel@tonic-gate int retried = 0;
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate retry:
1337c478bd9Sstevel@tonic-gate /*
1347c478bd9Sstevel@tonic-gate * Allocate a read-write handle but open the DB in readonly
1357c478bd9Sstevel@tonic-gate * mode. We do writes only to a temporary copy of the database.
1367c478bd9Sstevel@tonic-gate */
1377c478bd9Sstevel@tonic-gate if ((hdp = handle_alloc(root_dir, OPEN_RDWR)) == NULL) {
1387c478bd9Sstevel@tonic-gate return (NULL);
1397c478bd9Sstevel@tonic-gate }
1407c478bd9Sstevel@tonic-gate
1417c478bd9Sstevel@tonic-gate err = open_db(hdp, OPEN_RDONLY);
1427c478bd9Sstevel@tonic-gate
1437c478bd9Sstevel@tonic-gate /*
144f7b6b8cfScth * We don't want to unlink the db at this point - if we did we
145f7b6b8cfScth * would be creating a window where consumers would take a slow
146f7b6b8cfScth * code path (and those consumers might also trigger requests for
147f7b6b8cfScth * db creation, which we are already in the process of doing).
148f7b6b8cfScth * When we are done with our update, we use rename to install the
149f7b6b8cfScth * latest version of the db file.
1507c478bd9Sstevel@tonic-gate */
1517c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_FILE, path, sizeof (path));
1527c478bd9Sstevel@tonic-gate
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate * The flags argument is reserved for future use.
1557c478bd9Sstevel@tonic-gate */
1567c478bd9Sstevel@tonic-gate if (flags != 0) {
1577c478bd9Sstevel@tonic-gate handle_free(&hdp); /* also closes the DB */
1587c478bd9Sstevel@tonic-gate errno = EINVAL;
1597c478bd9Sstevel@tonic-gate return (NULL);
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate if (cache_alloc(hdp) != 0) {
1637c478bd9Sstevel@tonic-gate handle_free(&hdp);
1647c478bd9Sstevel@tonic-gate return (NULL);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate
1677c478bd9Sstevel@tonic-gate if (err) {
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate * Failed to open DB.
1707c478bd9Sstevel@tonic-gate * The most likely cause is that DB file did not exist.
1717c478bd9Sstevel@tonic-gate * Call di_devlink_close() to recreate the DB file and
1727c478bd9Sstevel@tonic-gate * retry di_devlink_open().
1737c478bd9Sstevel@tonic-gate */
1747c478bd9Sstevel@tonic-gate if (retried == 0) {
1757c478bd9Sstevel@tonic-gate (void) di_devlink_close(&hdp, 0);
1767c478bd9Sstevel@tonic-gate retried = 1;
1777c478bd9Sstevel@tonic-gate goto retry;
1787c478bd9Sstevel@tonic-gate }
1797c478bd9Sstevel@tonic-gate
1807c478bd9Sstevel@tonic-gate /*
1817c478bd9Sstevel@tonic-gate * DB cannot be opened, just return the
1827c478bd9Sstevel@tonic-gate * handle. We will recreate the DB later.
1837c478bd9Sstevel@tonic-gate */
1847c478bd9Sstevel@tonic-gate return (hdp);
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate
1877c478bd9Sstevel@tonic-gate /* Read the database into the cache */
1887c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count = DB_HDR(hdp)->update_count;
1897c478bd9Sstevel@tonic-gate (void) read_nodes(hdp, NULL, DB_HDR(hdp)->root_idx);
1907c478bd9Sstevel@tonic-gate (void) read_links(hdp, NULL, DB_HDR(hdp)->dngl_idx);
1917c478bd9Sstevel@tonic-gate
1927c478bd9Sstevel@tonic-gate (void) close_db(hdp);
1937c478bd9Sstevel@tonic-gate
1947c478bd9Sstevel@tonic-gate return (hdp);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate static void
get_db_path(struct di_devlink_handle * hdp,const char * fname,char * buf,size_t blen)1987c478bd9Sstevel@tonic-gate get_db_path(
1997c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp,
2007c478bd9Sstevel@tonic-gate const char *fname,
2017c478bd9Sstevel@tonic-gate char *buf,
2027c478bd9Sstevel@tonic-gate size_t blen)
2037c478bd9Sstevel@tonic-gate {
2047c478bd9Sstevel@tonic-gate char *dir = NULL;
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate #ifdef DEBUG
2077c478bd9Sstevel@tonic-gate if (dir = getenv(ALT_DB_DIR)) {
2087c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "get_db_path: alternate db dir: %s\n",
2097c478bd9Sstevel@tonic-gate dir);
2107c478bd9Sstevel@tonic-gate }
2117c478bd9Sstevel@tonic-gate #endif
2127c478bd9Sstevel@tonic-gate if (dir == NULL) {
213facf4a8dSllai dir = hdp->db_dir;
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate (void) snprintf(buf, blen, "%s/%s", dir, fname);
2177c478bd9Sstevel@tonic-gate }
2187c478bd9Sstevel@tonic-gate
2197c478bd9Sstevel@tonic-gate static int
open_db(struct di_devlink_handle * hdp,int flags)2207c478bd9Sstevel@tonic-gate open_db(struct di_devlink_handle *hdp, int flags)
2217c478bd9Sstevel@tonic-gate {
2227c478bd9Sstevel@tonic-gate size_t sz;
2237c478bd9Sstevel@tonic-gate long page_sz;
2247c478bd9Sstevel@tonic-gate int fd, rv, flg;
2257c478bd9Sstevel@tonic-gate struct stat sbuf;
2267c478bd9Sstevel@tonic-gate uint32_t count[DB_TYPES] = {0};
2277c478bd9Sstevel@tonic-gate char path[PATH_MAX];
2287c478bd9Sstevel@tonic-gate void *cp;
2297c478bd9Sstevel@tonic-gate
2307c478bd9Sstevel@tonic-gate assert(!DB_OPEN(hdp));
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate #ifdef DEBUG
2337c478bd9Sstevel@tonic-gate if (getenv(SKIP_DB)) {
2347c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "open_db: skipping database\n");
2357c478bd9Sstevel@tonic-gate return (-1);
2367c478bd9Sstevel@tonic-gate }
2377c478bd9Sstevel@tonic-gate #endif
2387c478bd9Sstevel@tonic-gate if ((page_sz = sysconf(_SC_PAGE_SIZE)) == -1) {
2397c478bd9Sstevel@tonic-gate return (-1);
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate
2427c478bd9Sstevel@tonic-gate /*
2437c478bd9Sstevel@tonic-gate * Use O_TRUNC flag for write access, so that the subsequent ftruncate()
2447c478bd9Sstevel@tonic-gate * call will zero-fill the entire file
2457c478bd9Sstevel@tonic-gate */
2467c478bd9Sstevel@tonic-gate if (IS_RDONLY(flags)) {
2477c478bd9Sstevel@tonic-gate flg = O_RDONLY;
2487c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_FILE, path, sizeof (path));
2497c478bd9Sstevel@tonic-gate } else {
2507c478bd9Sstevel@tonic-gate flg = O_RDWR|O_CREAT|O_TRUNC;
2517c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_TMP, path, sizeof (path));
2527c478bd9Sstevel@tonic-gate }
2537c478bd9Sstevel@tonic-gate
254facf4a8dSllai /*
255facf4a8dSllai * Avoid triggering /dev reconfigure for read when not present
256facf4a8dSllai */
257facf4a8dSllai if (IS_RDONLY(flags) &&
258facf4a8dSllai (strncmp(path, "/dev/", 5) == 0) && !device_exists(path)) {
259facf4a8dSllai return (-1);
260facf4a8dSllai }
261facf4a8dSllai
2627c478bd9Sstevel@tonic-gate if ((fd = open(path, flg, DB_PERMS)) == -1) {
2637c478bd9Sstevel@tonic-gate return (-1);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate
2667c478bd9Sstevel@tonic-gate if (IS_RDONLY(flags)) {
2677c478bd9Sstevel@tonic-gate flg = PROT_READ;
2687c478bd9Sstevel@tonic-gate rv = fstat(fd, &sbuf);
2697c478bd9Sstevel@tonic-gate sz = sbuf.st_size;
2707c478bd9Sstevel@tonic-gate } else {
2717c478bd9Sstevel@tonic-gate flg = PROT_READ | PROT_WRITE;
2727c478bd9Sstevel@tonic-gate sz = size_db(hdp, page_sz, count);
2737c478bd9Sstevel@tonic-gate rv = ftruncate(fd, sz);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate if (rv == -1 || sz < HDR_LEN) {
2777c478bd9Sstevel@tonic-gate if (rv != -1)
2787c478bd9Sstevel@tonic-gate errno = EINVAL;
2797c478bd9Sstevel@tonic-gate (void) close(fd);
2807c478bd9Sstevel@tonic-gate return (-1);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate
2837c478bd9Sstevel@tonic-gate cp = mmap(0, HDR_LEN, flg, MAP_SHARED, fd, 0);
2847c478bd9Sstevel@tonic-gate if (cp == MAP_FAILED) {
2857c478bd9Sstevel@tonic-gate (void) close(fd);
2867c478bd9Sstevel@tonic-gate return (-1);
2877c478bd9Sstevel@tonic-gate }
2887c478bd9Sstevel@tonic-gate DB(hdp)->hdr = (struct db_hdr *)cp;
2897c478bd9Sstevel@tonic-gate DB(hdp)->db_fd = fd;
2907c478bd9Sstevel@tonic-gate DB(hdp)->flags = flags;
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate if (IS_RDONLY(flags)) {
2937c478bd9Sstevel@tonic-gate rv = invalid_db(hdp, sz, page_sz);
2947c478bd9Sstevel@tonic-gate } else {
2957c478bd9Sstevel@tonic-gate rv = init_hdr(hdp, page_sz, count);
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate
2987c478bd9Sstevel@tonic-gate if (rv) {
2997c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "open_db: invalid DB(%s)\n", path);
3007c478bd9Sstevel@tonic-gate (void) close_db(hdp);
3017c478bd9Sstevel@tonic-gate return (-1);
3027c478bd9Sstevel@tonic-gate } else {
3037c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "open_db: DB(%s): opened\n", path);
3047c478bd9Sstevel@tonic-gate return (0);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate * A handle can be allocated for read-only or read-write access
3107c478bd9Sstevel@tonic-gate */
3117c478bd9Sstevel@tonic-gate static struct di_devlink_handle *
handle_alloc(const char * root_dir,uint_t flags)3127c478bd9Sstevel@tonic-gate handle_alloc(const char *root_dir, uint_t flags)
3137c478bd9Sstevel@tonic-gate {
314facf4a8dSllai char dev_dir[PATH_MAX], path[PATH_MAX], db_dir[PATH_MAX];
3157c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp, proto = {0};
316568e756aSvikram int install = 0;
317568e756aSvikram int isroot = 0;
318568e756aSvikram struct stat sb;
319568e756aSvikram char can_path[PATH_MAX];
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate assert(flags == OPEN_RDWR || flags == OPEN_RDONLY);
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate dev_dir[0] = '\0';
324facf4a8dSllai db_dir[0] = '\0';
3257c478bd9Sstevel@tonic-gate
3267c478bd9Sstevel@tonic-gate /*
3277c478bd9Sstevel@tonic-gate * NULL and the empty string are equivalent to "/"
3287c478bd9Sstevel@tonic-gate */
3297c478bd9Sstevel@tonic-gate if (root_dir && root_dir[0] != '\0') {
3307c478bd9Sstevel@tonic-gate
3317c478bd9Sstevel@tonic-gate if (root_dir[0] != '/') {
3327c478bd9Sstevel@tonic-gate errno = EINVAL;
3337c478bd9Sstevel@tonic-gate return (NULL);
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate
3367c478bd9Sstevel@tonic-gate #ifdef DEBUG
3377c478bd9Sstevel@tonic-gate /*LINTED*/
3387c478bd9Sstevel@tonic-gate assert(sizeof (dev_dir) >= PATH_MAX);
3397c478bd9Sstevel@tonic-gate #endif
340facf4a8dSllai if ((realpath(root_dir, dev_dir) == NULL) ||
341facf4a8dSllai (realpath(root_dir, db_dir) == NULL)) {
3427c478bd9Sstevel@tonic-gate return (NULL);
3437c478bd9Sstevel@tonic-gate }
344568e756aSvikram } else {
345568e756aSvikram /*
346568e756aSvikram * The dev dir is at /dev i.e. we are not doing a -r /altroot
347568e756aSvikram */
348568e756aSvikram isroot = 1;
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate
3517c478bd9Sstevel@tonic-gate if (strcmp(dev_dir, "/") == 0) {
352facf4a8dSllai dev_dir[0] = 0;
353facf4a8dSllai db_dir[0] = 0;
3547c478bd9Sstevel@tonic-gate } else {
355facf4a8dSllai (void) strlcpy(db_dir, dev_dir, sizeof (db_dir));
3567c478bd9Sstevel@tonic-gate }
3577c478bd9Sstevel@tonic-gate
358facf4a8dSllai (void) strlcat(dev_dir, DEV, sizeof (dev_dir));
359facf4a8dSllai (void) strlcat(db_dir, ETCDEV, sizeof (db_dir));
360facf4a8dSllai
361568e756aSvikram /*
362568e756aSvikram * The following code is for install. Readers and writers need
363568e756aSvikram * to be redirected to /tmp/etc/dev for the database file.
364568e756aSvikram * Note that we test for readonly /etc by actually creating a
365568e756aSvikram * file since statvfs is not a reliable method for determining
366568e756aSvikram * readonly filesystems.
367568e756aSvikram */
368568e756aSvikram install = 0;
369568e756aSvikram (void) snprintf(can_path, sizeof (can_path), "%s/%s", ETCDEV, DB_FILE);
370568e756aSvikram if (flags == OPEN_RDWR && isroot) {
371568e756aSvikram char di_test_db[PATH_MAX];
372568e756aSvikram int fd;
373568e756aSvikram (void) mutex_lock(&temp_file_mutex);
374568e756aSvikram (void) snprintf(di_test_db, sizeof (di_test_db), "%s.%d",
375568e756aSvikram DI_TEST_DB, getpid());
376568e756aSvikram fd = open(di_test_db, O_CREAT|O_RDWR|O_EXCL, 0644);
377568e756aSvikram if (fd == -1 && errno == EROFS && stat(can_path, &sb) == -1)
378568e756aSvikram install = 1;
379568e756aSvikram if (fd != -1) {
380568e756aSvikram (void) close(fd);
381568e756aSvikram (void) unlink(di_test_db);
382568e756aSvikram }
383568e756aSvikram (void) mutex_unlock(&temp_file_mutex);
384568e756aSvikram } else if (isroot) {
385568e756aSvikram /*
386568e756aSvikram * Readers can be non-privileged so we cannot test by creating
387568e756aSvikram * a file in /etc/dev. Instead we check if the database
388568e756aSvikram * file is missing in /etc/dev and is present in /tmp/etc/dev
389568e756aSvikram * and is owned by root.
390568e756aSvikram */
391568e756aSvikram char install_path[PATH_MAX];
392568e756aSvikram
393568e756aSvikram (void) snprintf(install_path, sizeof (install_path),
394568e756aSvikram "/tmp%s/%s", ETCDEV, DB_FILE);
395568e756aSvikram if (stat(can_path, &sb) == -1 && stat(install_path, &sb)
396568e756aSvikram != -1 && sb.st_uid == 0) {
397568e756aSvikram install = 1;
398568e756aSvikram }
399568e756aSvikram }
400568e756aSvikram
401568e756aSvikram /*
402568e756aSvikram * Check if we are in install. If we are, the database will be in
403568e756aSvikram * /tmp/etc/dev
404568e756aSvikram */
405568e756aSvikram if (install)
406568e756aSvikram (void) snprintf(db_dir, sizeof (db_dir), "/tmp%s", ETCDEV);
407568e756aSvikram
4087c478bd9Sstevel@tonic-gate proto.dev_dir = dev_dir;
409facf4a8dSllai proto.db_dir = db_dir;
4107c478bd9Sstevel@tonic-gate proto.flags = flags;
4117c478bd9Sstevel@tonic-gate proto.lock_fd = -1;
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate * Lock database if a read-write handle is being allocated.
4157c478bd9Sstevel@tonic-gate * Locks are needed to protect against multiple writers.
416f7b6b8cfScth * Readers don't need locks.
4177c478bd9Sstevel@tonic-gate */
4187c478bd9Sstevel@tonic-gate if (HDL_RDWR(&proto)) {
419ff2aee48Scth if (enter_db_lock(&proto, root_dir) != 1) {
4207c478bd9Sstevel@tonic-gate return (NULL);
4217c478bd9Sstevel@tonic-gate }
4227c478bd9Sstevel@tonic-gate }
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate DB(&proto)->db_fd = -1;
4257c478bd9Sstevel@tonic-gate
4267c478bd9Sstevel@tonic-gate hdp = calloc(1, sizeof (struct di_devlink_handle));
4277c478bd9Sstevel@tonic-gate if (hdp == NULL) {
4287c478bd9Sstevel@tonic-gate goto error;
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate
4317c478bd9Sstevel@tonic-gate *hdp = proto;
4327c478bd9Sstevel@tonic-gate
4337c478bd9Sstevel@tonic-gate /*
4347c478bd9Sstevel@tonic-gate * The handle hdp now contains a pointer to local storage
4357c478bd9Sstevel@tonic-gate * in the dev_dir field (obtained from the proto handle).
4367c478bd9Sstevel@tonic-gate * In the following line, a dynamically allocated version
4377c478bd9Sstevel@tonic-gate * is substituted.
4387c478bd9Sstevel@tonic-gate */
4397c478bd9Sstevel@tonic-gate
4407c478bd9Sstevel@tonic-gate if ((hdp->dev_dir = strdup(proto.dev_dir)) == NULL) {
4417c478bd9Sstevel@tonic-gate free(hdp);
4427c478bd9Sstevel@tonic-gate goto error;
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate
445facf4a8dSllai if ((hdp->db_dir = strdup(proto.db_dir)) == NULL) {
446facf4a8dSllai free(hdp->dev_dir);
447facf4a8dSllai free(hdp);
448facf4a8dSllai goto error;
449facf4a8dSllai }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate return (hdp);
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate error:
4547c478bd9Sstevel@tonic-gate if (HDL_RDWR(&proto)) {
4557c478bd9Sstevel@tonic-gate /* Unlink DB file on error */
4567c478bd9Sstevel@tonic-gate get_db_path(&proto, DB_FILE, path, sizeof (path));
4577c478bd9Sstevel@tonic-gate (void) unlink(path);
458ff2aee48Scth exit_db_lock(&proto);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate return (NULL);
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate static int
cache_alloc(struct di_devlink_handle * hdp)4657c478bd9Sstevel@tonic-gate cache_alloc(struct di_devlink_handle *hdp)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate size_t hash_sz = 0;
4687c478bd9Sstevel@tonic-gate
4697c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate if (DB_OPEN(hdp)) {
4727c478bd9Sstevel@tonic-gate hash_sz = DB_NUM(hdp, DB_LINK) / AVG_CHAIN_SIZE;
4737c478bd9Sstevel@tonic-gate }
4747c478bd9Sstevel@tonic-gate hash_sz = (hash_sz >= MIN_HASH_SIZE) ? hash_sz : MIN_HASH_SIZE;
4757c478bd9Sstevel@tonic-gate
4767c478bd9Sstevel@tonic-gate CACHE(hdp)->hash = calloc(hash_sz, sizeof (cache_link_t *));
4777c478bd9Sstevel@tonic-gate if (CACHE(hdp)->hash == NULL) {
4787c478bd9Sstevel@tonic-gate return (-1);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate CACHE(hdp)->hash_sz = hash_sz;
4817c478bd9Sstevel@tonic-gate
4827c478bd9Sstevel@tonic-gate return (0);
4837c478bd9Sstevel@tonic-gate }
4847c478bd9Sstevel@tonic-gate
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate static int
invalid_db(struct di_devlink_handle * hdp,size_t fsize,long page_sz)4877c478bd9Sstevel@tonic-gate invalid_db(struct di_devlink_handle *hdp, size_t fsize, long page_sz)
4887c478bd9Sstevel@tonic-gate {
4897c478bd9Sstevel@tonic-gate int i;
4907c478bd9Sstevel@tonic-gate char *cp;
4917c478bd9Sstevel@tonic-gate size_t sz;
4927c478bd9Sstevel@tonic-gate
4937c478bd9Sstevel@tonic-gate if (DB_HDR(hdp)->magic != DB_MAGIC || DB_HDR(hdp)->vers != DB_VERSION) {
4947c478bd9Sstevel@tonic-gate return (1);
4957c478bd9Sstevel@tonic-gate }
4967c478bd9Sstevel@tonic-gate
4977c478bd9Sstevel@tonic-gate if (DB_HDR(hdp)->page_sz == 0 || DB_HDR(hdp)->page_sz != page_sz) {
4987c478bd9Sstevel@tonic-gate return (1);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate
5017c478bd9Sstevel@tonic-gate sz = seg_size(hdp, DB_HEADER);
5027c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) {
5037c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "N[%u] = %u\n", i, DB_NUM(hdp, i));
5047c478bd9Sstevel@tonic-gate /* There must be at least 1 element of each type */
5057c478bd9Sstevel@tonic-gate if (DB_NUM(hdp, i) < 1) {
5067c478bd9Sstevel@tonic-gate return (1);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate sz += seg_size(hdp, i);
5097c478bd9Sstevel@tonic-gate assert(sz % page_sz == 0);
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate if (sz != fsize) {
5137c478bd9Sstevel@tonic-gate return (1);
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate if (!VALID_INDEX(hdp, DB_NODE, DB_HDR(hdp)->root_idx)) {
5177c478bd9Sstevel@tonic-gate return (1);
5187c478bd9Sstevel@tonic-gate }
5197c478bd9Sstevel@tonic-gate
5207c478bd9Sstevel@tonic-gate if (!VALID_INDEX(hdp, DB_LINK, DB_HDR(hdp)->dngl_idx)) {
5217c478bd9Sstevel@tonic-gate return (1);
5227c478bd9Sstevel@tonic-gate }
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate if (DB_EMPTY(hdp)) {
5257c478bd9Sstevel@tonic-gate return (1);
5267c478bd9Sstevel@tonic-gate }
5277c478bd9Sstevel@tonic-gate
5287c478bd9Sstevel@tonic-gate /*
5297c478bd9Sstevel@tonic-gate * The last character in the string segment must be a NUL char.
5307c478bd9Sstevel@tonic-gate */
5317c478bd9Sstevel@tonic-gate cp = get_string(hdp, DB_NUM(hdp, DB_STR) - 1);
5327c478bd9Sstevel@tonic-gate if (cp == NULL || *cp != '\0') {
5337c478bd9Sstevel@tonic-gate return (1);
5347c478bd9Sstevel@tonic-gate }
5357c478bd9Sstevel@tonic-gate
5367c478bd9Sstevel@tonic-gate return (0);
5377c478bd9Sstevel@tonic-gate }
5387c478bd9Sstevel@tonic-gate
5397c478bd9Sstevel@tonic-gate static int
read_nodes(struct di_devlink_handle * hdp,cache_node_t * pcnp,uint32_t nidx)5407c478bd9Sstevel@tonic-gate read_nodes(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx)
5417c478bd9Sstevel@tonic-gate {
5427c478bd9Sstevel@tonic-gate char *path;
5437c478bd9Sstevel@tonic-gate cache_node_t *cnp;
5447c478bd9Sstevel@tonic-gate struct db_node *dnp;
5457c478bd9Sstevel@tonic-gate const char *fcn = "read_nodes";
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
5487c478bd9Sstevel@tonic-gate
5497c478bd9Sstevel@tonic-gate /*
5507c478bd9Sstevel@tonic-gate * parent node should be NULL only for the root node
5517c478bd9Sstevel@tonic-gate */
5527c478bd9Sstevel@tonic-gate if ((pcnp == NULL) ^ (nidx == DB_HDR(hdp)->root_idx)) {
5537c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid parent or index(%u)\n",
5547c478bd9Sstevel@tonic-gate fcn, nidx);
5557c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
5567c478bd9Sstevel@tonic-gate return (-1);
5577c478bd9Sstevel@tonic-gate }
5587c478bd9Sstevel@tonic-gate
5597c478bd9Sstevel@tonic-gate for (; dnp = get_node(hdp, nidx); nidx = dnp->sib) {
5607c478bd9Sstevel@tonic-gate
5617c478bd9Sstevel@tonic-gate path = get_string(hdp, dnp->path);
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate /*
5647c478bd9Sstevel@tonic-gate * Insert at head of list to recreate original order
5657c478bd9Sstevel@tonic-gate */
5667c478bd9Sstevel@tonic-gate cnp = node_insert(hdp, pcnp, path, INSERT_HEAD);
5677c478bd9Sstevel@tonic-gate if (cnp == NULL) {
5687c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
5697c478bd9Sstevel@tonic-gate break;
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate assert(strcmp(path, "/") ^ (nidx == DB_HDR(hdp)->root_idx));
5737c478bd9Sstevel@tonic-gate assert(strcmp(path, "/") != 0 || dnp->sib == DB_NIL);
5747c478bd9Sstevel@tonic-gate
5757c478bd9Sstevel@tonic-gate if (read_minors(hdp, cnp, dnp->minor) != 0 ||
5767c478bd9Sstevel@tonic-gate read_nodes(hdp, cnp, dnp->child) != 0) {
5777c478bd9Sstevel@tonic-gate break;
5787c478bd9Sstevel@tonic-gate }
5797c478bd9Sstevel@tonic-gate
5807c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, nidx,
5817c478bd9Sstevel@tonic-gate cnp->path);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate return (dnp ? -1 : 0);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate
5877c478bd9Sstevel@tonic-gate static int
read_minors(struct di_devlink_handle * hdp,cache_node_t * pcnp,uint32_t nidx)5887c478bd9Sstevel@tonic-gate read_minors(struct di_devlink_handle *hdp, cache_node_t *pcnp, uint32_t nidx)
5897c478bd9Sstevel@tonic-gate {
5907c478bd9Sstevel@tonic-gate cache_minor_t *cmnp;
5917c478bd9Sstevel@tonic-gate struct db_minor *dmp;
5927c478bd9Sstevel@tonic-gate char *name, *nodetype;
5937c478bd9Sstevel@tonic-gate const char *fcn = "read_minors";
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
5967c478bd9Sstevel@tonic-gate
5977c478bd9Sstevel@tonic-gate if (pcnp == NULL) {
5987c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: minor[%u]: orphan minor\n", fcn,
5997c478bd9Sstevel@tonic-gate nidx);
6007c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
6017c478bd9Sstevel@tonic-gate return (-1);
6027c478bd9Sstevel@tonic-gate }
6037c478bd9Sstevel@tonic-gate
6047c478bd9Sstevel@tonic-gate for (; dmp = get_minor(hdp, nidx); nidx = dmp->sib) {
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate name = get_string(hdp, dmp->name);
6077c478bd9Sstevel@tonic-gate nodetype = get_string(hdp, dmp->nodetype);
6087c478bd9Sstevel@tonic-gate
6097c478bd9Sstevel@tonic-gate cmnp = minor_insert(hdp, pcnp, name, nodetype, NULL);
6107c478bd9Sstevel@tonic-gate if (cmnp == NULL) {
6117c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
6127c478bd9Sstevel@tonic-gate break;
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate
6157c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, nidx,
6167c478bd9Sstevel@tonic-gate cmnp->name);
6177c478bd9Sstevel@tonic-gate
6187c478bd9Sstevel@tonic-gate if (read_links(hdp, cmnp, dmp->link) != 0) {
6197c478bd9Sstevel@tonic-gate break;
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate return (dmp ? -1 : 0);
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate * If the link is dangling the corresponding minor will be absent.
6287c478bd9Sstevel@tonic-gate */
6297c478bd9Sstevel@tonic-gate static int
read_links(struct di_devlink_handle * hdp,cache_minor_t * pcmp,uint32_t nidx)6307c478bd9Sstevel@tonic-gate read_links(struct di_devlink_handle *hdp, cache_minor_t *pcmp, uint32_t nidx)
6317c478bd9Sstevel@tonic-gate {
6327c478bd9Sstevel@tonic-gate cache_link_t *clp;
6337c478bd9Sstevel@tonic-gate struct db_link *dlp;
6347c478bd9Sstevel@tonic-gate char *path, *content;
6357c478bd9Sstevel@tonic-gate
6367c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
6377c478bd9Sstevel@tonic-gate
6387c478bd9Sstevel@tonic-gate if (nidx != DB_NIL &&
6397c478bd9Sstevel@tonic-gate ((pcmp == NULL) ^ (nidx == DB_HDR(hdp)->dngl_idx))) {
6407c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "read_links: invalid minor or"
6417c478bd9Sstevel@tonic-gate " index(%u)\n", nidx);
6427c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
6437c478bd9Sstevel@tonic-gate return (-1);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate
6467c478bd9Sstevel@tonic-gate for (; dlp = get_link(hdp, nidx); nidx = dlp->sib) {
6477c478bd9Sstevel@tonic-gate
6487c478bd9Sstevel@tonic-gate path = get_string(hdp, dlp->path);
6497c478bd9Sstevel@tonic-gate content = get_string(hdp, dlp->content);
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate clp = link_insert(hdp, pcmp, path, content, dlp->attr);
6527c478bd9Sstevel@tonic-gate if (clp == NULL) {
6537c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
6547c478bd9Sstevel@tonic-gate break;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "read_links: link[%u]: %s%s\n",
6587c478bd9Sstevel@tonic-gate nidx, clp->path, pcmp == NULL ? "(DANGLING)" : "");
6597c478bd9Sstevel@tonic-gate }
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate return (dlp ? -1 : 0);
6627c478bd9Sstevel@tonic-gate }
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate int
di_devlink_close(di_devlink_handle_t * pp,int flag)6657c478bd9Sstevel@tonic-gate di_devlink_close(di_devlink_handle_t *pp, int flag)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate int i, rv;
6687c478bd9Sstevel@tonic-gate char tmp[PATH_MAX];
6697c478bd9Sstevel@tonic-gate char file[PATH_MAX];
6707c478bd9Sstevel@tonic-gate uint32_t next[DB_TYPES] = {0};
6717c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp;
6727c478bd9Sstevel@tonic-gate
6737c478bd9Sstevel@tonic-gate if (pp == NULL || *pp == NULL || !HDL_RDWR(*pp)) {
6747c478bd9Sstevel@tonic-gate errno = EINVAL;
6757c478bd9Sstevel@tonic-gate return (-1);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate
6787c478bd9Sstevel@tonic-gate hdp = *pp;
6797c478bd9Sstevel@tonic-gate *pp = NULL;
6807c478bd9Sstevel@tonic-gate
6817c478bd9Sstevel@tonic-gate /*
6827c478bd9Sstevel@tonic-gate * The caller encountered some error in their processing.
6837c478bd9Sstevel@tonic-gate * so handle isn't valid. Discard it and return success.
6847c478bd9Sstevel@tonic-gate */
6857c478bd9Sstevel@tonic-gate if (flag == DI_LINK_ERROR) {
6867c478bd9Sstevel@tonic-gate handle_free(&hdp);
6877c478bd9Sstevel@tonic-gate return (0);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate
6907c478bd9Sstevel@tonic-gate if (DB_ERR(hdp)) {
6917c478bd9Sstevel@tonic-gate handle_free(&hdp);
6927c478bd9Sstevel@tonic-gate errno = EINVAL;
6937c478bd9Sstevel@tonic-gate return (-1);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate
6967c478bd9Sstevel@tonic-gate /*
6977c478bd9Sstevel@tonic-gate * Extract the DB path before the handle is freed.
6987c478bd9Sstevel@tonic-gate */
6997c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_FILE, file, sizeof (file));
7007c478bd9Sstevel@tonic-gate get_db_path(hdp, DB_TMP, tmp, sizeof (tmp));
7017c478bd9Sstevel@tonic-gate
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate * update database with actual contents of /dev
7047c478bd9Sstevel@tonic-gate */
7057c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "di_devlink_close: update_count = %u\n",
7067c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count);
7077c478bd9Sstevel@tonic-gate
7087c478bd9Sstevel@tonic-gate /*
7097c478bd9Sstevel@tonic-gate * For performance reasons, synchronization of the database
7107c478bd9Sstevel@tonic-gate * with /dev is turned off by default. However, applications
7117c478bd9Sstevel@tonic-gate * with appropriate permissions can request a "sync" by
7127c478bd9Sstevel@tonic-gate * calling di_devlink_update().
7137c478bd9Sstevel@tonic-gate */
7147c478bd9Sstevel@tonic-gate if (CACHE(hdp)->update_count == 0) {
7157c478bd9Sstevel@tonic-gate CACHE(hdp)->update_count = 1;
7167c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO,
7177c478bd9Sstevel@tonic-gate "di_devlink_close: synchronizing DB\n");
7187c478bd9Sstevel@tonic-gate (void) synchronize_db(hdp);
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate
7217c478bd9Sstevel@tonic-gate /*
7227c478bd9Sstevel@tonic-gate * Resolve dangling links AFTER synchronizing DB with /dev as the
7237c478bd9Sstevel@tonic-gate * synchronization process may create dangling links.
7247c478bd9Sstevel@tonic-gate */
7257c478bd9Sstevel@tonic-gate resolve_dangling_links(hdp);
7267c478bd9Sstevel@tonic-gate
7277c478bd9Sstevel@tonic-gate /*
7287c478bd9Sstevel@tonic-gate * All changes to the cache are complete. Write out the cache
7297c478bd9Sstevel@tonic-gate * to the database only if it is not empty.
7307c478bd9Sstevel@tonic-gate */
7317c478bd9Sstevel@tonic-gate if (CACHE_EMPTY(hdp)) {
7327c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "di_devlink_close: skipping write\n");
7337c478bd9Sstevel@tonic-gate (void) unlink(file);
7347c478bd9Sstevel@tonic-gate handle_free(&hdp);
7357c478bd9Sstevel@tonic-gate return (0);
7367c478bd9Sstevel@tonic-gate }
7377c478bd9Sstevel@tonic-gate
7387c478bd9Sstevel@tonic-gate if (open_db(hdp, OPEN_RDWR) != 0) {
7397c478bd9Sstevel@tonic-gate handle_free(&hdp);
7407c478bd9Sstevel@tonic-gate return (-1);
7417c478bd9Sstevel@tonic-gate }
7427c478bd9Sstevel@tonic-gate
7437c478bd9Sstevel@tonic-gate /*
744ff2aee48Scth * Keep track of array assignments. There is at least
7457c478bd9Sstevel@tonic-gate * 1 element (the "NIL" element) per type.
7467c478bd9Sstevel@tonic-gate */
7477c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) {
7487c478bd9Sstevel@tonic-gate next[i] = 1;
7497c478bd9Sstevel@tonic-gate }
7507c478bd9Sstevel@tonic-gate
7517c478bd9Sstevel@tonic-gate (void) write_nodes(hdp, NULL, CACHE_ROOT(hdp), next);
7527c478bd9Sstevel@tonic-gate (void) write_links(hdp, NULL, CACHE(hdp)->dngl, next);
7537c478bd9Sstevel@tonic-gate DB_HDR(hdp)->update_count = CACHE(hdp)->update_count;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate rv = close_db(hdp);
7567c478bd9Sstevel@tonic-gate
7577c478bd9Sstevel@tonic-gate if (rv != 0 || DB_ERR(hdp) || rename(tmp, file) != 0) {
7587c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "di_devlink_close: %s error: %s\n",
7597c478bd9Sstevel@tonic-gate rv ? "close_db" : "DB or rename", strerror(errno));
7607c478bd9Sstevel@tonic-gate (void) unlink(tmp);
7617c478bd9Sstevel@tonic-gate (void) unlink(file);
7627c478bd9Sstevel@tonic-gate handle_free(&hdp);
7637c478bd9Sstevel@tonic-gate return (-1);
7647c478bd9Sstevel@tonic-gate }
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate handle_free(&hdp);
7677c478bd9Sstevel@tonic-gate
7687c478bd9Sstevel@tonic-gate (void) dprintf(DBG_INFO, "di_devlink_close: wrote DB(%s)\n", file);
7697c478bd9Sstevel@tonic-gate
7707c478bd9Sstevel@tonic-gate return (0);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate
7737c478bd9Sstevel@tonic-gate /*
7747c478bd9Sstevel@tonic-gate * Inits the database header.
7757c478bd9Sstevel@tonic-gate */
7767c478bd9Sstevel@tonic-gate static int
init_hdr(struct di_devlink_handle * hdp,long page_sz,uint32_t * count)7777c478bd9Sstevel@tonic-gate init_hdr(struct di_devlink_handle *hdp, long page_sz, uint32_t *count)
7787c478bd9Sstevel@tonic-gate {
7797c478bd9Sstevel@tonic-gate int i;
7807c478bd9Sstevel@tonic-gate
7817c478bd9Sstevel@tonic-gate DB_HDR(hdp)->magic = DB_MAGIC;
7827c478bd9Sstevel@tonic-gate DB_HDR(hdp)->vers = DB_VERSION;
7837c478bd9Sstevel@tonic-gate DB_HDR(hdp)->root_idx = DB_NIL;
7847c478bd9Sstevel@tonic-gate DB_HDR(hdp)->dngl_idx = DB_NIL;
7857c478bd9Sstevel@tonic-gate DB_HDR(hdp)->page_sz = (uint32_t)page_sz;
7867c478bd9Sstevel@tonic-gate
7877c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) {
7887c478bd9Sstevel@tonic-gate assert(count[i] >= 1);
7897c478bd9Sstevel@tonic-gate DB_NUM(hdp, i) = count[i];
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate
7927c478bd9Sstevel@tonic-gate return (0);
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate
7957c478bd9Sstevel@tonic-gate static int
write_nodes(struct di_devlink_handle * hdp,struct db_node * pdnp,cache_node_t * cnp,uint32_t * next)7967c478bd9Sstevel@tonic-gate write_nodes(
7977c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp,
7987c478bd9Sstevel@tonic-gate struct db_node *pdnp,
7997c478bd9Sstevel@tonic-gate cache_node_t *cnp,
8007c478bd9Sstevel@tonic-gate uint32_t *next)
8017c478bd9Sstevel@tonic-gate {
8027c478bd9Sstevel@tonic-gate uint32_t idx;
8037c478bd9Sstevel@tonic-gate struct db_node *dnp;
8047c478bd9Sstevel@tonic-gate const char *fcn = "write_nodes";
8057c478bd9Sstevel@tonic-gate
8067c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate for (; cnp != NULL; cnp = cnp->sib) {
8097c478bd9Sstevel@tonic-gate
8107c478bd9Sstevel@tonic-gate assert(cnp->path != NULL);
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate /* parent node should only be NULL for root node */
8137c478bd9Sstevel@tonic-gate if ((pdnp == NULL) ^ (cnp == CACHE_ROOT(hdp))) {
8147c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid parent for: %s\n",
8157c478bd9Sstevel@tonic-gate fcn, cnp->path);
8167c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
8177c478bd9Sstevel@tonic-gate break;
8187c478bd9Sstevel@tonic-gate }
8197c478bd9Sstevel@tonic-gate
8207c478bd9Sstevel@tonic-gate assert((strcmp(cnp->path, "/") != 0) ^
8217c478bd9Sstevel@tonic-gate (cnp == CACHE_ROOT(hdp)));
8227c478bd9Sstevel@tonic-gate
8237c478bd9Sstevel@tonic-gate idx = next[DB_NODE];
8247c478bd9Sstevel@tonic-gate if ((dnp = set_node(hdp, idx)) == NULL) {
8257c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
8267c478bd9Sstevel@tonic-gate break;
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate
8297c478bd9Sstevel@tonic-gate dnp->path = write_string(hdp, cnp->path, next);
8307c478bd9Sstevel@tonic-gate if (dnp->path == DB_NIL) {
8317c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
8327c478bd9Sstevel@tonic-gate break;
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate /* commit write for this node */
8357c478bd9Sstevel@tonic-gate next[DB_NODE]++;
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate if (pdnp == NULL) {
8387c478bd9Sstevel@tonic-gate assert(DB_HDR(hdp)->root_idx == DB_NIL);
8397c478bd9Sstevel@tonic-gate DB_HDR(hdp)->root_idx = idx;
8407c478bd9Sstevel@tonic-gate } else {
8417c478bd9Sstevel@tonic-gate dnp->sib = pdnp->child;
8427c478bd9Sstevel@tonic-gate pdnp->child = idx;
8437c478bd9Sstevel@tonic-gate }
8447c478bd9Sstevel@tonic-gate
8457c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: node[%u]: %s\n", fcn, idx,
8467c478bd9Sstevel@tonic-gate cnp->path);
8477c478bd9Sstevel@tonic-gate
8487c478bd9Sstevel@tonic-gate if (write_minors(hdp, dnp, cnp->minor, next) != 0 ||
8497c478bd9Sstevel@tonic-gate write_nodes(hdp, dnp, cnp->child, next) != 0) {
8507c478bd9Sstevel@tonic-gate break;
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate }
8537c478bd9Sstevel@tonic-gate
8547c478bd9Sstevel@tonic-gate return (cnp ? -1 : 0);
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate
8577c478bd9Sstevel@tonic-gate static int
write_minors(struct di_devlink_handle * hdp,struct db_node * pdnp,cache_minor_t * cmnp,uint32_t * next)8587c478bd9Sstevel@tonic-gate write_minors(
8597c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp,
8607c478bd9Sstevel@tonic-gate struct db_node *pdnp,
8617c478bd9Sstevel@tonic-gate cache_minor_t *cmnp,
8627c478bd9Sstevel@tonic-gate uint32_t *next)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate uint32_t idx;
8657c478bd9Sstevel@tonic-gate struct db_minor *dmp;
8667c478bd9Sstevel@tonic-gate const char *fcn = "write_minors";
8677c478bd9Sstevel@tonic-gate
8687c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate if (pdnp == NULL) {
8717c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: no node for minor: %s\n", fcn,
8727c478bd9Sstevel@tonic-gate cmnp ? cmnp->name : "<NULL>");
8737c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
8747c478bd9Sstevel@tonic-gate return (-1);
8757c478bd9Sstevel@tonic-gate }
8767c478bd9Sstevel@tonic-gate
8777c478bd9Sstevel@tonic-gate for (; cmnp != NULL; cmnp = cmnp->sib) {
8787c478bd9Sstevel@tonic-gate
8797c478bd9Sstevel@tonic-gate assert(cmnp->name != NULL);
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate idx = next[DB_MINOR];
8827c478bd9Sstevel@tonic-gate if ((dmp = set_minor(hdp, idx)) == NULL) {
8837c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
8847c478bd9Sstevel@tonic-gate break;
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate
8877c478bd9Sstevel@tonic-gate dmp->name = write_string(hdp, cmnp->name, next);
8887c478bd9Sstevel@tonic-gate dmp->nodetype = write_string(hdp, cmnp->nodetype, next);
8897c478bd9Sstevel@tonic-gate if (dmp->name == DB_NIL || dmp->nodetype == DB_NIL) {
8907c478bd9Sstevel@tonic-gate dmp->name = dmp->nodetype = DB_NIL;
8917c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
8927c478bd9Sstevel@tonic-gate break;
8937c478bd9Sstevel@tonic-gate }
8947c478bd9Sstevel@tonic-gate
8957c478bd9Sstevel@tonic-gate /* Commit writes to this minor */
8967c478bd9Sstevel@tonic-gate next[DB_MINOR]++;
8977c478bd9Sstevel@tonic-gate
8987c478bd9Sstevel@tonic-gate dmp->sib = pdnp->minor;
8997c478bd9Sstevel@tonic-gate pdnp->minor = idx;
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: minor[%u]: %s\n", fcn, idx,
9027c478bd9Sstevel@tonic-gate cmnp->name);
9037c478bd9Sstevel@tonic-gate
9047c478bd9Sstevel@tonic-gate if (write_links(hdp, dmp, cmnp->link, next) != 0) {
9057c478bd9Sstevel@tonic-gate break;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate
9097c478bd9Sstevel@tonic-gate return (cmnp ? -1 : 0);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate
9127c478bd9Sstevel@tonic-gate static int
write_links(struct di_devlink_handle * hdp,struct db_minor * pdmp,cache_link_t * clp,uint32_t * next)9137c478bd9Sstevel@tonic-gate write_links(
9147c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp,
9157c478bd9Sstevel@tonic-gate struct db_minor *pdmp,
9167c478bd9Sstevel@tonic-gate cache_link_t *clp,
9177c478bd9Sstevel@tonic-gate uint32_t *next)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate uint32_t idx;
9207c478bd9Sstevel@tonic-gate struct db_link *dlp;
9217c478bd9Sstevel@tonic-gate const char *fcn = "write_links";
9227c478bd9Sstevel@tonic-gate
9237c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
9247c478bd9Sstevel@tonic-gate
9257c478bd9Sstevel@tonic-gate /* A NULL minor if and only if the links are dangling */
9267c478bd9Sstevel@tonic-gate if (clp != NULL && ((pdmp == NULL) ^ (clp == CACHE(hdp)->dngl))) {
9277c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid minor for link\n", fcn);
9287c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
9297c478bd9Sstevel@tonic-gate return (-1);
9307c478bd9Sstevel@tonic-gate }
9317c478bd9Sstevel@tonic-gate
9327c478bd9Sstevel@tonic-gate for (; clp != NULL; clp = clp->sib) {
9337c478bd9Sstevel@tonic-gate
9347c478bd9Sstevel@tonic-gate assert(clp->path != NULL);
9357c478bd9Sstevel@tonic-gate
9367c478bd9Sstevel@tonic-gate if ((pdmp == NULL) ^ (clp->minor == NULL)) {
9377c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "%s: invalid minor for link"
9387c478bd9Sstevel@tonic-gate "(%s)\n", fcn, clp->path);
9397c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
9407c478bd9Sstevel@tonic-gate break;
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate
9437c478bd9Sstevel@tonic-gate idx = next[DB_LINK];
9447c478bd9Sstevel@tonic-gate if ((dlp = set_link(hdp, idx)) == NULL) {
9457c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
9467c478bd9Sstevel@tonic-gate break;
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate dlp->path = write_string(hdp, clp->path, next);
9507c478bd9Sstevel@tonic-gate dlp->content = write_string(hdp, clp->content, next);
9517c478bd9Sstevel@tonic-gate if (dlp->path == DB_NIL || dlp->content == DB_NIL) {
9527c478bd9Sstevel@tonic-gate dlp->path = dlp->content = DB_NIL;
9537c478bd9Sstevel@tonic-gate SET_DB_ERR(hdp);
9547c478bd9Sstevel@tonic-gate break;
9557c478bd9Sstevel@tonic-gate }
9567c478bd9Sstevel@tonic-gate
9577c478bd9Sstevel@tonic-gate dlp->attr = clp->attr;
9587c478bd9Sstevel@tonic-gate
9597c478bd9Sstevel@tonic-gate /* Commit writes to this link */
9607c478bd9Sstevel@tonic-gate next[DB_LINK]++;
9617c478bd9Sstevel@tonic-gate
9627c478bd9Sstevel@tonic-gate if (pdmp != NULL) {
9637c478bd9Sstevel@tonic-gate dlp->sib = pdmp->link;
9647c478bd9Sstevel@tonic-gate pdmp->link = idx;
9657c478bd9Sstevel@tonic-gate } else {
9667c478bd9Sstevel@tonic-gate dlp->sib = DB_HDR(hdp)->dngl_idx;
9677c478bd9Sstevel@tonic-gate DB_HDR(hdp)->dngl_idx = idx;
9687c478bd9Sstevel@tonic-gate }
9697c478bd9Sstevel@tonic-gate
9707c478bd9Sstevel@tonic-gate (void) dprintf(DBG_STEP, "%s: link[%u]: %s%s\n", fcn, idx,
9717c478bd9Sstevel@tonic-gate clp->path, pdmp == NULL ? "(DANGLING)" : "");
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate
9747c478bd9Sstevel@tonic-gate return (clp ? -1 : 0);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate static uint32_t
write_string(struct di_devlink_handle * hdp,const char * str,uint32_t * next)9797c478bd9Sstevel@tonic-gate write_string(struct di_devlink_handle *hdp, const char *str, uint32_t *next)
9807c478bd9Sstevel@tonic-gate {
9817c478bd9Sstevel@tonic-gate char *dstr;
9827c478bd9Sstevel@tonic-gate uint32_t idx;
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate assert(HDL_RDWR(hdp));
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate if (str == NULL) {
9877c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "write_string: NULL argument\n");
9887c478bd9Sstevel@tonic-gate return (DB_NIL);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate
9917c478bd9Sstevel@tonic-gate idx = next[DB_STR];
9927c478bd9Sstevel@tonic-gate if (!VALID_STR(hdp, idx, str)) {
9937c478bd9Sstevel@tonic-gate (void) dprintf(DBG_ERR, "write_string: invalid index[%u],"
9947c478bd9Sstevel@tonic-gate " string(%s)\n", idx, str);
9957c478bd9Sstevel@tonic-gate return (DB_NIL);
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate if ((dstr = set_string(hdp, idx)) == NULL) {
9997c478bd9Sstevel@tonic-gate return (DB_NIL);
10007c478bd9Sstevel@tonic-gate }
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate (void) strcpy(dstr, str);
10037c478bd9Sstevel@tonic-gate
10047c478bd9Sstevel@tonic-gate next[DB_STR] += strlen(dstr) + 1;
10057c478bd9Sstevel@tonic-gate
10067c478bd9Sstevel@tonic-gate return (idx);
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate
10097c478bd9Sstevel@tonic-gate static int
close_db(struct di_devlink_handle * hdp)10107c478bd9Sstevel@tonic-gate close_db(struct di_devlink_handle *hdp)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate int i, rv = 0;
10137c478bd9Sstevel@tonic-gate size_t sz;
10147c478bd9Sstevel@tonic-gate
10157c478bd9Sstevel@tonic-gate if (!DB_OPEN(hdp)) {
10167c478bd9Sstevel@tonic-gate #ifdef DEBUG
10177c478bd9Sstevel@tonic-gate assert(DB(hdp)->db_fd == -1);
10187c478bd9Sstevel@tonic-gate assert(DB(hdp)->flags == 0);
10197c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) {
10207c478bd9Sstevel@tonic-gate assert(DB_SEG(hdp, i) == NULL);
10217c478bd9Sstevel@tonic-gate assert(DB_SEG_PROT(hdp, i) == 0);
10227c478bd9Sstevel@tonic-gate }
10237c478bd9Sstevel@tonic-gate #endif
10247c478bd9Sstevel@tonic-gate return (0);
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate
10277c478bd9Sstevel@tonic-gate /* Unmap header after unmapping all other mapped segments */
10287c478bd9Sstevel@tonic-gate for (i = 0; i < DB_TYPES; i++) {
10297c478bd9Sstevel@tonic-gate if (DB_SEG(hdp, i)) {
10307c478bd9Sstevel@tonic-gate sz = seg_size(hdp, i);
10317c478bd9Sstevel@tonic-gate if (DB_RDWR(hdp))
10327c478bd9Sstevel@tonic-gate rv += msync(DB_SEG(hdp, i), sz, MS_SYNC);
10337c478bd9Sstevel@tonic-gate (void) munmap(DB_SEG(hdp, i), sz);
10347c478bd9Sstevel@tonic-gate DB_SEG(hdp, i) = NULL;
10357c478bd9Sstevel@tonic-gate DB_SEG_PROT(hdp, i) = 0;
10367c478bd9Sstevel@tonic-gate }
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate if (DB_RDWR(hdp))
10407c478bd9Sstevel@tonic-gate rv += msync((caddr_t)DB_HDR(hdp), HDR_LEN, MS_SYNC);
10417c478bd9Sstevel@tonic-gate (void) munmap((caddr_t)DB_HDR(hdp), HDR_LEN);
10427c478bd9Sstevel@tonic-gate DB(hdp)->hdr = NULL;
10437c478bd9Sstevel@tonic-gate
10447c478bd9Sstevel@tonic-gate (void) close(DB(hdp)->db_fd);
10457c478bd9Sstevel@tonic-gate DB(hdp)->db_fd = -1;
10467c478bd9Sstevel@tonic-gate DB(hdp)->flags = 0;
10477c478bd9Sstevel@tonic-gate
10487c478bd9Sstevel@tonic-gate return (rv ? -1 : 0);
10497c478bd9Sstevel@tonic-gate }
10507c478bd9Sstevel@tonic-gate
10517c478bd9Sstevel@tonic-gate
10527c478bd9Sstevel@tonic-gate static void
cache_free(struct di_devlink_handle * hdp)10537c478bd9Sstevel@tonic-gate cache_free(struct di_devlink_handle *hdp)
10547c478bd9Sstevel@tonic-gate {
10557c478bd9Sstevel@tonic-gate cache_link_t *clp;
10567c478bd9Sstevel@tonic-gate
10577c478bd9Sstevel@tonic-gate subtree_free(hdp, &(CACHE_ROOT(hdp)));
10587c478bd9Sstevel@tonic-gate assert(CACHE_LAST(hdp) == NULL);
10597c478bd9Sstevel@tonic-gate
10607c478bd9Sstevel@tonic-gate /*
10617c478bd9Sstevel@tonic-gate * Don't bother removing links from hash table chains,
10627c478bd9Sstevel@tonic-gate * as we are freeing the hash table itself.
10637c478bd9Sstevel@tonic-gate */
10647c478bd9Sstevel@tonic-gate while (CACHE(hdp)->dngl != NULL) {
10657c478bd9Sstevel@tonic-gate clp = CACHE(hdp)->dngl;
10667c478bd9Sstevel@tonic-gate CACHE(hdp)->dngl = clp->sib;
10677c478bd9Sstevel@tonic-gate assert(clp->minor == NULL);
10687c478bd9Sstevel@tonic-gate link_free(&clp);
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate
10717c478bd9Sstevel@tonic-gate assert((CACHE(hdp)->hash == NULL) ^ (CACHE(hdp)->hash_sz != 0));
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate free(CACHE(hdp)->hash);
10747c478bd9Sstevel@tonic-gate CACHE(hdp)->hash = NULL;
10757c478bd9Sstevel@tonic-gate CACHE(hdp)->hash_sz = 0;
10767c478bd9Sstevel@tonic-gate }
10777c478bd9Sstevel@tonic-gate
10787c478bd9Sstevel@tonic-gate static void
handle_free(struct di_devlink_handle ** pp)10797c478bd9Sstevel@tonic-gate handle_free(struct di_devlink_handle **pp)
10807c478bd9Sstevel@tonic-gate {
10817c478bd9Sstevel@tonic-gate struct di_devlink_handle *hdp = *pp;
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate *pp = NULL;
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate if (hdp == NULL)
10867c478bd9Sstevel@tonic-gate return;
10877c478bd9Sstevel@tonic-gate
10887c478bd9Sstevel@tonic-gate (void) close_db(hdp);
10897c478bd9Sstevel@tonic-gate cache_free(hdp);
10907c478bd9Sstevel@tonic-gate
10917c478bd9Sstevel@tonic-gate if (HDL_RDWR(hdp))
1092ff2aee48Scth exit_db_lock(hdp);
10937c478bd9Sstevel@tonic-gate assert(hdp->lock_fd == -1);
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate free(hdp->dev_dir);
1096a08731ecScth free(hdp->db_dir);
10977c478bd9Sstevel@tonic-gate free(hdp);
10987c478bd9Sstevel@tonic-gate }
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate /*
11017c478bd9Sstevel@tonic-gate * Frees the tree rooted at a node. Siblings of the subtree root
11027c478bd9Sstevel@tonic-gate * have to be handled by the caller.
11037c478bd9Sstevel@tonic-gate */
11047c478bd9Sstevel@tonic-gate static void
subtree_free(struct di_devlink_handle * hdp,cache_node_t ** pp)11057c478bd9Sstevel@tonic-gate subtree_free(struct di_devlink_handle *hdp, cache_node_t **pp)
11067c478bd9Sstevel@tonic-gate {
11077c478bd9Sstevel@tonic-gate cache_node_t *np;
11087c478bd9Sstevel@tonic-gate cache_link_t *clp;
11097c478bd9Sstevel@tonic-gate cache_minor_t *cmnp;
11107c478bd9Sstevel@tonic-gate
11117c478bd9Sstevel@tonic-gate if (pp == NULL || *pp == NULL)
11127c478bd9Sstevel@tonic-gate return;
11137c478bd9Sstevel@tonic-gate
11147c478bd9Sstevel@tonic-gate while ((*pp)->child != NULL) {
11157c478bd9Sstevel@tonic-gate np = (*pp)->child;
11167c478bd9Sstevel@tonic-gate (*pp)->child = np->sib;
11177c478bd9Sstevel@tonic-gate subtree_free(hdp, &np);
11187c478bd9Sstevel@tonic-gate }
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate while ((*pp)->minor != NULL) {
11217c478bd9Sstevel@tonic-gate cmnp = (*pp)->minor;
11227c478bd9Sstevel@tonic-gate (*pp)->minor = cmnp->sib;
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate while (cmnp->link != NULL) {
11257c478bd9Sstevel@tonic-gate clp = cmnp->link;
11267c478bd9Sstevel@tonic-gate cmnp->link = clp->sib;
11277c478bd9Sstevel@tonic-gate rm_link_from_hash(hdp, clp);
11287c478bd9Sstevel@tonic-gate link_free(&clp);