summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nfs/ChangeLog30
-rw-r--r--nfs/cache.c39
-rw-r--r--nfs/main.c2
-rw-r--r--nfs/name-cache.c69
-rw-r--r--nfs/nfs.h1
-rw-r--r--nfs/ops.c22
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);
diff --git a/nfs/main.c b/nfs/main.c
index d9702ecb..92a49861 100644
--- a/nfs/main.c
+++ b/nfs/main.c
@@ -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;
}
diff --git a/nfs/nfs.h b/nfs/nfs.h
index 5a3dd8a9..ff90744d 100644
--- a/nfs/nfs.h
+++ b/nfs/nfs.h
@@ -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 *);
diff --git a/nfs/ops.c b/nfs/ops.c
index d9060154..4520e516 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -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);