devinfo_devlink.c revision 2
2N/A * The contents of this file are subject to the terms of the 2N/A * Common Development and Distribution License (the "License"). 2N/A * You may not use this file except in compliance with the License. 2N/A * See the License for the specific language governing permissions 2N/A * and limitations under the License. 2N/A * When distributing Covered Code, include this CDDL HEADER in each 2N/A * If applicable, add the following below this CDDL HEADER, with the 2N/A * fields enclosed by brackets "[]" replaced with your own identifying 2N/A * information: Portions Copyright [yyyy] [name of copyright owner] 2N/A * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved. 2N/A * Paths are relative to "<root>/dev/" 2N/A * This file contains two sets of interfaces which operate on the reverse 2N/A * links database. One set (which includes di_devlink_open()/_close()) 2N/A * allows link generators like devfsadm(1M) and ucblinks(1B) (writers) to 2N/A * populate the database with /devices -> /dev mappings. Another set 2N/A * of interfaces (which includes di_devlink_init()/_fini()) allows 2N/A * applications (readers) to lookup the database for /dev links corresponding 2N/A * Writers operate on a cached version of the database. The cache is created 2N/A * when di_devlink_open() is called. As links in /dev are created and removed, 2N/A * the cache is updated to keep it in synch with /dev. When the /dev updates 2N/A * are complete, the link generator calls di_devlink_close() which writes 2N/A * out the cache to the database. 2N/A * Applications which need to lookup the database, call di_devlink_init(). 2N/A * di_devlink_init() checks the database file (if one exists). If the 2N/A * database is valid, it is mapped into the address space of the 2N/A * application. The database file consists of several segments. Each 2N/A * segment can be mapped in independently and is mapped on demand. 2N/A * --------------------- 2N/A * | ----------------- | 2N/A * | Version | HEADER 2N/A * | ----------------- | 2N/A * --------------------- 2N/A * --------------------- 2N/A * --------------------- 2N/A * --------------------- 2N/A * --------------------- 2N/A * Readers can lookup /dev links for a specific minor or 2N/A * lookup all /dev links. In the latter case, the node 2N/A * and minor segments are not mapped in and the reader 2N/A * walks through every link in the link segment. 2N/A * Allocate a read-write handle but open the DB in readonly 2N/A * mode. We do writes only to a temporary copy of the database. 2N/A * We don't want to unlink the db at this point - if we did we 2N/A * would be creating a window where consumers would take a slow 2N/A * code path (and those consumers might also trigger requests for 2N/A * db creation, which we are already in the process of doing). 2N/A * When we are done with our update, we use rename to install the 2N/A * latest version of the db file. 2N/A * The flags argument is reserved for future use. 2N/A * Failed to open DB. 2N/A * The most likely cause is that DB file did not exist. 2N/A * Call di_devlink_close() to recreate the DB file and 2N/A * retry di_devlink_open(). 2N/A * DB cannot be opened, just return the 2N/A * handle. We will recreate the DB later. 2N/A /* Read the database into the cache */ 2N/A * Use O_TRUNC flag for write access, so that the subsequent ftruncate() 2N/A * call will zero-fill the entire file 2N/A * Avoid triggering /dev reconfigure for read when not present 2N/A * A handle can be allocated for read-only or read-write access 2N/A * NULL and the empty string are equivalent to "/" 2N/A * The dev dir is at /dev i.e. we are not doing a -r /altroot 2N/A * The following code is for install. Readers and writers need 2N/A * Note that we test for readonly /etc by actually creating a 2N/A * file since statvfs is not a reliable method for determining 2N/A * readonly filesystems. 2N/A * Readers can be non-privileged so we cannot test by creating 2N/A * a file in /etc/dev. Instead we check if the database 2N/A * and is owned by root. 2N/A * Check if we are in install. If we are, the database will be in 2N/A * Lock database if a read-write handle is being allocated. 2N/A * Locks are needed to protect against multiple writers. 2N/A * Readers don't need locks. 2N/A * The handle hdp now contains a pointer to local storage 2N/A * in the dev_dir field (obtained from the proto handle). 2N/A * In the following line, a dynamically allocated version 2N/A /* Unlink DB file on error */ 2N/A /* There must be at least 1 element of each type */ 2N/A * The last character in the string segment must be a NUL char. 2N/A const char *
fcn =
"read_nodes";
2N/A * parent node should be NULL only for the root node 2N/A * Insert at head of list to recreate original order 2N/A const char *
fcn =
"read_minors";
2N/A * If the link is dangling the corresponding minor will be absent. 2N/A * The caller encountered some error in their processing. 2N/A * so handle isn't valid. Discard it and return success. 2N/A * Extract the DB path before the handle is freed. 2N/A * update database with actual contents of /dev 2N/A * For performance reasons, synchronization of the database 2N/A * with /dev is turned off by default. However, applications 2N/A * with appropriate permissions can request a "sync" by 2N/A * calling di_devlink_update(). 2N/A "di_devlink_close: synchronizing DB\n");
2N/A * Resolve dangling links AFTER synchronizing DB with /dev as the 2N/A * synchronization process may create dangling links. 2N/A * All changes to the cache are complete. Write out the cache 2N/A * to the database only if it is not empty. 2N/A * Keep track of array assignments. There is at least 2N/A * 1 element (the "NIL" element) per type. 2N/A * Inits the database header. 2N/A const char *
fcn =
"write_nodes";
2N/A /* parent node should only be NULL for root node */ 2N/A /* commit write for this node */ 2N/A const char *
fcn =
"write_minors";
2N/A /* Commit writes to this minor */ 2N/A const char *
fcn =
"write_links";
2N/A /* A NULL minor if and only if the links are dangling */ 2N/A /* Commit writes to this link */ 2N/A /* Unmap header after unmapping all other mapped segments */ 2N/A * Don't bother removing links from hash table chains, 2N/A * as we are freeing the hash table itself. 2N/A * Frees the tree rooted at a node. Siblings of the subtree root 2N/A * have to be handled by the caller. 2N/A * For primary link, content should point to a /devices node. 2N/A * If secondary, the primary link is derived from the secondary 2N/A * link contents. Secondary link contents can have two formats: 2N/A * Lookup the primary link if possible and find its minor. 2N/A /* realpath() used only as a last resort because it is expensive */ 2N/A * A realpath attempt to lookup a dangling link can invoke implicit 2N/A * reconfig so verify there's an actual device behind the link first. 2N/A * The elements are assumed to be detached from the cache tree. 2N/A * Returns the ':' preceding the minor name 2N/A const char *
fcn =
"lookup_minor";
2N/A * last_minor is used for nodes of TYPE_CACHE only. 2N/A * Returns 0 if normal return or -1 otherwise. 2N/A * There is a next component(s). Append a "/" separator for all 2N/A * but the first (root) component. 2N/A * Terminate walk if node is not found for a path component. 2N/A const char *
fcn =
"minor_delete";
2N/A /* detach minor from node */ 2N/A /* Move all remaining links to dangling list */ 2N/A const char *
fcn =
"delete_unused_nodes";
2N/A /* Unlink node from tree */ 2N/A const char *
fcn =
"link_delete";
2N/A * Defer resolving a secondary link to a minor until the 2N/A * database is closed. This ensures that the primary link 2N/A * (required for a successful resolve) has also been created. 2N/A * Returns 0 on match or 1 otherwise. 2N/A * Reset the counter to schedule a synchronization with /dev on the next 2N/A * di_devlink_close(). 2N/A const char *
fcn =
"synchronize_db";
2N/A * Walk through $ROOT/dev, reading every link and marking the 2N/A * corresponding cached version as valid(adding new links as needed). 2N/A * Then walk through the cache and remove all unmarked links. 2N/A * The link is stale, so remove it. Since the link 2N/A * will be destroyed, use a copy of the link path to 2N/A * invoke the remove function. 2N/A * We don't need to lock. If a consumer wants the very latest db 2N/A * then he must perform a di_devlink_init with the DI_MAKE_LINK 2N/A * flag to force a sync with devfsadm first. Otherwise, the 2N/A * current database file is opened and mmaped on demand: the rename 2N/A * associated with a db update does not change the contents 2N/A * of files already opened. 2N/A * If we failed to open DB the most likely cause is that DB file did 2N/A * not exist. If we have not done a retry, signal devfsadmd to 2N/A * recreate the DB file and retry. If we fail to open the DB after 2N/A * retry, we will walk /dev in di_devlink_walk. 2N/A /* Freeing the handle also closes the DB */ 2N/A * Currently allowed flags are: 2N/A * Minor path can be NULL. In that case, all links will be 2N/A * Walk all links in database if no minor path is specified. 2N/A * Store only the part after <root-dir>/dev/ 2N/A /* Skip the "NIL" (index == 0) link. */ 2N/A * Declare this local to the block with zero 2N/A * initializer so that it gets rezeroed 2N/A * for each iteration. 2N/A * If a minor matching the path exists, walk that minor's devlinks list. 2N/A * Then walk the dangling devlinks list. Non-matching devlinks will be 2N/A * filtered out in visit_link. 2N/A * It is legal for the link's content and type to be unknown. 2N/A * but one of absolute or relative path must be set. 2N/A * Filter based on minor path 2N/A * Filter based on link type 2N/A * Obtain path relative to dev_dir 2N/A * Skip directories we are not interested in. 2N/A * Skip files we are not interested in. 2N/A "do_recurse: skipping %s\n",
cur);
2N/A "do_recurse: Skipping entry: %s\n",
cur);
2N/A/* Allocate new node and link it in */ 2N/A * Allocate a new minor and link it in either at the tail or head 2N/A * of the minor list depending on the value of "prev". 2N/A * Some pseudo drivers don't specify nodetype. Assume pseudo if 2N/A * nodetype is not specified. 2N/A /* Add to node's minor list */ 2N/A /* Add to minor's link list */ 2N/A * Returns the element corresponding to idx. If the portion of file involved 2N/A * is not yet mapped, does an mmap() as well. Existing mappings are not changed. 2N/A * If the seg is already mapped in, use it if the access type is 2N/A "seg[%d]: idx=%u, seg_prot=%d, access=%d\n",
2N/A * Segment is not mapped. Mmap() the segment. 2N/A * Computes the size of a segment rounded up to the nearest page boundary. 2N/A /* Take "NIL" element into account */ 2N/A * If the handle is IS_RDWR then we lock as writer to "update" database, 2N/A * if IS_RDONLY then we lock as reader to "snapshot" database. The 2N/A * implementation uses advisory file locking. 2N/A * This function returns: 2N/A * == 1 success and grabbed the lock file, we can open the DB. 2N/A * == 0 success but did not lock the lock file, reader must walk 2N/A * the /dev directory. 2N/A /* Record locks are per-process. Protect against multiple threads. */ 2N/A * Typically the lock file and the database go hand in hand. 2N/A * If we find that the lock file does not exist (for some 2N/A * unknown reason) and we are the reader then we return 2N/A * success (after triggering devfsadm to create the file and 2N/A * a retry) so that we can still provide service via slow 2N/A * /dev walk. If we get a failure as a writer we want the 2N/A * error to manifests itself. 2N/A /* If reader, signal once to get files created */ 2N/A /* signal to get files created */ 2N/A return (0);
/* success, but not locked */ 2N/A return (-
1);
/* failed */ 2N/A /* Enter the lock. */ 2N/A return (
1);
/* success, locked */ 2N/A * Close and re-open lock file every time so that it is recreated if deleted. 2N/A * returns 1 if contents is a minor node in /devices. 2N/A * If mn_root is not NULL, mn_root is set to: 2N/A * if contents is a /dev node, mn_root = contents 2N/A * if contents is a /devices node, mn_root set to the '/' 2N/A * following /devices. 2N/A /* mn_root should point to the / following /devices */ 2N/A /* mn_root should point to the / following /devices/ */ 2N/A * Synchronous link creation interface routines 2N/A * The scope of the operation is determined by the "name" arg. 2N/A * "name" can be NULL, a driver name or a devfs pathname (without /devices) 2N/A * NULL => All devlinks in system 2N/A * <driver> => devlinks for named driver 2N/A * /pci@1 => devlinks for subtree rooted at pci@1 2N/A * devlink_create() returns 0 on success or an errno value on failure 2N/A * Retry all but unrecoverable errors in case devfsadm 2N/A * has been or needs to be restarted. As EAGAIN indicates 2N/A * possible deadlock detection or resource exhaustion, 2N/A * retry that without timing out. 2N/A /* Convert name into arg for door_call */ 2N/A /* Attempt to call the daemon */ 2N/A * If the daemon isn't running and with full 2N/A * privileges, we are most likely in the install 2N/A * environment. We can run devfsadm directly. 2N/A * Not install so cannot do much but retry in 2N/A * the hope that the daemon restarts. 2N/A * The "name" member of "struct dca" contains data in the following order 2N/A * root'\0'minor'\0'driver'\0' 2N/A * The root component is always present at offset 0 in the "name" field. 2N/A * The driver and minor are optional. If present they have a non-zero 2N/A * offset in the "name" member. 2N/A /* Check if name is a driver name */ 2N/A /* /devices prefix not allowed in devfs pathname */ 2N/A * Returns an indication whether the devfadm daemon is running, 2N/A * as determined by the existence of the sync door file. 2N/A * If the daemon is functioning, status of the door call 2N/A * is returned in dcp->dca_error. 2N/A * If the door used to communicate with the devfsadm daemon 2N/A * doesn't exist or isn't a door, the daemon may not be 2N/A /* Block signals until door call completes. */ 2N/A * The doors interface may return data in a different buffer 2N/A * If that happens, deallocate buffer via munmap() 2N/A /* Load the specified driver if driver name provided */ 2N/A if (
cpid == 0) {
/* child process */ 2N/A /* Parent process */ 2N/A "do_exec: child exited normally\n");
2N/A * The child was interrupted by a signal 2N/A * First search the links under the specified minor. On the 2N/A * 2nd pass, search the dangling list - secondary links may 2N/A * exist on this list since they are not resolved during the 2N/A for (i = 0; i <
2; i++) {
2N/A /* If i < 2, we terminated the walk prematurely */ 2N/A * Walk cached links corresponding to the given path. 2N/A * path path to a node or minor node. 2N/A * flags specifies the type of devlinks to be selected. 2N/A * If DI_PRIMARY_LINK is used, only primary links are selected. 2N/A * If DI_SECONDARY_LINK is specified, only secondary links 2N/A * If neither flag is specified, all devlinks are selected. 2N/A * re An extended regular expression in regex(5) format which 2N/A * selects the /dev links to be returned. The regular 2N/A * expression should use link pathnames relative to 2N/A * /dev. i.e. without the leading "/dev/" prefix. 2N/A * A NULL value matches all devlinks. 2N/A * debug level is initialized to -1. 2N/A * On first call into this routine, debug level is set. 2N/A * If debug level is zero, debugging msgs are disabled. 2N/A * We shouldn't be here if debug is disabled 2N/A * Set debug level on first call into this routine 2N/A /* debug msgs are enabled */ 2N/A /* Print a distinctive label for error msgs */