summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authorcth <none@none>2008-02-22 09:02:16 -0800
committercth <none@none>2008-02-22 09:02:16 -0800
commite37c6c376a1a22a828db3bb5ab40c86cb08f9c86 (patch)
tree4e26a9dc4fb51ae3c275b4a874d16228f566782f /usr/src/uts/common
parent931293416c5362b3d50b217b4390d1c88f7c7500 (diff)
downloadillumos-gate-e37c6c376a1a22a828db3bb5ab40c86cb08f9c86.tar.gz
6453345 devfs_getattr violates devfs locking rules
6527396 devfsadm -C taking hours after reconfiguration reboot 6661843 i_ddi_di_cache_invalidate() should only use taskq_dispatch on valid->invalid 6662461 reserved_links_exist() should be optimized
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/fs/dev/sdev_subr.c21
-rw-r--r--usr/src/uts/common/fs/devfs/devfs_vnops.c37
-rw-r--r--usr/src/uts/common/os/devcfg.c17
-rw-r--r--usr/src/uts/common/os/modctl.c45
-rw-r--r--usr/src/uts/common/sys/fs/sdev_impl.h2
-rw-r--r--usr/src/uts/common/sys/modctl.h3
6 files changed, 85 insertions, 40 deletions
diff --git a/usr/src/uts/common/fs/dev/sdev_subr.c b/usr/src/uts/common/fs/dev/sdev_subr.c
index 0159fc568e..77f47f4535 100644
--- a/usr/src/uts/common/fs/dev/sdev_subr.c
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c
@@ -521,7 +521,7 @@ sdev_get_moduleops(struct sdev_node *dv)
if (map->dir_invalid) {
if (map->dir_module && map->dir_newmodule &&
(strcmp(map->dir_module,
- map->dir_newmodule) == 0)) {
+ map->dir_newmodule) == 0)) {
load = 0;
}
sdev_replace_nsmap(map, map->dir_newmodule,
@@ -1230,7 +1230,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
(void) sdev_dirdelete(nddv, *ndvp);
*ndvp = NULL;
error = VOP_RMDIR(nddv->sdev_attrvp, nnm,
- nddv->sdev_attrvp, cred, NULL, 0);
+ nddv->sdev_attrvp, cred, NULL, 0);
if (error)
goto err_out;
} else {
@@ -1254,7 +1254,7 @@ sdev_rnmnode(struct sdev_node *oddv, struct sdev_node *odv,
error = VOP_REMOVE(nddv->sdev_attrvp,
nnm, cred, NULL, 0);
if (error)
- goto err_out;
+ goto err_out;
}
}
}
@@ -1811,7 +1811,7 @@ sdev_call_devfsadmd(struct sdev_node *ddv, struct sdev_node *dv, char *nm)
error = 0;
} else if (!DEVNAME_DEVFSADM_HAS_RUN(devfsadm_state)) {
sdcmn_err6(("lookup %s/%s starting devfsadm, 0x%x\n",
- ddv->sdev_name, nm, devfsadm_state));
+ ddv->sdev_name, nm, devfsadm_state));
sdev_devfsadmd_thread(ddv, dv, kcred);
mutex_enter(&dv->sdev_lookup_lock);
@@ -3026,7 +3026,7 @@ sdev_modctl_lookup(const char *path, vnode_t **r_vp)
int
sdev_modctl_readdir(const char *dir, char ***dirlistp,
- int *npathsp, int *npathsp_alloc)
+ int *npathsp, int *npathsp_alloc, int checking_empty)
{
char **pathlist = NULL;
char **newlist = NULL;
@@ -3081,18 +3081,17 @@ sdev_modctl_readdir(const char *dir, char ***dirlistp,
break;
for (dp = dbuf; ((intptr_t)dp < (intptr_t)dbuf + dbuflen);
- dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) {
+ dp = (dirent64_t *)((intptr_t)dp + dp->d_reclen)) {
nm = dp->d_name;
if (strcmp(nm, ".") == 0 || strcmp(nm, "..") == 0)
continue;
-
if (npaths == npaths_alloc) {
npaths_alloc += 64;
newlist = (char **)
kmem_zalloc((npaths_alloc + 1) *
- sizeof (char *), KM_SLEEP);
+ sizeof (char *), KM_SLEEP);
if (pathlist) {
bcopy(pathlist, newlist,
npaths * sizeof (char *));
@@ -3106,6 +3105,12 @@ sdev_modctl_readdir(const char *dir, char ***dirlistp,
bcopy(nm, s, n);
pathlist[npaths++] = s;
sdcmn_err11((" %s/%s\n", dir, s));
+
+ /* if checking empty, one entry is as good as many */
+ if (checking_empty) {
+ eof = 1;
+ break;
+ }
}
}
diff --git a/usr/src/uts/common/fs/devfs/devfs_vnops.c b/usr/src/uts/common/fs/devfs/devfs_vnops.c
index d459929000..5361b7e00d 100644
--- a/usr/src/uts/common/fs/devfs/devfs_vnops.c
+++ b/usr/src/uts/common/fs/devfs/devfs_vnops.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -180,6 +180,7 @@ devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr,
return (ENOENT);
}
+ rw_enter(&dv->dv_contents, RW_READER);
if (dv->dv_attr) {
/*
* obtain from the memory version of attribute.
@@ -195,6 +196,7 @@ devfs_getattr(struct vnode *vp, struct vattr *vap, int flags, struct cred *cr,
dsysdebug(error, ("vop_getattr %s %d\n", dv->dv_name, error));
dv_vattr_merge(dv, vap);
}
+ rw_exit(&dv->dv_contents);
/*
* Restrict the permissions of the node fronting the console
@@ -241,7 +243,7 @@ devfs_setattr_dir(
again: if (dv->dv_attr) {
error = secpolicy_vnode_setattr(cr, vp, vap,
- dv->dv_attr, flags, devfs_unlocked_access, dv);
+ dv->dv_attr, flags, devfs_unlocked_access, dv);
if (error)
goto out;
@@ -281,9 +283,9 @@ again: if (dv->dv_attr) {
if (vap->va_mask & (AT_MODE|AT_UID|AT_GID|AT_ATIME|AT_MTIME)) {
/* Set the attributes */
error = VOP_SETATTR(dv->dv_attrvp,
- vap, flags, cr, NULL);
+ vap, flags, cr, NULL);
dsysdebug(error,
- ("vop_setattr %s %d\n", dv->dv_name, error));
+ ("vop_setattr %s %d\n", dv->dv_name, error));
/*
* Some file systems may return EROFS for a setattr
@@ -459,8 +461,7 @@ devfs_setattr(
ASSERT(vp->v_type != VDIR);
*vattrp = dv_vattr_file;
error = VOP_GETATTR(dv->dv_attrvp, vattrp, 0, cr, ct);
- dsysdebug(error, ("vop_getattr %s %d\n",
- dv->dv_name, error));
+ dsysdebug(error, ("vop_getattr %s %d\n", dv->dv_name, error));
if (error)
goto out;
dv->dv_attr = vattrp;
@@ -469,10 +470,10 @@ devfs_setattr(
}
error = secpolicy_vnode_setattr(cr, vp, vap, dv->dv_attr,
- flags, devfs_unlocked_access, dv);
+ flags, devfs_unlocked_access, dv);
if (error) {
dsysdebug(error, ("devfs_setattr %s secpolicy error %d\n",
- dv->dv_name, error));
+ dv->dv_name, error));
goto out;
}
@@ -530,13 +531,13 @@ devfs_setattr(
} else {
if (mask & AT_MODE)
dcmn_err5(("%s persisting mode 0%o\n",
- dv->dv_name, vap->va_mode));
+ dv->dv_name, vap->va_mode));
if (mask & AT_UID)
dcmn_err5(("%s persisting uid %d\n",
- dv->dv_name, vap->va_uid));
+ dv->dv_name, vap->va_uid));
if (mask & AT_GID)
dcmn_err5(("%s persisting gid %d\n",
- dv->dv_name, vap->va_gid));
+ dv->dv_name, vap->va_gid));
if (dv->dv_attrvp == NULL) {
dvp = DVTOV(dv->dv_dotdot);
@@ -734,16 +735,14 @@ devfs_access(struct vnode *vp, int mode, int flags, struct cred *cr,
return (EACCES);
}
+ rw_enter(&dv->dv_contents, RW_READER);
if (dv->dv_attr && ((dv->dv_flags & DV_ACL) == 0)) {
- rw_enter(&dv->dv_contents, RW_READER);
- if (dv->dv_attr) {
- res = devfs_unlocked_access(dv, mode, cr);
- rw_exit(&dv->dv_contents);
- return (res);
- }
- rw_exit(&dv->dv_contents);
+ res = devfs_unlocked_access(dv, mode, cr);
+ } else {
+ res = VOP_ACCESS(dv->dv_attrvp, mode, flags, cr, ct);
}
- return (VOP_ACCESS(dv->dv_attrvp, mode, flags, cr, ct));
+ rw_exit(&dv->dv_contents);
+ return (res);
}
/*
diff --git a/usr/src/uts/common/os/devcfg.c b/usr/src/uts/common/os/devcfg.c
index bfc829934f..ff837895fb 100644
--- a/usr/src/uts/common/os/devcfg.c
+++ b/usr/src/uts/common/os/devcfg.c
@@ -7314,7 +7314,7 @@ i_ddi_di_cache_free(struct di_cache *cache)
void
i_ddi_di_cache_invalidate(int kmflag)
{
- uint_t flag;
+ int cache_valid;
if (!modrootloaded || !i_ddi_io_initialized()) {
if (di_cache_debug)
@@ -7322,16 +7322,15 @@ i_ddi_di_cache_invalidate(int kmflag)
return;
}
- /*
- * Invalidate the in-core cache and
- * increment devtree generation number
- */
- atomic_and_32(&di_cache.cache_valid, 0);
+ /* Increment devtree generation number. */
atomic_inc_ulong(&devtree_gen);
- flag = (kmflag == KM_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP;
-
- (void) taskq_dispatch(system_taskq, free_cache_task, NULL, flag);
+ /* Invalidate the in-core cache and dispatch free on valid->invalid */
+ cache_valid = atomic_swap_uint(&di_cache.cache_valid, 0);
+ if (cache_valid) {
+ (void) taskq_dispatch(system_taskq, free_cache_task, NULL,
+ (kmflag == KM_SLEEP) ? TQ_SLEEP : TQ_NOSLEEP);
+ }
if (di_cache_debug) {
cmn_err(CE_NOTE, "invalidation with km_flag: %s",
diff --git a/usr/src/uts/common/os/modctl.c b/usr/src/uts/common/os/modctl.c
index b4b0751d23..501cb7ba09 100644
--- a/usr/src/uts/common/os/modctl.c
+++ b/usr/src/uts/common/os/modctl.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -2046,7 +2046,7 @@ modctl_devreaddir(const char *udir, int udirlen,
goto err;
if ((ret = sdev_modctl_readdir(dir, &dirlist,
- &npaths, &npaths_alloc)) != 0) {
+ &npaths, &npaths_alloc, 0)) != 0) {
ASSERT(dirlist == NULL);
goto err;
}
@@ -2093,6 +2093,42 @@ err:
return (ret);
}
+static int
+modctl_devemptydir(const char *udir, int udirlen, int *uempty)
+{
+ char *dir;
+ int ret;
+ char **dirlist = NULL;
+ int npaths;
+ int npaths_alloc;
+ int empty;
+
+ /*
+ * 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, 1)) != 0) {
+ goto err;
+ }
+
+ empty = npaths ? 0 : 1;
+ if (copyout(&empty, uempty, sizeof (empty)))
+ ret = EFAULT;
+
+err:
+ if (dirlist)
+ sdev_modctl_readdir_free(dirlist, npaths, npaths_alloc);
+ kmem_free(dir, udirlen + 1);
+ return (ret);
+}
+
int
modctl_moddevname(int subcmd, uintptr_t a1, uintptr_t a2)
{
@@ -2347,6 +2383,11 @@ modctl(int cmd, uintptr_t a1, uintptr_t a2, uintptr_t a3, uintptr_t a4,
(char *)a3, (int64_t *)a4);
break;
+ case MODDEVEMPTYDIR: /* non-reconfiguring /dev emptydir */
+ error = modctl_devemptydir((const char *)a1, (size_t)a2,
+ (int *)a3);
+ break;
+
case MODDEVNAME:
error = modctl_moddevname((int)a1, a2, a3);
break;
diff --git a/usr/src/uts/common/sys/fs/sdev_impl.h b/usr/src/uts/common/sys/fs/sdev_impl.h
index 7e5f75d7f7..33142fe703 100644
--- a/usr/src/uts/common/sys/fs/sdev_impl.h
+++ b/usr/src/uts/common/sys/fs/sdev_impl.h
@@ -624,7 +624,7 @@ extern void *sdev_get_vtor(struct sdev_node *dv);
/*
* devinfo helpers
*/
-extern int sdev_modctl_readdir(const char *, char ***, int *, int *);
+extern int sdev_modctl_readdir(const char *, char ***, int *, int *, int);
extern void sdev_modctl_readdir_free(char **, int, int);
extern int sdev_modctl_devexists(const char *);
diff --git a/usr/src/uts/common/sys/modctl.h b/usr/src/uts/common/sys/modctl.h
index 818572a94d..0ff7ddc42c 100644
--- a/usr/src/uts/common/sys/modctl.h
+++ b/usr/src/uts/common/sys/modctl.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -269,6 +269,7 @@ struct modlinkage {
#define MODRETIRE 40
#define MODUNRETIRE 41
#define MODISRETIRED 42
+#define MODDEVEMPTYDIR 43
/*
* sub cmds for MODEVENTS