diff options
author | cth <none@none> | 2008-02-22 09:02:16 -0800 |
---|---|---|
committer | cth <none@none> | 2008-02-22 09:02:16 -0800 |
commit | e37c6c376a1a22a828db3bb5ab40c86cb08f9c86 (patch) | |
tree | 4e26a9dc4fb51ae3c275b4a874d16228f566782f /usr/src/uts/common | |
parent | 931293416c5362b3d50b217b4390d1c88f7c7500 (diff) | |
download | illumos-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.c | 21 | ||||
-rw-r--r-- | usr/src/uts/common/fs/devfs/devfs_vnops.c | 37 | ||||
-rw-r--r-- | usr/src/uts/common/os/devcfg.c | 17 | ||||
-rw-r--r-- | usr/src/uts/common/os/modctl.c | 45 | ||||
-rw-r--r-- | usr/src/uts/common/sys/fs/sdev_impl.h | 2 | ||||
-rw-r--r-- | usr/src/uts/common/sys/modctl.h | 3 |
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 |