summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2016-03-07 00:40:25 +0100
committerJustus Winter <justus@gnupg.org>2016-03-07 00:40:25 +0100
commit852301b1c6072c72bc010f9c201df5dd36284462 (patch)
treeb36869bcfc3e9dcc88f57b652817ea890ab94959
parent918d1166a87d4111ddefb477c9a45ee1c2dce169 (diff)
add patch series
-rw-r--r--debian/patches/flavio0001-Remove-global-netfs-lock-and-use-hard-and-soft-refer.patch775
-rw-r--r--debian/patches/series1
2 files changed, 776 insertions, 0 deletions
diff --git a/debian/patches/flavio0001-Remove-global-netfs-lock-and-use-hard-and-soft-refer.patch b/debian/patches/flavio0001-Remove-global-netfs-lock-and-use-hard-and-soft-refer.patch
new file mode 100644
index 00000000..78e6a27e
--- /dev/null
+++ b/debian/patches/flavio0001-Remove-global-netfs-lock-and-use-hard-and-soft-refer.patch
@@ -0,0 +1,775 @@
+From 72c6525daf26404bbc3a0e20c90d1cd6cd824eff Mon Sep 17 00:00:00 2001
+From: Flavio Cruz <flaviocruz@gmail.com>
+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
+- <hurd/libnetfs.h> 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. */
++ <hurd/libnetfs.h> 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
+
diff --git a/debian/patches/series b/debian/patches/series
index a2db4949..ea689462 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -37,3 +37,4 @@ exec_filename0003-Use-the-new-_hurd_exec_file_name-function.patch
exec_filename0004-This-patch-is-an-amendment-of-exec_filename_exec.pat.patch
gpg0001-trans-add-transparent-GnuPG-translator.patch
crash0001-xxx-crash-logging-works.patch
+flavio0001-Remove-global-netfs-lock-and-use-hard-and-soft-refer.patch