summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/os
diff options
context:
space:
mode:
authorllai1 <none@none>2006-08-25 17:24:25 -0700
committerllai1 <none@none>2006-08-25 17:24:25 -0700
commitfacf4a8d7b59fde89a8662b4f4c73a758e6c402c (patch)
tree4e0024c5508351006df1496ec4be6e7b564c3ce8 /usr/src/uts/common/os
parentadcafb0fe4c49c4d46c0b393dfba36d4e1b55c0e (diff)
downloadillumos-gate-facf4a8d7b59fde89a8662b4f4c73a758e6c402c.tar.gz
PSARC/2003/246 Filesystem Driven Device Naming
5050715 logical device names not created during early boot 6292952 devfsadm mishandles optarg 6362924 devfsadm secondary link generation is not zones aware 6413127 Integrate the Devname Project 6464196 bfu should remove pt_chmod, obsoleted by /dev filesystem --HG-- rename : usr/src/cmd/pt_chmod/Makefile => deleted_files/usr/src/cmd/pt_chmod/Makefile rename : usr/src/cmd/pt_chmod/pt_chmod.c => deleted_files/usr/src/cmd/pt_chmod/pt_chmod.c
Diffstat (limited to 'usr/src/uts/common/os')
-rw-r--r--usr/src/uts/common/os/devcfg.c68
-rw-r--r--usr/src/uts/common/os/devctl.c447
-rw-r--r--usr/src/uts/common/os/modconf.c47
-rw-r--r--usr/src/uts/common/os/modctl.c164
-rw-r--r--usr/src/uts/common/os/vfs_conf.c8
5 files changed, 601 insertions, 133 deletions
diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c
index d78dacc1fe..9a2b6b745f 100644
--- a/usr/src/uts/common/os/devcfg.c
+++ b/usr/src/uts/common/os/devcfg.c
@@ -49,6 +49,7 @@
#include <sys/strsubr.h>
#include <sys/fs/snode.h>
#include <sys/fs/dv_node.h>
+#include <sys/reboot.h>
#ifdef DEBUG
int ddidebug = DDI_AUDIT;
@@ -111,6 +112,13 @@ dev_info_t *clone_dip;
dev_info_t *scsi_vhci_dip; /* MPXIO dip */
major_t clone_major;
+/*
+ * A non-global zone's /dev is derived from the device tree.
+ * This generation number serves to indicate when a zone's
+ * /dev may need to be updated.
+ */
+volatile ulong_t devtree_gen; /* generation number */
+
/* block all future dev_info state changes */
static hrtime_t volatile devinfo_freeze = 0;
@@ -119,6 +127,9 @@ static ulong_t devinfo_attach_detach = 0;
extern kmutex_t global_vhci_lock;
+/* bitset of DS_SYSAVAIL & DS_RECONFIG - no races, no lock */
+static int devname_state = 0;
+
/*
* The devinfo snapshot cache and related variables.
* The only field in the di_cache structure that needs initialization
@@ -3000,8 +3011,8 @@ i_ddi_forceattach_drivers()
* I/O subsystem initialization is considered complete when devfsadm
* is executed.
*
- * NOTE: The start of syseventd in S60devfsadm happen to be convenient
- * indicator for the completion of I/O initialization during boot.
+ * NOTE: The start of syseventd happens to be a convenient indicator
+ * of the completion of I/O initialization during boot.
* The implementation should be replaced by something more robust.
*/
int
@@ -3011,6 +3022,55 @@ i_ddi_io_initialized()
return (sysevent_daemon_init);
}
+/*
+ * May be used to determine system boot state
+ * "Available" means the system is for the most part up
+ * and initialized, with all system services either up or
+ * capable of being started. This state is set by devfsadm
+ * during the boot process. The /dev filesystem infers
+ * from this when implicit reconfig can be performed,
+ * ie, devfsadm can be invoked. Please avoid making
+ * further use of this unless it's really necessary.
+ */
+int
+i_ddi_sysavail()
+{
+ return (devname_state & DS_SYSAVAIL);
+}
+
+/*
+ * May be used to determine if boot is a reconfigure boot.
+ */
+int
+i_ddi_reconfig()
+{
+ return (devname_state & DS_RECONFIG);
+}
+
+/*
+ * Note system services are up, inform /dev.
+ */
+void
+i_ddi_set_sysavail()
+{
+ if ((devname_state & DS_SYSAVAIL) == 0) {
+ devname_state |= DS_SYSAVAIL;
+ sdev_devstate_change();
+ }
+}
+
+/*
+ * Note reconfiguration boot, inform /dev.
+ */
+void
+i_ddi_set_reconfig()
+{
+ if ((devname_state & DS_RECONFIG) == 0) {
+ devname_state |= DS_RECONFIG;
+ sdev_devstate_change();
+ }
+}
+
/*
* device tree walking
@@ -6757,9 +6817,11 @@ i_ddi_di_cache_invalidate(int kmflag)
}
/*
- * Invalidate the in-core cache
+ * Invalidate the in-core cache and
+ * increment devtree generation number
*/
atomic_and_32(&di_cache.cache_valid, 0);
+ atomic_inc_ulong(&devtree_gen);
flag = (kmflag == KM_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
diff --git a/usr/src/uts/common/os/devctl.c b/usr/src/uts/common/os/devctl.c
index 57a7c05ac8..90354cde34 100644
--- a/usr/src/uts/common/os/devctl.c
+++ b/usr/src/uts/common/os/devctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -51,7 +50,6 @@
#include <sys/fs/snode.h>
#include <sys/fs/dv_node.h>
#include <sys/kobj.h>
-
#include <sys/devctl_impl.h>
@@ -65,6 +63,8 @@ int devid_discovery_secs = 0;
int devid_cache_read_disable = 0;
int devid_cache_write_disable = 0;
+int sdev_cache_read_disable = 0;
+int sdev_cache_write_disable = 0;
int kfio_report_error = 0; /* kernel file i/o operations */
int devid_report_error = 0; /* devid cache operations */
@@ -78,13 +78,46 @@ static kmutex_t devid_discovery_mutex;
static kcondvar_t devid_discovery_cv;
static clock_t devid_last_discovery = 0;
+
+static int devid_nvp2nvl(nvfd_t *, nvlist_t **);
+static nvp_list_t *devid_nvl2nvp(nvlist_t *, char *);
+static void devid_nvp_free(nvp_list_t *);
+
+static int sdev_nvp2nvl(nvfd_t *, nvlist_t **);
+static nvp_list_t *sdev_nvl2nvp(nvlist_t *, char *);
+static void sdev_nvp_free(nvp_list_t *);
+
/*
- * Descriptor for /etc/devices/devid_cache
+ * Descriptors for the /etc/devices cache files
*/
-nvfd_t devid_cache_fd = {
+static nvfd_t devid_cache_fd = {
"/etc/devices/devid_cache",
+ devid_nvp2nvl, /* nvf_nvp2nvl */
+ devid_nvl2nvp, /* nvf_nvl2nvp */
+ devid_nvp_free, /* nvf_nvp_free */
+ NULL, /* nvf_write_complete */
+ 0, NULL, NULL, 0
+
};
-static nvfd_t *dcfd = &devid_cache_fd;
+static nvfd_t sdev_cache_fd = {
+ "/etc/devices/devname_cache",
+ sdev_nvp2nvl, /* nvf_nvp2nvl */
+ sdev_nvl2nvp, /* nvf_nvl2nvp */
+ sdev_nvp_free, /* nvf_nvp_free */
+ NULL, /* nvf_write_complete */
+ 0, NULL, NULL, 0
+};
+
+static nvfd_t *dcfd = &devid_cache_fd;
+nvfd_t *sdevfd = &sdev_cache_fd;
+
+static nvfd_t *cachefds[] = {
+ &devid_cache_fd,
+ &sdev_cache_fd
+};
+
+#define NCACHEFDS ((sizeof (cachefds)) / (sizeof (nvfd_t *)))
+
extern int modrootloaded;
@@ -122,6 +155,11 @@ i_ddi_devices_init(void)
dcfd->nvf_tail = NULL;
rw_init(&dcfd->nvf_lock, NULL, RW_DRIVER, NULL);
+ sdevfd->nvf_flags = 0;
+ sdevfd->nvf_list = NULL;
+ sdevfd->nvf_tail = NULL;
+ rw_init(&sdevfd->nvf_lock, NULL, RW_DRIVER, NULL);
+
mutex_init(&devid_discovery_mutex, NULL, MUTEX_DEFAULT, NULL);
cv_init(&devid_discovery_cv, NULL, CV_DRIVER, NULL);
}
@@ -546,44 +584,63 @@ e_fwrite_nvlist(nvfd_t *nvfd, nvlist_t *nvl)
}
static void
-nvp_free(nvp_list_t *np)
+devid_nvp_free(nvp_list_t *np)
+{
+ nvp_devid_t *dp = NVP2DEVID(np);
+
+ if (dp->nvp_devpath)
+ kmem_free(dp->nvp_devpath, strlen(dp->nvp_devpath)+1);
+ if (dp->nvp_devid)
+ kmem_free(dp->nvp_devid, ddi_devid_sizeof(dp->nvp_devid));
+
+ kmem_free(dp, sizeof (nvp_devid_t));
+}
+
+static void
+sdev_nvp_free(nvp_list_t *np)
{
- if (np->nvp_devpath)
- kmem_free(np->nvp_devpath, strlen(np->nvp_devpath)+1);
- if (np->nvp_devid)
- kmem_free(np->nvp_devid, ddi_devid_sizeof(np->nvp_devid));
+ nvp_devname_t *dp = NVP2DEVNAME(np);
+ int i;
+ char **p;
+
+ if (dp->nvp_npaths > 0) {
+ p = dp->nvp_paths;
+ for (i = 0; i < dp->nvp_npaths; i++, p++) {
+ kmem_free(*p, strlen(*p)+1);
+ }
+ kmem_free(dp->nvp_paths,
+ dp->nvp_npaths * sizeof (char *));
+ kmem_free(dp->nvp_expirecnts,
+ dp->nvp_npaths * sizeof (int));
+ }
- kmem_free(np, sizeof (nvp_list_t));
+ kmem_free(dp, sizeof (nvp_devname_t));
}
static void
-nvp_list_free(nvp_list_t *nvp)
+nvp_list_free(nvfd_t *nvf, nvp_list_t *nvp)
{
nvp_list_t *np;
nvp_list_t *next;
for (np = nvp; np; np = next) {
next = np->nvp_next;
- nvp_free(np);
+ (nvf->nvf_nvp_free)(np);
}
}
+
/*
- * Free the devid-related information in an nvp element
- * If no more data is stored in the nvp element, free
- * it and unlink it from the list
- *
- * Since at present there is no further use of nvp's,
- * there's nothing to check.
+ * Free an nvp element in a list
*/
-static nvp_list_t *
-nfd_devid_free_and_unlink(nvfd_t *nvf, nvp_list_t *np)
+void
+nfd_nvp_free_and_unlink(nvfd_t *nvf, nvp_list_t *np)
{
nvp_list_t *pv, *next;
pv = np->nvp_prev;
next = np->nvp_next;
- nvp_free(np);
+ (nvf->nvf_nvp_free)(np);
/* remove element at head */
if (pv == NULL) {
@@ -602,12 +659,10 @@ nfd_devid_free_and_unlink(nvfd_t *nvf, nvp_list_t *np)
pv->nvp_next = next;
next->nvp_prev = pv;
}
-
- return (next);
}
-static void
-nfd_devid_link(nvfd_t *nvf, nvp_list_t *np)
+void
+nfd_nvp_link(nvfd_t *nvf, nvp_list_t *np)
{
if (nvf->nvf_list == NULL) {
nvf->nvf_list = np;
@@ -622,16 +677,17 @@ nfd_devid_link(nvfd_t *nvf, nvp_list_t *np)
/*
* Convert a device path/nvlist pair to an nvp_list_t
* Used to parse the nvlist format when reading
+ * /etc/devices/devid_cache
*/
static nvp_list_t *
-nvlist_to_nvp(nvlist_t *nvl, char *name)
+devid_nvl2nvp(nvlist_t *nvl, char *name)
{
- nvp_list_t *np;
+ nvp_devid_t *np;
ddi_devid_t devidp;
int rval;
uint_t n;
- np = kmem_zalloc(sizeof (nvp_list_t), KM_SLEEP);
+ np = kmem_zalloc(sizeof (nvp_devid_t), KM_SLEEP);
np->nvp_devpath = i_ddi_strdup(name, KM_SLEEP);
NVP_DEVID_DEBUG_PATH((np->nvp_devpath));
@@ -654,18 +710,70 @@ nvlist_to_nvp(nvlist_t *nvl, char *name)
}
}
- return (np);
+ return (NVPLIST(np));
}
/*
+ * Convert a device path/nvlist pair to an nvp_list_t
+ * Used to parse the nvlist format when reading
+ * /etc/devices/devname_cache
+ */
+static nvp_list_t *
+sdev_nvl2nvp(nvlist_t *nvl, char *name)
+{
+ nvp_devname_t *np;
+ char **strs;
+ int *cnts;
+ uint_t nstrs, ncnts;
+ int rval, i;
+
+ /* name of the sublist must match what we created */
+ if (strcmp(name, DP_DEVNAME_ID) != 0) {
+ return (NULL);
+ }
+
+ np = kmem_zalloc(sizeof (nvp_devname_t), KM_SLEEP);
+
+ rval = nvlist_lookup_string_array(nvl,
+ DP_DEVNAME_NCACHE_ID, &strs, &nstrs);
+ if (rval) {
+ kmem_free(np, sizeof (nvp_devname_t));
+ return (NULL);
+ }
+
+ np->nvp_npaths = nstrs;
+ np->nvp_paths = kmem_zalloc(nstrs * sizeof (char *), KM_SLEEP);
+ for (i = 0; i < nstrs; i++) {
+ np->nvp_paths[i] = i_ddi_strdup(strs[i], KM_SLEEP);
+ }
+ np->nvp_expirecnts = kmem_zalloc(nstrs * sizeof (int), KM_SLEEP);
+ for (i = 0; i < nstrs; i++) {
+ np->nvp_expirecnts[i] = 4; /* XXX sdev_nc_expirecnt */
+ }
+
+ rval = nvlist_lookup_int32_array(nvl,
+ DP_DEVNAME_NC_EXPIRECNT_ID, &cnts, &ncnts);
+ if (rval == 0) {
+ ASSERT(ncnts == nstrs);
+ ncnts = max(ncnts, nstrs);
+ for (i = 0; i < nstrs; i++) {
+ np->nvp_expirecnts[i] = cnts[i];
+ }
+ }
+
+ return (NVPLIST(np));
+}
+
+
+/*
* Convert a list of nvp_list_t's to a single nvlist
- * Used when writing the nvlist file
+ * Used when writing the nvlist file.
*/
static int
-nvp_to_nvlist(nvfd_t *nvfd, nvlist_t **ret_nvl)
+devid_nvp2nvl(nvfd_t *nvfd, nvlist_t **ret_nvl)
{
nvlist_t *nvl, *sub_nvl;
- nvp_list_t *np;
+ nvp_devid_t *np;
int rval;
ASSERT(modrootloaded);
@@ -677,7 +785,7 @@ nvp_to_nvlist(nvfd_t *nvfd, nvlist_t **ret_nvl)
return (DDI_FAILURE);
}
- for (np = nvfd->nvf_list; np; np = np->nvp_next) {
+ for (np = NVF_DEVID_LIST(nvfd); np; np = NVP_DEVID_NEXT(np)) {
if (np->nvp_devid == NULL)
continue;
NVP_DEVID_DEBUG_PATH(np->nvp_devpath);
@@ -689,18 +797,16 @@ nvp_to_nvlist(nvfd_t *nvfd, nvlist_t **ret_nvl)
goto err;
}
- if (np->nvp_devid) {
- rval = nvlist_add_byte_array(sub_nvl, DP_DEVID_ID,
- (uchar_t *)np->nvp_devid,
- ddi_devid_sizeof(np->nvp_devid));
- if (rval == 0) {
- NVP_DEVID_DEBUG_DEVID(np->nvp_devid);
- } else {
- KFIOERR((CE_CONT,
- "%s: nvlist add error %d (devid)\n",
- nvfd->nvf_name, rval));
- goto err;
- }
+ rval = nvlist_add_byte_array(sub_nvl, DP_DEVID_ID,
+ (uchar_t *)np->nvp_devid,
+ ddi_devid_sizeof(np->nvp_devid));
+ if (rval == 0) {
+ NVP_DEVID_DEBUG_DEVID(np->nvp_devid);
+ } else {
+ KFIOERR((CE_CONT,
+ "%s: nvlist add error %d (devid)\n",
+ nvfd->nvf_name, rval));
+ goto err;
}
rval = nvlist_add_nvlist(nvl, np->nvp_devpath, sub_nvl);
@@ -723,6 +829,76 @@ err:
return (DDI_FAILURE);
}
+/*
+ * Convert a list of nvp_list_t's to a single nvlist
+ * Used when writing the nvlist file.
+ */
+static int
+sdev_nvp2nvl(nvfd_t *nvfd, nvlist_t **ret_nvl)
+{
+ nvlist_t *nvl, *sub_nvl;
+ nvp_devname_t *np;
+ int rval;
+
+ ASSERT(modrootloaded);
+
+ rval = nvlist_alloc(&nvl, NV_UNIQUE_NAME, KM_SLEEP);
+ if (rval != 0) {
+ KFIOERR((CE_CONT, "%s: nvlist alloc error %d\n",
+ nvfd->nvf_name, rval));
+ return (DDI_FAILURE);
+ }
+
+ if ((np = NVF_DEVNAME_LIST(nvfd)) != NULL) {
+ ASSERT(NVP_DEVNAME_NEXT(np) == NULL);
+
+ rval = nvlist_alloc(&sub_nvl, NV_UNIQUE_NAME, KM_SLEEP);
+ if (rval != 0) {
+ KFIOERR((CE_CONT, "%s: nvlist alloc error %d\n",
+ nvfd->nvf_name, rval));
+ sub_nvl = NULL;
+ goto err;
+ }
+
+ rval = nvlist_add_string_array(sub_nvl,
+ DP_DEVNAME_NCACHE_ID, np->nvp_paths, np->nvp_npaths);
+ if (rval != 0) {
+ KFIOERR((CE_CONT,
+ "%s: nvlist add error %d (sdev)\n",
+ nvfd->nvf_name, rval));
+ goto err;
+ }
+
+ rval = nvlist_add_int32_array(sub_nvl,
+ DP_DEVNAME_NC_EXPIRECNT_ID,
+ np->nvp_expirecnts, np->nvp_npaths);
+ if (rval != 0) {
+ KFIOERR((CE_CONT,
+ "%s: nvlist add error %d (sdev)\n",
+ nvfd->nvf_name, rval));
+ goto err;
+ }
+
+ rval = nvlist_add_nvlist(nvl, DP_DEVNAME_ID, sub_nvl);
+ if (rval != 0) {
+ KFIOERR((CE_CONT, "%s: nvlist add error %d (sublist)\n",
+ nvfd->nvf_name, rval));
+ goto err;
+ }
+ nvlist_free(sub_nvl);
+ }
+
+ *ret_nvl = nvl;
+ return (DDI_SUCCESS);
+
+err:
+ if (sub_nvl)
+ nvlist_free(sub_nvl);
+ nvlist_free(nvl);
+ *ret_nvl = NULL;
+ return (DDI_FAILURE);
+}
+
/*
* Read a file in the nvlist format
@@ -769,17 +945,18 @@ fread_nvp_list(nvfd_t *nvfd)
* convert nvlist for this device to
* an nvp_list_t struct
*/
- np = nvlist_to_nvp(sublist, name);
- np->nvp_next = NULL;
- np->nvp_prev = nvp_tail;
+ np = (nvfd->nvf_nvl2nvp)(sublist, name);
+ if (np) {
+ np->nvp_next = NULL;
+ np->nvp_prev = nvp_tail;
- if (nvp_list == NULL) {
- nvp_list = np;
- } else {
- nvp_tail->nvp_next = np;
+ if (nvp_list == NULL) {
+ nvp_list = np;
+ } else {
+ nvp_tail->nvp_next = np;
+ }
+ nvp_tail = np;
}
- nvp_tail = np;
-
break;
default:
@@ -800,7 +977,7 @@ fread_nvp_list(nvfd_t *nvfd)
error:
nvlist_free(nvl);
if (nvp_list)
- nvp_list_free(nvp_list);
+ nvp_list_free(nvfd, nvp_list);
return (rval);
}
@@ -810,7 +987,7 @@ i_ddi_read_one_nvfile(nvfd_t *nvfd)
{
int rval;
- KFDEBUG((CE_CONT, "Reading %s\n", nvfd->nvf_name));
+ KFDEBUG((CE_CONT, "reading %s\n", nvfd->nvf_name));
rval = fread_nvp_list(nvfd);
if (rval) {
@@ -836,39 +1013,26 @@ i_ddi_read_one_nvfile(nvfd_t *nvfd)
return (rval);
}
+/* for information possibly required to mount root */
void
i_ddi_read_devices_files(void)
{
- nvfd_t nvfd;
- int rval;
-
mdi_read_devices_files();
- if (devid_cache_read_disable)
- return;
-
- nvfd.nvf_name = dcfd->nvf_name;
- nvfd.nvf_flags = 0;
- nvfd.nvf_list = NULL;
- nvfd.nvf_tail = NULL;
- rw_init(&nvfd.nvf_lock, NULL, RW_DRIVER, NULL);
-
- rval = i_ddi_read_one_nvfile(&nvfd);
-
- rw_enter(&dcfd->nvf_lock, RW_WRITER);
-
- if (rval == 0) {
- if (dcfd->nvf_list != NULL) {
- nvp_list_free(dcfd->nvf_list);
- }
- dcfd->nvf_list = nvfd.nvf_list;
- dcfd->nvf_tail = nvfd.nvf_tail;
+ if (devid_cache_read_disable == 0) {
+ ASSERT(dcfd->nvf_list == NULL);
+ (void) i_ddi_read_one_nvfile(dcfd);
}
- dcfd->nvf_flags = nvfd.nvf_flags;
-
- rw_exit(&dcfd->nvf_lock);
+}
- rw_destroy(&nvfd.nvf_lock);
+/* may be done after root is mounted */
+void
+i_ddi_read_devname_file(void)
+{
+ if (sdev_cache_read_disable == 0) {
+ ASSERT(sdevfd->nvf_list == NULL);
+ (void) i_ddi_read_one_nvfile(sdevfd);
+ }
}
static int
@@ -1003,8 +1167,8 @@ e_ddi_devid_discovery(ddi_devid_t devid)
int
e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
{
- nvp_list_t *np;
- nvp_list_t *new_nvp;
+ nvp_devid_t *np;
+ nvp_devid_t *new_nvp;
ddi_devid_t new_devid;
int new_devid_size;
char *path, *fullpath;
@@ -1022,14 +1186,14 @@ e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
DEVID_LOG_REG(("register", devid, path));
- new_nvp = kmem_zalloc(sizeof (nvp_list_t), KM_SLEEP);
+ new_nvp = kmem_zalloc(sizeof (nvp_devid_t), KM_SLEEP);
new_devid_size = ddi_devid_sizeof(devid);
new_devid = kmem_alloc(new_devid_size, KM_SLEEP);
(void) bcopy(devid, new_devid, new_devid_size);
rw_enter(&dcfd->nvf_lock, RW_WRITER);
- for (np = dcfd->nvf_list; np != NULL; np = np->nvp_next) {
+ for (np = NVF_DEVID_LIST(dcfd); np; np = NVP_DEVID_NEXT(np)) {
if (strcmp(path, np->nvp_devpath) == 0) {
DEVID_DEBUG2((CE_CONT,
"register: %s path match\n", path));
@@ -1041,7 +1205,7 @@ e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
np->nvp_dip = dip;
NVF_MARK_DIRTY(dcfd);
rw_exit(&dcfd->nvf_lock);
- kmem_free(new_nvp, sizeof (nvp_list_t));
+ kmem_free(new_nvp, sizeof (nvp_devid_t));
kmem_free(path, pathlen);
goto exit;
}
@@ -1063,8 +1227,7 @@ e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
* may map to multiple paths but one path
* should only map to one devid.
*/
- (void) nfd_devid_free_and_unlink(
- dcfd, np);
+ nfd_nvp_free_and_unlink(dcfd, NVPLIST(np));
np = NULL;
break;
} else {
@@ -1074,7 +1237,7 @@ e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
NVP_DEVID_DIP | NVP_DEVID_REGISTERED;
np->nvp_dip = dip;
rw_exit(&dcfd->nvf_lock);
- kmem_free(new_nvp, sizeof (nvp_list_t));
+ kmem_free(new_nvp, sizeof (nvp_devid_t));
kmem_free(path, pathlen);
kmem_free(new_devid, new_devid_size);
return (DDI_SUCCESS);
@@ -1093,7 +1256,7 @@ e_devid_cache_register(dev_info_t *dip, ddi_devid_t devid)
new_nvp->nvp_devid = new_devid;
NVF_MARK_DIRTY(dcfd);
- nfd_devid_link(dcfd, new_nvp);
+ nfd_nvp_link(dcfd, NVPLIST(new_nvp));
rw_exit(&dcfd->nvf_lock);
@@ -1101,7 +1264,8 @@ exit:
if (free_devid)
kmem_free(free_devid, ddi_devid_sizeof(free_devid));
- wake_nvpflush_daemon(dcfd);
+ if (!devid_cache_write_disable)
+ wake_nvpflush_daemon();
return (DDI_SUCCESS);
}
@@ -1115,11 +1279,11 @@ exit:
void
e_devid_cache_unregister(dev_info_t *dip)
{
- nvp_list_t *np;
+ nvp_devid_t *np;
rw_enter(&dcfd->nvf_lock, RW_WRITER);
- for (np = dcfd->nvf_list; np != NULL; np = np->nvp_next) {
+ for (np = NVF_DEVID_LIST(dcfd); np; np = NVP_DEVID_NEXT(np)) {
if (np->nvp_devid == NULL)
continue;
if ((np->nvp_flags & NVP_DEVID_DIP) && np->nvp_dip == dip) {
@@ -1138,26 +1302,26 @@ e_devid_cache_unregister(dev_info_t *dip)
void
e_devid_cache_cleanup(void)
{
- nvp_list_t *np, *next;
+ nvp_devid_t *np, *next;
rw_enter(&dcfd->nvf_lock, RW_WRITER);
- for (np = dcfd->nvf_list; np != NULL; np = next) {
- next = np->nvp_next;
+ for (np = NVF_DEVID_LIST(dcfd); np; np = next) {
+ next = NVP_DEVID_NEXT(np);
if (np->nvp_devid == NULL)
continue;
if ((np->nvp_flags & NVP_DEVID_REGISTERED) == 0) {
DEVID_LOG_REMOVE((CE_CONT,
"cleanup: %s\n", np->nvp_devpath));
NVF_MARK_DIRTY(dcfd);
- next = nfd_devid_free_and_unlink(dcfd, np);
+ nfd_nvp_free_and_unlink(dcfd, NVPLIST(np));
}
}
rw_exit(&dcfd->nvf_lock);
if (NVF_IS_DIRTY(dcfd))
- wake_nvpflush_daemon(dcfd);
+ wake_nvpflush_daemon();
}
@@ -1229,7 +1393,7 @@ static int
e_devid_cache_devi_path_lists(ddi_devid_t devid, int retmax,
int *retndevis, dev_info_t **retdevis, int *retnpaths, char **retpaths)
{
- nvp_list_t *np;
+ nvp_devid_t *np;
int ndevis, npaths;
dev_info_t *dip, *pdip;
int circ;
@@ -1238,7 +1402,7 @@ e_devid_cache_devi_path_lists(ddi_devid_t devid, int retmax,
ndevis = 0;
npaths = 0;
- for (np = dcfd->nvf_list; np != NULL; np = np->nvp_next) {
+ for (np = NVF_DEVID_LIST(dcfd); np; np = NVP_DEVID_NEXT(np)) {
if (np->nvp_devid == NULL)
continue;
if (ddi_devid_valid(np->nvp_devid) != DDI_SUCCESS) {
@@ -1514,6 +1678,25 @@ static clock_t nvpticks;
static void nvpflush_daemon(void);
+void
+nvf_register_write_complete(nvfd_t *fd, void (*f)(nvfd_t *))
+{
+ fd->nvf_write_complete = f;
+}
+
+void
+nvf_unregister_write_complete(nvfd_t *fd)
+{
+ fd->nvf_write_complete = NULL;
+}
+
+static void
+nvf_write_complete(nvfd_t *fd)
+{
+ if (fd->nvf_write_complete) {
+ (*(fd->nvf_write_complete))(fd);
+ }
+}
void
i_ddi_start_flush_daemon(void)
@@ -1523,8 +1706,9 @@ i_ddi_start_flush_daemon(void)
mutex_init(&nvpflush_lock, NULL, MUTEX_DRIVER, NULL);
cv_init(&nvpflush_cv, NULL, CV_DRIVER, NULL);
- if (NVF_IS_DIRTY(dcfd)) {
- wake_nvpflush_daemon(dcfd);
+ if ((NVF_IS_DIRTY(dcfd) && !devid_cache_write_disable) ||
+ (NVF_IS_DIRTY(sdevfd) && !sdevfd && sdev_cache_write_disable)) {
+ wake_nvpflush_daemon();
}
}
@@ -1542,6 +1726,7 @@ nvpflush_timeout(void *arg)
nvpflush_id = timeout(nvpflush_timeout, NULL, nticks);
} else {
do_nvpflush = 1;
+ NVPDAEMON_DEBUG((CE_CONT, "signal nvpdaemon\n"));
cv_signal(&nvpflush_cv);
nvpflush_id = 0;
nvpflush_timer_busy = 0;
@@ -1549,17 +1734,16 @@ nvpflush_timeout(void *arg)
}
}
-static void
-wake_nvpflush_daemon(nvfd_t *nvfp)
+void
+wake_nvpflush_daemon()
{
clock_t nticks;
/*
- * If root is readonly or the system isn't up yet
+ * If the system isn't up yet
* don't even think about starting a flush.
*/
- if (devid_cache_write_disable ||
- !i_ddi_io_initialized() || NVF_IS_READONLY(nvfp))
+ if (!i_ddi_io_initialized())
return;
mutex_enter(&nvpflush_lock);
@@ -1603,7 +1787,7 @@ nvpflush_one(nvfd_t *nvfd)
rw_exit(&nvfd->nvf_lock);
return (DDI_FAILURE);
}
- if (nvp_to_nvlist(nvfd, &nvl) != DDI_SUCCESS) {
+ if (((nvfd->nvf_nvp2nvl)(nvfd, &nvl)) != DDI_SUCCESS) {
KFIOERR((CE_CONT, "nvpflush: "
"%s nvlist construction failed\n", nvfd->nvf_name));
rw_exit(&nvfd->nvf_lock);
@@ -1654,12 +1838,14 @@ nvpflush_one(nvfd_t *nvfd)
return (rval);
}
+
static void
nvpflush_daemon(void)
{
callb_cpr_t cprinfo;
clock_t clk;
int rval;
+ int i;
ASSERT(modrootloaded);
@@ -1701,21 +1887,40 @@ nvpflush_daemon(void)
* Try flushing what's dirty, reschedule if there's
* a failure or data gets marked as dirty again.
*/
- NVPDAEMON_DEBUG((CE_CONT, "nvpdaemon: flush\n"));
- rval = nvpflush_one(dcfd);
+ for (i = 0; i < NCACHEFDS; i++) {
+ rw_enter(&cachefds[i]->nvf_lock, RW_READER);
+ if (NVF_IS_DIRTY(cachefds[i])) {
+ NVPDAEMON_DEBUG((CE_CONT,
+ "nvpdaemon: flush %s\n",
+ cachefds[i]->nvf_name));
+ rw_exit(&cachefds[i]->nvf_lock);
+ rval = nvpflush_one(cachefds[i]);
+ rw_enter(&cachefds[i]->nvf_lock, RW_READER);
+ if (rval != DDI_SUCCESS ||
+ NVF_IS_DIRTY(cachefds[i])) {
+ rw_exit(&cachefds[i]->nvf_lock);
+ NVPDAEMON_DEBUG((CE_CONT,
+ "nvpdaemon: %s dirty again\n",
+ cachefds[i]->nvf_name));
+ wake_nvpflush_daemon();
+ } else {
+ rw_exit(&cachefds[i]->nvf_lock);
+ nvf_write_complete(cachefds[i]);
+ }
+ } else {
+ NVPDAEMON_DEBUG((CE_CONT,
+ "nvpdaemon: not dirty %s\n",
+ cachefds[i]->nvf_name));
+ rw_exit(&cachefds[i]->nvf_lock);
+ }
+ }
- rw_enter(&dcfd->nvf_lock, RW_READER);
- if (rval != DDI_SUCCESS || NVF_IS_DIRTY(dcfd)) {
- rw_exit(&dcfd->nvf_lock);
- NVPDAEMON_DEBUG((CE_CONT, "nvpdaemon: dirty again\n"));
- wake_nvpflush_daemon(dcfd);
- } else
- rw_exit(&dcfd->nvf_lock);
mutex_enter(&nvpflush_lock);
nvpbusy = 0;
}
}
+
void
i_ddi_clean_devices_files(void)
{
diff --git a/usr/src/uts/common/os/modconf.c b/usr/src/uts/common/os/modconf.c
index 35eb1c6825..2992567207 100644
--- a/usr/src/uts/common/os/modconf.c
+++ b/usr/src/uts/common/os/modconf.c
@@ -57,6 +57,7 @@
#include <sys/kcpc.h>
#include <sys/cpc_pcbe.h>
#include <sys/kstat.h>
+#include <sys/fs/sdev_node.h>
extern int moddebug;
@@ -216,6 +217,17 @@ struct mod_ops mod_dacfops = {
};
/*
+ * /dev fs modules
+ */
+static int mod_infodev(struct modldev *, struct modlinkage *, int *);
+static int mod_installdev(struct modldev *, struct modlinkage *);
+static int mod_removedev(struct modldev *, struct modlinkage *);
+
+struct mod_ops mod_devfsops = {
+ mod_installdev, mod_removedev, mod_infodev
+};
+
+/*
* PCBE (Performance Counter BackEnd) modules.
*/
static int mod_installpcbe(struct modlpcbe *, struct modlinkage *);
@@ -483,6 +495,41 @@ mod_removepcbe(struct modlpcbe *modl, struct modlinkage *modlp)
return (EBUSY);
}
+/*
+ * manage /dev fs modules
+ */
+/*ARGSUSED*/
+static int
+mod_infodev(struct modldev *modl, struct modlinkage *modlp, int *p0)
+{
+ if (mod_getctl(modlp) == NULL) {
+ *p0 = -1;
+ return (0); /* module is not yet installed */
+ }
+
+ *p0 = 0;
+ return (0);
+}
+
+static int
+mod_installdev(struct modldev *modl, struct modlinkage *modlp)
+{
+ struct modctl *mcp;
+
+ if ((mcp = mod_getctl(modlp)) == NULL)
+ return (EINVAL);
+ return (sdev_module_register(mcp->mod_modname, modl->dev_ops));
+}
+
+/*
+ * /dev modules are not unloadable.
+ */
+/*ARGSUSED*/
+static int
+mod_removedev(struct modldev *modl, struct modlinkage *modlp)
+{
+ return (EBUSY);
+}
/*
* Install a new driver
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index e776a36310..3509231ee2 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -79,6 +78,7 @@
#include <ipp/ipp_impl.h>
#include <sys/fs/dv_node.h>
#include <sys/strsubr.h>
+#include <sys/fs/sdev_node.h>
static int mod_circdep(struct modctl *);
static int modinfo(modid_t, struct modinfo *);
@@ -679,7 +679,8 @@ new_vfs_in_modpath()
return (1); /* always reread driver.conf the first time */
}
-static int modctl_load_drvconf(major_t major)
+static int
+modctl_load_drvconf(major_t major)
{
int ret;
@@ -785,6 +786,8 @@ modctl_getmaj(char *uname, uint_t ulen, int *umajorp)
int retval;
major_t major;
+ if (ulen == 0)
+ return (EINVAL);
if ((retval = copyinstr(uname, name,
(ulen < 256) ? ulen : 256, 0)) != 0)
return (retval);
@@ -1640,6 +1643,144 @@ modctl_allocpriv(const char *name)
return (error);
}
+static int
+modctl_devexists(const char *upath, int pathlen)
+{
+ char *path;
+ int ret;
+
+ /*
+ * copy in the path, including the terminating null
+ */
+ pathlen++;
+ if (pathlen <= 1 || pathlen > MAXPATHLEN)
+ return (EINVAL);
+ path = kmem_zalloc(pathlen + 1, KM_SLEEP);
+ if ((ret = copyinstr(upath, path, pathlen, NULL)) == 0) {
+ ret = sdev_modctl_devexists(path);
+ }
+
+ kmem_free(path, pathlen + 1);
+ return (ret);
+}
+
+static int
+modctl_devreaddir(const char *udir, int udirlen,
+ char *upaths, int64_t *ulensp)
+{
+ char *paths = NULL;
+ char **dirlist = NULL;
+ char *dir;
+ int64_t ulens;
+ int64_t lens;
+ int i, n;
+ int ret = 0;
+ char *p;
+ int npaths;
+ int npaths_alloc;
+
+ /*
+ * If upaths is NULL then we are only computing the amount of space
+ * needed to return the paths, with the value returned in *ulensp. If we
+ * are copying out paths then we get the amount of space allocated by
+ * the caller. If the actual space needed for paths is larger, or
+ * things are changing out from under us, then we return EAGAIN.
+ */
+ if (upaths) {
+ if (ulensp == NULL)
+ return (EINVAL);
+ if (copyin(ulensp, &ulens, sizeof (ulens)) != 0)
+ return (EFAULT);
+ }
+
+ /*
+ * copyin the /dev path including terminating null
+ */
+ udirlen++;
+ if (udirlen <= 1 || udirlen > MAXPATHLEN)
+ return (EINVAL);
+ dir = kmem_zalloc(udirlen + 1, KM_SLEEP);
+ if ((ret = copyinstr(udir, dir, udirlen, NULL)) != 0)
+ goto err;
+
+ if ((ret = sdev_modctl_readdir(dir, &dirlist,
+ &npaths, &npaths_alloc)) != 0) {
+ ASSERT(dirlist == NULL);
+ goto err;
+ }
+
+ lens = 0;
+ for (i = 0; i < npaths; i++) {
+ lens += strlen(dirlist[i]) + 1;
+ }
+ lens++; /* add one for double termination */
+
+ if (upaths) {
+ if (lens > ulens) {
+ ret = EAGAIN;
+ goto out;
+ }
+
+ paths = kmem_alloc(lens, KM_SLEEP);
+
+ p = paths;
+ for (i = 0; i < npaths; i++) {
+ n = strlen(dirlist[i]) + 1;
+ bcopy(dirlist[i], p, n);
+ p += n;
+ }
+ *p = 0;
+
+ if (copyout(paths, upaths, lens)) {
+ ret = EFAULT;
+ goto err;
+ }
+ }
+
+out:
+ /* copy out the amount of space needed to hold the paths */
+ if (copyout(&lens, ulensp, sizeof (lens)))
+ ret = EFAULT;
+
+err:
+ if (dirlist)
+ sdev_modctl_readdir_free(dirlist, npaths, npaths_alloc);
+ if (paths)
+ kmem_free(paths, lens);
+ kmem_free(dir, udirlen + 1);
+ return (ret);
+}
+
+int
+modctl_moddevname(int subcmd, uintptr_t a1, uintptr_t a2)
+{
+ int error = 0;
+
+ switch (subcmd) {
+ case MODDEVNAME_LOOKUPDOOR:
+ case MODDEVNAME_DEVFSADMNODE:
+ error = devname_filename_register(subcmd, (char *)a1);
+ break;
+ case MODDEVNAME_NSMAPS:
+ error = devname_nsmaps_register((char *)a1, (size_t)a2);
+ break;
+ case MODDEVNAME_PROFILE:
+ error = devname_profile_update((char *)a1, (size_t)a2);
+ break;
+ case MODDEVNAME_RECONFIG:
+ i_ddi_set_reconfig();
+ break;
+ case MODDEVNAME_SYSAVAIL:
+ i_ddi_set_sysavail();
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
+
/*ARGSUSED5*/
int
modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
@@ -1845,6 +1986,19 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
error = modctl_remdrv_cleanup((const char *)a1);
break;
+ case MODDEVEXISTS: /* non-reconfiguring /dev lookup */
+ error = modctl_devexists((const char *)a1, (size_t)a2);
+ break;
+
+ case MODDEVREADDIR: /* non-reconfiguring /dev readdir */
+ error = modctl_devreaddir((const char *)a1, (size_t)a2,
+ (char *)a3, (int64_t *)a4);
+ break;
+
+ case MODDEVNAME:
+ error = modctl_moddevname((int)a1, a2, a3);
+ break;
+
default:
error = EINVAL;
break;
@@ -3626,7 +3780,7 @@ mod_in_autounload()
if (c == 0) \
return (0);
-static int
+int
gmatch(const char *s, const char *p)
{
int c, sc;
diff --git a/usr/src/uts/common/os/vfs_conf.c b/usr/src/uts/common/os/vfs_conf.c
index c43cd62c39..ae953b5030 100644
--- a/usr/src/uts/common/os/vfs_conf.c
+++ b/usr/src/uts/common/os/vfs_conf.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -79,6 +78,7 @@ struct vfssw vfssw[] = {
{ "swapfs", swapinit }, /* SWAPFS */
{ "mntfs" }, /* MNTFS */
{ "devfs" }, /* DEVFS */
+ { "dev" }, /* DEV */
{ "ctfs" }, /* CONTRACTFS */
{ "objfs" }, /* OBJFS */
{ "" }, /* reserved for loadable fs */