summaryrefslogtreecommitdiff
path: root/ext2fs
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs')
-rw-r--r--ext2fs/dir.c4
-rw-r--r--ext2fs/ext2fs.c2
-rw-r--r--ext2fs/ext2fs.h9
-rw-r--r--ext2fs/inode.c239
4 files changed, 28 insertions, 226 deletions
diff --git a/ext2fs/dir.c b/ext2fs/dir.c
index 2dfe1d76..6cdfba27 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 beb7cad9..d0fdfe7a 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 9667b6f6..96d8e9db 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 7af617c5..d83bedca 100644
--- a/ext2fs/inode.c
+++ b/ext2fs/inode.c
@@ -39,144 +39,33 @@
#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. */
+/* The user must define this function if she wants to use the node
+ cache. Create and initialize a node. */
error_t
-diskfs_cached_lookup (ino_t inum, struct node **npp)
+diskfs_user_make_node (struct node **npp, struct lookup_context *ctx)
{
- 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
@@ -193,38 +82,12 @@ diskfs_node_norefs (struct node *np)
free (np);
}
-/* The last hard reference to a node has gone away; arrange to have
- all the weak references dropped that can be. */
+/* The user must define this function if she wants to use the node
+ cache. 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);
}
@@ -242,9 +105,10 @@ diskfs_new_hardrefs (struct node *np)
allow_pager_softrefs (np);
}
-/* Read stat information out of the ext2_inode. */
-static error_t
-read_node (struct node *np)
+/* The user must define this function if she wants to use the node
+ cache. Read stat information out of the on-disk node. */
+error_t
+diskfs_user_read_node (struct node *np, struct lookup_context *ctx)
{
error_t err;
struct stat *st = &np->dn_stat;
@@ -384,6 +248,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 +459,11 @@ diskfs_node_reload (struct node *node)
}
pokel_flush (&dn->indir_pokel);
flush_node_pager (node);
- read_node (node);
+ diskfs_user_read_node (node, NULL);
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 ()