changeset 3854:406e18bafdbd

6533722 devfsadmd and hald are off to the races
author jacobs
date Mon, 19 Mar 2007 11:35:26 -0700
parents 5db618f33022
children df4146229995
files usr/src/cmd/devfsadm/devfsadm.c usr/src/cmd/devfsadm/devfsadm_impl.h
diffstat 2 files changed, 93 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/devfsadm/devfsadm.c	Mon Mar 19 11:20:20 2007 -0700
+++ b/usr/src/cmd/devfsadm/devfsadm.c	Mon Mar 19 11:35:26 2007 -0700
@@ -245,6 +245,12 @@
 
 static int is_blank(char *);
 
+/* sysevent queue related globals */
+static mutex_t  syseventq_mutex = DEFAULTMUTEX;
+static syseventq_t *syseventq_front;
+static syseventq_t *syseventq_back;
+static void process_syseventq();
+
 int
 main(int argc, char *argv[])
 {
@@ -966,7 +972,7 @@
 	 * Log sysevent and notify RCM.
 	 */
 	if (ev_subclass)
-		build_and_log_event(EC_DEV_ADD, ev_subclass, dcip->dci_root,
+		build_and_enq_event(EC_DEV_ADD, ev_subclass, dcip->dci_root,
 		    node);
 
 	if ((dcip->dci_flags & DCA_NOTIFY_RCM) && rcm_hdl)
@@ -1324,6 +1330,9 @@
 		invalidate_enumerate_cache();
 		rm_all_links_from_cache();
 		(void) di_devlink_close(&devlink_cache, DI_LINK_ERROR);
+
+		/* send any sysevents that were queued up. */
+		process_syseventq();
 	}
 
 	/*
@@ -1395,6 +1404,12 @@
 		if (update_database)
 			(void) di_devlink_update(devlink_cache);
 		(void) di_devlink_close(&devlink_cache, 0);
+
+		/*
+		 * now that the devlinks db cache has been flushed, it is safe
+		 * to send any sysevents that were queued up.
+		 */
+		process_syseventq();
 	}
 
 	exit_dev_lock();
