bug-hurd
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]