diff options
Diffstat (limited to 'nfs/cache.c')
-rw-r--r-- | nfs/cache.c | 129 |
1 files changed, 91 insertions, 38 deletions
diff --git a/nfs/cache.c b/nfs/cache.c index 65b46575..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. @@ -21,49 +21,64 @@ #include "nfs.h" #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 FHANDLE. */ +/* Compute and return a hash key for NFS file handle DATA of LEN + bytes. */ static inline int -hash (void *fhandle) +hash (int *data, size_t len) { unsigned int h = 0; + char *cp = (char *)data; int i; - for (i = 0; i < NFS_FHSIZE; i++) - h += ((char *)fhandle)[i]; + for (i = 0; i < len; i++) + h += cp[i]; return h % CACHESIZE; } -/* Lookup the specified file handle FHANDLE 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. */ -struct node * -lookup_fhandle (void *fhandle) +/* 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; - int h = hash (fhandle); + int h; + + h = hash (p, len); spin_lock (&netfs_node_refcnt_lock); for (np = nodehash[h]; np; np = np->nn->hnext) { - if (bcmp (np->nn->handle, fhandle, NFS_FHSIZE) != 0) + if (np->nn->handle.size != len + || memcmp (np->nn->handle.data, p, len) != 0) continue; np->references++; spin_unlock (&netfs_node_refcnt_lock); mutex_lock (&np->lock); - return np; + *npp = np; + return; } + /* Could not find it */ nn = malloc (sizeof (struct netnode)); - bcopy (fhandle, nn->handle, NFS_FHSIZE); + assert (nn); + + nn->handle.size = len; + memcpy (nn->handle.data, p, len); nn->stat_updated = 0; nn->dtrans = NOT_POSSIBLE; nn->dead_dir = 0; @@ -79,34 +94,58 @@ lookup_fhandle (void *fhandle) spin_unlock (&netfs_node_refcnt_lock); - return np; + *npp = np; } +/* 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 netcred *)-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); @@ -123,27 +162,41 @@ netfs_node_norefs (struct node *np) } } -/* Change the file handle used for node NP to be HANDLE. Make sure the - hash table stays up to date. */ -void -recache_handle (struct node *np, void *handle) +/* 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 handle. The lock on the node should be held. */ +int * +recache_handle (int *p, struct node *np) { int h; + size_t len; + + if (protocol_version == 2) + len = NFS2_FHSIZE; + else + { + 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; + memcpy (np->nn->handle.data, p, len); - bcopy (handle, np->nn->handle, NFS_FHSIZE); - - h = hash (handle); + /* Reinsert it */ + h = hash (p, len); np->nn->hnext = nodehash[h]; if (np->nn->hnext) np->nn->hnext->nn->hprevp = &np->nn->hnext; np->nn->hprevp = &nodehash[h]; spin_unlock (&netfs_node_refcnt_lock); + return p + len / sizeof (int); } - |