Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 5 Mar 2003 14:15:50 -0800 (PST)
From:      John Baldwin <jhb@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 26396 for review
Message-ID:  <200303052215.h25MFoYh004418@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=26396

Change 26396 by jhb@jhb_laptop on 2003/03/05 14:15:49

	- Sort more of the static function prototypes into alphabetical
	  order and add some new ones.
	- Make the stuff to print out the name of dead witnesses conditional
	  on #if 1 for now to make it easier to remove later.
	- Add a depart() function to remove a dead witness from the lock
	  order hierarchy and free it and call depart() from witness_destroy()
	  when the refcount hits zero.
	- Change rebalancetree() to take the type list pointer as an argument
	  so that it will actually compile.
	- Add a reparentchildren() function to take all the children of one
	  witness and add them as direct children of another witness.  We
	  use this in depart() to reparent all the children of a dead witness
	  to each of its parents.

Affected files ...

.. //depot/projects/smpng/sys/kern/subr_witness.c#80 edit

Differences ...

==== //depot/projects/smpng/sys/kern/subr_witness.c#80 (text+ko) ====

@@ -152,17 +152,20 @@
 	struct	lock_class *w_class;
 };
 
+#ifdef BLESSING
+static int	blessed(struct witness *, struct witness *);
+#endif
+static int	depart(struct witness *w);
 static struct	witness *enroll(const char *description,
 				struct lock_class *lock_class);
 static int	insertchild(struct witness *parent, struct witness *child);
+static int	isitmychild(struct witness *parent, struct witness *child);
+static int	isitmydescendant(struct witness *parent, struct witness *child);
 static int	itismychild(struct witness *parent, struct witness *child);
+static int	rebalancetree(struct witness_list *list);
 static void	removechild(struct witness *parent, struct witness *child);
-static int	isitmychild(struct witness *parent, struct witness *child);
-static int	isitmydescendant(struct witness *parent, struct witness *child);
-static int	rebalancetree(void);
-#ifdef BLESSING
-static int	blessed(struct witness *, struct witness *);
-#endif
+static int	reparentchildren(struct witness *newparent,
+		    struct witness *oldparent);
 static void	witness_displaydescendants(void(*)(const char *fmt, ...),
 					   struct witness *);
 static void	witness_leveldescendents(struct witness *parent, int level);
@@ -442,7 +445,9 @@
 witness_destroy(struct lock_object *lock)
 {
 	struct witness *w;
-	int print;
+#if 1
+	const char *name = NULL;
+#endif
 
 	if (witness_cold)
 		panic("lock (%s) %s destroyed while witness_cold",
@@ -457,29 +462,20 @@
 		mtx_lock_spin(&w_mtx);
 		MPASS(w->w_refcount > 0);
 		w->w_refcount--;
-		print = 0;
-		if (w->w_refcount == 0) {
-			/*
-			 * If no locks for this witness were ever acquired,
-			 * then return the witness to the free list.
-			 */
-			if (w->w_file == NULL) {
-				if (w->w_class->lc_flags & LC_SLEEPLOCK)
-					STAILQ_REMOVE(&w_sleep, w, witness,
-					    w_typelist);
-				else
-					STAILQ_REMOVE(&w_spin, w, witness,
-					    w_typelist);
-				STAILQ_REMOVE(&w_all, w, witness, w_list);
-				witness_free(w);
-			} else if (w->w_dead_squawked == 0) {
-				w->w_dead_squawked = 1;
-				print = 1;
-			}
-		}
-		mtx_unlock_spin(&w_mtx);
-		if (print)
+#if 1
+		if (w->w_refcount == 0)
+			name = w->w_name;
+#endif
+		/*
+		 * Lock is already released if we have an allocation failure
+		 * and depart() fails.
+		 */
+		if (w->w_refcount != 0 || depart(w))
+			mtx_unlock_spin(&w_mtx);
+#if 1
+		if (name != NULL)
 			printf("dead witness: %s\n", w->w_name);
+#endif
 	}
 
 	mtx_lock(&all_mtx);
@@ -1119,23 +1115,66 @@
 	return (w);
 }
 
