changeset 4707:9eb89bebeca5

6578845 cfgadm_sata should use libdevinfo to check for devices
author vikram
date Mon, 23 Jul 2007 16:03:40 -0700
parents 570cc70164ad
children 83b15139bb86
files usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c
diffstat 1 files changed, 86 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c	Mon Jul 23 15:50:30 2007 -0700
+++ b/usr/src/lib/cfgadm_plugins/sata/common/cfga_sata.c	Mon Jul 23 16:03:40 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1131,6 +1131,77 @@
 	return (DI_WALK_CONTINUE);
 }
 
+struct chk_dev {
+	int c_isblk;
+	char *c_minor;
+};
+
+/*ARGSUSED*/
+static int
+chk_dev_fcn(di_node_t node, di_minor_t minor, void *arg)
+{
+	char	*mn;
+	struct chk_dev *chkp = (struct chk_dev *)arg;
+
+	mn = di_minor_name(minor);
+	if (mn == NULL)
+		return (DI_WALK_CONTINUE);
+
+	if (strcmp(mn, chkp->c_minor) != 0)
+		return (DI_WALK_CONTINUE);
+
+	chkp->c_isblk = di_minor_spectype(minor) == S_IFBLK ? 1 : 0;
+
+	return (DI_WALK_TERMINATE);
+}
+
+/*
+ * Don't use devfs if stat() in /devices fails. Use libdevinfo instead.
+ * Retired devices don't show up in devfs.
+ *
+ *	Returns:
+ *		1 - minor exists and is of type BLK
+ *		0 - minor does not exist or is not of type BLK.
+ */
+static int
+is_devinfo_blk(char *minor_path)
+{
+	char	*minor_portion;
+	struct chk_dev chk_dev;
+	di_node_t node;
+	int	rv;
+
+	/*
+	 * prune minor path for di_init() - no /devices prefix and no minor name
+	 */
+	if (strncmp(minor_path, "/devices/", strlen("/devices/")) != 0)
+		return (0);
+
+	minor_portion = strrchr(minor_path, *MINOR_SEP);
+	if (minor_portion == NULL)
+		return (0);
+
+	*minor_portion = 0;
+
+	node = di_init(minor_path + strlen("/devices"), DINFOMINOR);
+
+	*minor_portion = *MINOR_SEP;
+
+	if (node == DI_NODE_NIL)
+		return (0);
+
+	chk_dev.c_isblk = 0;
+	chk_dev.c_minor = minor_portion + 1;
+
+	rv = di_walk_minor(node, NULL, 0, &chk_dev, chk_dev_fcn);
+
+	di_fini(node);
+
+	if (rv == 0 && chk_dev.c_isblk)
+		return (1);
+	else
+		return (0);
+}
 
 /*
  * The dynamic component buffer returned by this function has to be freed!
@@ -1212,11 +1283,23 @@
 			(void) snprintf(minor_path, MAXPATHLEN,
 			    "%s/%s", devpath, dep->d_name);
 
-			if (stat(minor_path, &sb) < 0)
-				continue;
+			/*
+			 * If stat() fails, the device *may* be retired.
+			 * Check via libdevinfo if the device has a BLK minor.
+			 * We don't use libdevinfo all the time, since taking
+			 * a snapshot is slower than a stat().
+			 */
+			if (stat(minor_path, &sb) < 0) {
+				if (is_devinfo_blk(minor_path)) {
+					break;
+				} else {
+					continue;
+				}
+			}
 
 			if (S_ISBLK(sb.st_mode))
 				break;
+
 		}
 
 		(void) closedir(dp);