diff options
author | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-16 16:12:19 +0200 |
---|---|---|
committer | Justus Winter <4winter@informatik.uni-hamburg.de> | 2015-04-16 16:12:19 +0200 |
commit | 08f35d5a5b978a6461a5f92f2aeadf2b2a37ea45 (patch) | |
tree | f77d73c57c7785340e4c66f20e9e71f2cbc2ffa1 /debian/patches/0010-libdiskfs-implement-a-node-cache.patch | |
parent | 5d93815af69fd98a5851d22ed48e25ade93ba3ff (diff) |
add patch series
Diffstat (limited to 'debian/patches/0010-libdiskfs-implement-a-node-cache.patch')
-rw-r--r-- | debian/patches/0010-libdiskfs-implement-a-node-cache.patch | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/debian/patches/0010-libdiskfs-implement-a-node-cache.patch b/debian/patches/0010-libdiskfs-implement-a-node-cache.patch new file mode 100644 index 00000000..c0c42926 --- /dev/null +++ b/debian/patches/0010-libdiskfs-implement-a-node-cache.patch @@ -0,0 +1,687 @@ +From 2bb8bfa49d35ab2f7b33587e59c4a9c635642ea0 Mon Sep 17 00:00:00 2001 +From: Justus Winter <4winter@informatik.uni-hamburg.de> +Date: Wed, 15 Apr 2015 13:17:06 +0200 +Subject: [PATCH hurd 10/16] libdiskfs: implement a node cache + +xxx + +Move the node cache from ext2fs into libdiskfs. + +* ext2fs/dir.c +* ext2fs/ext2fs.c +* ext2fs/ext2fs.h +* ext2fs/inode.c +* libdiskfs/Makefile +* libdiskfs/diskfs.h +* libdiskfs/node-cache.c +--- + ext2fs/dir.c | 4 +- + ext2fs/ext2fs.c | 2 - + ext2fs/ext2fs.h | 9 -- + ext2fs/inode.c | 228 ++++---------------------------------------- + libdiskfs/Makefile | 2 +- + libdiskfs/diskfs.h | 17 ++++ + libdiskfs/node-cache.c | 249 +++++++++++++++++++++++++++++++++++++++++++++++++ + 7 files changed, 289 insertions(+), 222 deletions(-) + create mode 100644 libdiskfs/node-cache.c + +diff --git a/ext2fs/dir.c b/ext2fs/dir.c +index 2dfe1d7..6cdfba2 100644 +--- a/ext2fs/dir.c ++++ b/ext2fs/dir.c +@@ -306,7 +306,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + + /* Here below are the spec dotdot cases. */ + else if (type == RENAME || type == REMOVE) +- np = ifind (inum); ++ np = diskfs_cached_ifind (inum); + + else if (type == LOOKUP) + { +@@ -359,7 +359,7 @@ diskfs_lookup_hard (struct node *dp, const char *name, enum lookup_type type, + diskfs_nput (np); + } + else if (type == RENAME || type == REMOVE) +- /* We just did ifind to get np; that allocates ++ /* We just did diskfs_cached_ifind to get np; that allocates + no new references, so we don't have anything to do */ + ; + else if (type == LOOKUP) +diff --git a/ext2fs/ext2fs.c b/ext2fs/ext2fs.c +index beb7cad..d0fdfe7 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 9667b6f..96d8e9d 100644 +--- a/ext2fs/ext2fs.h ++++ b/ext2fs/ext2fs.h +@@ -159,9 +159,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; + +@@ -419,12 +416,6 @@ dino_deref (struct ext2_inode *inode) + + /* Write all active disknodes into the inode pager. */ + void write_all_disknodes (); +- +-/* Lookup node INUM (which must have a reference already) and return it +- without allocating any new references. */ +-struct node *ifind (ino_t inum); +- +-void inode_init (void); + + /* ---------------------------------------------------------------- */ + +diff --git a/ext2fs/inode.c b/ext2fs/inode.c +index 7af617c..22a0c8e 100644 +--- a/ext2fs/inode.c ++++ b/ext2fs/inode.c +@@ -39,144 +39,34 @@ + #define UF_IMMUTABLE 0 + #endif + +-#define INOHSZ 8192 +-#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 +- nodecache_lock. +- +- Every node in the nodehash 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 nodehash. */ +-static struct node *nodehash[INOHSZ]; +-static size_t nodehash_nr_items; +-static pthread_rwlock_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; +-} +- +-/* Lookup node with inode number INUM. Returns NULL if the node is +- not found in the node cache. */ +-static struct node * +-lookup (ino_t inum) +-{ +- struct node *np; +- for (np = nodehash[INOHASH(inum)]; np; np = diskfs_node_disknode (np)->hnext) +- if (np->cache_id == inum) +- return np; +- return NULL; +-} +- +-/* Fetch inode INUM, set *NPP to the node structure; +- gain one user reference and lock the node. */ ++/* XXX */ + error_t +-diskfs_cached_lookup (ino_t inum, struct node **npp) ++diskfs_user_make_node (struct node **npp) + { +- error_t err; +- struct node *np, *tmp; ++ struct node *np; + struct disknode *dn; + +- pthread_rwlock_rdlock (&nodecache_lock); +- np = lookup (inum); +- if (np) +- goto gotit; +- pthread_rwlock_unlock (&nodecache_lock); +- + /* Create the new node. */ + np = diskfs_make_node_alloc (sizeof *dn); +- dn = diskfs_node_disknode (np); +- np->cache_id = inum; ++ if (np == NULL) ++ return ENOMEM; + + /* Format specific data for the new node. */ ++ 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); + +- pthread_mutex_lock (&np->lock); +- +- /* Put NP in NODEHASH. */ +- pthread_rwlock_wrlock (&nodecache_lock); +- tmp = lookup (inum); +- if (tmp) +- { +- /* We lost a race. */ +- diskfs_nput (np); +- np = tmp; +- goto gotit; +- } +- +- dn->hnext = nodehash[INOHASH(inum)]; +- if (dn->hnext) +- diskfs_node_disknode (dn->hnext)->hprevp = &dn->hnext; +- dn->hprevp = &nodehash[INOHASH(inum)]; +- nodehash[INOHASH(inum)] = np; +- diskfs_nref_light (np); +- nodehash_nr_items += 1; +- pthread_rwlock_unlock (&nodecache_lock); +- +- /* Get the contents of NP off disk. */ +- err = read_node (np); +- +- if (!diskfs_check_readonly () && !np->dn_stat.st_gen) +- { +- pthread_spin_lock (&generation_lock); +- if (++next_generation < diskfs_mtime->seconds) +- next_generation = diskfs_mtime->seconds; +- np->dn_stat.st_gen = next_generation; +- pthread_spin_unlock (&generation_lock); +- np->dn_set_ctime = 1; +- } +- +- if (err) +- return err; +- else +- { +- *npp = np; +- return 0; +- } +- +- gotit: +- diskfs_nref (np); +- pthread_rwlock_unlock (&nodecache_lock); +- pthread_mutex_lock (&np->lock); + *npp = np; + return 0; + } + +-/* Lookup node INUM (which must have a reference already) and return it +- without allocating any new references. */ +-struct node * +-ifind (ino_t inum) +-{ +- struct node *np; +- +- pthread_rwlock_rdlock (&nodecache_lock); +- np = lookup (inum); +- pthread_rwlock_unlock (&nodecache_lock); +- +- assert (np); +- return np; +-} +- + /* The last reference to a node has gone away; drop + it from the hash table and clean all state in the dn structure. */ + void +@@ -196,35 +86,8 @@ diskfs_node_norefs (struct node *np) + /* The last hard reference to a node has gone away; arrange to have + all the weak references dropped that can be. */ + void +-diskfs_try_dropping_softrefs (struct node *np) ++diskfs_user_try_dropping_softrefs (struct node *np) + { +- pthread_rwlock_wrlock (&nodecache_lock); +- if (diskfs_node_disknode (np)->hprevp != NULL) +- { +- /* Check if someone reacquired a reference through the +- nodehash. */ +- struct references result; +- refcounts_references (&np->refcounts, &result); +- +- if (result.hard > 0) +- { +- /* A reference was reacquired through a hash table lookup. +- It's fine, we didn't touch anything yet. */ +- pthread_rwlock_unlock (&nodecache_lock); +- return; +- } +- +- *diskfs_node_disknode (np)->hprevp = diskfs_node_disknode (np)->hnext; +- if (diskfs_node_disknode (np)->hnext) +- diskfs_node_disknode (diskfs_node_disknode (np)->hnext)->hprevp = +- diskfs_node_disknode (np)->hprevp; +- diskfs_node_disknode (np)->hnext = NULL; +- diskfs_node_disknode (np)->hprevp = NULL; +- nodehash_nr_items -= 1; +- diskfs_nrele_light (np); +- } +- pthread_rwlock_unlock (&nodecache_lock); +- + drop_pager_softrefs (np); + } + +@@ -243,8 +106,8 @@ diskfs_new_hardrefs (struct node *np) + } + + /* Read stat information out of the ext2_inode. */ +-static error_t +-read_node (struct node *np) ++error_t ++diskfs_user_read_node (struct node *np) + { + error_t err; + struct stat *st = &np->dn_stat; +@@ -384,6 +247,16 @@ read_node (struct node *np) + linux, some devices). */ + np->allocsize = 0; + ++ if (!diskfs_check_readonly () && !np->dn_stat.st_gen) ++ { ++ pthread_spin_lock (&generation_lock); ++ if (++next_generation < diskfs_mtime->seconds) ++ next_generation = diskfs_mtime->seconds; ++ np->dn_stat.st_gen = next_generation; ++ pthread_spin_unlock (&generation_lock); ++ np->dn_set_ctime = 1; ++ } ++ + return 0; + } + +@@ -585,72 +458,11 @@ diskfs_node_reload (struct node *node) + } + pokel_flush (&dn->indir_pokel); + flush_node_pager (node); +- read_node (node); ++ diskfs_user_read_node (node); + + return 0; + } + +-/* For each active node, call FUN. The node is to be locked around the call +- to FUN. If FUN returns non-zero for any node, then immediately stop, and +- return that value. */ +-error_t +-diskfs_node_iterate (error_t (*fun)(struct node *)) +-{ +- error_t err = 0; +- int n; +- size_t num_nodes; +- struct node *node, **node_list, **p; +- +- 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 +- nodecache_lock, but we can't hold this while locking the +- individual node locks). */ +- num_nodes = nodehash_nr_items; +- +- /* TODO This method doesn't scale beyond a few dozen nodes and should be +- replaced. */ +- node_list = malloc (num_nodes * sizeof (struct node *)); +- if (node_list == NULL) +- { +- 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 = diskfs_node_disknode (node)->hnext) +- { +- *p++ = node; +- +- /* We acquire a hard reference for node, but without using +- diskfs_nref. We do this so that diskfs_new_hardrefs will not +- get called. */ +- refcounts_ref (&node->refcounts, NULL); +- } +- +- pthread_rwlock_unlock (&nodecache_lock); +- +- p = node_list; +- while (num_nodes-- > 0) +- { +- node = *p++; +- if (!err) +- { +- pthread_mutex_lock (&node->lock); +- err = (*fun)(node); +- pthread_mutex_unlock (&node->lock); +- } +- diskfs_nrele (node); +- } +- +- free (node_list); +- return err; +-} +- + /* Write all active disknodes into the ext2_inode pager. */ + void + write_all_disknodes () +diff --git a/libdiskfs/Makefile b/libdiskfs/Makefile +index 996e86a..47b9339 100644 +--- a/libdiskfs/Makefile ++++ b/libdiskfs/Makefile +@@ -41,7 +41,7 @@ OTHERSRCS = conch-fetch.c conch-set.c dir-clear.c dir-init.c dir-renamed.c \ + extern-inline.c \ + node-create.c node-drop.c node-make.c node-rdwr.c node-update.c \ + node-nref.c node-nput.c node-nrele.c node-nrefl.c node-nputl.c \ +- node-nrelel.c \ ++ node-nrelel.c node-cache.c \ + peropen-make.c peropen-rele.c protid-make.c protid-rele.c \ + init-init.c init-startup.c init-first.c init-main.c \ + rdwr-internal.c boot-start.c demuxer.c node-times.c shutdown.c \ +diff --git a/libdiskfs/diskfs.h b/libdiskfs/diskfs.h +index 7a21dff..22c4aa6 100644 +--- a/libdiskfs/diskfs.h ++++ b/libdiskfs/diskfs.h +@@ -80,6 +80,9 @@ struct peropen + filesystem. */ + struct node + { ++ /* Links on hash list. */ ++ struct node *hnext, **hprevp; ++ + struct disknode *dn; + + io_statbuf_t dn_stat; +@@ -1102,4 +1105,18 @@ struct store *diskfs_init_main (struct argp *startup_argp, + /* Make errors go somewhere reasonable. */ + void diskfs_console_stdio (); + ++//XXX ++/* XXX */ ++error_t diskfs_user_make_node (struct node **npp); ++/* Read stat information out of the ext2_inode. */ ++error_t diskfs_user_read_node (struct node *np); ++/* The last hard reference to a node has gone away; arrange to have ++ all the weak references dropped that can be. */ ++void diskfs_user_try_dropping_softrefs (struct node *np); ++ ++/* Lookup node INUM (which must have a reference already) and return it ++ without allocating any new references. */ ++struct node *diskfs_cached_ifind (ino_t inum); ++ ++ + #endif /* hurd/diskfs.h */ +diff --git a/libdiskfs/node-cache.c b/libdiskfs/node-cache.c +new file mode 100644 +index 0000000..58249bf +--- /dev/null ++++ b/libdiskfs/node-cache.c +@@ -0,0 +1,249 @@ ++/* Inode cache. ++ ++ Copyright (C) 1994-2015 Free Software Foundation, Inc. ++ ++ This file is part of the GNU Hurd. ++ ++ The GNU Hurd is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License as ++ published by the Free Software Foundation; either version 2, or (at ++ your option) any later version. ++ ++ The GNU Hurd is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with the GNU Hurd. If not, see <http://www.gnu.org/licenses/>. */ ++ ++#include "priv.h" ++ ++#define INOHSZ 8192 ++#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 ++ nodecache_lock. ++ ++ Every node in the nodehash 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 nodehash. */ ++static struct node *nodehash[INOHSZ]; ++static size_t nodehash_nr_items; ++static pthread_rwlock_t nodecache_lock = PTHREAD_RWLOCK_INITIALIZER; ++ ++/* Initialize the inode hash table. */ ++static void __attribute__ ((constructor)) ++nodecache_init () ++{ ++} ++ ++/* Lookup node with inode number INUM. Returns NULL if the node is ++ not found in the node cache. */ ++static struct node * ++lookup (ino_t inum) ++{ ++ struct node *np; ++ for (np = nodehash[INOHASH(inum)]; np; np = np->hnext) ++ if (np->cache_id == inum) ++ return np; ++ return NULL; ++} ++ ++/* Fetch inode INUM, set *NPP to the node structure; ++ gain one user reference and lock the node. */ ++error_t __attribute__ ((weak)) ++diskfs_cached_lookup (ino_t inum, struct node **npp) ++{ ++ error_t err; ++ struct node *np, *tmp; ++ ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ if (np) ++ goto gotit; ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ err = diskfs_user_make_node (&np); ++ if (err) ++ return err; ++ ++ np->cache_id = inum; ++ pthread_mutex_lock (&np->lock); ++ ++ /* Put NP in NODEHASH. */ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ tmp = lookup (inum); ++ if (tmp) ++ { ++ /* We lost a race. */ ++ diskfs_nput (np); ++ np = tmp; ++ goto gotit; ++ } ++ ++ np->hnext = nodehash[INOHASH(inum)]; ++ if (np->hnext) ++ np->hnext->hprevp = &np->hnext; ++ np->hprevp = &nodehash[INOHASH(inum)]; ++ nodehash[INOHASH(inum)] = np; ++ diskfs_nref_light (np); ++ nodehash_nr_items += 1; ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ /* Get the contents of NP off disk. */ ++ err = diskfs_user_read_node (np); ++ if (err) ++ return err; ++ else ++ { ++ *npp = np; ++ return 0; ++ } ++ ++ gotit: ++ diskfs_nref (np); ++ pthread_rwlock_unlock (&nodecache_lock); ++ pthread_mutex_lock (&np->lock); ++ *npp = np; ++ return 0; ++} ++ ++/* Lookup node INUM (which must have a reference already) and return it ++ without allocating any new references. */ ++struct node * ++diskfs_cached_ifind (ino_t inum) ++{ ++ struct node *np; ++ ++ pthread_rwlock_rdlock (&nodecache_lock); ++ np = lookup (inum); ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ assert (np); ++ return np; ++} ++ ++void __attribute__ ((weak)) ++diskfs_try_dropping_softrefs (struct node *np) ++{ ++ pthread_rwlock_wrlock (&nodecache_lock); ++ if (np->hprevp != NULL) ++ { ++ /* Check if someone reacquired a reference through the ++ nodehash. */ ++ struct references result; ++ refcounts_references (&np->refcounts, &result); ++ ++ if (result.hard > 0) ++ { ++ /* A reference was reacquired through a hash table lookup. ++ It's fine, we didn't touch anything yet. */ ++ pthread_rwlock_unlock (&nodecache_lock); ++ return; ++ } ++ ++ *np->hprevp = np->hnext; ++ if (np->hnext) ++ np->hnext->hprevp = np->hprevp; ++ np->hnext = NULL; ++ np->hprevp = NULL; ++ nodehash_nr_items -= 1; ++ diskfs_nrele_light (np); ++ } ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ diskfs_user_try_dropping_softrefs (np); ++} ++ ++/* For each active node, call FUN. The node is to be locked around the call ++ to FUN. If FUN returns non-zero for any node, then immediately stop, and ++ return that value. */ ++error_t __attribute__ ((weak)) ++diskfs_node_iterate (error_t (*fun)(struct node *)) ++{ ++ error_t err = 0; ++ int n; ++ size_t num_nodes; ++ struct node *node, **node_list, **p; ++ ++ 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 ++ nodecache_lock, but we can't hold this while locking the ++ individual node locks). */ ++ /* XXX: Can we? */ ++ num_nodes = nodehash_nr_items; ++ ++ /* TODO This method doesn't scale beyond a few dozen nodes and should be ++ replaced. */ ++ node_list = malloc (num_nodes * sizeof (struct node *)); ++ if (node_list == NULL) ++ { ++ pthread_rwlock_unlock (&nodecache_lock); ++ error (0, 0, "unable to allocate temporary node table"); ++ return ENOMEM; ++ } ++ ++ p = node_list; ++ for (n = 0; n < INOHSZ; n++) ++ for (node = nodehash[n]; node; node = node->hnext) ++ { ++ *p++ = node; ++ ++ /* We acquire a hard reference for node, but without using ++ diskfs_nref. We do this so that diskfs_new_hardrefs will not ++ get called. */ ++ refcounts_ref (&node->refcounts, NULL); ++ } ++ ++ pthread_rwlock_unlock (&nodecache_lock); ++ ++ p = node_list; ++ while (num_nodes-- > 0) ++ { ++ node = *p++; ++ if (!err) ++ { ++ pthread_mutex_lock (&node->lock); ++ err = (*fun)(node); ++ pthread_mutex_unlock (&node->lock); ++ } ++ diskfs_nrele (node); ++ } ++ ++ free (node_list); ++ return err; ++} ++ ++/* XXX */ ++error_t __attribute__ ((weak)) ++diskfs_user_make_node (struct node **npp) ++{ ++ assert (! "diskfs_user_make_node not implemented"); ++} ++ ++/* Read stat information out of the ext2_inode. */ ++error_t __attribute__ ((weak)) ++diskfs_user_read_node (struct node *np) ++{ ++ assert (! "diskfs_user_read_node not implemented"); ++} ++ ++/* The last hard reference to a node has gone away; arrange to have ++ all the weak references dropped that can be. */ ++void __attribute__ ((weak)) ++diskfs_user_try_dropping_softrefs (struct node *np) ++{ ++ assert (! "diskfs_user_try_dropping_softrefs not implemented"); ++} ++ +-- +2.1.4 + |