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;