diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-15 02:17:23 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-15 02:17:23 +0200 |
commit | 7ccfc391aa9556193dc145779c972e4d4ac7b187 (patch) | |
tree | 6ae0a86cd7d5a564886e8f7673614fbdcc2319f3 /debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch | |
parent | 567c26ffa6161cbeda3a3a76c0dd9d43020cf77c (diff) |
add patch series
Diffstat (limited to 'debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch')
-rw-r--r-- | debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch | 310 |
1 files changed, 310 insertions, 0 deletions
diff --git a/debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch b/debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch new file mode 100644 index 00000000..02e7fa4f --- /dev/null +++ b/debian/patches/0003-isofs-use-a-seperate-lock-to-protect-node_cache.patch @@ -0,0 +1,310 @@ +From 912151f13737af551d3d3dd2e45faef3bd7c78cb Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Tue, 13 May 2014 15:16:31 +0200 +Subject: [PATCH hurd 03/10] isofs: use a seperate lock to protect node_cache + +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 | 146 +++++++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 105 insertions(+), 41 deletions(-) + +diff --git a/isofs/inode.c b/isofs/inode.c +index 247d8ac..37bf1ac 100644 +--- a/isofs/inode.c ++++ b/isofs/inode.c +@@ -48,35 +48,53 @@ 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; ++/* nodecache_lock must be acquired before diskfs_node_refcnt_lock. */ ++static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; + + /* Forward */ + static error_t read_disknode (struct node *, + struct dirrect *, struct rrip_lookup *); + + ++/* Lookup node with id ID. Returns NULL if the node is not found in ++ the node cache. */ ++static struct node * ++lookup (off_t id) ++{ ++ int i; ++ for (i = 0; i < node_cache_size; i++) ++ if (node_cache[i].id == id ++ && node_cache[i].np) ++ return node_cache[i].np; ++ return NULL; ++} ++ + /* 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 + inode_cache_find (off_t id, struct node **npp) + { +- int i; +- +- for (i = 0; i < node_cache_size; i++) +- if (node_cache[i].id == id +- && node_cache[i].np) +- { +- *npp = node_cache[i].np; +- (*npp)->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- pthread_mutex_lock (&(*npp)->lock); +- return; +- } +- *npp = 0; ++ *npp = lookup (id); ++ if (*npp) ++ { ++ diskfs_nref (*npp); ++ pthread_rwlock_unlock (&nodecache_lock); ++ pthread_mutex_lock (&(*npp)->lock); ++ } + } + + +@@ -92,7 +110,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) +@@ -137,6 +155,7 @@ cache_inode (struct node *np, struct dirrect *record, + c->id = id; + c->dr = record; + c->file_start = np->dn->file_start; ++ diskfs_nref_light (np); + c->np = np; + + /* PLUS 1 so that we don't store zero cache ID's (not allowed by diskfs) */ +@@ -155,7 +174,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; +@@ -166,6 +185,8 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + struct rrip_lookup rr; + struct disknode *dn; + ++ pthread_rwlock_unlock (&nodecache_lock); ++ + rrip_lookup (node_cache[id].dr, &rr, 1); + + /* We should never cache the wrong directory entry */ +@@ -174,7 +195,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 +206,26 @@ 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); ++ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (c->np != NULL) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ np = c->np; ++ goto gotit; ++ } + 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; + +@@ -203,9 +234,9 @@ diskfs_cached_lookup (ino_t id, struct node **npp) + return err; + } + +- +- np->references++; +- pthread_spin_unlock (&diskfs_node_refcnt_lock); ++ gotit: ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); + pthread_mutex_lock (&np->lock); + *npp = np; + return 0; +@@ -307,7 +338,8 @@ load_inode (struct node **npp, struct dirrect *record, + error_t err; + off_t file_start; + struct disknode *dn; +- struct node *np; ++ struct node *np, *tmp; ++ off_t id; + + err = calculate_file_start (record, &file_start, rr); + if (err) +@@ -315,27 +347,23 @@ load_inode (struct node **npp, struct dirrect *record, + if (rr->valid & VALID_CL) + record = rr->realdirent; + +- pthread_spin_lock (&diskfs_node_refcnt_lock); +- + /* First check the cache */ + if (use_file_start_id (record, rr)) +- inode_cache_find (file_start << store->log2_block_size, npp); ++ id = file_start << store->log2_block_size; + else +- inode_cache_find ((off_t) ((void *) record - (void *) disk_image), npp); ++ id = (off_t) ((void *) record - (void *) disk_image); + ++ pthread_rwlock_rdlock (&nodecache_lock); ++ inode_cache_find (id, npp); + if (*npp) +- { +- pthread_spin_unlock (&diskfs_node_refcnt_lock); +- return 0; +- } ++ return 0; ++ pthread_rwlock_unlock (&nodecache_lock); + + /* 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 +372,25 @@ 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); ++ tmp = lookup (id); ++ if (tmp) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ diskfs_nref (tmp); ++ *npp = tmp; ++ pthread_rwlock_unlock (&nodecache_lock); ++ return 0; ++ } ++ + 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 +544,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 +557,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.1.4 + |