summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-12 15:55:27 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-12 15:55:27 +0200
commit81392d0937737682bbbbfa462a185dcb2dc8dd62 (patch)
tree9225ff62560850aaf53212e946bd15c0ff710d66
parentcef7f9f811be1b5201f8fd68c78747119a066245 (diff)
add ext2fs-nodehash-lock.patch
-rw-r--r--debian/patches/ext2fs-nodehash-lock.patch147
-rw-r--r--debian/patches/series1
2 files changed, 148 insertions, 0 deletions
diff --git a/debian/patches/ext2fs-nodehash-lock.patch b/debian/patches/ext2fs-nodehash-lock.patch
new file mode 100644
index 00000000..2c63643c
--- /dev/null
+++ b/debian/patches/ext2fs-nodehash-lock.patch
@@ -0,0 +1,147 @@
+diff --git a/ext2fs/inode.c b/ext2fs/inode.c
+index ed78265..2264034 100644
+--- a/ext2fs/inode.c
++++ b/ext2fs/inode.c
+@@ -48,6 +48,7 @@
+
+ static struct node *nodehash[INOHSZ];
+ static size_t nodehash_nr_items;
++static pthread_mutex_t nodehash_lock = PTHREAD_MUTEX_INITIALIZER;
+
+ static error_t read_node (struct node *np);
+
+@@ -71,12 +72,12 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
+ struct node *np;
+ struct disknode *dn;
+
+- pthread_spin_lock (&diskfs_node_refcnt_lock);
++ pthread_mutex_lock (&nodehash_lock);
+ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+ if (np->cache_id == inum)
+ {
+- np->references++;
+- pthread_spin_unlock (&diskfs_node_refcnt_lock);
++ diskfs_nref (np);
++ pthread_mutex_unlock (&nodehash_lock);
+ pthread_mutex_lock (&np->lock);
+ *npp = np;
+ return 0;
+@@ -86,7 +87,7 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
+ dn = malloc (sizeof (struct disknode));
+ if (! dn)
+ {
+- pthread_spin_unlock (&diskfs_node_refcnt_lock);
++ pthread_mutex_unlock (&nodehash_lock);
+ return ENOMEM;
+ }
+ dn->dirents = 0;
+@@ -107,9 +108,10 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
+ dn->hnext->dn->hprevp = &dn->hnext;
+ dn->hprevp = &nodehash[INOHASH(inum)];
+ nodehash[INOHASH(inum)] = np;
++ diskfs_nref_light (np);
+ nodehash_nr_items += 1;
+
+- pthread_spin_unlock (&diskfs_node_refcnt_lock);
++ pthread_mutex_unlock (&nodehash_lock);
+
+ /* Get the contents of NP off disk. */
+ err = read_node (np);
+@@ -140,14 +142,13 @@ ifind (ino_t inum)
+ {
+ struct node *np;
+
+- pthread_spin_lock (&diskfs_node_refcnt_lock);
++ pthread_mutex_lock (&nodehash_lock);
+ for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+ {
+ if (np->cache_id != inum)
+ continue;
+
+- assert (np->references);
+- pthread_spin_unlock (&diskfs_node_refcnt_lock);
++ pthread_mutex_unlock (&nodehash_lock);
+ return np;
+ }
+ assert (0);
+@@ -158,11 +159,6 @@ ifind (ino_t inum)
+ void
+ diskfs_node_norefs (struct node *np)
+ {
+- *np->dn->hprevp = np->dn->hnext;
+- if (np->dn->hnext)
+- np->dn->hnext->dn->hprevp = np->dn->hprevp;
+- nodehash_nr_items -= 1;
+-
+ if (np->dn->dirents)
+ free (np->dn->dirents);
+ assert (!np->dn->pager);
+@@ -180,6 +176,31 @@ diskfs_node_norefs (struct node *np)
+ void
+ diskfs_try_dropping_softrefs (struct node *np)
+ {
++ pthread_mutex_lock (&nodehash_lock);
++ if (np->dn->hnext != NULL)
++ {
++ /* Check if someone reacquired a reference through the
++ nodehash. */
++ unsigned int references;
++ pthread_spin_lock (&diskfs_node_refcnt_lock);
++ references = np->references;
++ pthread_spin_unlock (&diskfs_node_refcnt_lock);
++
++ if (references > 0)
++ {
++ pthread_mutex_unlock (&nodehash_lock);
++ return;
++ }
++
++ *np->dn->hprevp = np->dn->hnext;
++ if (np->dn->hnext)
++ np->dn->hnext->dn->hprevp = np->dn->hprevp;
++ np->dn->hnext = NULL;
++ nodehash_nr_items -= 1;
++ diskfs_nrele_light (np);
++ }
++ pthread_mutex_unlock (&nodehash_lock);
++
+ drop_pager_softrefs (np);
+ }
+
+@@ -556,12 +577,12 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
+ size_t num_nodes;
+ struct node *node, **node_list, **p;
+
+- pthread_spin_lock (&diskfs_node_refcnt_lock);
++ pthread_mutex_lock (&nodehash_lock);
+
+ /* We must copy everything from the hash table into another data structure
+ to avoid running into any problems with the hash-table being modified
+ during processing (normally we delegate access to hash-table with
+- diskfs_node_refcnt_lock, but we can't hold this while locking the
++ nodehash_lock, but we can't hold this while locking the
+ individual node locks). */
+ num_nodes = nodehash_nr_items;
+
+@@ -570,7 +591,7 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
+ node_list = malloc (num_nodes * sizeof (struct node *));
+ if (node_list == NULL)
+ {
+- pthread_spin_unlock (&diskfs_node_refcnt_lock);
++ pthread_mutex_unlock (&nodehash_lock);
+ ext2_debug ("unable to allocate temporary node table");
+ return ENOMEM;
+ }
+@@ -580,10 +601,10 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
+ for (node = nodehash[n]; node; node = node->dn->hnext)
+ {
+ *p++ = node;
+- node->references++;
++ diskfs_nref (node);
+ }
+
+- pthread_spin_unlock (&diskfs_node_refcnt_lock);
++ pthread_mutex_unlock (&nodehash_lock);
+
+ p = node_list;
+ while (num_nodes-- > 0)
diff --git a/debian/patches/series b/debian/patches/series
index 1c6ce664..7189b96c 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -52,3 +52,4 @@ ext2fs-cache-superblock.patch
0009-ext2fs-improve-enable-disable-_caching.patch
0010-fatfs-improve-enable-disable-_caching.patch
+ext2fs-nodehash-lock.patch