summaryrefslogtreecommitdiff
path: root/fatfs
diff options
context:
space:
mode:
authorJustus Winter <4winter@informatik.uni-hamburg.de>2015-04-16 16:12:05 +0200
committerJustus Winter <4winter@informatik.uni-hamburg.de>2015-04-17 22:16:14 +0200
commitb497f1613187c142ad6d0b76761a49811c37da80 (patch)
tree1d9cf49eabbb1e9c2de5768ae52aeaa895c93a59 /fatfs
parent4266bb02b1f3342d3fc4920c07c71592a14acdd9 (diff)
fatfs: port to libdiskfs' node cache
* fatfs/inode.c: Drop all cache-related code. (diskfs_user_make_node): New function. (diskfs_cached_lookup_in_dirbuf): Reimplement using the `lookup_context'. (read_node): Rename to diskfs_user_read_node and adopt accordingly. (diskfs_try_dropping_softrefs): Rename to `diskfs_user_try_dropping_softrefs'. (diskfs_node_reload): Pass context to `diskfs_user_read_node'. (diskfs_alloc_node): Pass `dir' via context to `diskfs_user_read_node'. * fatfs/fatfs.h (struct disknode): Drop fields `hnext', `hprevp'. (struct lookup_context): New definition. (ifind): Drop declaration. * fatfs/dir.c (diskfs_lookup_hard): Adjust accordingly. * fatfs/main.c (fetch_root): Likewise.
Diffstat (limited to 'fatfs')
-rw-r--r--fatfs/dir.c6
-rw-r--r--fatfs/fatfs.h17
-rw-r--r--fatfs/inode.c292
-rw-r--r--fatfs/main.c6
4 files changed, 46 insertions, 275 deletions
diff --git a/fatfs/dir.c b/fatfs/dir.c
index 5a38c63a..9eea74c1 100644
--- a/fatfs/dir.c
+++ b/fatfs/dir.c
@@ -342,7 +342,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)
{
@@ -395,7 +395,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)
@@ -732,7 +732,7 @@ diskfs_dirrewrite_hard (struct node *dp, struct node *np, struct dirstat *ds)
assert (err != EINVAL);
/* Lookup the node, we already have a reference. */
- oldnp = ifind (inode);
+ oldnp = diskfs_cached_ifind (inode);
assert (ds->type == RENAME);
assert (ds->stat == HERE_TIS);
diff --git a/fatfs/fatfs.h b/fatfs/fatfs.h
index 9d385463..3c3d8366 100644
--- a/fatfs/fatfs.h
+++ b/fatfs/fatfs.h
@@ -36,9 +36,6 @@ struct disknode
{
cluster_t start_cluster;
- /* Links on hash list. */
- struct node *hnext, **hprevp;
-
/* The inode as returned by virtual inode management routines. */
inode_t inode;
@@ -71,6 +68,18 @@ struct disknode
int dir_idx;
};
+struct lookup_context
+{
+ /* The inode as returned by virtual inode management routines. */
+ inode_t inode;
+
+ /* Use BUF as the directory file map. */
+ vm_address_t buf;
+
+ /* Directory this node was allocated in (used by diskfs_alloc_node). */
+ struct node *dir;
+};
+
struct user_pager_info
{
struct node *node;
@@ -117,8 +126,6 @@ void flush_node_pager (struct node *node);
void write_all_disknodes ();
-struct node *ifind (ino_t inum);
-
error_t fat_get_next_cluster (cluster_t cluster, cluster_t *next_cluster);
void fat_to_unix_filename (const char *, char *);
diff --git a/fatfs/inode.c b/fatfs/inode.c
index f228618d..610f3575 100644
--- a/fatfs/inode.c
+++ b/fatfs/inode.c
@@ -37,69 +37,21 @@
#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
- 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, vm_address_t buf);
-
-/* 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 = np->dn->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 (ino64_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);
-
- /* Format specific data for the new node. */
- dn = malloc (sizeof (struct disknode));
- if (! dn)
+ /* Create the new node. */
+ np = diskfs_make_node_alloc (sizeof *dn);
+ if (np == NULL)
return ENOMEM;
+ /* Format specific data for the new node. */
+ dn = np->dn;
dn->pager = 0;
dn->first = 0;
dn->last = 0;
@@ -108,49 +60,9 @@ diskfs_cached_lookup (ino64_t inum, struct node **npp)
dn->chain_extension_lock = PTHREAD_SPINLOCK_INITIALIZER;
pthread_rwlock_init (&dn->alloc_lock, NULL);
pthread_rwlock_init (&dn->dirent_lock, NULL);
-
- /* Create the new node. */
- np = diskfs_make_node (dn);
- np->cache_id = inum;
- np->dn->inode = vi_lookup(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;
- }
-
- 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);
- nodehash_nr_items += 1;
- pthread_rwlock_unlock (&nodecache_lock);
-
- /* Get the contents of NP off disk. */
- err = read_node (np, 0);
-
- if (err)
- return err;
- else
- {
- *npp = np;
- return 0;
- }
-
- gotit:
- diskfs_nref (np);
- pthread_rwlock_unlock (&nodecache_lock);
- pthread_mutex_lock (&np->lock);
+ dn->inode = ctx->inode;
+ dn->dirnode = ctx->dir;
*npp = np;
return 0;
}
@@ -162,78 +74,8 @@ error_t
diskfs_cached_lookup_in_dirbuf (int inum, struct node **npp, vm_address_t buf)
{
error_t err;
- struct node *np;
- struct disknode *dn;
-
- pthread_rwlock_rdlock (&nodecache_lock);
- for (np = nodehash[INOHASH(inum)]; np; np = np->dn->hnext)
- if (np->cache_id == inum)
- {
- diskfs_nref (np);
- pthread_rwlock_unlock (&nodecache_lock);
- pthread_mutex_lock (&np->lock);
- *npp = np;
- return 0;
- }
- pthread_rwlock_unlock (&nodecache_lock);
-
- /* Format specific data for the new node. */
- dn = malloc (sizeof (struct disknode));
- if (! dn)
- return ENOMEM;
-
- dn->pager = 0;
- dn->first = 0;
- dn->last = 0;
- dn->length_of_chain = 0;
- dn->chain_complete = 0;
- dn->chain_extension_lock = PTHREAD_SPINLOCK_INITIALIZER;
- pthread_rwlock_init (&dn->alloc_lock, NULL);
- pthread_rwlock_init (&dn->dirent_lock, NULL);
-
- /* Create the new node. */
- np = diskfs_make_node (dn);
- np->cache_id = inum;
- np->dn->inode = vi_lookup(inum);
-
- pthread_mutex_lock (&np->lock);
-
- /* Put NP in NODEHASH. */
- pthread_rwlock_wrlock (&nodecache_lock);
- 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);
- nodehash_nr_items += 1;
- pthread_rwlock_unlock (&nodecache_lock);
-
- /* Get the contents of NP off disk. */
- err = read_node (np, buf);
-
- if (err)
- return err;
- else
- {
- *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;
+ struct lookup_context ctx = { buf: buf, inode: vi_lookup (inum) };
+ return diskfs_cached_lookup_context (inum, npp, &ctx);
}
/* The last reference to a node has gone away; drop it from the hash
@@ -258,41 +100,15 @@ diskfs_node_norefs (struct node *np)
assert (!np->dn->pager);
- free (np->dn);
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 (np->dn->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->dn->hprevp = np->dn->hnext;
- if (np->dn->hnext)
- np->dn->hnext->dn->hprevp = np->dn->hprevp;
- np->dn->hnext = NULL;
- np->dn->hprevp = NULL;
- nodehash_nr_items -= 1;
- diskfs_nrele_light (np);
- }
- pthread_rwlock_unlock (&nodecache_lock);
-
drop_pager_softrefs (np);
}
@@ -310,9 +126,10 @@ diskfs_new_hardrefs (struct node *np)
allow_pager_softrefs (np);
}
-/* Read stat information out of the directory entry. */
-static error_t
-read_node (struct node *np, vm_address_t buf)
+/* 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)
{
/* XXX This needs careful investigation. */
error_t err;
@@ -323,6 +140,7 @@ read_node (struct node *np, vm_address_t buf)
struct vi_key vk = vi_key(np->dn->inode);
vm_prot_t prot = VM_PROT_READ;
memory_object_t memobj;
+ vm_address_t buf = ctx->buf;
vm_size_t buflen = 0;
int our_buf = 0;
@@ -359,7 +177,7 @@ read_node (struct node *np, vm_address_t buf)
/* FIXME: We know intimately that the parent dir is locked
by libdiskfs. The only case it is not locked is for NFS
(fsys_getfile) and we disabled that. */
- dp = ifind (vk.dir_inode);
+ dp = diskfs_cached_ifind (vk.dir_inode);
assert (dp);
/* Map in the directory contents. */
@@ -572,7 +390,7 @@ error_t
diskfs_node_reload (struct node *node)
{
struct cluster_chain *last = node->dn->first;
-
+ static struct lookup_context ctx = { buf: 0 };
while (last)
{
struct cluster_chain *next = last->next;
@@ -580,61 +398,8 @@ diskfs_node_reload (struct node *node)
last = next;
}
flush_node_pager (node);
- read_node (node, 0);
- 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;
-
- node_list = alloca (num_nodes * sizeof (struct node *));
- p = node_list;
- for (n = 0; n < INOHSZ; n++)
- for (node = nodehash[n]; node; node = node->dn->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);
- }
-
- return err;
+ return diskfs_user_read_node (node, &ctx);
}
/* Write all active disknodes into the ext2_inode pager. */
@@ -812,7 +577,8 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node)
ino_t inum;
inode_t inode;
struct node *np;
-
+ struct lookup_context ctx = { dir: dir };
+
assert (!diskfs_readonly);
/* FIXME: We use a magic key here that signals read_node that we are
@@ -821,12 +587,10 @@ diskfs_alloc_node (struct node *dir, mode_t mode, struct node **node)
if (err)
return err;
- err = diskfs_cached_lookup (inum, &np);
+ err = diskfs_cached_lookup_context (inum, &np, &ctx);
if (err)
return err;
- /* FIXME: We know that readnode couldn't put this in. */
- np->dn->dirnode = dir;
refcounts_ref (&dir->refcounts, NULL);
*node = np;
diff --git a/fatfs/main.c b/fatfs/main.c
index 2bbcdfaa..00c56bc5 100644
--- a/fatfs/main.c
+++ b/fatfs/main.c
@@ -143,7 +143,7 @@ fetch_root ()
{
error_t err;
ino_t inum;
- inode_t inode;
+ struct lookup_context ctx;
memset (&dr_root_node, 0, sizeof(struct dirrect));
@@ -196,13 +196,13 @@ fetch_root ()
from the vi_zero_key (in the dir_offset value) as well as all
normal virtual inode keys (in the dir_inode value). Enter the
disknode into the inode table. */
- err = vi_new ((struct vi_key) {0, 1}, &inum, &inode);
+ err = vi_new ((struct vi_key) {0, 1}, &inum, &ctx.inode);
assert_perror (err);
/* Allocate a node for the root directory disknode in
diskfs_root_node. */
if (!err)
- err = diskfs_cached_lookup (inum, &diskfs_root_node);
+ err = diskfs_cached_lookup_context (inum, &diskfs_root_node, &ctx);
assert_perror (err);