9ns: Fix concurrent TF removal bug

If you had two threads removing a child from a parent at the same time,
get_locked_and_kreffed_parent() would return a TF that was not the
parent of the child.  I think the check for child->parent was from before I
deferred clearning ->parent until __tf_free().

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/src/ns/tree_file.c b/kern/src/ns/tree_file.c
index 2623a92..be21d2b 100644
--- a/kern/src/ns/tree_file.c
+++ b/kern/src/ns/tree_file.c
@@ -254,7 +254,15 @@
 	if (!parent)
 		return NULL;
 	qlock(&parent->file.qlock);
-	if (parent != child->parent) {
+	/* Checking the parent == child->parent isn't enough here.  That works for
+	 * rename, but not removal/unlink.  Older versions of TF code cleared
+	 * child->parent, but now that's dealt with in tf_free.
+	 *
+	 * We're doing a lockless peek at child's flags.  We hold the potential
+	 * parent's lock, so if they are ours, no one will be messing with the
+	 * disconnected flag.  If they are messing with it, then parent !=
+	 * child->parent.  Also, once disconnected is set, it is never clear. */
+	if ((child->flags & TF_F_DISCONNECTED) || (parent != child->parent)) {
 		qunlock(&parent->file.qlock);
 		tf_kref_put(parent);
 		return NULL;