facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * CDDL HEADER START
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The contents of this file are subject to the terms of the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Common Development and Distribution License (the "License").
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * You may not use this file except in compliance with the License.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * See the License for the specific language governing permissions
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * and limitations under the License.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * When distributing Covered Code, include this CDDL HEADER in each
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * If applicable, add the following below this CDDL HEADER, with the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * fields enclosed by brackets "[]" replaced with your own identifying
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * information: Portions Copyright [yyyy] [name of copyright owner]
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * CDDL HEADER END
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Use is subject to license terms.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * negative cache handling for the /dev fs
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * ncache is a negative cache of failed lookups. An entry
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * is added after an attempt to configure a device by that
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * name failed. An accumulation of these entries over time
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * gives us a set of device name for which implicit reconfiguration
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * does not need to be attempted. If a name is created matching
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * an entry in ncache, that entry is removed, with the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * persistent store updated.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Implicit reconfig is initiated for any name during lookup that
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * can't be resolved from the backing store and that isn't
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * present in the negative cache. This functionality is
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * enabled during system startup once communication with devfsadm
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * can be achieved. Since readdir is more general, implicit
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * reconfig initiated by reading a directory isn't enabled until
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * the system is more fully booted, at the time of the multi-user
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * milestone, corresponding to init state 2.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * A maximum is imposed on the number of entries in the cache
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * to limit some script going wild and as a defense against attack.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The default limit is 64 and can be adjusted via sdev_nc_max_entries.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Each entry also has a expiration count. When looked up a name in
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * the cache is set to the default. Subsequent boots will decrement
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * the count if a name isn't referenced. This permits a once-only
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * entry to eventually be removed over time.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * sdev_reconfig_delay implements a "debounce" of the timing beyond
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * system available indication, providing what the filesystem considers
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * to be the system-is-fully-booted state. This is provided to adjust
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * the timing if some application startup is performing a readdir
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * in /dev that initiates a troublesome implicit reconfig on every boot.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * sdev_nc_disable_reset can be used to disable clearing the negative cache
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * on reconfig boot. The default is to clear the cache on reconfig boot.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * sdev_nc_disable can be used to disable the negative cache itself.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * sdev_reconfig_disable can be used to disable implicit reconfig.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The default is that implicit reconfig is enabled.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/* tunables and defaults */
83c4dfe9546fd839e7a52bca7e9920da918f916ejg/* tunables */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/* globals */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/* static prototypes */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void sdev_ncache_write(void);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void sdev_ncache_process_store(void);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void sdev_nc_free_unlinked_node(sdev_nc_node_t *);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic sdev_nc_node_t *sdev_nc_findpath(sdev_nc_list_t *, char *);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void sdev_nc_insertnode(sdev_nc_list_t *, sdev_nc_node_t *);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void sdev_nc_free_bootonly(void);
83c4dfe9546fd839e7a52bca7e9920da918f916ejgstatic int sdev_ncache_unpack_nvlist(nvf_handle_t, nvlist_t *, char *);
83c4dfe9546fd839e7a52bca7e9920da918f916ejgstatic int sdev_ncache_pack_list(nvf_handle_t, nvlist_t **);
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Registration for /etc/devices/devname_cache
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * called once at filesystem initialization
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * called at mount of the global instance
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * currently the global instance is never unmounted
83c4dfe9546fd839e7a52bca7e9920da918f916ejg list_create(nvf_list(sdevfd_handle), sizeof (nvp_devname_t),
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
83c4dfe9546fd839e7a52bca7e9920da918f916ejgstatic void
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Unpack a device path/nvlist pair to internal data list format.
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Used to decode the nvlist format into the internal representation
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * when reading /etc/devices/devname_cache.
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Note that the expiration counts are optional, for compatibility
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * with earlier instances of the cache. If not present, the
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * expire counts are initialized to defaults.
83c4dfe9546fd839e7a52bca7e9920da918f916ejgsdev_ncache_unpack_nvlist(nvf_handle_t fd, nvlist_t *nvl, char *name)
83c4dfe9546fd839e7a52bca7e9920da918f916ejg /* name of the sublist must match what we created */
83c4dfe9546fd839e7a52bca7e9920da918f916ejg return (-1);
83c4dfe9546fd839e7a52bca7e9920da918f916ejg return (-1);
83c4dfe9546fd839e7a52bca7e9920da918f916ejg np->nvp_paths = kmem_zalloc(nstrs * sizeof (char *), KM_SLEEP);
83c4dfe9546fd839e7a52bca7e9920da918f916ejg for (i = 0; i < nstrs; i++) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg np->nvp_expirecnts = kmem_zalloc(nstrs * sizeof (int), KM_SLEEP);
83c4dfe9546fd839e7a52bca7e9920da918f916ejg for (i = 0; i < nstrs; i++) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg if (rval == 0) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg for (i = 0; i < nstrs; i++) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg return (0);
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Pack internal format cache data to a single nvlist.
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Used when writing the nvlist file.
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Note this is called indirectly by the nvpflush daemon.
83c4dfe9546fd839e7a52bca7e9920da918f916ejgsdev_ncache_pack_list(nvf_handle_t fd, nvlist_t **ret_nvl)
83c4dfe9546fd839e7a52bca7e9920da918f916ejg if (rval != 0) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg if (rval != 0) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg if (rval != 0) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg if (rval != 0) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg if (rval != 0) {
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Run through the data read from the backing cache store
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * to establish the initial state of the neg. cache.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
83c4dfe9546fd839e7a52bca7e9920da918f916ejg for (np = list_head(listp); np; np = list_next(listp, np)) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai } else if (sdev_nc_verbose) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "?%s: truncating from ncache (max %d)\n",
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * called by nvpflush daemon to inform us that an update of
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * the cache file has been completed.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err5(("ncache write complete but dirty again\n"));
83c4dfe9546fd839e7a52bca7e9920da918f916ejg * Prepare to perform an update of the neg. cache backing store.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /* proper lock ordering here is essential */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai np->nvp_paths = kmem_zalloc(n * sizeof (char *), KM_SLEEP);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai np->nvp_expirecnts = kmem_zalloc(n * sizeof (int), KM_SLEEP);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai np->nvp_paths[i] = i_ddi_strdup(lp->ncn_name, KM_SLEEP);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai (NCL_LIST_DIRTY | NCL_LIST_WENABLE | NCL_LIST_WRITING)) ==
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Once boot is complete, decrement the expire count of each entry
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * in the cache not touched by a reference. Remove any that
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * goes to zero. This effectively removes random entries over
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Upon transition to the login state on a reconfigure boot,
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * a debounce timer is set up so that we cache all the nonsense
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * lookups we're hit with by the windowing system startup.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai/*ARGSUSED*/
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai if (nsecs == 0) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Called to inform the filesystem of progress during boot,
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * either a notice of reconfiguration boot or an indication of
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * system boot complete. At system boot complete, set up a
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * timer at the expiration of which no further failed lookups
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * will be added to the negative cache.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The dev filesystem infers from reconfig boot that implicit
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * reconfig need not be invoked at all as all available devices
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * will have already been named.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * The dev filesystem infers from "system available" that devfsadmd
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * can now be run and hence implicit reconfiguration may be initiated.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * During early stages of system startup, implicit reconfig is
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * not done to avoid impacting boot performance.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Track system state and manage interesting transitions
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * The /dev filesystem fills a hot-plug .vs.
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * public-namespace gap by invoking 'devfsadm' once
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * as a result of the first /dev lookup failure
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * (or getdents/readdir). Originally, it was thought
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * that a reconfig reboot did not have a hot-plug gap,
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * but this is not true - the gap is just smaller:
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * it exists from the the time the smf invocation of
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * devfsadm completes its forced devinfo snapshot,
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * to the time when the smf devfsadmd daemon invocation
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * is set up and listening for hotplug sysevents.
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * Since there is still a gap with reconfig reboot,
89dfdb3f985a88e7d40543a4bf41dc09d44b9fdeSrikanth, Ramana * we no longer set 'sdev_reconfig_boot'.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Lookup: filter out entries in the negative cache
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Return 1 if the lookup should not cause a reconfig.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai return (0);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai sdcmn_err5(("%s/%s: lookup by %s cached, no reconfig\n",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "?%s/%s: lookup by %s cached, no reconfig\n",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaisdev_lookup_failed(sdev_node_t *dv, char *nm, int failed_flags)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * If we're still in the initial boot stage, always update
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * the cache - we may not have received notice of the
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * reconfig boot state yet. On a reconfigure boot, entries
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * from the backing store are not re-persisted on update,
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * but new entries are marked as needing an update.
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai * Never cache dynamic or non-global nodes.
3c5e027b0f15017d4b6afff01915ea70ae476223Eric Taylor (sdev_boot_state != SDEV_BOOT_STATE_COMPLETE)) ||
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai (!sdev_reconfig_boot && ((failed_flags & SLF_REBUILT))))) {
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai mutex_init(&ncl->ncl_mutex, NULL, MUTEX_DEFAULT, NULL);
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaisdev_nc_insertnode(sdev_nc_list_t *ncl, sdev_nc_node_t *new)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "%s by %s: not adding to ncache (max %d)\n",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "not adding to ncache (max %d)\n",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /* don't mark list dirty for nodes from store */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai "?%s by %s: add to ncache\n",
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaisdev_nc_addname(sdev_nc_list_t *ncl, sdev_node_t *dv, char *nm, int flags)
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllai /* dynamic and non-global nodes are never cached */
facf4a8d7b59fde89a8662b4f4c73a758e6c402cllaistatic void