summaryrefslogtreecommitdiff
path: root/libnetfs
diff options
context:
space:
mode:
authorFlavio Cruz <flaviocruz@gmail.com>2016-03-15 04:50:02 -0400
committerJustus Winter <justus@gnupg.org>2016-03-21 19:45:11 +0100
commit5eef605eb523e4148ccd22578327492178cfd0c4 (patch)
treeaab9f03896e9acec97d99b5617bf7792f6022f0d /libnetfs
parent0da2914ac9d9321cca2d402b2c505881e436c725 (diff)
netfs: Remove global reference count lock.
* 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.
Diffstat (limited to 'libnetfs')
-rw-r--r--libnetfs/drop-node.c1
-rw-r--r--libnetfs/init-init.c2
-rw-r--r--libnetfs/make-node.c2
-rw-r--r--libnetfs/netfs.h42
-rw-r--r--libnetfs/nput.c27
-rw-r--r--libnetfs/nref.c10
-rw-r--r--libnetfs/nrele.c37
7 files changed, 83 insertions, 38 deletions
diff --git a/libnetfs/drop-node.c b/libnetfs/drop-node.c
index 2fe5ce9f..f0d69be9 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 a088ad51..9ca1aacf 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 6bd8109c..a292dc62 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 67a6a9a0..6c989a48 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 522c714a..b04fc4b0 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 86b49927..a40cf4db 100644
--- a/libnetfs/nref.c
+++ b/libnetfs/nref.c
@@ -23,7 +23,11 @@
void
netfs_nref (struct node *np)
{
- pthread_spin_lock (&netfs_node_refcnt_lock);
- np->references++;
- pthread_spin_unlock (&netfs_node_refcnt_lock);
+ refcounts_ref (&np->refcounts, NULL);
+}
+
+void
+netfs_nref_light (struct node *np)
+{
+ refcounts_ref_weak (&np->refcounts, NULL);
}
diff --git a/libnetfs/nrele.c b/libnetfs/nrele.c
index 6f9a0144..4dddd1f4 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);
}