diff options
Diffstat (limited to 'nfs/cache.c')
-rw-r--r-- | nfs/cache.c | 102 |
1 files changed, 66 insertions, 36 deletions
diff --git a/nfs/cache.c b/nfs/cache.c index e09b7c38..8f87f5d0 100644 --- a/nfs/cache.c +++ b/nfs/cache.c @@ -1,5 +1,5 @@ -/* Node cache management for NFS client implementation - Copyright (C) 1995, 1996 Free Software Foundation, Inc. +/* cache.c - Node cache management for NFS client implementation. + Copyright (C) 1995, 1996, 1997, 2002 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. This file is part of the GNU Hurd. @@ -23,11 +23,15 @@ #include <string.h> #include <netinet/in.h> -/* Hash table containing all the nodes currently active. */ -#define CACHESIZE 512 +/* Hash table containing all the nodes currently active. XXX Was 512, + however, a prime is much nicer for the hash function. 509 is nice + as not only is it prime, it also keeps the array within a page or + two. */ +#define CACHESIZE 509 static struct node *nodehash [CACHESIZE]; -/* Compute and return a hash key for NFS file handle DATA of LEN bytes. */ +/* Compute and return a hash key for NFS file handle DATA of LEN + bytes. */ static inline int hash (int *data, size_t len) { @@ -41,42 +45,40 @@ hash (int *data, size_t len) return h % CACHESIZE; } -/* Lookup the file handle in RPC result at P in the hash table. If it - is not present, initialize a new node structure and insert it into - the hash table. Whichever course, a new reference is generated and - the node is returned in *NPP. Return the address in the RPC result - after the file handle. */ -int * -lookup_fhandle (int *p, struct node **npp) +/* Lookup the file handle P (length LEN) in the hash table. If it is + not present, initialize a new node structure and insert it into the + hash table. Whichever course, a new reference is generated and the + node is returned in *NPP; the lock on the node, (*NPP)->LOCK, is + held. */ +void +lookup_fhandle (void *p, size_t len, struct node **npp) { struct node *np; struct netnode *nn; - size_t len; int h; - if (protocol_version == 2) - len = NFS2_FHSIZE; - else - len = ntohl (*p++); h = hash (p, len); spin_lock (&netfs_node_refcnt_lock); for (np = nodehash[h]; np; np = np->nn->hnext) { if (np->nn->handle.size != len - || bcmp (np->nn->handle.data, p, len) != 0) + || memcmp (np->nn->handle.data, p, len) != 0) continue; np->references++; spin_unlock (&netfs_node_refcnt_lock); mutex_lock (&np->lock); *npp = np; - return p + len / sizeof (int); + return; } + /* Could not find it */ nn = malloc (sizeof (struct netnode)); + assert (nn); + nn->handle.size = len; - bcopy (p, nn->handle.data, len); + memcpy (nn->handle.data, p, len); nn->stat_updated = 0; nn->dtrans = NOT_POSSIBLE; nn->dead_dir = 0; @@ -93,34 +95,57 @@ lookup_fhandle (int *p, struct node **npp) spin_unlock (&netfs_node_refcnt_lock); *npp = np; - return p + len / sizeof (int); } +/* Package holding args to forked_node_delete. */ +struct fnd +{ + struct node *dir; + char *name; +}; + +/* Worker function to delete nodes that don't have any more local + references or links. */ +any_t +forked_node_delete (any_t arg) +{ + struct fnd *args = arg; + + mutex_lock (&args->dir->lock); + netfs_attempt_unlink ((struct iouser *)-1, args->dir, args->name); + netfs_nput (args->dir); + free (args->name); + free (args); + return 0; +}; + /* Called by libnetfs when node NP has no more references. (See - <hurd/libnetfs.h> for details. Just clear local state and remove - from the hash table. */ + <hurd/libnetfs.h> for details. Just clear its local state and + remove it from the hash table. Called and expected to leave with + NETFS_NODE_REFCNT_LOCK held. */ void netfs_node_norefs (struct node *np) { if (np->nn->dead_dir) { - struct node *dir; - char *name; + struct fnd *args; + + args = malloc (sizeof (struct fnd)); + assert (args); np->references++; spin_unlock (&netfs_node_refcnt_lock); - dir = np->nn->dead_dir; - name = np->nn->dead_name; + args->dir = np->nn->dead_dir; + args->name = np->nn->dead_name; np->nn->dead_dir = 0; np->nn->dead_name = 0; netfs_nput (np); - mutex_lock (&dir->lock); - netfs_attempt_unlink ((struct iouser *)-1, dir, name); - - netfs_nput (dir); - free (name); + /* Do this in a separate thread so that we don't wait for it; it + acquires a lock on the dir, which we are not allowed to + do. */ + cthread_detach (cthread_fork (forked_node_delete, (any_t) args)); /* Caller expects us to leave this locked... */ spin_lock (&netfs_node_refcnt_lock); @@ -139,7 +164,7 @@ netfs_node_norefs (struct node *np) /* Change the file handle used for node NP to be the handle at P. Make sure the hash table stays up to date. Return the address - after the hnadle. */ + after the handle. The lock on the node should be held. */ int * recache_handle (int *p, struct node *np) { @@ -149,16 +174,22 @@ recache_handle (int *p, struct node *np) if (protocol_version == 2) len = NFS2_FHSIZE; else - len = ntohl (*p++); + { + len = ntohl (*p); + p++; + } + /* Unlink it */ spin_lock (&netfs_node_refcnt_lock); *np->nn->hprevp = np->nn->hnext; if (np->nn->hnext) np->nn->hnext->nn->hprevp = np->nn->hprevp; + /* Change the name */ np->nn->handle.size = len; - bcopy (p, np->nn->handle.data, len); + memcpy (np->nn->handle.data, p, len); + /* Reinsert it */ h = hash (p, len); np->nn->hnext = nodehash[h]; if (np->nn->hnext) @@ -169,4 +200,3 @@ recache_handle (int *p, struct node *np) return p + len / sizeof (int); } - |