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
--- a/usr/src/cmd/devfsadm/devfsadm.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/cmd/devfsadm/devfsadm.c Fri Feb 22 09:02:16 2008 -0800
@@ -3153,9 +3153,6 @@
{
char *ptr, path[PATH_MAX + 1];
char *fcn = "rm_parent_dir_if_empty: ";
- finddevhdl_t fhandle;
- const char *f;
- int rv;
vprint(REMOVE_MID, "%schecking %s if empty\n", fcn, pathname);
@@ -3173,17 +3170,8 @@
*ptr = '\0';
- if ((rv = finddev_readdir(path, &fhandle)) != 0) {
- err_print(OPENDIR_FAILED, path, strerror(rv));
- return;
- }
-
- /*
- * An empty pathlist implies an empty directory
- */
- f = finddev_next(fhandle);
- finddev_close(fhandle);
- if (f == NULL) {
+ if (finddev_emptydir(path)) {
+ /* directory is empty */
if (s_rmdir(path) == 0) {
vprint(REMOVE_MID,
"%sremoving empty dir %s\n", fcn, path);
@@ -8970,6 +8958,15 @@
}
/*
+ * Return 1 if we have reserved links.
+ */
+int
+devfsadm_have_reserved()
+{
+ return (enumerate_reserved ? 1 : 0);
+}
+
+/*
* This functions errs on the side of caution. If there is any error
* we assume that the devlink is *not* reserved
*/
--- a/usr/src/cmd/devfsadm/devfsadm.h Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/cmd/devfsadm/devfsadm.h Fri Feb 22 09:02:16 2008 -0800
@@ -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.
*/
@@ -250,6 +250,7 @@
char *s_strdup(const char *ptr);
/* Private interface between reserve subsystm and disks link generator */
+int devfsadm_have_reserved(void);
int devfsadm_is_reserved(devlink_re_t re_array[], char *devlink);
int devfsadm_reserve_id_cache(devlink_re_t re_array[], enumerate_file_t *head);
--- a/usr/src/cmd/devfsadm/disk_link.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/cmd/devfsadm/disk_link.c Fri Feb 22 09:02:16 2008 -0800
@@ -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.
*/
@@ -150,16 +150,14 @@
int targ;
int *intp;
- if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
- "target", &intp) <= 0) {
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "target", &intp) <= 0) {
return (DEVFSADM_CONTINUE);
}
targ = *intp;
- if (di_prop_lookup_ints(DDI_DEV_T_ANY, node,
- "lun", &intp) <= 0) {
- lun = 0;
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "lun", &intp) <= 0) {
+ lun = 0;
} else {
- lun = *intp;
+ lun = *intp;
}
(void) sprintf(disk, "t%dd%d", targ, lun);
@@ -181,10 +179,10 @@
if (di_prop_lookup_strings(DDI_DEV_T_ANY, node,
"client-guid", (char **)&wwn) > 0) {
- if (strlcpy((char *)ascii_wwn, (char *)wwn, sizeof (ascii_wwn))
- >= sizeof (ascii_wwn)) {
+ if (strlcpy((char *)ascii_wwn, (char *)wwn,
+ sizeof (ascii_wwn)) >= sizeof (ascii_wwn)) {
devfsadm_errprint("SUNW_disk_link: GUID too long:%d",
- strlen((char *)wwn));
+ strlen((char *)wwn));
return (DEVFSADM_CONTINUE);
}
lun = 0;
@@ -468,7 +466,6 @@
char *s;
char l[PATH_MAX];
int switch_link = 0;
- struct stat sb;
char *mn = di_minor_name(minor);
if (dvlink_cache == NULL || mn == NULL) {
@@ -476,10 +473,8 @@
return (DEVFSADM_FAILURE);
}
- if (stat(ENUMERATE_RESERVED, &sb) == -1) {
- devfsadm_print(disk_mid, "%s: No reserved file: %s. Will "
- "not bypass new link creation\n",
- modname, ENUMERATE_RESERVED);
+ if (!devfsadm_have_reserved()) {
+ devfsadm_print(disk_mid, "%s: No reserved links\n", modname);
return (DEVFSADM_FAILURE);
}
@@ -512,8 +507,8 @@
return (DEVFSADM_FAILURE);
}
(void) snprintf(s+1, sizeof (phys_path) - (s + 1 - phys_path),
- "%s%s", *mn == *(MN_SMI) ? MN_EFI : MN_SMI,
- strstr(s, ",raw") ? ",raw" : "");
+ "%s%s", *mn == *(MN_SMI) ? MN_EFI : MN_SMI,
+ strstr(s, ",raw") ? ",raw" : "");
(void) di_devlink_cache_walk(dvlink_cache, DISK_LINK_RE,
phys_path, DI_PRIMARY_LINK, &head, dvlink_cb);
}
--- a/usr/src/cmd/truss/print.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/cmd/truss/print.c Fri Feb 22 09:02:16 2008 -0800
@@ -1113,6 +1113,7 @@
case MODREMDRVCLEANUP: s = "MODREMDRVCLEANUP"; break;
case MODDEVEXISTS: s = "MODDEVEXISTS"; break;
case MODDEVREADDIR: s = "MODDEVREADDIR"; break;
+ case MODDEVEMPTYDIR: s = "MODDEVEMPTYDIR"; break;
case MODDEVNAME: s = "MODDEVNAME"; break;
case MODGETDEVFSPATH_MI_LEN:
s = "MODGETDEVFSPATH_MI_LEN"; break;
--- a/usr/src/lib/libdevinfo/devinfo_finddev.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/lib/libdevinfo/devinfo_finddev.c Fri Feb 22 09:02:16 2008 -0800
@@ -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.
*/
@@ -256,6 +256,65 @@
return (finddev_readdir_alt(path, handlep));
}
+/*
+ * Return true if a directory is empty
+ * Use the standard library readdir to determine if a directory is
+ * empty.
+ */
+static int
+finddev_emptydir_alt(const char *path)
+{
+ DIR *dir;
+ struct dirent *dp;
+
+ if ((dir = opendir(path)) == NULL)
+ return (ENOENT);
+
+ while ((dp = readdir(dir)) != NULL) {
+ if ((strcmp(dp->d_name, ".") == 0) ||
+ (strcmp(dp->d_name, "..") == 0))
+ continue;
+ (void) closedir(dir);
+ return (0); /* not empty */
+ }
+ (void) closedir(dir);
+ return (1); /* empty */
+}
+
+/*
+ * Use of the dev filesystem's private readdir does (not trigger
+ * the implicit device reconfiguration) to determine if a directory
+ * is empty.
+ *
+ * Note: only useable with paths mounted on an instance of the
+ * dev filesystem.
+ *
+ * Does not return the . and .. entries.
+ * Empty directories are returned as an zero-length list.
+ * ENOENT is returned as a NULL list pointer.
+ */
+static int
+finddev_emptydir_devfs(const char *path)
+{
+ int rv;
+ int empty;
+
+ rv = modctl(MODDEVEMPTYDIR, path, strlen(path), &empty);
+ if (rv == 0) {
+ return (empty);
+ }
+ return (0);
+}
+
+int
+finddev_emptydir(const char *path)
+{
+ if (GLOBAL_DEV_PATH(path)) {
+ return (finddev_emptydir_devfs(path));
+ }
+ return (finddev_emptydir_alt(path));
+}
+
void
finddev_close(finddevhdl_t arg)
{
--- a/usr/src/lib/libdevinfo/libdevinfo.h Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/lib/libdevinfo/libdevinfo.h Fri Feb 22 09:02:16 2008 -0800
@@ -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.
*/
@@ -473,6 +473,7 @@
extern int device_exists(const char *);
extern int finddev_readdir(const char *, finddevhdl_t *);
+extern int finddev_emptydir(const char *);
extern void finddev_close(finddevhdl_t);
extern const char *finddev_next(finddevhdl_t);
--- a/usr/src/lib/libdevinfo/mapfile-vers Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/lib/libdevinfo/mapfile-vers Fri Feb 22 09:02:16 2008 -0800
@@ -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.
#
# ident "%Z%%M% %I% %E% SMI"
@@ -207,9 +207,10 @@
di_prom_prop_lookup_slot_names;
di_prop_find;
device_exists;
+ finddev_close;
+ finddev_emptydir;
+ finddev_next;
finddev_readdir;
- finddev_close;
- finddev_next;
di_flags;
di_retire_device;
di_unretire_device;
--- a/usr/src/uts/common/fs/dev/sdev_subr.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c Fri Feb 22 09:02:16 2008 -0800
@@ -521,7 +521,7 @@
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 @@
(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 @@
error = VOP_REMOVE(nddv->sdev_attrvp,
nnm, cred, NULL, 0);
if (error)
- goto err_out;
+ goto err_out;
}
}
}
@@ -1811,7 +1811,7 @@
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 @@
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 @@
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 @@
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;
+ }
}
}
--- a/usr/src/uts/common/fs/devfs/devfs_vnops.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/uts/common/fs/devfs/devfs_vnops.c Fri Feb 22 09:02:16 2008 -0800
@@ -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 @@
return (ENOENT);
}
+ rw_enter(&dv->dv_contents, RW_READER);
if (dv->dv_attr) {
/*
* obtain from the memory version of attribute.
@@ -195,6 +196,7 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
} 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 @@
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);
}
/*
--- a/usr/src/uts/common/os/devcfg.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/uts/common/os/devcfg.c Fri Feb 22 09:02:16 2008 -0800
@@ -7314,7 +7314,7 @@
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 @@
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",
--- a/usr/src/uts/common/os/modctl.c Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/uts/common/os/modctl.c Fri Feb 22 09:02:16 2008 -0800
@@ -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 @@
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 @@
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 @@
(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;
--- a/usr/src/uts/common/sys/fs/sdev_impl.h Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/uts/common/sys/fs/sdev_impl.h Fri Feb 22 09:02:16 2008 -0800
@@ -624,7 +624,7 @@
/*
* 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 *);
--- a/usr/src/uts/common/sys/modctl.h Fri Feb 22 08:41:57 2008 -0800
+++ b/usr/src/uts/common/sys/modctl.h Fri Feb 22 09:02:16 2008 -0800
@@ -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 @@
#define MODRETIRE 40
#define MODUNRETIRE 41
#define MODISRETIRED 42
+#define MODDEVEMPTYDIR 43
/*
* sub cmds for MODEVENTS