[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 5/6] isofs: use a seperate lock to protect node_cache
From: |
Justus Winter |
Subject: |
[PATCH 5/6] isofs: use a seperate lock to protect node_cache |
Date: |
Sun, 1 Jun 2014 22:03:03 +0200 |
Previously, isofs used diskfs_node_refcnt_lock to serialize access to
the node_cache.
Use a separate lock to protect node_cache. Adjust the reference
counting accordingly. Every node in the node_cache carries a light
reference. When we are asked to give up that light reference, we
reacquire our lock momentarily to check whether someone else
reacquired a reference through the node_cache.
* isofs/inode.c (nodecache_lock): New lock.
(inode_cache_find): Use a separate lock to protect node_cache.
Adjust the reference counting accordingly.
(diskfs_cached_lookup): Likewise.
(load_inode): Likewise.
(cache_inode): Update comment accordingly.
(diskfs_node_iterate): Likewise.
(diskfs_node_norefs): Move the code removing the node from node_cache...
(diskfs_try_dropping_softrefs): ... here, where we check whether
someone reacquired a reference, and if so hold on to our light
reference.
---
isofs/inode.c | 83 +++++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 58 insertions(+), 25 deletions(-)
diff --git a/isofs/inode.c b/isofs/inode.c
index cdc05ae..010d724 100644
--- a/isofs/inode.c
+++ b/isofs/inode.c
@@ -48,9 +48,19 @@ struct node_cache
struct node *np; /* if live */
};
+/* The node_cache is a cache of nodes.
+
+ Access to node_cache, node_cache_size, and node_cache_alloced is
+ protected by nodecache_lock.
+
+ Every node in the node_cache carries a light reference. When we
+ are asked to give up that light reference, we reacquire our lock
+ momentarily to check whether someone else reacquired a reference
+ through the node_cache. */
static int node_cache_size = 0;
static int node_cache_alloced = 0;
struct node_cache *node_cache = 0;
+static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER;
/* Forward */
static error_t read_disknode (struct node *,
@@ -58,7 +68,7 @@ static error_t read_disknode (struct node *,
/* See if node with identifier ID is in the cache. If so, return it,
- with one additional reference. diskfs_node_refcnt_lock must be held
+ with one additional reference. nodecache_lock must be held
on entry to the call, and will be released iff the node was found
in the cache. */
void
@@ -71,8 +81,8 @@ inode_cache_find (off_t id, struct node **npp)
&& node_cache[i].np)
{
*npp = node_cache[i].np;
- (*npp)->references++;
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
+ diskfs_nref (*npp);
+ pthread_rwlock_unlock (&nodecache_lock);
pthread_mutex_lock (&(*npp)->lock);
return;
}
@@ -92,7 +102,7 @@ use_file_start_id (struct dirrect *record, struct
rrip_lookup *rr)
}
/* Enter NP into the cache. The directory entry we used is DR, the
- cached Rock-Ridge info RR. diskfs_node_refcnt_lock must be held. */
+ cached Rock-Ridge info RR. nodecache_lock must be held. */
void
cache_inode (struct node *np, struct dirrect *record,
struct rrip_lookup *rr)
@@ -155,7 +165,7 @@ diskfs_cached_lookup (ino_t id, struct node **npp)
to avoid presenting zero cache ID's. */
id--;
- pthread_spin_lock (&diskfs_node_refcnt_lock);
+ pthread_rwlock_rdlock (&nodecache_lock);
assert (id < node_cache_size);
np = node_cache[id].np;
@@ -174,7 +184,7 @@ diskfs_cached_lookup (ino_t id, struct node **npp)
dn = malloc (sizeof (struct disknode));
if (!dn)
{
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
+ pthread_rwlock_unlock (&nodecache_lock);
release_rrip (&rr);
return ENOMEM;
}
@@ -185,16 +195,17 @@ diskfs_cached_lookup (ino_t id, struct node **npp)
if (!np)
{
free (dn);
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
+ pthread_rwlock_unlock (&nodecache_lock);
release_rrip (&rr);
return ENOMEM;
}
np->cache_id = id + 1; /* see above for rationale for increment */
pthread_mutex_lock (&np->lock);
c->np = np;
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
+ diskfs_nref_light (np);
+ pthread_rwlock_unlock (&nodecache_lock);
- err = read_disknode (np, node_cache[id].dr, &rr);
+ err = read_disknode (np, dn->dr, &rr);
if (!err)
*npp = np;
@@ -204,8 +215,8 @@ diskfs_cached_lookup (ino_t id, struct node **npp)
}
- np->references++;
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
+ diskfs_nref (np);
+ pthread_rwlock_unlock (&nodecache_lock);
pthread_mutex_lock (&np->lock);
*npp = np;
return 0;
@@ -315,7 +326,7 @@ load_inode (struct node **npp, struct dirrect *record,
if (rr->valid & VALID_CL)
record = rr->realdirent;
- pthread_spin_lock (&diskfs_node_refcnt_lock);
+ pthread_rwlock_rdlock (&nodecache_lock);
/* First check the cache */
if (use_file_start_id (record, rr))
@@ -323,19 +334,16 @@ load_inode (struct node **npp, struct dirrect *record,
else
inode_cache_find ((off_t) ((void *) record - (void *) disk_image), npp);
+ pthread_rwlock_unlock (&nodecache_lock);
+
if (*npp)
- {
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
- return 0;
- }
+ return 0;
/* Create a new node */
dn = malloc (sizeof (struct disknode));
if (!dn)
- {
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
- return ENOMEM;
- }
+ return ENOMEM;
+
dn->fileinfo = 0;
dn->dr = record;
dn->file_start = file_start;
@@ -344,14 +352,14 @@ load_inode (struct node **npp, struct dirrect *record,
if (!np)
{
free (dn);
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
return ENOMEM;
}
pthread_mutex_lock (&np->lock);
+ pthread_rwlock_wrlock (&nodecache_lock);
cache_inode (np, record, rr);
- pthread_spin_unlock (&diskfs_node_refcnt_lock);
+ pthread_rwlock_unlock (&nodecache_lock);
err = read_disknode (np, record, rr);
*npp = np;
@@ -505,9 +513,6 @@ error_t (*diskfs_read_symlink_hook) (struct node *, char *)
void
diskfs_node_norefs (struct node *np)
{
- assert (node_cache[np->cache_id - 1].np == np);
- node_cache[np->cache_id - 1].np = 0;
-
if (np->dn->translator)
free (np->dn->translator);
@@ -521,6 +526,34 @@ diskfs_node_norefs (struct node *np)
void
diskfs_try_dropping_softrefs (struct node *np)
{
+ pthread_rwlock_wrlock (&nodecache_lock);
+ if (np->cache_id != 0)
+ {
+ assert (node_cache[np->cache_id - 1].np == np);
+
+ /* Check if someone reacquired a reference through the
+ node_cache. */
+ unsigned int references;
+ pthread_spin_lock (&diskfs_node_refcnt_lock);
+ references = np->references;
+ pthread_spin_unlock (&diskfs_node_refcnt_lock);
+
+ /* An additional reference is acquired by libdiskfs across calls
+ to diskfs_try_dropping_softrefs. */
+ if (references > 1)
+ {
+ /* A reference was reacquired through a hash table lookup.
+ It's fine, we didn't touch anything yet. */
+ pthread_rwlock_unlock (&nodecache_lock);
+ return;
+ }
+
+ node_cache[np->cache_id - 1].np = 0;
+ np->cache_id = 0;
+ diskfs_nrele_light (np);
+ }
+ pthread_rwlock_unlock (&nodecache_lock);
+
drop_pager_softrefs (np);
}
--
2.0.0.rc2