summaryrefslogtreecommitdiff
path: root/debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-18 14:20:17 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2014-05-18 14:20:17 +0200
commitf902a475b6252a91c77e7f77b6e1eccc2ee781ec (patch)
tree43a3c131a66a150bbbf9dee954d18537abcef54c /debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch
parent84e6742d184b1ac41df1b00ac666e63a41632a98 (diff)
add patch series
Diffstat (limited to 'debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch')
-rw-r--r--debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch314
1 files changed, 314 insertions, 0 deletions
diff --git a/debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch b/debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch
new file mode 100644
index 00000000..fee4854f
--- /dev/null
+++ b/debian/patches/0016-ext2fs-use-librbtree-for-the-nodehash.patch
@@ -0,0 +1,314 @@
+From 54e3e8084aad34ddcd74aea215d83eb3f641d248 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 16/16] ext2fs: use librbtree 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
+red-black tree instead, which guarantees a lookup performance in
+O(log N) time.
+
+* ext2fs/inode.c (INOHSZ, INOHASH): Remove.
+(nodehash): Use a red-black tree.
+(node_cmp_lookup, node_cmp_insert, node_get_np): New functions.
+(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, add
+red-black tree node. Because we store disknode objects in the tree,
+we also need a pointer to the node object, and the cache_id for
+efficient operations on the rb tree.
+* ext2fs/ext2fs.c (main): Drop inode_init.
+---
+ ext2fs/Makefile | 2 +-
+ ext2fs/ext2fs.c | 2 -
+ ext2fs/ext2fs.h | 7 ++--
+ ext2fs/inode.c | 124 +++++++++++++++++++++++++++++---------------------------
+ 4 files changed, 70 insertions(+), 65 deletions(-)
+
+diff --git a/ext2fs/Makefile b/ext2fs/Makefile
+index 8d2e68c..b075dc0 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 rbtree 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..3505bb7 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/rbtree.h>
+ #include <assert.h>
+ #include <pthread.h>
+ #include <sys/mman.h>
+@@ -155,13 +156,13 @@ clear_bit (unsigned num, char *bitmap)
+ /* ext2fs specific per-file data. */
+ struct disknode
+ {
++ /* Red-black-tree node for the node cache. */
++ struct rbtree_node tree_node;
++
+ /* For a directory, this array holds the number of directory entries in
+ 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..0142bf6 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,45 @@
+ 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 rbtree nodehash = RBTREE_INITIALIZER;
+ static size_t nodehash_nr_items;
+ static pthread_mutex_t nodehash_lock = PTHREAD_MUTEX_INITIALIZER;
+
+-static error_t read_node (struct node *np);
++static inline struct node *
++node_get_np (const struct rbtree_node *node)
++{
++ struct disknode *dn;
+
+-pthread_spinlock_t generation_lock = PTHREAD_SPINLOCK_INITIALIZER;
++ dn = rbtree_entry (node, struct disknode, tree_node);
+
+-/* Initialize the inode hash table. */
+-void
+-inode_init ()
++ return diskfs_disknode_node (dn);
++}
++
++static inline int
++node_cmp_lookup (const ino_t inum,
++ const struct rbtree_node *node)
+ {
+- int n;
+- for (n = 0; n < INOHSZ; n++)
+- nodehash[n] = 0;
++ struct node *np = node_get_np (node);
++
++ if (inum == np->cache_id)
++ return 0;
++ else if (inum < np->cache_id)
++ return -1;
++ else
++ return 1;
+ }
+
++static inline int
++node_cmp_insert (const struct rbtree_node *a,
++ const struct rbtree_node *b)
++{
++ return node_cmp_lookup (node_get_np (a)->cache_id, b);
++}
++
++static error_t read_node (struct node *np);
++
++pthread_spinlock_t generation_lock = PTHREAD_SPINLOCK_INITIALIZER;
++
+ /* Fetch inode INUM, set *NPP to the node structure;
+ gain one user reference and lock the node. */
+ error_t
+@@ -79,47 +95,42 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
+ {
+ error_t err;
+ struct node *np;
++ struct rbtree_node *node;
++ unsigned long slot;
+ 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)
++ node = rbtree_lookup_slot (&nodehash, inum, node_cmp_lookup, slot);
++ if (node != NULL)
++ {
++ np = node_get_np (node);
++ diskfs_nref (np);
++ pthread_mutex_unlock (&nodehash_lock);
++ pthread_mutex_lock (&np->lock);
++ *npp = np;
++ return 0;
++ }
++
++ /* Create the new node. */
++ np = diskfs_make_node_alloc (sizeof *dn);
++ if (np == NULL)
+ {
+ pthread_mutex_unlock (&nodehash_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);
++ rbtree_insert_slot (&nodehash, slot, &dn->tree_node);
+ nodehash_nr_items += 1;
+-
+ pthread_mutex_unlock (&nodehash_lock);
+
+ /* Get the contents of NP off disk. */
+@@ -149,16 +160,14 @@ diskfs_cached_lookup (ino_t inum, struct node **npp)
+ struct node *
+ ifind (ino_t inum)
+ {
+- struct node *np;
++ struct rbtree_node *node;
+
+ pthread_mutex_lock (&nodehash_lock);
+- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
++ node = rbtree_lookup (&nodehash, inum, node_cmp_lookup);
++ if (node != NULL)
+ {
+- if (np->cache_id != inum)
+- continue;
+-
+ pthread_mutex_unlock (&nodehash_lock);
+- return np;
++ return node_get_np (node);
+ }
+ assert (0);
+ }
+@@ -176,7 +185,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);
+ }
+
+@@ -186,7 +194,7 @@ void
+ diskfs_try_dropping_softrefs (struct node *np)
+ {
+ pthread_mutex_lock (&nodehash_lock);
+- if (np->dn->hnext != NULL)
++ if (np->cache_id != 0)
+ {
+ /* Check if someone reacquired a reference through the
+ nodehash. */
+@@ -200,11 +208,9 @@ diskfs_try_dropping_softrefs (struct node *np)
+ return;
+ }
+
+- *np->dn->hprevp = np->dn->hnext;
+- if (np->dn->hnext)
+- np->dn->hnext->dn->hprevp = np->dn->hprevp;
+- np->dn->hnext = NULL;
++ rbtree_remove (&nodehash, &(diskfs_node_disknode (np))->tree_node);
+ nodehash_nr_items -= 1;
++ np->cache_id = 0;
+ diskfs_nrele_light (np);
+ }
+ pthread_mutex_unlock (&nodehash_lock);
+@@ -581,7 +587,7 @@ error_t
+ diskfs_node_iterate (error_t (*fun)(struct node *))
+ {
+ error_t err = 0;
+- int n;
++ struct rbtree_node *n;
+ size_t num_nodes;
+ struct node *node, **node_list, **p;
+
+@@ -605,12 +611,12 @@ diskfs_node_iterate (error_t (*fun)(struct node *))
+ }
+
+ p = node_list;
+- for (n = 0; n < INOHSZ; n++)
+- for (node = nodehash[n]; node; node = node->dn->hnext)
+- {
+- *p++ = node;
+- diskfs_nref (node);
+- }
++ for (n = rbtree_first (&nodehash); n; n = rbtree_next (n))
++ {
++ node = node_get_np (n);
++ *p++ = node;
++ diskfs_nref (node);
++ }
+
+ pthread_mutex_unlock (&nodehash_lock);
+
+--
+2.0.0.rc2
+