summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bushnell <thomas@gnu.org>1997-07-29 20:57:33 +0000
committerThomas Bushnell <thomas@gnu.org>1997-07-29 20:57:33 +0000
commit4d75b660a263b510e2a2b2176196c20a8af58851 (patch)
tree13e9cbf0f9f150fb71059e18b7dd7f8c6add744e
parentb9d1d34ace30ce6c0f0a209b35b74527b7c7bd63 (diff)
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 preference to name_cache_timeout for negative hits. * nfs.h (name_cache_neg_timeout): New variable. * main.c (DEFAULT_NAME_CACHE_NEG_TIMEOUT): New macro. (name_cache_neg_timeout): Initialize new variable. (OPT_NCACHE_NEG_TO): New option key. (common_options): Add --name-cache-neg-timeout switch. (parse_common_opt): Process OPT_NCACHE_NEG_TO option key. * ops.c (netfs_attempt_lookup): Do cast of -1 correctly to match check_lookup_cache and ANSI C rules. * name-cache.c (check_lookup_cache): Unlock DIR correctly before returning a negative cache hit. * rpc.c (rpc_receive_thread): Don't print "dropping reply" messages any more. * ops.c (netfs_attempt_lookup): Cash all lookups, both positive and negative. (netfs_attempt_mkdir): Purge cache before creating directory entry. (netfs_attempt_link): Likewise. (netfs_attempt_create_file): Likewise. * ops.c (netfs_attempt_lookup): Pass correct node to enter_lookup_cache as the child. Thu Jul 24 13:15:56 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> * name-cache.c: New file. * ops.c (netfs_attempt_lookup): Check lookup cache before trying RPC. After successful lookup, make cache entry. (netfs_attempt_unlink): Purge cache before doing operation. (netfs_attempt_rmdir): Likewise. (netfs_attempt_rename): Purge cache for both names before operation. * nfs.h (enter_lookup_cache, purge_lookup_cache, check_lookup_cache): New prototypes. * Makefile (SRCS): Add name-cache.c. * nfs.h (name_cache_timeout): New variable. * main.c (DEFAULT_NAME_CACHE_TIMEOUT): New macro. (name_cache_timeout): Initialize new variable. (OPT_NCACHE_TO): New option key. (common_options): Add --name-cache-timeout switch. (parse_common_opt): Process OPT_NCACHE_TO option key. * cache.c (lookup_fhandle): Don't parse NFS XDR format, instead take a length arg. Return void. All callers changed to use new function xdr_decode_fhandle. * nfs.c (xdr_decode_fhandle): New function. * nfs.h (xdr_decode_fhandle): New prototype. (lookup_fhandle): Update prototype.
-rw-r--r--nfs/ChangeLog57
-rw-r--r--nfs/Makefile4
-rw-r--r--nfs/cache.c23
-rw-r--r--nfs/main.c22
-rw-r--r--nfs/mount.c4
-rw-r--r--nfs/name-cache.c272
-rw-r--r--nfs/nfs.c12
-rw-r--r--nfs/nfs.h14
-rw-r--r--nfs/ops.c49
-rw-r--r--nfs/rpc.c4
10 files changed, 437 insertions, 24 deletions
diff --git a/nfs/ChangeLog b/nfs/ChangeLog
index 33845ac1..084a1bf2 100644
--- a/nfs/ChangeLog
+++ b/nfs/ChangeLog
@@ -1,3 +1,60 @@
+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
+ preference to name_cache_timeout for negative hits.
+
+ * nfs.h (name_cache_neg_timeout): New variable.
+ * main.c (DEFAULT_NAME_CACHE_NEG_TIMEOUT): New macro.
+ (name_cache_neg_timeout): Initialize new variable.
+ (OPT_NCACHE_NEG_TO): New option key.
+ (common_options): Add --name-cache-neg-timeout switch.
+ (parse_common_opt): Process OPT_NCACHE_NEG_TO option key.
+
+ * ops.c (netfs_attempt_lookup): Do cast of -1 correctly to match
+ check_lookup_cache and ANSI C rules.
+
+ * name-cache.c (check_lookup_cache): Unlock DIR correctly before
+ returning a negative cache hit.
+
+ * rpc.c (rpc_receive_thread): Don't print "dropping reply"
+ messages any more.
+
+ * ops.c (netfs_attempt_lookup): Cash all lookups, both positive
+ and negative.
+ (netfs_attempt_mkdir): Purge cache before creating directory
+ entry.
+ (netfs_attempt_link): Likewise.
+ (netfs_attempt_create_file): Likewise.
+
+ * ops.c (netfs_attempt_lookup): Pass correct node to
+ enter_lookup_cache as the child.
+
+Thu Jul 24 13:15:56 1997 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c: New file.
+ * ops.c (netfs_attempt_lookup): Check lookup cache before trying
+ RPC. After successful lookup, make cache entry.
+ (netfs_attempt_unlink): Purge cache before doing operation.
+ (netfs_attempt_rmdir): Likewise.
+ (netfs_attempt_rename): Purge cache for both names before operation.
+ * nfs.h (enter_lookup_cache, purge_lookup_cache,
+ check_lookup_cache): New prototypes.
+ * Makefile (SRCS): Add name-cache.c.
+
+ * nfs.h (name_cache_timeout): New variable.
+ * main.c (DEFAULT_NAME_CACHE_TIMEOUT): New macro.
+ (name_cache_timeout): Initialize new variable.
+ (OPT_NCACHE_TO): New option key.
+ (common_options): Add --name-cache-timeout switch.
+ (parse_common_opt): Process OPT_NCACHE_TO option key.
+
+ * cache.c (lookup_fhandle): Don't parse NFS XDR format, instead
+ take a length arg. Return void. All callers changed to use new
+ function xdr_decode_fhandle.
+ * nfs.c (xdr_decode_fhandle): New function.
+ * nfs.h (xdr_decode_fhandle): New prototype.
+ (lookup_fhandle): Update prototype.
+
1997-07-23 Miles Bader <miles@gnu.ai.mit.edu>
* main.c: Include <error.h>.
diff --git a/nfs/Makefile b/nfs/Makefile
index f7a7d3bf..05fbd90c 100644
--- a/nfs/Makefile
+++ b/nfs/Makefile
@@ -1,5 +1,5 @@
#
-# Copyright (C) 1995, 1996 Free Software Foundation
+# Copyright (C) 1995, 1996, 1997 Free Software Foundation
# Written by Michael I. Bushnell.
#
# This file is part of the GNU Hurd.
@@ -23,7 +23,7 @@ makemode := server
target = nfs
LCLHDRS = nfs.h mount.h nfs-spec.h
-SRCS = ops.c rpc.c mount.c nfs.c cache.c consts.c main.c
+SRCS = ops.c rpc.c mount.c nfs.c cache.c consts.c main.c name-cache.c
OBJS = $(subst .c,.o,$(SRCS))
HURDLIBS=ports netfs fshelp threads iohelp
diff --git a/nfs/cache.c b/nfs/cache.c
index e09b7c38..f854949c 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.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -41,23 +41,17 @@ 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. */
+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);
@@ -71,7 +65,7 @@ lookup_fhandle (int *p, struct node **npp)
spin_unlock (&netfs_node_refcnt_lock);
mutex_lock (&np->lock);
*npp = np;
- return p + len / sizeof (int);
+ return;
}
nn = malloc (sizeof (struct netnode));
@@ -93,7 +87,6 @@ lookup_fhandle (int *p, struct node **npp)
spin_unlock (&netfs_node_refcnt_lock);
*npp = np;
- return p + len / sizeof (int);
}
/* Called by libnetfs when node NP has no more references. (See
diff --git a/nfs/main.c b/nfs/main.c
index add6ecc8..d9702ecb 100644
--- a/nfs/main.c
+++ b/nfs/main.c
@@ -42,6 +42,12 @@ extern char *localhost ();
/* Default number of seconds to timeout cached file contents. */
#define DEFAULT_CACHE_TIMEOUT 3
+/* Default number of seconds to timeout cache positive dir hits. */
+#define DEFAULT_NAME_CACHE_TIMEOUT 3
+
+/* Default number of seconds to timeout cache negative dir hits. */
+#define DEFAULT_NAME_CACHE_NEG_TIMEOUT 3
+
/* Default maximum number of bytes to read at once. */
#define DEFAULT_READ_SIZE 8192
@@ -55,6 +61,12 @@ int stat_timeout = DEFAULT_STAT_TIMEOUT;
/* Number of seconds to timeout cached file contents. */
int cache_timeout = DEFAULT_CACHE_TIMEOUT;
+/* Number of seconds to timeout cached positive dir hits. */
+int name_cache_timeout = DEFAULT_NAME_CACHE_TIMEOUT;
+
+/* Number of seconds to timeout cached negative dir hits. */
+int name_cache_neg_timeout = DEFAULT_NAME_CACHE_NEG_TIMEOUT;
+
/* Number of seconds to wait for first retransmission of an RPC. */
int initial_transmit_timeout = 1;
@@ -89,6 +101,8 @@ int write_size = DEFAULT_WRITE_SIZE;
#define OPT_MNT_PROG -11
#define OPT_NFS_PROG -12
#define OPT_PMAP_PORT -13
+#define OPT_NCACHE_TO -14
+#define OPT_NCACHE_NEG_TO -15
/* Return a string corresponding to the printed rep of DEFAULT_what */
#define ___D(what) #what
@@ -118,6 +132,12 @@ static const struct argp_option common_options[] =
"Timeout for cached stat information (default " _D(STAT_TIMEOUT) ")"},
{"cache-timeout", OPT_CACHE_TO, "SEC", 0,
"Timeout for cached file data (default " _D(CACHE_TIMEOUT) ")"},
+ {"name-cache-timeout", OPT_NCACHE_TO, "SEC", 0,
+ "Timeout for positive directory cache entries (default "
+ _D(NAME_CACHE_TIMEOUT) ")"},
+ {"name-cache-neg-timeout", OPT_NCACHE_NEG_TO, "SEC", 0,
+ "Timeout for negative directory cache entires (default "
+ _D(NAME_CACHE_NEG_TIMEOUT) ")"},
{"init-transmit-timeout", OPT_INIT_TR_TO,"SEC", 0},
{"max-transmit-timeout", OPT_MAX_TR_TO, "SEC", 0},
@@ -145,6 +165,8 @@ parse_common_opt (int key, char *arg, struct argp_state *state)
case OPT_CACHE_TO: cache_timeout = atoi (arg); break;
case OPT_INIT_TR_TO: initial_transmit_timeout = atoi (arg); break;
case OPT_MAX_TR_TO: max_transmit_timeout = atoi (arg); break;
+ case OPT_NCACHE_TO: name_cache_timeout = atoi (arg); break;
+ case OPT_NCACHE_NEG_TO: name_cache_neg_timeout = atoi (arg); break;
default:
return ARGP_ERR_UNKNOWN;
diff --git a/nfs/mount.c b/nfs/mount.c
index 965d00a9..5c9ec3bc 100644
--- a/nfs/mount.c
+++ b/nfs/mount.c
@@ -1,5 +1,5 @@
/*
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
Written by Michael I. Bushnell, p/BSG.
This file is part of the GNU Hurd.
@@ -181,7 +181,7 @@ mount_root (char *name, char *host)
}
/* Create the node for root */
- lookup_fhandle (p, &np);
+ xdr_decode_fhandle (p, &np);
free (rpcbuf);
mutex_unlock (&np->lock);
diff --git a/nfs/name-cache.c b/nfs/name-cache.c
new file mode 100644
index 00000000..314867d7
--- /dev/null
+++ b/nfs/name-cache.c
@@ -0,0 +1,272 @@
+/* Directory name lookup caching
+
+ Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ Written by Thomas Bushnell, n/BSG, & Miles Bader.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ The GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include "nfs.h"
+#include <string.h>
+#include <cacheq.h>
+
+
+/* Maximum number of names to cache at once */
+#define MAXCACHE 200
+
+/* Maximum length of file name we bother caching */
+#define CACHE_NAME_LEN 100
+
+/* Cache entry */
+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;
+
+ /* 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];
+
+ /* Strlen of NAME. If this is zero, it's an unused entry. */
+ size_t name_len;
+
+ /* Time that this cache entry was created. */
+ time_t cache_stamp;
+
+ /* XXX */
+ int stati;
+};
+
+/* The contents of the cache in no particular order */
+static struct cacheq lookup_cache = { sizeof (struct lookup_cache) };
+
+static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER;
+
+/* Buffer to hold statistics */
+static struct stats
+{
+ long pos_hits;
+ long neg_hits;
+ long miss;
+ long fetch_errors;
+} statistics;
+
+#define PARTIAL_THRESH 100
+#define NPARTIALS MAXCACHE / PARTIAL_THRESH
+struct stats partial_stats [NPARTIALS];
+
+
+/* If there's an entry for NAME, of length NAME_LEN, in directory DIR in the
+ cache, return its entry, otherwise 0. CACHE_LOCK must be held. */
+static struct lookup_cache *
+find_cache (char *dir, size_t len, const char *name, size_t name_len)
+{
+ struct lookup_cache *c;
+ int i;
+
+ /* Search the list. All unused entries are contiguous at the end of the
+ list, so we can stop searching when we see the first one. */
+ for (i = 0, c = lookup_cache.mru;
+ c && c->name_len;
+ c = c->hdr.next, i++)
+ if (c->name_len == name_len
+ && c->dir_cache_len == len
+ && c->name[0] == name[0]
+ && bcmp (c->dir_cache_fh, dir, len) == 0
+ && strcmp (c->name, name) == 0)
+ {
+ c->stati = i / 100;
+ return c;
+ }
+
+ return 0;
+}
+
+/* Node NP has just been found in DIR with NAME. If NP is null, that
+ means that this name has been confirmed as absent in the directory.
+ DIR is the fhandle of the directory; its length is LEN. */
+void
+enter_lookup_cache (char *dir, size_t len, struct node *np, char *name)
+{
+ struct lookup_cache *c;
+ size_t name_len = strlen (name);
+
+ if (name_len > CACHE_NAME_LEN - 1)
+ return;
+
+ spin_lock (&cache_lock);
+
+ if (lookup_cache.length == 0)
+ /* There should always be an lru_cache; this being zero means that the
+ cache hasn't been initialized yet. Do so. */
+ cacheq_set_length (&lookup_cache, MAXCACHE);
+
+ /* See if there's an old entry for NAME in DIR. If not, replace the least
+ recently used entry. */
+ c = find_cache (dir, len, name, name_len) ?: lookup_cache.lru;
+
+ /* 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;
+ strcpy (c->name, name);
+ c->name_len = name_len;
+ c->cache_stamp = mapped_time->seconds;
+
+ /* Now C becomes the MRU entry! */
+ cacheq_make_mru (&lookup_cache, c);
+
+ spin_unlock (&cache_lock);
+}
+
+/* Purge all references in the cache to NAME within directory DIR. */
+void
+purge_lookup_cache (struct node *dp, char *name, size_t namelen)
+{
+ struct lookup_cache *c, *next;
+
+ spin_lock (&cache_lock);
+ for (c = lookup_cache.mru; c; c = next)
+ {
+ /* Save C->hdr.next, since we may move C from this position. */
+ next = c->hdr.next;
+
+ if (c->name_len == namelen
+ && c->dir_cache_len == dp->nn->handle.size
+ && bcmp (c->dir_cache_fh, dp->nn->handle.data, c->dir_cache_len) == 0
+ && strcmp (c->name, name) == 0)
+ {
+ c->name_len = 0;
+ cacheq_make_lru (&lookup_cache, c); /* Use C as the next free
+ entry. */
+ }
+ }
+ spin_unlock (&cache_lock);
+}
+
+/* Register a negative hit for an entry in the Nth stat class */
+void
+register_neg_hit (int n)
+{
+ int i;
+
+ statistics.neg_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].neg_hits++;
+}
+
+/* Register a positive hit for an entry in the Nth stat class */
+void
+register_pos_hit (int n)
+{
+ int i;
+
+ statistics.pos_hits++;
+
+ for (i = 0; i < n; i++)
+ partial_stats[i].miss++;
+ for (; i < NPARTIALS; i++)
+ partial_stats[i].pos_hits++;
+}
+
+/* Register a miss */
+void
+register_miss ()
+{
+ int i;
+
+ statistics.miss++;
+ for (i = 0; i < NPARTIALS; i++)
+ partial_stats[i].miss++;
+}
+
+
+
+/* Scan the cache looking for NAME inside DIR. If we don't know
+ anything entry at all, then return 0. If the entry is confirmed to
+ not exist, then return -1. Otherwise, return NP for the entry, with
+ a newly allocated reference. For any return value but 0, unlock
+ DP before returning. */
+struct node *
+check_lookup_cache (struct node *dir, char *name)
+{
+ struct lookup_cache *c;
+
+ spin_lock (&cache_lock);
+
+ c = find_cache (dir->nn->handle.data, dir->nn->handle.size,
+ name, strlen (name));
+ if (c)
+ {
+ int timeout = c->node_cache_len
+ ? name_cache_timeout
+ : name_cache_neg_timeout;
+
+ /* Make sure the entry is still usable; if not, zap it now. */
+ if (mapped_time->seconds - c->cache_stamp >= timeout)
+ {
+ register_neg_hit (c->stati);
+ c->name_len = 0;
+ cacheq_make_lru (&lookup_cache, c);
+ spin_unlock (&cache_lock);
+ return 0;
+ }
+
+ cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */
+
+ if (c->node_cache_len == 0)
+ /* A negative cache entry. */
+ {
+ register_neg_hit (c->stati);
+ spin_unlock (&cache_lock);
+ mutex_unlock (&dir->lock);
+ return (struct node *)-1;
+ }
+ else
+ {
+ struct node *np;
+ char handle[NFS3_FHSIZE];
+ size_t len;
+
+ 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);
+
+ return np;
+ }
+ }
+
+ register_miss ();
+ spin_unlock (&cache_lock);
+
+ return 0;
+}
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 5ccf7186..f71e82ca 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -371,6 +371,18 @@ xdr_decode_64bit (int *p, long long *n)
return p;
}
+/* Decode *P into an fhandle and look up the associated node. Return
+ the address of the following data. */
+int *
+xdr_decode_fhandle (int *p, struct node **npp)
+{
+ size_t len;
+
+ len = protocol_version == 2 ? NFS2_FHSIZE : ntohl (*p++);
+ lookup_fhandle (p, len, npp);
+ return p + len / sizeof (int);
+}
+
/* Decode *P into a stat structure; return the address of the
following data. */
int *
diff --git a/nfs/nfs.h b/nfs/nfs.h
index 51cd3e46..5a3dd8a9 100644
--- a/nfs/nfs.h
+++ b/nfs/nfs.h
@@ -88,6 +88,12 @@ extern int stat_timeout;
/* How long to keep around file contents caches */
extern int cache_timeout;
+/* How long to keep around positive dir cache entries */
+extern int name_cache_timeout;
+
+/* How long to keep around negative dir cache entries */
+extern int name_cache_neg_timeout;
+
/* How long to wait for replies before re-sending RPC's. */
extern int initial_transmit_timeout;
extern int max_transmit_timeout;
@@ -160,6 +166,7 @@ int *xdr_encode_sattr_stat (int *, struct stat *);
int *xdr_encode_create_state (int *, mode_t, uid_t);
int *xdr_decode_fattr (int *, struct stat *);
int *xdr_decode_string (int *, char *);
+int *xdr_decode_fhandle (int *, struct node **);
int *nfs_initialize_rpc (int, struct iouser *, size_t, void **,
struct node *, uid_t);
error_t nfs_error_trans (int);
@@ -177,5 +184,10 @@ void timeout_service_thread (void);
void rpc_receive_thread (void);
/* cache.c */
-int *lookup_fhandle (int *, struct node **);
+void lookup_fhandle (void *, size_t, struct node **);
int *recache_handle (int *, struct node *);
+
+/* name-cache.c */
+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 *);
diff --git a/nfs/ops.c b/nfs/ops.c
index 877b697f..d9060154 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -543,6 +543,9 @@ verify_nonexistent (struct iouser *cred, struct node *dir,
void *rpcbuf;
error_t err;
+ /* Don't use the lookup cache for this; we want a full sync to
+ get as close to real exclusive create behavior as possible. */
+
assert (protocol_version == 2);
p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
@@ -569,12 +572,32 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np,
int *p;
void *rpcbuf;
error_t err;
+ char dirhandle[NFS3_FHSIZE];
+ size_t dirlen;
+
+ /* Check the cache first. */
+ *newnp = check_lookup_cache (np, name);
+ if (*newnp)
+ {
+ if (*newnp == (struct node *) -1)
+ {
+ *newnp = 0;
+ return ENOENT;
+ }
+ else
+ return 0;
+ }
p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
+ /* Remember the directory handle for later cache use. */
+
+ dirlen = np->nn->handle.size;
+ bcopy (np->nn->handle.data, dirhandle, dirlen);
+
mutex_unlock (&np->lock);
err = conduct_rpc (&rpcbuf, &p);
@@ -583,7 +606,7 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np,
err = nfs_error_trans (ntohl (*p++));
if (!err)
{
- p = lookup_fhandle (p, newnp);
+ p = xdr_decode_fhandle (p, newnp);
p = process_returned_stat (*newnp, p, 1);
}
if (err)
@@ -602,6 +625,9 @@ netfs_attempt_lookup (struct iouser *cred, struct node *np,
else
*newnp = 0;
+ /* Notify the cache of the hit or miss. */
+ enter_lookup_cache (dirhandle, dirlen, *newnp, name);
+
free (rpcbuf);
return err;
@@ -628,6 +654,8 @@ netfs_attempt_mkdir (struct iouser *cred, struct node *np,
mode &= ~S_ISUID;
}
+ purge_lookup_cache (np, name, strlen (name));
+
p = nfs_initialize_rpc (NFSPROC_MKDIR (protocol_version),
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
@@ -638,7 +666,7 @@ netfs_attempt_mkdir (struct iouser *cred, struct node *np,
if (!err)
err = nfs_error_trans (ntohl (*p++));
- p = lookup_fhandle (p, &newnp);
+ p = xdr_decode_fhandle (p, &newnp);
p = process_returned_stat (newnp, p, 1);
/* Did we set the owner correctly? If not, try, but ignore failures. */
@@ -664,6 +692,8 @@ netfs_attempt_rmdir (struct iouser *cred, struct node *np,
/* Should we do the same sort of thing here as with attempt_unlink? */
+ purge_lookup_cache (np, name, strlen (name));
+
p = nfs_initialize_rpc (NFSPROC_RMDIR (protocol_version),
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
@@ -712,6 +742,8 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
mutex_unlock (&np->lock);
mutex_lock (&dir->lock);
+ purge_lookup_cache (dir, name, strlen (name));
+
p = xdr_encode_fhandle (p, &dir->nn->handle);
p = xdr_encode_string (p, name);
@@ -755,6 +787,8 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
mutex_unlock (&np->lock);
mutex_lock (&dir->lock);
+
+ purge_lookup_cache (dir, name, strlen (name));
err = conduct_rpc (&rpcbuf, &p);
if (!err)
{
@@ -840,6 +874,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
mutex_unlock (&np->lock);
mutex_lock (&dir->lock);
+ purge_lookup_cache (dir, name, strlen (name));
err = conduct_rpc (&rpcbuf, &p);
if (!err)
err = nfs_error_trans (ntohl (*p++));
@@ -878,6 +913,7 @@ netfs_attempt_link (struct iouser *cred, struct node *dir,
}
mutex_unlock (&np->lock);
+ purge_lookup_cache (dir, name, strlen (name));
err = conduct_rpc (&rpcbuf, &p);
if (!err)
{
@@ -998,6 +1034,8 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np,
}
}
+ purge_lookup_cache (np, name, strlen (name));
+
p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
@@ -1024,7 +1062,7 @@ netfs_attempt_create_file (struct iouser *cred, struct node *np,
err = nfs_error_trans (ntohl (*p++));
if (!err)
{
- p = lookup_fhandle (p, newnp);
+ p = xdr_decode_fhandle (p, newnp);
p = process_returned_stat (*newnp, p, 1);
}
if (err)
@@ -1112,6 +1150,9 @@ netfs_attempt_unlink (struct iouser *cred, struct node *dir,
netfs_nput (np);
mutex_lock (&dir->lock);
+
+ purge_lookup_cache (dir, name, strlen (name));
+
p = nfs_initialize_rpc (NFSPROC_REMOVE (protocol_version),
cred, 0, &rpcbuf, dir, -1);
p = xdr_encode_fhandle (p, &dir->nn->handle);
@@ -1145,6 +1186,7 @@ netfs_attempt_rename (struct iouser *cred, struct node *fromdir,
return EOPNOTSUPP; /* XXX */
mutex_lock (&fromdir->lock);
+ purge_lookup_cache (fromdir, fromname, strlen (fromname));
p = nfs_initialize_rpc (NFSPROC_RENAME (protocol_version),
cred, 0, &rpcbuf, fromdir, -1);
p = xdr_encode_fhandle (p, &fromdir->nn->handle);
@@ -1152,6 +1194,7 @@ netfs_attempt_rename (struct iouser *cred, struct node *fromdir,
mutex_unlock (&fromdir->lock);
mutex_lock (&todir->lock);
+ purge_lookup_cache (todir, toname, strlen (toname));
p = xdr_encode_fhandle (p, &todir->nn->handle);
p = xdr_encode_string (p, toname);
mutex_unlock (&todir->lock);
diff --git a/nfs/rpc.c b/nfs/rpc.c
index 8068e0ff..90d534ba 100644
--- a/nfs/rpc.c
+++ b/nfs/rpc.c
@@ -1,5 +1,5 @@
/* SunRPC management for NFS client
- Copyright (C) 1994, 1995, 1996 Free Software Foundation
+ Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -368,8 +368,10 @@ rpc_receive_thread ()
break;
}
}
+#if notanymore
if (!r)
fprintf (stderr, "NFS dropping reply xid %d\n", xid);
+#endif
mutex_unlock (&outstanding_lock);
}
}