@@ -1578,7 +1593,7 @@
 		if (strcmp(ESC_DEVFS_DEVI_ADD, subclass) == 0) {
 			add_minor_pathname(path, NULL, dev_ev_subclass);
 			if (branch_event) {
-				build_and_log_event(EC_DEV_BRANCH,
+				build_and_enq_event(EC_DEV_BRANCH,
 				    ESC_DEV_BRANCH_ADD, path, DI_NODE_NIL);
 			}
 
@@ -1592,7 +1607,7 @@
 			hot_cleanup(path, NULL, dev_ev_subclass,
 			    driver_name, instance);
 			if (branch_event) {
-				build_and_log_event(EC_DEV_BRANCH,
+				build_and_enq_event(EC_DEV_BRANCH,
 				    ESC_DEV_BRANCH_REMOVE, path, DI_NODE_NIL);
 			}
 		}
@@ -1612,7 +1627,7 @@
 			dev_ev_subclass = ESC_DEV_BRANCH_REMOVE;
 
 		lock_dev();
-		build_and_log_event(EC_DEV_BRANCH, dev_ev_subclass, path,
+		build_and_enq_event(EC_DEV_BRANCH, dev_ev_subclass, path,
 		    DI_NODE_NIL);
 		unlock_dev(CACHE_STATE);
 	} else
@@ -3826,6 +3841,10 @@
 			 * database code may hold.
 			 */
 			(void) di_devlink_close(&devlink_cache, 0);
+
+			/* send any sysevents that were queued up. */
+			process_syseventq();
+
 			if (fcntl(dev_lock_fd, F_SETLKW, &lock) == -1) {
 				err_print(LOCK_FAILED, dev_lockfile,
 						strerror(errno));
@@ -8046,12 +8065,69 @@
 	}
 }
 
+/*
+ * When devfsadmd needs to generate sysevents, they are queued for later
+ * delivery this allows them to be delivered after the devlinks db cache has
+ * been flushed guaranteeing that applications consuming these events have
+ * access to an accurate devlinks db.  The queue is a FIFO, sysevents to be
+ * inserted in the front of the queue and consumed off the back.
+ */
 static void
-build_and_log_event(char *class, char *subclass, char *node_path,
-    di_node_t node)
+enqueue_sysevent(char *class, char *subclass, nvlist_t *nvl)
+{
+	syseventq_t *tmp;
+
+	if ((tmp = s_zalloc(sizeof (*tmp))) == NULL)
+		return;
+
+	tmp->class = s_strdup(class);
+	tmp->subclass = s_strdup(subclass);
+	tmp->nvl = nvl;
+
+	(void) mutex_lock(&syseventq_mutex);
+	if (syseventq_front != NULL)
+		syseventq_front->next = tmp;
+	else
+		syseventq_back = tmp;
+	syseventq_front = tmp;
+	(void) mutex_unlock(&syseventq_mutex);
+}
+
+static void
+process_syseventq()
+{
+	(void) mutex_lock(&syseventq_mutex);
+	while (syseventq_back != NULL) {
+		syseventq_t *tmp = syseventq_back;
+
+		vprint(CHATTY_MID, "sending queued event: %s, %s\n",
+			tmp->class, tmp->subclass);
+
+		log_event(tmp->class, tmp->subclass, tmp->nvl);
+
+		if (tmp->class != NULL)
+			free(tmp->class);
+		if (tmp->subclass != NULL)
+			free(tmp->subclass);
+		if (tmp->nvl != NULL)
+			nvlist_free(tmp->nvl);
+		syseventq_back = syseventq_back->next;
+		if (syseventq_back == NULL)
+			syseventq_front = NULL;
+		free(tmp);
+	}
+	(void) mutex_unlock(&syseventq_mutex);
+}
+
+static void
+build_and_enq_event(char *class, char *subclass, char *node_path,
+	di_node_t node)
 {
 	nvlist_t *nvl;
 
+	vprint(CHATTY_MID, "build_and_enq_event(%s, %s, %s, 0x%8.8x)\n",
+		class, subclass, node_path, (int)node);
+
 	if (node != DI_NODE_NIL)
 		nvl = build_event_attributes(class, subclass, node_path, node,
 		    di_driver_name(node), di_instance(node));
@@ -8060,8 +8136,7 @@
 		    NULL, -1);
 
 	if (nvl) {
-		log_event(class, subclass, nvl);
-		nvlist_free(nvl);
+		enqueue_sysevent(class, subclass, nvl);
 	}
 }
 
--- a/usr/src/cmd/devfsadm/devfsadm_impl.h	Mon Mar 19 11:20:20 2007 -0700
+++ b/usr/src/cmd/devfsadm/devfsadm_impl.h	Mon Mar 19 11:35:26 2007 -0700
@@ -109,7 +109,7 @@
 
 #define	DEVFSADM_DEFAULT_FILE "/etc/default/devfsadm"
 
-#define	MINOR_FINI_TIMEOUT_DEFAULT 3
+#define	MINOR_FINI_TIMEOUT_DEFAULT 2
 
 #define	SYNCH_DOOR_PERMS	(S_IRUSR | S_IWUSR)
 
@@ -362,6 +362,14 @@
 	struct rcm_eventq *next;
 };
 
+/* sysevent queue related */
+typedef struct syseventq_s {
+	struct syseventq_s *next;
+	char *class;
+	char *subclass;
+	nvlist_t *nvl;
+} syseventq_t;
+
 static int devfsadm_enumerate_int_start(char *devfs_path,
 	int index, char **buf, devfsadm_enumerate_t rules[],
 	int nrules, char *start);
@@ -493,7 +501,7 @@
 static nvlist_t *build_event_attributes(char *, char *, char *,
     di_node_t, char *, int);
 static void log_event(char *, char *, nvlist_t *);
-static void build_and_log_event(char *, char *, char *, di_node_t);
+static void build_and_enq_event(char *, char *, char *, di_node_t);
 
 static void read_logindevperm_file(void);
 static void set_logindev_perms(char *devlink);