From 1ea83c98a8fb8f58a4de8368d1fa29d341a2a73c Mon Sep 17 00:00:00 2001 From: Richard Braun Date: Fri, 7 Feb 2014 22:54:24 +0100 Subject: trans/fakeroot: fix cached node retrieval on lookup When a client finds a node from the hash table, it could happen that another thread is still holding one reference on it before the current thread has acquired its own. Simply checking for a non zero refcount isn't enough, the new client must atomically acquire its own reference. * trans/fakeroot.c (netfs_S_dir_lookup): Find and acquire node reference while holding netfs_node_refcnt_lock. --- trans/fakeroot.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'trans') diff --git a/trans/fakeroot.c b/trans/fakeroot.c index 30386126..c519180c 100644 --- a/trans/fakeroot.c +++ b/trans/fakeroot.c @@ -348,6 +348,10 @@ netfs_S_dir_lookup (struct protid *diruser, redo_hash_lookup: pthread_mutex_lock (&idport_ihash_lock); pthread_mutex_lock (&dnp->lock); + /* The hashtable may not hold a true reference on the node. Acquire the + refcount lock so that, if a node is found, its reference counter cannot + drop to 0 before we get our own reference. */ + pthread_spin_lock (&netfs_node_refcnt_lock); struct netnode *nn = hurd_ihash_find (&idport_ihash, idport); if (nn != NULL) { @@ -359,12 +363,17 @@ netfs_S_dir_lookup (struct protid *diruser, /* But it might be in the process of being released. If so, unlock the hash table to give the node a chance to actually be removed and retry. */ + pthread_spin_unlock (&netfs_node_refcnt_lock); pthread_mutex_unlock (&dnp->lock); pthread_mutex_unlock (&idport_ihash_lock); goto redo_hash_lookup; } + /* Otherwise, reference it right away. */ np = nn->np; + np->references++; + pthread_spin_unlock (&netfs_node_refcnt_lock); + mach_port_deallocate (mach_task_self (), idport); if (np == dnp) @@ -377,12 +386,12 @@ netfs_S_dir_lookup (struct protid *diruser, pthread_mutex_unlock (&dnp->lock); } - netfs_nref (np); err = check_openmodes (np->nn, (flags & (O_RDWR|O_EXEC)), file); pthread_mutex_unlock (&idport_ihash_lock); } else { + pthread_spin_unlock (&netfs_node_refcnt_lock); err = new_node (file, idport, 1, flags, &np); pthread_mutex_unlock (&dnp->lock); if (!err) -- cgit v1.2.3