diff options
Diffstat (limited to 'nfs')
-rw-r--r-- | nfs/ChangeLog | 30 | ||||
-rw-r--r-- | nfs/cache.c | 39 | ||||
-rw-r--r-- | nfs/main.c | 2 | ||||
-rw-r--r-- | nfs/name-cache.c | 69 | ||||
-rw-r--r-- | nfs/nfs.h | 1 | ||||
-rw-r--r-- | nfs/ops.c | 22 |
6 files changed, 129 insertions, 34 deletions
diff --git a/nfs/ChangeLog b/nfs/ChangeLog index 084a1bf2..f8385c26 100644 --- a/nfs/ChangeLog +++ b/nfs/ChangeLog @@ -1,3 +1,33 @@ +Wed Aug 6 15:23:03 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * ops.c (netfs_attempt_unlink): Purge cache-held references + *before* counting live references. Use new function. + * name-cache.c (purge_lookup_cache_node): New function. + * nfs.h (purge_lookup_cache_node): New decl. + + * cache.c (netfs_node_norefs): Don't do delete RPC here, fork off + a separate thread to do it. + (struct fnd): New type. + (forked_node_delete): New function. + +Mon Aug 4 15:56:37 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * name-cache.c (struct lookup_cache): Drop members `node_cache_fh' + and `node_cache_len'. New member `np'. + (enter_lookup_cache): Fill C->np instead of C->node_cache_fh. + Acquire an additional reference on NP to keep it live. If there + was a reference there before, release it. + (purge_lookup_cache): If there is a reference to a node on a + purged entry, release it. + (check_lookup_cache): If there is a reference to a node on an + out-of-date entry, release it. When returning live positive hits, + use the NP stored instead of looking one up. + +Fri Aug 1 15:56:56 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> + + * main.c (netfs_append_args): Append --name-cache-timeout and + --name-cache-neg-timeout values. + Tue Jul 29 15:38:15 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> * name-cache.c (check_lookup_cache): Use name_cache_neg_timeout in diff --git a/nfs/cache.c b/nfs/cache.c index f854949c..183660b0 100644 --- a/nfs/cache.c +++ b/nfs/cache.c @@ -89,6 +89,28 @@ lookup_fhandle (void *p, size_t len, struct node **npp) *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. */ @@ -97,23 +119,22 @@ netfs_node_norefs (struct node *np) { if (np->nn->dead_dir) { - struct node *dir; - char *name; + struct fnd *args; + + args = malloc (sizeof (struct fnd)); 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); @@ -242,6 +242,8 @@ netfs_append_args (char **argz, size_t *argz_len) FOPT ("--cache-timeout=%d", cache_timeout); FOPT ("--init-transmit-timeout=%d", initial_transmit_timeout); FOPT ("--max-transmit-timeout=%d", max_transmit_timeout); + FOPT ("--name-cache-timeout=%d", name_cache_timeout); + FOPT ("--name-cache-neg-timeout=%d", name_cache_neg_timeout); if (! err) err = netfs_append_std_options (argz, argz_len); diff --git a/nfs/name-cache.c b/nfs/name-cache.c index 314867d7..bc5babe6 100644 --- a/nfs/name-cache.c +++ b/nfs/name-cache.c @@ -36,11 +36,14 @@ struct lookup_cache struct cacheq_hdr hdr; /* File handles and lengths for cache entries. 0 for NODE_CACHE_LEN - means a `negative' entry -- recording that there's definitely no node with - this name. */ - char dir_cache_fh[NFS3_FHSIZE], node_cache_fh[NFS3_FHSIZE]; - size_t dir_cache_len, node_cache_len; - + means a */ + char dir_cache_fh[NFS3_FHSIZE]; + size_t dir_cache_len; + + /* Zero means a `negative' entry -- recording that there's + definitely no node with this name. */ + struct node *np; + /* Name of the node NODE_CACHE_ID in the directory DIR_CACHE_ID. Entries with names too long to fit in this buffer aren't cached at all. */ char name[CACHE_NAME_LEN]; @@ -126,9 +129,11 @@ enter_lookup_cache (char *dir, size_t len, struct node *np, char *name) /* Fill C with the new entry. */ bcopy (dir, c->dir_cache_fh, len); c->dir_cache_len = len; - if (np) - bcopy (np->nn->handle.data, c->node_cache_fh, np->nn->handle.size); - c->node_cache_len = np ? np->nn->handle.size : 0; + if (c->np) + netfs_nrele (c->np); + c->np = np; + if (c->np) + netfs_nref (c->np); strcpy (c->name, name); c->name_len = name_len; c->cache_stamp = mapped_time->seconds; @@ -156,13 +161,40 @@ purge_lookup_cache (struct node *dp, char *name, size_t namelen) && bcmp (c->dir_cache_fh, dp->nn->handle.data, c->dir_cache_len) == 0 && strcmp (c->name, name) == 0) { + if (c->np) + netfs_nrele (c->np); c->name_len = 0; + c->np = 0; cacheq_make_lru (&lookup_cache, c); /* Use C as the next free entry. */ } } spin_unlock (&cache_lock); } + +/* Purge all references in the cache to node NP. */ +void +purge_lookup_cache_node (struct node *np) +{ + struct lookup_cache *c, *next; + + spin_lock (&cache_lock); + for (c = lookup_cache.mru; c; c = next) + { + next = c->hdr.next; + + if (c->np == np) + { + netfs_nrele (c->np); + c->name_len = 0; + c->np = 0; + cacheq_make_lru (&lookup_cache, c); + } + } + spin_unlock (&cache_lock); +} + + /* Register a negative hit for an entry in the Nth stat class */ void @@ -221,7 +253,7 @@ check_lookup_cache (struct node *dir, char *name) name, strlen (name)); if (c) { - int timeout = c->node_cache_len + int timeout = c->np ? name_cache_timeout : name_cache_neg_timeout; @@ -229,7 +261,10 @@ check_lookup_cache (struct node *dir, char *name) if (mapped_time->seconds - c->cache_stamp >= timeout) { register_neg_hit (c->stati); + if (c->np) + netfs_nrele (c->np); c->name_len = 0; + c->np = 0; cacheq_make_lru (&lookup_cache, c); spin_unlock (&cache_lock); return 0; @@ -237,7 +272,7 @@ check_lookup_cache (struct node *dir, char *name) cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */ - if (c->node_cache_len == 0) + if (c->np == 0) /* A negative cache entry. */ { register_neg_hit (c->stati); @@ -248,18 +283,14 @@ check_lookup_cache (struct node *dir, char *name) else { struct node *np; - char handle[NFS3_FHSIZE]; - size_t len; + np = c->np; + netfs_nref (np); register_pos_hit (c->stati); - mutex_unlock (&dir->lock); - - bcopy (c->node_cache_fh, handle, c->node_cache_len); - len = c->node_cache_len; - spin_unlock (&cache_lock); - - lookup_fhandle (handle, len, &np); + + mutex_unlock (&dir->lock); + mutex_lock (&np->lock); return np; } @@ -191,3 +191,4 @@ int *recache_handle (int *, struct node *); void enter_lookup_cache (char *, size_t, struct node *, char *); void purge_lookup_cache (struct node *, char *, size_t); struct node *check_lookup_cache (struct node *, char *); +void purge_lookup_cache_node (struct node *); @@ -1108,6 +1108,14 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, return err; } + /* Restore the locks to sanity. */ + mutex_unlock (&np->lock); + mutex_lock (&dir->lock); + + /* Purge the cache of entries for this node, so that we don't + regard cache-held references as live. */ + purge_lookup_cache_node (np); + /* See if there are any other users of this node than the one we just got; if so, we must give this file another link so that when we delete the one we are asked for it doesn't go @@ -1117,8 +1125,9 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, char *newname; int n = 0; + mutex_unlock (&dir->lock); + newname = malloc (50); - mutex_unlock (&np->lock); do { sprintf (newname, ".nfs%xgnu.%d", (int) np, n++); @@ -1137,6 +1146,7 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, /* Write down what name we gave it; we'll delete this when all our uses vanish. */ mutex_lock (&np->lock); + if (np->nn->dead_dir) netfs_nrele (np->nn->dead_dir); netfs_nref (dir); @@ -1146,12 +1156,12 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir, np->nn->dead_name = newname; if (np->nn->dtrans == NOT_POSSIBLE) np->nn->dtrans = POSSIBLE; - } - netfs_nput (np); - - mutex_lock (&dir->lock); - purge_lookup_cache (dir, name, strlen (name)); + netfs_nput (np); + mutex_lock (&dir->lock); + } + else + netfs_nrele (np); p = nfs_initialize_rpc (NFSPROC_REMOVE (protocol_version), cred, 0, &rpcbuf, dir, -1); |