summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdiskfs/ChangeLog57
-rw-r--r--libdiskfs/lookup.c35
-rw-r--r--libdiskfs/name-cache.c112
-rw-r--r--nfs/ChangeLog71
-rw-r--r--nfs/Makefile4
-rw-r--r--nfs/mount.c3
-rw-r--r--nfs/mount.h4
-rw-r--r--nfs/nfs-spec.h (renamed from nfs/rpcsvc/nfs_prot.h)23
-rw-r--r--nfs/nfs.c31
-rw-r--r--nfs/nfs.h3
-rw-r--r--nfs/ops.c531
-rw-r--r--nfs/rpc.c5
-rw-r--r--nfs/rpcsvc/mount.h81
-rw-r--r--nfsd/ChangeLog8
-rw-r--r--nfsd/loop.c2
-rw-r--r--nfsd/nfsd.h2
-rw-r--r--nfsd/ops.c2
-rw-r--r--tasks7
18 files changed, 743 insertions, 238 deletions
diff --git a/libdiskfs/ChangeLog b/libdiskfs/ChangeLog
index 3ae2e004..a0d446e8 100644
--- a/libdiskfs/ChangeLog
+++ b/libdiskfs/ChangeLog
@@ -1,3 +1,60 @@
+Tue Sep 3 10:48:05 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (diskfs_enter_lookup_cache): Cache `.' and `..'
+ just like other nodes.
+ (diskfs_check_lookup_cache): If we get a cache hit on `..', then
+ do the inverse locking semantic, and only return success if things
+ are stable around the call.
+
+Fri Aug 30 21:57:18 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * lookup.c (cache_misses): New variable, to find out what sort of
+ thing all the cache misses are.
+ (cm_lock): New variable.
+ (diskfs_lookup): Keep track of cache misses in cache_misses.
+
+ * name-cache.c (MAXCACHE): 200 now. After experimentation, this
+ appears to be a pretty good value. Very little benefit after
+ this.
+
+Fri Aug 30 20:41:27 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (struct lookup_cache): Delete member `hits'.
+ New member `stati'.
+ (diskfs_enter_lookup_cache): Don't initialize C->hits.
+ (find_cache): Set C->stati before returning.
+ (build_partial): Delete function.
+ (diskfs_check_lookup_cache): Delete calls to build_partial.
+ Register all statistics through register_neg_hit,
+ register_pos_hit, and register_miss.
+ (MAXCACHE): 2000 now.
+
+Wed Aug 28 12:20:53 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (MAXCACHE): 500 for now.
+
+Mon Aug 26 15:10:55 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (MAXCACHE): Increase to 50000.
+ (struct lookup_cache): New member `hits'.
+ (statistics): Name struct type `struct stats'.
+ (diskfs_enter_lookup_cache): Initialize C->hits.
+ (PARTIAL_THRESH, NPARTIALS): New macros.
+ (partial_stats): New variable.
+ (build_partial): New function.
+ (diskfs_check_lookup_cache): Call build_partial after statistics
+ frobbing.
+
+ * name-cache.c (diskfs_check_lookup_cache): Increment members of
+ statistics while still holding CACHE_LOCK.
+
+Fri Aug 16 18:23:25 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * name-cache.c (diskfs_check_lookup_cache): Keep track of negative
+ hits properly.
+ * lookup.c (diskfs_lookup): On LOOKUPs that fail to find the node,
+ enter a negative cache entry.
+
Thu Aug 15 16:07:23 1996 Miles Bader <miles@gnu.ai.mit.edu>
* opts-version.c (diskfs_extra_version): New (weak) reference.
diff --git a/libdiskfs/lookup.c b/libdiskfs/lookup.c
index 40ce8937..282d829f 100644
--- a/libdiskfs/lookup.c
+++ b/libdiskfs/lookup.c
@@ -20,6 +20,17 @@
#include "priv.h"
+static struct
+{
+ int present;
+ int absent;
+ int errors;
+ int dot;
+ int dotdot;
+} cache_misses;
+static spin_lock_t cm_lock = SPIN_LOCK_INITIALIZER;
+
+
/* Lookup in directory DP (which is locked) the name NAME. TYPE will
either be LOOKUP, CREATE, RENAME, or REMOVE. CRED identifies the
user making the call.
@@ -71,7 +82,7 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
struct protid *cred)
{
error_t err;
-
+
if (type == REMOVE || type == RENAME)
assert (np);
@@ -119,6 +130,26 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
}
err = diskfs_lookup_hard (dp, name, type, np, ds, cred);
+
+ spin_lock (&cm_lock);
+ if (type == LOOKUP)
+ {
+ if (err == ENOENT)
+ cache_misses.absent++;
+ else if (err)
+ cache_misses.errors++;
+ else
+ cache_misses.present++;
+ if (name[0] == '.')
+ {
+ if (name[1] == '\0')
+ cache_misses.dot++;
+ else if (name[1] == '.' && name[2] == '\0')
+ cache_misses.dotdot++;
+ }
+ }
+ spin_unlock (&cm_lock);
+
if (err && err != ENOENT)
return err;
@@ -137,6 +168,8 @@ diskfs_lookup (struct node *dp, char *name, enum lookup_type type,
if ((type == LOOKUP || type == CREATE) && !err && np)
diskfs_enter_lookup_cache (dp, *np, name);
+ else if (type == LOOKUP && err == ENOENT)
+ diskfs_enter_lookup_cache (dp, 0, name);
return err;
}
diff --git a/libdiskfs/name-cache.c b/libdiskfs/name-cache.c
index 2cf1ed8b..808c16f4 100644
--- a/libdiskfs/name-cache.c
+++ b/libdiskfs/name-cache.c
@@ -24,7 +24,7 @@
#include <cacheq.h>
/* Maximum number of names to cache at once */
-#define MAXCACHE 256
+#define MAXCACHE 200
/* Maximum length of file name we bother caching */
#define CACHE_NAME_LEN 100
@@ -44,7 +44,10 @@ struct lookup_cache
char name[CACHE_NAME_LEN];
/* Strlen of NAME. If this is zero, it's an unused entry. */
- size_t name_len;
+ size_t name_len;
+
+ /* XXX */
+ int stati;
};
/* The contents of the cache in no particular order */
@@ -53,13 +56,18 @@ static struct cacheq lookup_cache = { sizeof (struct lookup_cache) };
static spin_lock_t cache_lock = SPIN_LOCK_INITIALIZER;
/* Buffer to hold statistics */
-static struct
+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 it's entry, otherwise 0. CACHE_LOCK must be held. */
@@ -67,15 +75,21 @@ static struct lookup_cache *
find_cache (struct node *dir, 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 (c = lookup_cache.mru; c && c->name_len; c = c->hdr.next)
+ 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_id == dir->cache_id
&& c->name[0] == name[0] && strcmp (c->name, name) == 0)
- return c;
-
+ {
+ c->stati = i / 100;
+ return c;
+ }
+
return 0;
}
@@ -90,13 +104,6 @@ diskfs_enter_lookup_cache (struct node *dir, struct node *np, char *name)
if (name_len > CACHE_NAME_LEN - 1)
return;
- /* Never cache . or ..; it's too much trouble to get the locking
- order right. */
- if (name[0] == '.'
- && (name[1] == '\0'
- || (name[1] == '.' && name[2] == '\0')))
- return;
-
spin_lock (&cache_lock);
if (lookup_cache.length == 0)
@@ -145,6 +152,47 @@ diskfs_purge_lookup_cache (struct node *dp, struct node *np)
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
@@ -163,15 +211,18 @@ diskfs_check_lookup_cache (struct node *dir, char *name)
cacheq_make_mru (&lookup_cache, c); /* Record C as recently used. */
- statistics.pos_hits++;
- spin_unlock (&cache_lock);
-
if (id == 0)
/* A negative cache entry. */
- return (struct node *)-1;
+ {
+ register_neg_hit (c->stati);
+ spin_unlock (&cache_lock);
+ return (struct node *)-1;
+ }
else if (id == dir->cache_id)
/* The cached node is the same as DIR. */
{
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
diskfs_nref (dir);
return dir;
}
@@ -179,12 +230,35 @@ diskfs_check_lookup_cache (struct node *dir, char *name)
/* Just a normal entry in DIR; get the actual node. */
{
struct node *np;
- error_t err = diskfs_cached_lookup (id, &np);
+ error_t err;
+
+ register_pos_hit (c->stati);
+ spin_unlock (&cache_lock);
+
+ if (name[0] == '.' && name[1] == '.' && name[2] == '\0')
+ {
+ mutex_unlock (&dir->lock);
+ err = diskfs_cached_lookup (id, &np);
+ mutex_lock (&dir->lock);
+
+ /* In the window where DP was unlocked, we might
+ have lost. So check the cache again, and see
+ if it's still there; if so, then we win. */
+ c = find_cache (dir, "..", 2);
+ if (!c || c->node_cache_id != id)
+ {
+ /* Lose */
+ mutex_unlock (&np->lock);
+ return 0;
+ }
+ }
+ else
+ err = diskfs_cached_lookup (id, &np);
return err ? 0 : np;
}
}
- statistics.miss++;
+ register_miss ();
spin_unlock (&cache_lock);
return 0;
diff --git a/nfs/ChangeLog b/nfs/ChangeLog
index dfe11aa4..e3c5c4a9 100644
--- a/nfs/ChangeLog
+++ b/nfs/ChangeLog
@@ -1,3 +1,74 @@
+Tue Sep 3 14:00:25 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * nfs-spec.h: Renamed from rpcsvc/nfs_prot.h.
+ * mount.c: Include "mount.h" instead of <rpcsvc/mount.h>.
+ * nfs.h: Include "nfs-spec.h" instead of <rpcsvc/nfs_prot.h>.
+ * rpcsvc/mount.h: Deleted file.
+ * rpcsvc: Deleted directory.
+ * mount.h (MOUNTPROG): Renamed from MOUNT_RPC_PROGRAM.
+ (MOUNTVERS): Renamed from MOUNT_RPC_VERSION.
+ * Makefile (RPCSVC_FILES): Deleted var.
+ (lndist, lndist-rpcsvc-files,
+ $(top_srcdir)/hurd-snap/$(dir)/rpcsvc): Deleted targets.
+ (LCLHDRS): Added mount.h and nfs-spec.h.
+
+Thu Aug 29 10:41:27 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * rpcsvc/nfs_prot.h (createmode): Spell EXCLUSIVE correctly.
+ * nfs.c (hurd_mode_to_nfs_type): New function.
+ * nfs.h (hurd_mode_to_nfs_type): New decl.
+ * ops.c (netfs_attempt_rmdir): process_wcc_stat for NP, not DIR.
+ (netfs_attempt_link): Spell netfs_validate_stat correctly.
+ (minor, major): New macros.
+ (netfs_report_access): Don't try and return an error.
+
+ * rpc.c (conduct_rpc): Tolerate and return errors from write.
+
+ * Makefile (RPCSVC_FILES): New variable.
+ (lndist): Depend on lndist-rpcsvc-files.
+ (lndist-rpcsvc-files, $(top_srcdir)/hurd-snap/$(dir)/rpcsvc): New
+ targets.
+
+Fri Aug 16 11:56:53 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * ops.c (process_wcc_stat): New function.
+ (netfs_attempt_chown): Use process_wcc_stat instead of
+ register_fresh_stat. Pack and unpack v3 SETATTR structure if
+ appropriate.
+ (netfs_attempt_chmod): Likewise.
+ (netfs_attempt_utimes): Likewise.
+ (netfs_attempt_set_size): Likewise.
+ (netfs_attempt_lookup): Use process_returned_stat instead of
+ register_fresh state. Unpack v3 LOOKUP structure if appropriate.
+ (netfs_attempt_link): Likewise.
+ (verify_nonexistent): Assert that we are v2.
+ (netfs_report_access): Use NFS3PROC_ACCESS if we are v3.
+ (netfs_check_open_permissions): Use netfs_report_access.
+ (netfs_attempt_readlink): Unpack v3 READLINK structure if
+ appropriate.
+ (netfs_attempt_read): Pack and unpack v3 READ structure in
+ appropriate. Use process_returned_stat instead of
+ register_fresh_stat.
+ (netfs_attempt_write): Pack and unpack v3 WRITE structure in
+ appropriate. Use process_wcc_stat instead of
+ register_fresh_stat.
+ (netfs_attempt_create_file): Pack and unpack v3 CREATE structure
+ if appropriate. Use process_returned_stat instead of
+ register_fresh_stat.
+ (netfs_attempt_link) [CHRDEV, BLKDEV, FIFO, SOCK]: If v3, use new
+ MKNOD call instead of CREATE with overloaded mode.
+ (netfs_attempt_link) [SYMLINK]: If pack and unpack v3 SYMLINK
+ structure if appropriate.
+ (netfs_attempt_unlink): Unpack v3 REMOVE structure if appropriate.
+ (netfs_attempt_rmdir): Unpack v3 RMDIR structure if appropriate.
+ (netfs_attempt_rename): Unpack v3 RENAME structure if appropriate.
+
+ * rpcsvc/nfs_prot.h (ACCESS3_READ, ACCESS3_LOOKUP, ACCESS3_MODIFY,
+ ACCESS3_EXTEND, ACCESS3_DELETE, ACCESS3_EXECUTE): New macros.
+
+ * ops.c (netfs_attempt_chown): Bother to read NFS error/success
+ value.
+
Thu Aug 15 15:24:29 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
* ops.c (verify_nonexistent): Don't need to lock DIR; it's already
diff --git a/nfs/Makefile b/nfs/Makefile
index 66ecaeac..da35cc03 100644
--- a/nfs/Makefile
+++ b/nfs/Makefile
@@ -22,10 +22,12 @@ dir := nfs
makemode := server
target = nfs
-LCLHDRS = nfs.h
+LCLHDRS = nfs.h mount.h nfs-spec.h
SRCS = ops.c rpc.c mount.c cred.c nfs.c cache.c consts.c main.c
OBJS = $(subst .c,.o,$(SRCS))
nfs: $(OBJS) ../libports/libports.a ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a ../libthreads/libthreads.a
include ../Makeconf
+
+
diff --git a/nfs/mount.c b/nfs/mount.c
index a7ceaf50..ce1329e2 100644
--- a/nfs/mount.c
+++ b/nfs/mount.c
@@ -20,7 +20,6 @@
#include "nfs.h"
-#include <rpcsvc/mount.h>
#include <rpc/pmap_prot.h>
#include <errno.h>
#include <sys/socket.h>
@@ -29,6 +28,8 @@
#include <netinet/in.h>
#include <stdio.h>
+#include "mount.h"
+
/* Service name for portmapper */
char *pmap_service_name = "sunrpc";
diff --git a/nfs/mount.h b/nfs/mount.h
index b1862442..fce8ee4c 100644
--- a/nfs/mount.h
+++ b/nfs/mount.h
@@ -20,8 +20,8 @@
/* These constants define the RPC mount protocol; see RFC 1094. */
-#define MOUNT_RPC_PROGRAM 100005
-#define MOUNT_RPC_VERSION 1
+#define MOUNTPROG 100005
+#define MOUNTVERS 1
/* Obnoxious arbitrary limits */
#define MOUNT_MNTPATHLEN 1024
diff --git a/nfs/rpcsvc/nfs_prot.h b/nfs/nfs-spec.h
index 476c72ef..32f5b09d 100644
--- a/nfs/rpcsvc/nfs_prot.h
+++ b/nfs/nfs-spec.h
@@ -74,6 +74,29 @@ enum sattr_time_how
SET_TO_CLIENT_TIME = 2,
};
+/* Construction of ACCESS arg to NFS3PROC_ACCESS. */
+#define ACCESS3_READ 0x01
+#define ACCESS3_LOOKUP 0x02
+#define ACCESS3_MODIFY 0x04
+#define ACCESS3_EXTEND 0x08
+#define ACCESS3_DELETE 0x10
+#define ACCESS3_EXECUTE 0x20
+
+/* STABLE arg to NFS3PROC_READ */
+enum stable_how {
+ UNSTABLE = 0,
+ DATA_SYNC = 1,
+ FILE_SYNC = 2,
+};
+
+/* MODE arg to NFS3PROC_CREATE */
+enum createmode
+{
+ UNCHECKED = 0,
+ GUARDED = 1,
+ EXCLUSIVE = 2,
+};
+
#define NFS_PROGRAM ((u_long)100003)
#define NFS_VERSION ((u_long)2)
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 490f494b..a44e1fde 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -97,6 +97,37 @@ hurd_mode_to_nfs_mode (mode_t mode)
return mode & 07777;
}
+/* Convert a Hurd mode to an NFS type */
+int
+hurd_mode_to_nfs_type (mode_t mode)
+{
+ switch (mode & S_IFMT)
+ {
+ case S_IFDIR:
+ return NFDIR;
+
+ case S_IFCHR:
+ default:
+ return NFCHR;
+
+ case S_IFBLK:
+ return NFBLK;
+
+ case S_IFREG:
+ return NFREG;
+
+ case S_IFLNK:
+ return NFLNK;
+
+ case S_IFSOCK:
+ return NFSOCK;
+
+ case S_IFIFO:
+ return protocol_version == 2 ? NF2FIFO : NF3FIFO;
+ }
+}
+
+
/* Each of the functions on this page copies its second arg to *P,
converting it to XDR representation along the way. They then
diff --git a/nfs/nfs.h b/nfs/nfs.h
index 29fc8ccc..758ba9e9 100644
--- a/nfs/nfs.h
+++ b/nfs/nfs.h
@@ -21,7 +21,7 @@ typedef int bool_t; /* Ick. */
#include <sys/stat.h>
#include <sys/types.h>
-#include <rpcsvc/nfs_prot.h>
+#include "nfs-spec.h"
#include <hurd/netfs.h>
/* A file handle */
@@ -164,6 +164,7 @@ int cred_has_uid (struct netcred *, uid_t);
int cred_has_gid (struct netcred *, gid_t);
/* nfs.c */
+int hurd_mode_to_nfs_type (mode_t);
int *xdr_encode_fhandle (int *, struct fhandle *);
int *xdr_encode_data (int *, char *, size_t);
int *xdr_encode_string (int *, char *);
diff --git a/nfs/ops.c b/nfs/ops.c
index 50218fa5..5251d423 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -74,6 +74,61 @@ register_fresh_stat (struct node *np, int *p)
return ret;
}
+/* Handle returned wcc information for various calls. In protocol
+ version 2, this is just register_fresh_stat. In version 3, it
+ checks to see if stat information is present too. If this follows
+ an operation that we expect has modified the attributes, MOD should
+ be set. (This unpacks the post_op_attr XDR type.) */
+int *
+process_returned_stat (struct node *np, int *p, int mod)
+{
+ int attrs_exist;
+
+ if (protocol_version == 2)
+ return register_fresh_stat (np, p);
+ else
+ {
+ attrs_exist = ntohl (*p++);
+ if (attrs_exist)
+ p = register_fresh_stat (np, p);
+ else if (mod)
+ /* We know that our values are now wrong */
+ np->nn->stat_updated = 0;
+ return p;
+ }
+}
+
+
+/* Handle returned wcc information for various calls. In protocol
+ version 2, this is just register_fresh_stat. In version 3, it does
+ the wcc_data interpretation too. If this follows an operation that
+ we expect has modified the attributes, MOD should be set.
+ (This unpacks the wcc_data XDR type.) */
+int *
+process_wcc_stat (struct node *np, int *p, int mod)
+{
+ if (protocol_version == 2)
+ return register_fresh_stat (np, p);
+ else
+ {
+ int attrs_exist;
+
+ /* First the pre_op_attr */
+ attrs_exist = ntohl (*p++);
+ if (attrs_exist)
+ {
+ /* Just skip them for now */
+ p += 2 * sizeof (int); /* size */
+ p += 2 * sizeof (int); /* mtime */
+ p += 2 * sizeof (int); /* atime */
+ }
+
+ /* Now the post_op_attr */
+ return process_returned_stat (np, p, mod);
+ }
+}
+
+
/* Implement the netfs_validate_stat callback as described in
<hurd/netfs.h>. */
error_t
@@ -116,11 +171,16 @@ netfs_attempt_chown (struct netcred *cred, struct node *np,
cred, 0, &rpcbuf, np, gid);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_ids (p, uid, gid);
+ if (protocol_version == 3)
+ *p++ = 0; /* guard_check == 0 */
err = conduct_rpc (&rpcbuf, &p);
-
if (!err)
- register_fresh_stat (np, p);
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
free (rpcbuf);
@@ -185,14 +245,17 @@ netfs_attempt_chmod (struct netcred *cred, struct node *np,
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_mode (p, mode);
+ if (protocol_version == 3)
+ *p++ = 0; /* guard check == 0 */
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
- if (!err)
- register_fresh_stat (np, p);
-
free (rpcbuf);
return err;
}
@@ -220,13 +283,16 @@ netfs_attempt_utimes (struct netcred *cred, struct node *np,
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_times (p, atime, mtime);
+ if (protocol_version == 3)
+ *p++ = 0; /* guard check == 0 */
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
- register_fresh_stat (np, p);
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
free (rpcbuf);
return err;
@@ -246,14 +312,17 @@ netfs_attempt_set_size (struct netcred *cred, struct node *np,
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_sattr_size (p, size);
+ if (protocol_version == 3)
+ *p++ = 0; /* guard_check == 0 */
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
- if (!err)
- register_fresh_stat (np, p);
-
free (rpcbuf);
return err;
}
@@ -324,6 +393,7 @@ netfs_attempt_read (struct netcred *cred, struct node *np,
size_t trans_len;
error_t err;
size_t amt, thisamt;
+ int eof;
for (amt = *len; amt;)
{
@@ -336,36 +406,44 @@ netfs_attempt_read (struct netcred *cred, struct node *np,
p = xdr_encode_fhandle (p, &np->nn->handle);
*p++ = htonl (offset);
*p++ = htonl (thisamt);
- *p++ = 0;
+ if (protocol_version == 2)
+ *p++ = 0;
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (err)
{
- free (rpcbuf);
- return err;
- }
-
- p = register_fresh_stat (np, p);
-
- trans_len = ntohl (*p++);
- if (trans_len > thisamt)
- trans_len = thisamt; /* ??? */
+ err = nfs_error_trans (ntohl (*p++));
+
+ if (!err || protocol_version == 3)
+ p = process_returned_stat (np, p, !err);
+
+ if (err)
+ {
+ free (rpcbuf);
+ return err;
+ }
- bcopy (p, data, trans_len);
- free (rpcbuf);
+ trans_len = ntohl (*p++);
+ if (trans_len > thisamt)
+ trans_len = thisamt; /* ??? */
- data += trans_len;
- offset += trans_len;
- amt -= trans_len;
+ if (protocol_version == 3)
+ eof = ntohl (*p++);
+ else
+ eof = (trans_len < thisamt);
+
+ bcopy (p, data, trans_len);
+ free (rpcbuf);
+
+ data += trans_len;
+ offset += trans_len;
+ amt -= trans_len;
- /* If we got a short count, that means we're all done */
- if (trans_len < thisamt)
- {
- *len -= amt;
- return 0;
+ if (eof)
+ {
+ *len -= amt;
+ return 0;
+ }
}
}
return 0;
@@ -381,6 +459,7 @@ netfs_attempt_write (struct netcred *cred, struct node *np,
void *rpcbuf;
error_t err;
size_t amt, thisamt;
+ size_t count;
for (amt = *len; amt;)
{
@@ -391,26 +470,47 @@ netfs_attempt_write (struct netcred *cred, struct node *np,
p = nfs_initialize_rpc (NFSPROC_WRITE (protocol_version),
cred, thisamt, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
- *p++ = 0;
+ if (protocol_version == 2)
+ *p++ = 0;
*p++ = htonl (offset);
- *p++ = 0;
+ if (protocol_version == 2)
+ *p++ = 0;
+ if (protocol_version == 3)
+ *p++ = htonl (FILE_SYNC);
p = xdr_encode_data (p, data, thisamt);
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err || protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ if (!err)
+ {
+ if (protocol_version == 3)
+ {
+ count = ntohl (*p++);
+ p++; /* ignore COMMITTED */
+ /* ignore verf for now */
+ p += NFS3_WRITEVERFSIZE / sizeof (int);
+ }
+ else
+ /* assume it wrote the whole thing */
+ count = thisamt;
+
+ free (rpcbuf);
+ amt -= count;
+ data += count;
+ offset += count;
+ }
+ }
+
if (err)
{
*len = 0;
free (rpcbuf);
return err;
}
- register_fresh_stat (np, p);
- free (rpcbuf);
- amt -= thisamt;
- data += thisamt;
- offset += thisamt;
}
return 0;
}
@@ -424,6 +524,8 @@ verify_nonexistent (struct netcred *cred, struct node *dir,
void *rpcbuf;
error_t err;
+ assert (protocol_version == 2);
+
p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
cred, 0, &rpcbuf, dir, -1);
p = xdr_encode_fhandle (p, &dir->nn->handle);
@@ -458,12 +560,25 @@ netfs_attempt_lookup (struct netcred *cred, struct node *np,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
{
- p = lookup_fhandle (p, newnp);
- register_fresh_stat (*newnp, p);
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err)
+ {
+ p = lookup_fhandle (p, newnp);
+ p = process_returned_stat (*newnp, p, 1);
+ }
+ if (err)
+ *newnp = 0;
+ if (protocol_version == 3)
+ {
+ if (*newnp)
+ mutex_unlock (&(*newnp)->lock);
+ mutex_lock (&np->lock);
+ p = process_returned_stat (np, p, 0);
+ mutex_unlock (&np->lock);
+ if (*newnp)
+ mutex_lock (&(*newnp)->lock);
+ }
}
else
*newnp = 0;
@@ -519,7 +634,11 @@ netfs_attempt_rmdir (struct netcred *cred, struct node *np,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (protocol_version == 3)
+ p = process_wcc_stat (np, p, !err);
+ }
free (rpcbuf);
return err;
@@ -586,42 +705,71 @@ netfs_attempt_link (struct netcred *cred, struct node *dir,
return err;
}
- p = xdr_encode_string (p, np->nn->transarg.name);
- p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ if (protocol_version == 2)
+ {
+ p = xdr_encode_string (p, np->nn->transarg.name);
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ }
+ else
+ {
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ p = xdr_encode_string (p, np->nn->transarg.name);
+ }
mutex_unlock (&np->lock);
mutex_lock (&dir->lock);
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
{
- /* NFSPROC_SYMLINK stupidly does not pass back an
- fhandle, so we have to fetch one now. */
- p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
- cred, 0, &rpcbuf, dir, -1);
- p = xdr_encode_fhandle (p, &dir->nn->handle);
- p = xdr_encode_string (p, name);
+ err = nfs_error_trans (ntohl (*p++));
+
+ if (protocol_version == 2 && !err)
+ {
+ free (rpcbuf);
+
+ /* NFSPROC_SYMLINK stupidly does not pass back an
+ fhandle, so we have to fetch one now. */
+ p = nfs_initialize_rpc (NFSPROC_LOOKUP (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- mutex_unlock (&dir->lock);
-
- if (err)
- err = EGRATUITOUS; /* damn */
- else
+ mutex_unlock (&dir->lock);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err)
+ {
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ p = process_returned_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ }
+ if (err)
+ err = EGRATUITOUS; /* damn */
+ }
+ else if (protocol_version == 3)
{
- mutex_lock (&np->lock);
- p = recache_handle (p, np);
- register_fresh_stat (np, p);
- mutex_unlock (&np->lock);
+ if (!err)
+ {
+ mutex_unlock (&dir->lock);
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ p = process_returned_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ mutex_lock (&dir->lock);
+ }
+ p = process_wcc_stat (dir, p, !err);
+ mutex_unlock (&dir->lock);
}
+ else
+ mutex_unlock (&dir->lock);
}
else
mutex_unlock (&dir->lock);
+
+ free (rpcbuf);
break;
case CHRDEV:
@@ -629,40 +777,87 @@ netfs_attempt_link (struct netcred *cred, struct node *dir,
case FIFO:
case SOCK:
- mutex_lock (&dir->lock);
- err = verify_nonexistent (cred, dir, name);
- if (err)
- return err;
+ if (protocol_version == 2)
+ {
+ mutex_lock (&dir->lock);
+ err = verify_nonexistent (cred, dir, name);
+ if (err)
+ return err;
- p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
- cred, 0, &rpcbuf, dir, -1);
- p = xdr_encode_fhandle (p, &dir->nn->handle);
- p = xdr_encode_string (p, name);
- mutex_unlock (&dir->lock);
+ p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
+ cred, 0, &rpcbuf, dir, -1);
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
+ mutex_unlock (&dir->lock);
+
+ mutex_lock (&np->lock);
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ return err;
+ }
+
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ mutex_unlock (&np->lock);
- mutex_lock (&np->lock);
- err = netfs_validate_stat (np, cred);
- if (err)
+ mutex_lock (&dir->lock);
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ err = nfs_error_trans (ntohl (*p++));
+ mutex_unlock (&dir->lock);
+
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ register_fresh_stat (np, p);
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ }
+ else
{
+ mutex_lock (&dir->lock);
+ p = nfs_initialize_rpc (NFS3PROC_MKNOD, cred, 0, &rpcbuf, dir, -1);
+ p = xdr_encode_fhandle (p, &dir->nn->handle);
+ p = xdr_encode_string (p, name);
+ mutex_unlock (&dir->lock);
+
+ mutex_lock (&np->lock);
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ return err;
+ }
+ *p++ = htonl (hurd_mode_to_nfs_type (np->nn_stat.st_mode));
+ p = xdr_encode_sattr_stat (p, &np->nn_stat);
+ if (np->nn->dtrans == BLKDEV || np->nn->dtrans == CHRDEV)
+ {
+#define major(D) (((D)>>8) & 0xff)
+#define minor(D) ((D) & 0xff)
+ *p++ = htonl (major (np->nn_stat.st_rdev));
+ *p++ = htonl (minor (np->nn_stat.st_rdev));
+ }
mutex_unlock (&np->lock);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err)
+ {
+ mutex_lock (&np->lock);
+ p = recache_handle (p, np);
+ p = process_returned_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ }
+ mutex_lock (&dir->lock);
+ p = process_wcc_stat (dir, p, !err);
+ mutex_unlock (&dir->lock);
+ }
free (rpcbuf);
- return err;
}
-
- p = xdr_encode_sattr_stat (p, &np->nn_stat);
- mutex_unlock (&np->lock);
-
- mutex_lock (&dir->lock);
- err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
- mutex_unlock (&dir->lock);
-
- mutex_lock (&np->lock);
- p = recache_handle (p, np);
- register_fresh_stat (np, p);
- mutex_unlock (&np->lock);
-
break;
}
@@ -743,26 +938,57 @@ netfs_attempt_create_file (struct netcred *cred, struct node *np,
void *rpcbuf;
error_t err;
- err = verify_nonexistent (cred, np, name);
- if (err)
- return err;
+ /* RFC 1094 says that create is always exclusive. But Sun doesn't
+ actually *implement* the spec. No, of course not. So we have to do
+ it for them. */
+ if (protocol_version == 2)
+ {
+ err = verify_nonexistent (cred, np, name);
+ if (err)
+ return err;
+ }
p = nfs_initialize_rpc (NFSPROC_CREATE (protocol_version),
cred, 0, &rpcbuf, np, -1);
p = xdr_encode_fhandle (p, &np->nn->handle);
p = xdr_encode_string (p, name);
- p = xdr_encode_create_state (p, mode);
+ if (protocol_version == 3)
+ {
+ /* We happen to know this is where the XID is. */
+ int verf = *(int *)rpcbuf;
+
+ *p++ = ntohl (EXCLUSIVE);
+ /* 8 byte verf */
+ *p++ = ntohl (verf);
+ p++;
+ }
+ else
+ p = xdr_encode_create_state (p, mode);
err = conduct_rpc (&rpcbuf, &p);
- if (!err)
- err = nfs_error_trans (ntohl (*p++));
mutex_unlock (&np->lock);
if (!err)
{
- p = lookup_fhandle (p, newnp);
- register_fresh_stat (*newnp, p);
+ err = nfs_error_trans (ntohl (*p++));
+ if (!err)
+ {
+ p = lookup_fhandle (p, newnp);
+ p = process_returned_stat (*newnp, p, 1);
+ }
+ if (err)
+ *newnp = 0;
+ if (protocol_version == 3)
+ {
+ if (*newnp)
+ mutex_unlock (&(*newnp)->lock);
+ mutex_lock (&np->lock);
+ p = process_wcc_stat (np, p, 1);
+ mutex_unlock (&np->lock);
+ if (*newnp)
+ mutex_lock (&(*newnp)->lock);
+ }
}
else
*newnp = 0;
@@ -839,7 +1065,11 @@ netfs_attempt_unlink (struct netcred *cred, struct node *dir,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (protocol_version == 3)
+ p = process_wcc_stat (dir, p, !err);
+ }
free (rpcbuf);
@@ -874,7 +1104,15 @@ netfs_attempt_rename (struct netcred *cred, struct node *fromdir,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (protocol_version == 3)
+ {
+ mutex_lock (&fromdir->lock);
+ p = process_wcc_stat (fromdir, p, !err);
+ p = process_wcc_stat (todir, p, !err);
+ }
+ }
free (rpcbuf);
return err;
@@ -902,10 +1140,13 @@ netfs_attempt_readlink (struct netcred *cred, struct node *np,
err = conduct_rpc (&rpcbuf, &p);
if (!err)
- err = nfs_error_trans (ntohl (*p++));
-
- if (!err)
- p = xdr_decode_string (p, buf);
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ if (protocol_version == 3)
+ p = process_returned_stat (np, p, 0);
+ if (!err)
+ p = xdr_decode_string (p, buf);
+ }
free (rpcbuf);
return err;
@@ -961,11 +1202,13 @@ error_t
netfs_check_open_permissions (struct netcred *cred, struct node *np,
int flags, int newnode)
{
+ int modes;
+
if ((flags & (O_READ|O_WRITE|O_EXEC)) == 0)
return 0;
- if ((flags & (O_READ|O_WRITE|O_EXEC))
- == (flags & guess_mode_use (np, cred)))
+ netfs_report_access (cred, np, &modes);
+ if ((flags & (O_READ|O_WRITE|O_EXEC)) == (flags & modes))
return 0;
else
return EACCES;
@@ -978,9 +1221,53 @@ netfs_report_access (struct netcred *cred,
struct node *np,
int *types)
{
- *types = guess_mode_use (np, cred);
-}
+ if (protocol_version == 2)
+ *types = guess_mode_use (np, cred);
+ else
+ {
+ int *p;
+ void *rpcbuf;
+ error_t err;
+ int ret;
+ int write_check, execute_check;
+ err = netfs_validate_stat (np, cred);
+ if (err)
+ goto fallback;
+ if (S_ISDIR (np->nn_stat.st_mode))
+ {
+ write_check = ACCESS3_MODIFY | ACCESS3_DELETE | ACCESS3_EXTEND;
+ execute_check = ACCESS3_LOOKUP;
+ }
+ else
+ {
+ write_check = ACCESS3_MODIFY;
+ execute_check = ACCESS3_EXECUTE;
+ }
+
+ p = nfs_initialize_rpc (NFS3PROC_ACCESS, cred, 0, &rpcbuf, np, -1);
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+ *p++ = htonl (ACCESS3_READ | write_check | execute_check);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ {
+ err = nfs_error_trans (ntohl (*p++));
+ p = process_returned_stat (np, p, 0);
+ if (!err)
+ {
+ ret = ntohl (*p++);
+ *types = ((ret & ACCESS3_READ ? O_READ : 0)
+ | (ret & write_check ? O_WRITE : 0)
+ | (ret & execute_check ? O_EXEC : 0));
+ }
+ else
+ /* fall back, sigh. */
+ fallback:
+ *types = guess_mode_use (np, cred);
+ }
+ }
+}
/* These definitions have unfortunate side effects, don't use them,
clever though they are. */
diff --git a/nfs/rpc.c b/nfs/rpc.c
index 7df05c36..81c98fc1 100644
--- a/nfs/rpc.c
+++ b/nfs/rpc.c
@@ -193,7 +193,10 @@ conduct_rpc (void **rpcbuf, int **pp)
nc = (void *) *pp - *rpcbuf - sizeof (struct rpc_list);
cc = write (main_udp_socket, *rpcbuf + sizeof (struct rpc_list), nc);
if (cc == -1)
- assert_perror (errno);
+ {
+ unlink_rpc (hdr);
+ return errno;
+ }
else
assert (cc == nc);
diff --git a/nfs/rpcsvc/mount.h b/nfs/rpcsvc/mount.h
deleted file mode 100644
index 2dc3dc88..00000000
--- a/nfs/rpcsvc/mount.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#define MNTPATHLEN 1024
-#define MNTNAMLEN 255
-#define FHSIZE 32
-
-typedef char fhandle[FHSIZE];
-bool_t xdr_fhandle();
-
-
-struct fhstatus {
- u_int fhs_status;
- union {
- fhandle fhs_fhandle;
- } fhstatus_u;
-};
-typedef struct fhstatus fhstatus;
-bool_t xdr_fhstatus();
-
-
-typedef char *dirpath;
-bool_t xdr_dirpath();
-
-
-typedef char *name;
-bool_t xdr_name();
-
-
-typedef struct mountbody *mountlist;
-bool_t xdr_mountlist();
-
-
-struct mountbody {
- name ml_hostname;
- dirpath ml_directory;
- mountlist ml_next;
-};
-typedef struct mountbody mountbody;
-bool_t xdr_mountbody();
-
-
-typedef struct groupnode *groups;
-bool_t xdr_groups();
-
-
-struct groupnode {
- name gr_name;
- groups gr_next;
-};
-typedef struct groupnode groupnode;
-bool_t xdr_groupnode();
-
-
-typedef struct exportnode *exports;
-bool_t xdr_exports();
-
-
-struct exportnode {
- dirpath ex_dir;
- groups ex_groups;
- exports ex_next;
-};
-typedef struct exportnode exportnode;
-bool_t xdr_exportnode();
-
-
-#define MOUNTPROG ((u_long)100005)
-#define MOUNTVERS ((u_long)1)
-#define MOUNTPROC_NULL ((u_long)0)
-extern void *mountproc_null_1();
-#define MOUNTPROC_MNT ((u_long)1)
-extern fhstatus *mountproc_mnt_1();
-#define MOUNTPROC_DUMP ((u_long)2)
-extern mountlist *mountproc_dump_1();
-#define MOUNTPROC_UMNT ((u_long)3)
-extern void *mountproc_umnt_1();
-#define MOUNTPROC_UMNTALL ((u_long)4)
-extern void *mountproc_umntall_1();
-#define MOUNTPROC_EXPORT ((u_long)5)
-extern exports *mountproc_export_1();
-#define MOUNTPROC_EXPORTALL ((u_long)6)
-extern exports *mountproc_exportall_1();
-
diff --git a/nfsd/ChangeLog b/nfsd/ChangeLog
index 744bd3b8..aee85ea1 100644
--- a/nfsd/ChangeLog
+++ b/nfsd/ChangeLog
@@ -1,3 +1,11 @@
+Tue Sep 3 14:15:50 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
+
+ * loop.c: Include "../nfs/mount.h" instead of
+ "../nfs/rpcsvc/mount.h".
+ * ops.c: Likewise.
+ * nfsd.h: Include "../nfs/nfs-spec.h" instead of
+ "../nfs/rpcsvc/nfs_prot.h".
+
Wed Aug 14 13:46:45 1996 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu>
* ops.c (nfstable): Renamed to nfs2table.
diff --git a/nfsd/loop.c b/nfsd/loop.c
index 7d047490..87e133ad 100644
--- a/nfsd/loop.c
+++ b/nfsd/loop.c
@@ -24,7 +24,7 @@
#include "nfsd.h"
#include <rpc/pmap_prot.h>
-#include "../nfs/rpcsvc/mount.h"
+#include "../nfs/mount.h"
#undef TRUE
#undef FALSE
diff --git a/nfsd/nfsd.h b/nfsd/nfsd.h
index d6d7aac9..b225c1cd 100644
--- a/nfsd/nfsd.h
+++ b/nfsd/nfsd.h
@@ -25,7 +25,7 @@ typedef int bool_t;
#include <errno.h>
#include <netinet/in.h>
#include <cthreads.h>
-#include "../nfs/rpcsvc/nfs_prot.h" /* XXX */
+#include "../nfs/nfs-spec.h" /* XXX */
#include <hurd/fs.h>
/* These should be configuration options */
diff --git a/nfsd/ops.c b/nfsd/ops.c
index efcfa103..cf86aa12 100644
--- a/nfsd/ops.c
+++ b/nfsd/ops.c
@@ -26,7 +26,7 @@
#include <dirent.h>
#include "nfsd.h"
-#include "../nfs/rpcsvc/mount.h" /* XXX */
+#include "../nfs/mount.h" /* XXX */
#include <rpc/pmap_prot.h>
static error_t
diff --git a/tasks b/tasks
index 0376d4a0..56cad8e1 100644
--- a/tasks
+++ b/tasks
@@ -1,4 +1,4 @@
-GNU Hurd Task List Version 1.16. Last updated 8 August 1996.
+GNU Hurd Task List Version 1.17. Last updated 3 September 1996.
If you would like to work on one of these, please contact
thomas@gnu.ai.mit.edu. It's important that you let me know what's being
@@ -48,10 +48,6 @@ microkernel work there as well as with mib@gnu.ai.mit.edu.
in functionality to the Unix ITIMER_PROF and ITIMER_VIRTUAL timers.
!!!
- * Mach 3.0 needs to provide a way for users to do statistical PC
- profiling similar to the Unix profil system call.
-
-!!!
* Mach 3.0 needs to make switches from MEMORY_OBJECT_COPY_DELAY to
MEMORY_OBJECT_COPY_NONE have the effect of immediately completing any
delayed copies.
@@ -154,7 +150,6 @@ Hurd work (these are brief descriptions; mib can give more information):
* Filesystem implementations (using libdiskfs) for other popular
formats. Importantly, MSDOS FAT format.
-
* Transparent FTP translator.
* A fancy terminal driver that uses readline and supports detach/attach.