diff options
author | Justus Winter <justus@gnupg.org> | 2016-03-07 00:40:25 +0100 |
---|---|---|
committer | Justus Winter <justus@gnupg.org> | 2016-03-07 00:40:25 +0100 |
commit | 852301b1c6072c72bc010f9c201df5dd36284462 (patch) | |
tree | b36869bcfc3e9dcc88f57b652817ea890ab94959 | |
parent | 918d1166a87d4111ddefb477c9a45ee1c2dce169 (diff) |
add patch series
-rw-r--r-- | debian/patches/flavio0001-Remove-global-netfs-lock-and-use-hard-and-soft-refer.patch | 775 | ||||
-rw-r--r-- | debian/patches/series | 1 |
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 |