From 72c6525daf26404bbc3a0e20c90d1cd6cd824eff Mon Sep 17 00:00:00 2001 From: Flavio Cruz Date: Sun, 6 Mar 2016 18:14:52 -0500 Subject: [PATCH hurd] Remove global netfs lock and use hard and soft references for nodes. * libnetfs/drop-node.c: Remove use of netfs_node_refcnt_lock. * libnetfs/init-init.c: Remove netfs_node_refcnt_lock. * libnetfs/make-node.c: Initialize refcounts in refcounts_init. * libnetfs/netfs.h: Use refcounts_t for tracking node references. Remove netfs_node_refcnt_lock. Add netfs_nref_light, netfs_nrele_light and handler netfs_try_dropping_softrefs. Adjust comments. * libnetfs/nput.c: Use refcounts_t. Call netfs_try_dropping_softrefs to remove any soft reference that the translator might have acquired during the lifetime of the node. Implement empty netfs_try_dropping_softrefs. * libnetfs/nref.c: Implement netfs_nref_light. * libnetfs/nrele.c: Use refcounts_t and netfs_try_dropping_softrefs. Implement netfs_nrele_light. * ftpfs/dir.c: Use netfs_nref without locking the old netfs_node_refcnt_lock. * ftpfs/node.c: Likewise. * usermux/mux.c: Use netfs_nref to increase hard references of the node. * hostmux/mux.c: Use netfs_nref to increase hard references of the node. * trans/fakeroot.c (new_node): Use a light reference when storing a node in the hash table. * trans/fakeroot.c (netfs_try_dropping_softrefs): Implement netfs_try_dropping_softrefs to remove the node from the hash table. * trans/fakeroot.c (netfs_node_norefs): Remove code to remove the node from the hash table. * trans/fakeroot.c (netfs_S_dir_lookup): Simplify lookup code since we don't need to lock netfs_node_refcnt_lock anymore. * procfs/netfs.c: Remove use of netfs_node_refcnt_lock. * nfs/cache.c: Add mutex to handle exclusive access to nodehash. This replaces the use of netfs_node_refcnt_lock. * nfs/cache.c (lookup_handle): Use nodehash_ihash_lock when accessing nodehash. Use netfs_nref_light to add one soft reference to the node just added to nodehash. * nfs/cache.c (netfs_node_norefs): Use netfs_nref. Don't use netfs_node_refcnt_lock and don't remove the node from nodehash here. * nfs/cache.c (netfs_try_dropping_softrefs): Drop the light reference when the node has no more hard references. * nfs/cache.c (recache_handle): Use nodehash_ihash_lock instead. * nfs/ops.c (netds_attempt_unlink): Use refcounts_references. * console/console.c (netfs_node_norefs): Use a soft reference to store a node in dir_node, cons_node, disp_node, inp_node. * console/console.c (netfs_try_dropping_softrefs): When dropping all soft references remove node pointer from the fields above. --- console/console.c | 64 ++++++++++++++++++++++++++++++---------------------- ftpfs/dir.c | 27 +++++----------------- ftpfs/node.c | 8 +------ hostmux/mux.c | 6 ++--- libnetfs/drop-node.c | 1 - libnetfs/init-init.c | 2 -- libnetfs/make-node.c | 2 +- libnetfs/netfs.h | 42 ++++++++++++++++++++++------------ libnetfs/nput.c | 27 ++++++++++++++-------- libnetfs/nref.c | 12 +++++++--- libnetfs/nrele.c | 37 ++++++++++++++++++++++++------ nfs/cache.c | 40 ++++++++++++++++++-------------- nfs/ops.c | 5 +++- procfs/netfs.c | 4 ---- trans/fakeroot.c | 45 +++++++++++++++++++++--------------- usermux/mux.c | 6 ++--- 16 files changed, 187 insertions(+), 141 deletions(-) diff --git a/console/console.c b/console/console.c index 57ae813..9c5869d 100644 --- a/console/console.c +++ b/console/console.c @@ -415,47 +415,51 @@ new_node (struct node **np, vcons_t vcons, vcons_node_type type) /* Node management. */ -/* Node NP has no more references; free all its associated - storage. */ +/* We need to drop the soft references on NP. */ void -netfs_node_norefs (struct node *np) +netfs_try_dropping_softrefs (struct node *np) { vcons_t vcons = np->nn->vcons; + int release = FALSE; - /* The root node does never go away. */ - assert (!np->nn->cons && np->nn->vcons); - - /* Avoid deadlock. */ - pthread_spin_unlock (&netfs_node_refcnt_lock); - - /* Find the back reference to ourself in the virtual console - structure, and delete it. */ pthread_mutex_lock (&vcons->lock); - pthread_spin_lock (&netfs_node_refcnt_lock); - if (np->references) + if (np == vcons->dir_node) { - /* Someone else got a reference while we were attempting to go - away. This can happen in netfs_attempt_lookup. In this - case, just unlock the node and do nothing else. */ - pthread_mutex_unlock (&vcons->lock); - pthread_mutex_unlock (&np->lock); - return; + release = TRUE; + vcons->dir_node = 0; } - if (np == vcons->dir_node) - vcons->dir_node = 0; else if (np == vcons->cons_node) - vcons->cons_node = 0; + { + release = TRUE; + vcons->cons_node = 0; + } else if (np == vcons->disp_node) - vcons->disp_node = 0; - else { - assert (np == vcons->inpt_node); + release = TRUE; + vcons->disp_node = 0; + } + else if (np == vcons->inpt_node) + { + release = TRUE; vcons->inpt_node = 0; } + if (release) + netfs_nrele_light (np); pthread_mutex_unlock (&vcons->lock); /* Release our reference. */ - vcons_release (vcons); + if (release) + vcons_release (vcons); + +} + +/* Node NP has no more references; free all its associated + storage. */ +void +netfs_node_norefs (struct node *np) +{ + /* The root node does never go away. */ + assert (!np->nn->cons && np->nn->vcons); free (np->nn); free (np); @@ -634,7 +638,10 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir, the virtual console. */ err = new_node (node, vcons, VCONS_NODE_DIR); if (!err) - vcons->dir_node = *node; + { + vcons->dir_node = *node; + netfs_nref_light (*node); + } else release_vcons = 1; } @@ -663,6 +670,7 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir, if (!err) { vcons->cons_node = *node; + netfs_nref_light (*node); ref_vcons = 1; } } @@ -682,6 +690,7 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir, if (!err) { vcons->disp_node = *node; + netfs_nref_light (*node); ref_vcons = 1; } } @@ -701,6 +710,7 @@ netfs_attempt_lookup (struct iouser *user, struct node *dir, if (!err) { vcons->inpt_node = *node; + netfs_nref_light (*node); ref_vcons = 1; } } diff --git a/ftpfs/dir.c b/ftpfs/dir.c index 733a2dc..2ea29b5 100644 --- a/ftpfs/dir.c +++ b/ftpfs/dir.c @@ -654,10 +654,8 @@ ftpfs_dir_lookup (struct ftpfs_dir *dir, const char *name, { /* If there's already a node, add a ref so that it doesn't go away. */ - pthread_spin_lock (&netfs_node_refcnt_lock); - if (e->node) - e->node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + if (e->node) + netfs_nref (e->node); if (! e->node) /* No node; make one and install it into E. */ @@ -682,11 +680,7 @@ ftpfs_dir_lookup (struct ftpfs_dir *dir, const char *name, if (!err && dir->num_live_entries++ == 0) /* Keep a reference to dir's node corresponding to children. */ - { - pthread_spin_lock (&netfs_node_refcnt_lock); - dir->node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); - } + netfs_nref (dir->node); } } @@ -737,10 +731,8 @@ ftpfs_dir_null_lookup (struct ftpfs_dir *dir, struct node **node) /* We've got a dir entry, get a node for it. */ { /* If there's already a node, add a ref so that it doesn't go away. */ - pthread_spin_lock (&netfs_node_refcnt_lock); if (e->node) - e->node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + netfs_nref (e->node); if (! e->node) /* No node; make one and install it into E. */ @@ -749,11 +741,7 @@ ftpfs_dir_null_lookup (struct ftpfs_dir *dir, struct node **node) if (!err && dir->num_live_entries++ == 0) /* Keep a reference to dir's node corresponding to children. */ - { - pthread_spin_lock (&netfs_node_refcnt_lock); - dir->node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); - } + netfs_nref (dir->node); } if (! err) @@ -783,10 +771,7 @@ ftpfs_dir_create (struct ftpfs *fs, struct node *node, const char *rmt_path, return ENOMEM; } - /* Hold a reference to the new dir's node. */ - pthread_spin_lock (&netfs_node_refcnt_lock); - node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + netfs_nref (node); hurd_ihash_init (&new->htable, offsetof (struct ftpfs_dir_entry, dir_locp)); hurd_ihash_set_gki (&new->htable, ihash_hash, ihash_compare); diff --git a/ftpfs/node.c b/ftpfs/node.c index 74cd402..cc9bf43 100644 --- a/ftpfs/node.c +++ b/ftpfs/node.c @@ -84,10 +84,7 @@ netfs_node_norefs (struct node *node) { struct netnode *nn = node->nn; - /* Ftpfs_detach_node does ref count frobbing (of other nodes), so we have - to unlock NETFS_NODE_REFCNT_LOCK during it. */ - node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + netfs_nref (node); /* Remove NODE from any entry it is attached to. */ ftpfs_detach_node (node); @@ -108,7 +105,4 @@ netfs_node_norefs (struct node *node) free (nn); free (node); - - /* Caller expects us to leave this locked... */ - pthread_spin_lock (&netfs_node_refcnt_lock); } diff --git a/hostmux/mux.c b/hostmux/mux.c index 81d3961..ddca89d 100644 --- a/hostmux/mux.c +++ b/hostmux/mux.c @@ -240,10 +240,8 @@ lookup_cached (struct hostmux *mux, const char *host, int purge, if (strcasecmp (host, nm->name) == 0) { - pthread_spin_lock (&netfs_node_refcnt_lock); - if (nm->node) - nm->node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + if (nm->node) + netfs_nref (nm->node); if (nm->node) { diff --git a/libnetfs/drop-node.c b/libnetfs/drop-node.c index 2fe5ce9..f0d69be 100644 --- a/libnetfs/drop-node.c +++ b/libnetfs/drop-node.c @@ -25,5 +25,4 @@ netfs_drop_node (struct node *np) { fshelp_drop_transbox (&np->transbox); netfs_node_norefs (np); - pthread_spin_unlock (&netfs_node_refcnt_lock); } diff --git a/libnetfs/init-init.c b/libnetfs/init-init.c index a088ad5..9ca1aac 100644 --- a/libnetfs/init-init.c +++ b/libnetfs/init-init.c @@ -24,8 +24,6 @@ /* For safe inlining of netfs_node_netnode and netfs_netnode_node. */ size_t const _netfs_sizeof_struct_node = sizeof (struct node); -pthread_spinlock_t netfs_node_refcnt_lock = PTHREAD_SPINLOCK_INITIALIZER; - struct node *netfs_root_node = 0; struct port_bucket *netfs_port_bucket = 0; struct port_class *netfs_protid_class = 0; diff --git a/libnetfs/make-node.c b/libnetfs/make-node.c index 6bd8109..a292dc6 100644 --- a/libnetfs/make-node.c +++ b/libnetfs/make-node.c @@ -27,7 +27,7 @@ init_node (struct node *np, struct netnode *nn) np->nn = nn; pthread_mutex_init (&np->lock, NULL); - np->references = 1; + refcounts_init (&np->refcounts, 1, 0); np->sockaddr = MACH_PORT_NULL; np->owner = 0; diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h index 67a6a9a..6c989a4 100644 --- a/libnetfs/netfs.h +++ b/libnetfs/netfs.h @@ -82,8 +82,8 @@ struct node pthread_mutex_t lock; - /* The number of references to this node. */ - int references; + /* Hard and soft references to this node. */ + refcounts_t refcounts; mach_port_t sockaddr; @@ -397,10 +397,6 @@ netfs_netnode_node (struct netnode *netnode) return (struct node *) ((char *) netnode - _netfs_sizeof_struct_node); } -/* Whenever node->references is to be touched, this lock must be - held. Cf. netfs_nrele, netfs_nput, netfs_nref and netfs_drop_node. */ -extern pthread_spinlock_t netfs_node_refcnt_lock; - /* Normally called in main. This function sets up some of the netfs server's internal state. */ void netfs_init (void); @@ -425,22 +421,38 @@ struct protid *netfs_make_protid (struct peropen *po, struct iouser *user); struct peropen *netfs_make_peropen (struct node *, int, struct peropen *context); -/* Add a reference to node NP. Unless you already hold a reference, +/* Add a hard reference to node NP. Unless you already hold a reference, NP must be locked. */ void netfs_nref (struct node *np); -/* Releases a node. Drops a reference to node NP, which must not be - locked by the caller. If this was the last reference, drops the - node. The node cannot be used again without first obtaining a - reference to it. */ +/* Add a light reference to a node. */ +void netfs_nref_light (struct node *np); + +/* Releases a hard reference on NP. If NP is locked by anyone, then + this cannot be the last hard reference (because you must hold a + hard reference in order to hold the lock). If this is the last + hard reference then request soft references to be dropped. */ void netfs_nrele (struct node *np); -/* Puts a node back. Drops a reference to the node NP, which must be - locked by the caller (this lock will be released by netfs_nput). - If this was the last reference, drops the node. The node cannot be - used again without first obtaining a reference to it. */ +/* Release a soft reference on NP. If NP is locked by anyone, then + this cannot be the last reference (because you must hold a hard + reference in order to hold the lock). */ +void netfs_nrele_light (struct node *np); + +/* Puts a node back by releasing a hard reference on NP, which must + be locked by the caller (this lock will be released by netfs_nput). + If this was the last reference, then request soft references to be + dropped. */ void netfs_nput (struct node *np); +/* The user must define this function in order to drop the soft references + that this node may have. When this function is called, node NP has just + lost its hard references and is now trying to also drop its soft references. + If the node is stored in another data structure (for caching purposes), + this allows the user to remove it so that the node can be safely deleted + from memory. */ +void netfs_try_dropping_softrefs (struct node *np); + /* Called internally when no more references to node NP exist. */ void netfs_drop_node (struct node *np); diff --git a/libnetfs/nput.c b/libnetfs/nput.c index 522c714..b04fc4b 100644 --- a/libnetfs/nput.c +++ b/libnetfs/nput.c @@ -23,15 +23,24 @@ void netfs_nput (struct node *np) { - pthread_spin_lock (&netfs_node_refcnt_lock); - assert (np->references); - np->references--; - if (np->references == 0) + struct references result; + + refcounts_demote (&np->refcounts, &result); + + if (result.hard == 0) + netfs_try_dropping_softrefs (np); + + refcounts_deref_weak (&np->refcounts, &result); + + if (result.hard == 0 && result.weak == 0) netfs_drop_node (np); - /* netfs_drop_node drops netfs_node_refcnt_lock for us. */ else - { - pthread_spin_unlock (&netfs_node_refcnt_lock); - pthread_mutex_unlock (&np->lock); - } + pthread_mutex_unlock (&np->lock); +} + +/* The last hard reference to NP has gone away; the user must define + this function in order to drop all the soft references. */ +void __attribute__ ((weak)) +netfs_try_dropping_softrefs (struct node *np) +{ } diff --git a/libnetfs/nref.c b/libnetfs/nref.c index 86b4992..d48d9c8 100644 --- a/libnetfs/nref.c +++ b/libnetfs/nref.c @@ -23,7 +23,13 @@ void netfs_nref (struct node *np) { - pthread_spin_lock (&netfs_node_refcnt_lock); - np->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + struct references result; + refcounts_ref (&np->refcounts, &result); +} + +void +netfs_nref_light (struct node *np) +{ + struct references result; + refcounts_ref_weak (&np->refcounts, &result); } diff --git a/libnetfs/nrele.c b/libnetfs/nrele.c index 6f9a014..4dddd1f 100644 --- a/libnetfs/nrele.c +++ b/libnetfs/nrele.c @@ -23,15 +23,38 @@ void netfs_nrele (struct node *np) { - pthread_spin_lock (&netfs_node_refcnt_lock); - assert (np->references); - np->references--; - if (np->references == 0) + struct references result; + int locked = FALSE; + + refcounts_demote (&np->refcounts, &result); + + if (result.hard == 0) + { + pthread_mutex_lock (&np->lock); + netfs_try_dropping_softrefs (np); + locked = TRUE; + } + + refcounts_deref_weak (&np->refcounts, &result); + + if (result.hard == 0 && result.weak == 0) + { + if (! locked) + pthread_mutex_lock (&np->lock); + netfs_drop_node (np); + } else if (locked) + pthread_mutex_unlock (&np->lock); +} + +void +netfs_nrele_light (struct node *np) +{ + struct references result; + + refcounts_deref_weak (&np->refcounts, &result); + if (result.hard == 0 && result.weak == 0) { pthread_mutex_lock (&np->lock); netfs_drop_node (np); - /* netfs_drop_node drops netfs_node_refcnt_lock for us. */ } - else - pthread_spin_unlock (&netfs_node_refcnt_lock); } diff --git a/nfs/cache.c b/nfs/cache.c index b48152e..2015603 100644 --- a/nfs/cache.c +++ b/nfs/cache.c @@ -49,6 +49,8 @@ static struct hurd_ihash nodehash = + offsetof (struct netnode, slot), NULL, NULL, ihash_hash, ihash_compare); +pthread_mutex_t nodehash_ihash_lock = PTHREAD_MUTEX_INITIALIZER; + /* Lookup the file handle HANDLE in the hash table. If it is not present, initialize a new node structure and insert it into the hash table. Whichever course, a new reference is generated and the @@ -60,12 +62,12 @@ lookup_fhandle (struct fhandle *handle, struct node **npp) struct node *np; struct netnode *nn; - pthread_spin_lock (&netfs_node_refcnt_lock); + pthread_mutex_lock (&nodehash_ihash_lock); np = hurd_ihash_find (&nodehash, (hurd_ihash_key_t) handle); if (np) { - np->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + netfs_nref (np); + pthread_mutex_unlock (&nodehash_ihash_lock); pthread_mutex_lock (&np->lock); *npp = np; return; @@ -84,9 +86,9 @@ lookup_fhandle (struct fhandle *handle, struct node **npp) nn->dead_name = 0; hurd_ihash_add (&nodehash, (hurd_ihash_key_t) &nn->handle, np); + netfs_nref_light (np); + pthread_mutex_unlock (&nodehash_ihash_lock); pthread_mutex_lock (&np->lock); - - pthread_spin_unlock (&netfs_node_refcnt_lock); *npp = np; } @@ -114,9 +116,7 @@ forked_node_delete (void *arg) }; /* Called by libnetfs when node NP has no more references. (See - for details. Just clear its local state and - remove it from the hash table. Called and expected to leave with - NETFS_NODE_REFCNT_LOCK held. */ + for details. */ void netfs_node_norefs (struct node *np) { @@ -129,8 +129,7 @@ netfs_node_norefs (struct node *np) args = malloc (sizeof (struct fnd)); assert (args); - np->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + netfs_nref (np); args->dir = np->nn->dead_dir; args->name = np->nn->dead_name; @@ -149,19 +148,26 @@ netfs_node_norefs (struct node *np) errno = err; perror ("pthread_create"); } - - /* Caller expects us to leave this locked... */ - pthread_spin_lock (&netfs_node_refcnt_lock); } else { - hurd_ihash_locp_remove (&nodehash, np->nn->slot); if (np->nn->dtrans == SYMLINK) - free (np->nn->transarg.name); + free (np->nn->transarg.name); free (np); } } +/* When dropping soft refs, we simply remove the node from the + node cache. */ +void +netfs_try_dropping_softrefs (struct node *np) +{ + pthread_mutex_lock (&nodehash_ihash_lock); + hurd_ihash_locp_remove (&nodehash, np->nn->slot); + netfs_nrele_light (np); + pthread_mutex_unlock (&nodehash_ihash_lock); +} + /* Change the file handle used for node NP to be the handle at P. Make sure the hash table stays up to date. Return the address after the handle. The lock on the node should be held. */ @@ -179,7 +185,7 @@ recache_handle (int *p, struct node *np) } /* Unlink it */ - pthread_spin_lock (&netfs_node_refcnt_lock); + pthread_mutex_lock (&nodehash_ihash_lock); hurd_ihash_locp_remove (&nodehash, np->nn->slot); /* Change the name */ @@ -189,6 +195,6 @@ recache_handle (int *p, struct node *np) /* Reinsert it */ hurd_ihash_add (&nodehash, (hurd_ihash_key_t) &np->nn->handle, np); - pthread_spin_unlock (&netfs_node_refcnt_lock); + pthread_mutex_unlock (&nodehash_ihash_lock); return p + len / sizeof (int); } diff --git a/nfs/ops.c b/nfs/ops.c index 79cd3a6..33ab38b 100644 --- a/nfs/ops.c +++ b/nfs/ops.c @@ -1267,7 +1267,10 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, one we just got; if so, we must give this file another link so that when we delete the one we are asked for it doesn't go away entirely. */ - if (np->references > 1) + struct references result; + refcounts_references (&np->refcounts, &result); + + if (result.hard > 1) { char *newname = 0; int n = 0; diff --git a/procfs/netfs.c b/procfs/netfs.c index 276c57c..0b3d31a 100644 --- a/procfs/netfs.c +++ b/procfs/netfs.c @@ -222,12 +222,8 @@ error_t netfs_attempt_lookup (struct iouser *user, struct node *dir, free all its associated storage. */ void netfs_node_norefs (struct node *np) { - pthread_spin_unlock (&netfs_node_refcnt_lock); - procfs_cleanup (np); free (np); - - pthread_spin_lock (&netfs_node_refcnt_lock); } /* The user may define this function (but should define it together diff --git a/trans/fakeroot.c b/trans/fakeroot.c index cb4f818..6fdf75a 100644 --- a/trans/fakeroot.c +++ b/trans/fakeroot.c @@ -110,6 +110,9 @@ new_node (file_t file, mach_port_t idport, int locked, int openmodes, if (!locked) pthread_mutex_lock (&idport_ihash_lock); + /* The light reference allows us to safely keep the node in the + hash table. */ + netfs_nref_light (*np); err = hurd_ihash_add (&idport_ihash, nn->idport, *np); if (err) goto lose; @@ -155,22 +158,31 @@ set_faked_attribute (struct node *np, unsigned int faked) } } +void +netfs_try_dropping_softrefs (struct node *np) +{ + /* We have to drop our light reference by removing the node from the + idport_ihash hash table. */ + pthread_mutex_lock (&idport_ihash_lock); + + hurd_ihash_locp_remove (&idport_ihash, netfs_node_netnode (np)->idport_locp); + netfs_nrele_light (np); + + pthread_mutex_unlock (&idport_ihash_lock); +} + /* Node NP has no more references; free all its associated storage. */ void netfs_node_norefs (struct node *np) { pthread_mutex_unlock (&np->lock); - pthread_spin_unlock (&netfs_node_refcnt_lock); - pthread_mutex_lock (&idport_ihash_lock); - hurd_ihash_locp_remove (&idport_ihash, netfs_node_netnode (np)->idport_locp); - pthread_mutex_unlock (&idport_ihash_lock); + /* NP was already removed from idport_ihash through + netfs_try_dropping_softrefs. */ mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->file); mach_port_deallocate (mach_task_self (), netfs_node_netnode (np)->idport); free (np); - - pthread_spin_lock (&netfs_node_refcnt_lock); } /* This is the cleanup function we install in netfs_protid_class. If @@ -363,29 +375,27 @@ 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); np = hurd_ihash_find (&idport_ihash, idport); if (np != NULL) { - /* We already know about this node. */ + /* We quickly check that NP has hard references. If the node is being + removed, netfs_try_dropping_softrefs is attempting to drop the light + reference on this. */ + struct references result; + + refcounts_references (&np->refcounts, &result); - if (np->references == 0) + if (result.hard == 0) { - /* But it might be in the process of being released. If so, - unlock the hash table to give the node a chance to actually + /* 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->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + netfs_nref (np); mach_port_deallocate (mach_task_self (), idport); @@ -405,7 +415,6 @@ netfs_S_dir_lookup (struct protid *diruser, } else { - pthread_spin_unlock (&netfs_node_refcnt_lock); err = new_node (file, idport, 1, flags & (O_RDWR|O_EXEC), &np); pthread_mutex_unlock (&dnp->lock); if (!err) diff --git a/usermux/mux.c b/usermux/mux.c index bfa95fd..7c57f94 100644 --- a/usermux/mux.c +++ b/usermux/mux.c @@ -298,10 +298,8 @@ lookup_cached (struct usermux *mux, const char *user, int purge, if (strcasecmp (user, nm->name) == 0) { - pthread_spin_lock (&netfs_node_refcnt_lock); - if (nm->node) - nm->node->references++; - pthread_spin_unlock (&netfs_node_refcnt_lock); + if (nm->node) + netfs_nref (nm->node); if (nm->node) { -- 2.1.4