+/* Don't let the door bang you on the way out... */
+static int
+depart(struct witness *w)
+{
+	struct witness_child_list_entry *wcl, *nwcl;
+	struct witness_list *list;
+	struct witness *parent;
+
+	MPASS(w->w_refcount == 0);
+	if (w->w_class->lc_flags & LC_SLEEPLOCK)
+		list = &w_sleep;
+	else
+		list = &w_spin;
+	/*
+	 * First, we run through the entire tree looking for any
+	 * witnesses that the outgoing witness is a child of.  For
+	 * each parent that we find, we reparent all the direct
+	 * children of the outgoing witness to its parent.
+	 */
+	STAILQ_FOREACH(parent, list, w_typelist) {
+		if (!isitmychild(parent, w))
+			continue;
+		removechild(parent, w);
+		if (!reparentchildren(parent, w))
+			return (0);
+	}
+
+	/*
+	 * Now we go through and free up the child list of the
+	 * outgoing witness.
+	 */
+	for (wcl = w->w_children; wcl != NULL; wcl = nwcl) {
+		nwcl = wcl->wcl_next;
+		witness_child_free(wcl);
+	}
+
+	/*
+	 * Detach from various lists and free.
+	 */
+	STAILQ_REMOVE(list, w, witness, w_typelist);
+	STAILQ_REMOVE(&w_all, w, witness, w_list);
+	witness_free(w);
+
+	/* Finally, fixup the tree. */
+	return (rebalancetree(list));
+}
+
+
 /*
- * Prune the whole tree.  We look for cases where a lock is now
- * both a descendant and a direct child of a given lock.  In that
- * case, we want to remove the direct child link from the tree.
+ * Prune an entire lock order tree.  We look for cases where a lock
+ * is now both a descendant and a direct child of a given lock.  In
+ * that case, we want to remove the direct child link from the tree.
  *
  * Returns false if insertchild() fails.
  */
 static int
-rebalancetree(void)
+rebalancetree(struct witness_list *list)
 {
 	struct witness *child, *parent;
-	struct witness_list *list;
 
-	if (parent->w_class->lc_flags & LC_SLEEPLOCK)
-		list = &w_sleep;
-	else
-		list = &w_spin;
 	STAILQ_FOREACH(child, list, w_typelist) {
 		STAILQ_FOREACH(parent, list, w_typelist) {
 			if (!isitmychild(parent, child))
@@ -1178,9 +1217,30 @@
 	return (1);
 }
 
+/*
+ * Make all the direct descendants of oldparent be direct descendants
+ * of newparent.
+ */
 static int
+reparentchildren(struct witness *newparent, struct witness *oldparent)
+{
+	struct witness_child_list_entry *wcl;
+	int i;
+
+	/* Avoid making a witness a child of itself. */
+	MPASS(!itismychild(oldparent, newparent));
+	
+	for (wcl = oldparent->w_children; wcl != NULL; wcl = wcl->wcl_next)
+		for (i = 0; i < wcl->wcl_count; i++)
+			if (!insertchild(newparent, wcl->wcl_children[i]))
+				return (0);
+	return (1);
+}
+
+static int
 itismychild(struct witness *parent, struct witness *child)
 {
+	struct witness_list *list;
 
 	MPASS(child != NULL && parent != NULL);
 	if ((parent->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK)) !=
@@ -1193,7 +1253,11 @@
 	if (!insertchild(parent, child))
 		return (0);
 
-	return (rebalancetree());
+	if (parent->w_class->lc_flags & LC_SLEEPLOCK)
+		list = &w_sleep;
+	else
+		list = &w_spin;
+	return (rebalancetree(list));
 }
 
 static void

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe p4-projects" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200303052215.h25MFoYh004418>