summaryrefslogtreecommitdiff
path: root/debian/patches/0014-ext2fs-use-librdxtree-for-the-nodehash.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/0014-ext2fs-use-librdxtree-for-the-nodehash.patch')
-rw-r--r--debian/patches/0014-ext2fs-use-librdxtree-for-the-nodehash.patch308
1 files changed, 308 insertions, 0 deletions
diff --git a/debian/patches/0014-ext2fs-use-librdxtree-for-the-nodehash.patch b/debian/patches/0014-ext2fs-use-librdxtree-for-the-nodehash.patch
new file mode 100644
index 00000000..fb3ca46e
--- /dev/null
+++ b/debian/patches/0014-ext2fs-use-librdxtree-for-the-nodehash.patch
@@ -0,0 +1,308 @@
+From a02756d13bc21f7a12573a71b38a08ef7b02e8a6 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Wed, 14 May 2014 15:30:19 +0200
+Subject: [PATCH 14/14] ext2fs: use librdxtree for the nodehash
+
+Previously, a lookup of a node through nodehash took O(N / INOHSZ).
+With INOHSZ being a constant (512) this is linear in N. Use a radix
+tree instead, which gives us a lookup in time linear with the size of
+keys.
+
+* ext2fs/inode.c (INOHSZ, INOHASH): Remove.
+(nodehash): Use a radix tree.
+(inode_init): Remove.
+(diskfs_cached_lookup): Adjust accordingly.
+(ifind, diskfs_try_dropping_softrefs, diskfs_node_iterate): Likewise.
+* ext2fs/ext2fs.h (struct disknode): Remove list pointers.
+* ext2fs/ext2fs.c (main): Drop inode_init.
+---
+ ext2fs/Makefile | 2 +-
+ ext2fs/ext2fs.c | 2 -
+ ext2fs/ext2fs.h | 4 +-
+ ext2fs/inode.c | 121 +++++++++++++++++++++-----------------------------------
+ 4 files changed, 48 insertions(+), 81 deletions(-)
+
+diff --git a/ext2fs/Makefile b/ext2fs/Makefile
+index 8d2e68c..f93d696 100644
+--- a/ext2fs/Makefile
++++ b/ext2fs/Makefile
+@@ -23,7 +23,7 @@ target = ext2fs
+ SRCS = balloc.c dir.c ext2fs.c getblk.c hyper.c ialloc.c \
+ inode.c pager.c pokel.c truncate.c storeinfo.c msg.c xinl.c
+ OBJS = $(SRCS:.c=.o)
+-HURDLIBS = diskfs pager iohelp fshelp store ports ihash shouldbeinlibc
++HURDLIBS = diskfs pager iohelp fshelp store ports ihash rdxtree shouldbeinlibc
+ OTHERLIBS = -lpthread $(and $(HAVE_LIBBZ2),-lbz2) $(and $(HAVE_LIBZ),-lz)
+
+ include ../Makeconf
+diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c
+index 128b6ed..0409dfb 100644
+--- a/ext2fs/ext2fs.c
++++ b/ext2fs/ext2fs.c
+@@ -185,8 +185,6 @@ main (int argc, char **argv)
+
+ map_hypermetadata ();
+
+- inode_init ();
+-
+ /* Set diskfs_root_node to the root inode. */
+ err = diskfs_cached_lookup (EXT2_ROOT_INO, &diskfs_root_node);
+ if (err)
+diff --git a/ext2fs/ext2fs.h b/ext2fs/ext2fs.h
+index 3422af2..8eaa846 100644
+--- a/ext2fs/ext2fs.h
++++ b/ext2fs/ext2fs.h
+@@ -26,6 +26,7 @@
+ #include <hurd/store.h>
+ #include <hurd/diskfs.h>
+ #include <hurd/ihash.h>
++#include <hurd/rdxtree.h>
+ #include <assert.h>
+ #include <pthread.h>
+ #include <sys/mman.h>
+@@ -159,9 +160,6 @@ struct disknode
+ each DIRBLKSIZE piece of the directory. */
+ int *dirents;
+
+- /* Links on hash list. */
+- struct node *hnext, **hprevp;
+-
+ /* Lock to lock while fiddling with this inode's block allocation info. */
+ pthread_rwlock_t alloc_lock;
+
+diff --git a/ext2fs/inode.c b/ext2fs/inode.c
+index 7ec343f..fea39ae 100644
+--- a/ext2fs/inode.c
++++ b/ext2fs/inode.c
+@@ -20,6 +20,7 @@
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+ #include "ext2fs.h"
++#include <stddef.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <stdio.h>
+@@ -39,13 +40,6 @@
+ #define UF_IMMUTABLE 0
+ #endif
+
+-#define INOHSZ 512
+-#if ((INOHSZ&(INOHSZ-1)) == 0)
+-#define INOHASH(ino) ((ino)&(INOHSZ-1))
+-#else
+-#define INOHASH(ino) (((unsigned)(ino))%INOHSZ)
+-#endif
+-
+ /* The nodehash is a cache of nodes.
+
+ Access to nodehash and nodehash_nr_items is protected by
+@@ -55,23 +49,14 @@
+ asked to give up that light reference, we reacquire our lock
+ momentarily to check whether someone else reacquired a reference
+ through the nodehash. */
+-static struct node *nodehash[INOHSZ];
++static struct rdxtree nodecache = RDXTREE_INITIALIZER;
+ static size_t nodehash_nr_items;
+-static pthread_mutex_t nodehash_lock = PTHREAD_MUTEX_INITIALIZER;
++static pthread_mutex_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER;
+
+ static error_t read_node (struct node *np);
+
+ pthread_spinlock_t generation_lock = PTHREAD_SPINLOCK_INITIALIZER;
+
+-/* Initialize the inode hash table. */
+-void
+-inode_init ()
+-{
+- int n;
+- for (n = 0; n < INOHSZ; n++)
+- nodehash[n] = 0;
+-}
+-
+ /* Fetch inode INUM, set *NPP to the node structure;
+ gain one user reference and lock the node. */
+ error_t
+@@ -81,46 +66,40 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
+ struct node *np;
+ struct disknode *dn;
+
+- pthread_mutex_lock (&nodehash_lock);
+- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+- if (np->cache_id == inum)
+- {
+- diskfs_nref (np);
+- pthread_mutex_unlock (&nodehash_lock);
+- pthread_mutex_lock (&np->lock);
+- *npp = np;
+- return 0;
+- }
+-
+- /* Format specific data for the new node. */
+- dn = malloc (sizeof (struct disknode));
+- if (! dn)
++ pthread_rwlock_rdlock (&nodecache_lock);
++ np = rdxtree_lookup (&nodecache, inum);
++ if (np != NULL)
++ {
++ diskfs_nref (np);
++ pthread_rwlock_unlock (&nodecache_lock);
++ pthread_mutex_lock (&np->lock);
++ *npp = np;
++ return 0;
++ }
++ pthread_rwlock_unlock (&nodecache_lock);
++
++ /* Create the new node. */
++ np = diskfs_make_node_alloc (sizeof *dn);
++ if (np == NULL)
+ {
+- pthread_mutex_unlock (&nodehash_lock);
++ pthread_mutex_unlock (&nodecache_lock);
+ return ENOMEM;
+ }
++ np->cache_id = inum;
++ dn = diskfs_node_disknode (np);
+ dn->dirents = 0;
+ dn->dir_idx = 0;
+ dn->pager = 0;
+ pthread_rwlock_init (&dn->alloc_lock, NULL);
+ pokel_init (&dn->indir_pokel, diskfs_disk_pager, disk_cache);
+-
+- /* Create the new node. */
+- np = diskfs_make_node (dn);
+- np->cache_id = inum;
+-
+ pthread_mutex_lock (&np->lock);
+
+ /* Put NP in NODEHASH. */
+- dn->hnext = nodehash[INOHASH(inum)];
+- if (dn->hnext)
+- dn->hnext->dn->hprevp = &dn->hnext;
+- dn->hprevp = &nodehash[INOHASH(inum)];
+- nodehash[INOHASH(inum)] = np;
+ diskfs_nref_light (np);
++ pthread_rwlock_wrlock (&nodecache_lock);
++ rdxtree_insert (&nodecache, inum, np);
+ nodehash_nr_items += 1;
+-
+- pthread_mutex_unlock (&nodehash_lock);
++ pthread_rwlock_unlock (&nodecache_lock);
+
+ /* Get the contents of NP off disk. */
+ err = read_node (np);
+@@ -151,16 +130,12 @@ ifind (ino_t inum)
+ {
+ struct node *np;
+
+- pthread_mutex_lock (&nodehash_lock);
+- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
+- {
+- if (np->cache_id != inum)
+- continue;
++ pthread_rwlock_rdlock (&nodecache_lock);
++ np = rdxtree_lookup (&nodecache, inum);
++ pthread_rwlock_unlock (&nodecache_lock);
+
+- pthread_mutex_unlock (&nodehash_lock);
+- return np;
+- }
+- assert (0);
++ assert (np);
++ return np;
+ }
+
+ /* The last reference to a node has gone away; drop
+@@ -176,7 +151,6 @@ diskfs_node_norefs (struct node *np)
+ pokel_inherit (&global_pokel, &np->dn->indir_pokel);
+ pokel_finalize (&np->dn->indir_pokel);
+
+- free (np->dn);
+ free (np);
+ }
+
+@@ -185,8 +159,8 @@ diskfs_node_norefs (struct node *np)
+ void
+ diskfs_try_dropping_softrefs (struct node *np)
+ {
+- pthread_mutex_lock (&nodehash_lock);
+- if (np->dn->hnext != NULL)
++ pthread_rwlock_wrlock (&nodecache_lock);
++ if (np->cache_id != 0)
+ {
+ /* Check if someone reacquired a reference through the
+ nodehash. */
+@@ -196,18 +170,16 @@ diskfs_try_dropping_softrefs (struct node *np)
+ {
+ /* A reference was reacquired through a hash table lookup.
+ It's fine, we didn't touch anything yet. */
+- pthread_mutex_unlock (&nodehash_lock);
++ pthread_rwlock_unlock (&nodecache_lock);
+ return;
+ }
+
+- *np->dn->hprevp = np->dn->hnext;
+- if (np->dn->hnext)
+- np->dn->hnext->dn->hprevp = np->dn->hprevp;
+- np->dn->hnext = NULL;
++ rdxtree_remove (&nodecache, np->cache_id);
+ nodehash_nr_items -= 1;
++ np->cache_id = 0;
+ diskfs_nrele_light (np);
+ }
+- pthread_mutex_unlock (&nodehash_lock);
++ pthread_rwlock_unlock (&nodecache_lock);
+
+ drop_pager_softrefs (np);
+ }
+@@ -581,16 +553,16 @@ error_t
+ diskfs_node_iterate (error_t (*fun)(struct node *))
+ {
+ error_t err = 0;
+- int n;
++ struct rdxtree_iter iter;
+ size_t num_nodes;
+ struct node *node, **node_list, **p;
+
+- pthread_mutex_lock (&nodehash_lock);
++ pthread_rwlock_rdlock (&nodecache_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
+- nodehash_lock, but we can't hold this while locking the
++ nodecache_lock, but we can't hold this while locking the
+ individual node locks). */
+ num_nodes = nodehash_nr_items;
+
+@@ -599,20 +571,19 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
+ node_list = malloc (num_nodes * sizeof (struct node *));
+ if (node_list == NULL)
+ {
+- pthread_mutex_unlock (&nodehash_lock);
++ pthread_rwlock_unlock (&nodecache_lock);
+ ext2_debug ("unable to allocate temporary node table");
+ return ENOMEM;
+ }
+
+ p = node_list;
+- for (n = 0; n < INOHSZ; n++)
+- for (node = nodehash[n]; node; node = node->dn->hnext)
+- {
+- *p++ = node;
+- diskfs_nref (node);
+- }
+-
+- pthread_mutex_unlock (&nodehash_lock);
++ rdxtree_for_each (&nodecache, &iter, node)
++ {
++ *p++ = node;
++ diskfs_nref (node);
++ }
++
++ pthread_rwlock_unlock (&nodecache_lock);
+
+ p = node_list;
+ while (num_nodes-- > 0)
+--
+2.0.0.rc2
+