summaryrefslogtreecommitdiff
path: root/nfs
diff options
context:
space:
mode:
authorMichael I. Bushnell <mib@gnu.org>1996-07-18 04:35:29 +0000
committerMichael I. Bushnell <mib@gnu.org>1996-07-18 04:35:29 +0000
commit94cef36797600d11a50d09828fa80df8a73dfd1c (patch)
treeb7cba9afef95489eedef534d3e6946eb13f595ba /nfs
parent88dbbbf9e48e24f1ac007c1e4eeffd9caf8e2fad (diff)
*** empty log message ***
Diffstat (limited to 'nfs')
-rw-r--r--nfs/pager.c448
-rw-r--r--nfs/rpcsvc/mount.h81
-rw-r--r--nfs/rpcsvc/nfs_prot.h343
3 files changed, 872 insertions, 0 deletions
diff --git a/nfs/pager.c b/nfs/pager.c
new file mode 100644
index 00000000..687a0e2f
--- /dev/null
+++ b/nfs/pager.c
@@ -0,0 +1,448 @@
+/*
+ Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG.
+
+ 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 <unistd.h>
+#include <hurd/pager.h>
+#include <netinet/in.h>
+#include <string.h>
+
+struct user_pager_info
+{
+ struct node *np;
+ struct pager *p;
+ int max_prot;
+};
+
+struct pager_cache_rec
+{
+ struct pager_cache_rec *next;
+ vm_offset_t offset;
+ struct pager *p;
+ time_t fetched;
+};
+
+static struct pager_cache_rec *pager_cache_recs;
+static spin_lock_t pager_cache_rec_lock = SPIN_LOCK_INITIALIZER;
+static spin_lock_t node2pagelock = SPIN_LOCK_INITIALIZER;
+static struct port_bucket *pager_bucket;
+
+void
+register_new_page (struct pager *p, vm_offset_t offset)
+{
+ struct pager_cache_rec *pc;
+
+ pc = malloc (sizeof (struct pager_cache_rec));
+ pc->offset = offset;
+ pc->p = p;
+ ports_port_ref (p);
+ pc->fetched = mapped_time->seconds;
+
+ spin_lock (&pager_cache_rec_lock);
+ pc->next = pager_cache_recs;
+ pager_cache_recs = pc;
+ spin_unlock (&pager_cache_rec_lock);
+}
+
+any_t
+flush_pager_cache_thread (any_t foo2)
+{
+ struct pager_cache_rec *pc, *next, **ppc, *list;
+
+ for (;;)
+ {
+ sleep (1);
+
+ /* Dequeue from the main list and queue locally the recs
+ for expired pages. */
+ list = 0;
+ spin_lock (&pager_cache_rec_lock);
+ for (pc = pager_cache_recs, ppc = &pager_cache_recs;
+ pc;
+ ppc = &pc->next, pc = next)
+ {
+ next = pc->next;
+ if (mapped_time->seconds - pc->fetched > cache_timeout)
+ {
+ *ppc = pc->next;
+ pc->next = list;
+ list = pc;
+ }
+ }
+ spin_unlock (&pager_cache_rec_lock);
+
+ /* And now, one at a time, expire them */
+ for (pc = list; pc; pc = next)
+ {
+ pager_return_some (pc->p, pc->offset, vm_page_size, 0);
+ next = pc->next;
+ ports_port_deref (pc->p);
+ free (pc);
+ }
+ }
+}
+
+error_t
+pager_read_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t *buf,
+ int *writelock)
+{
+ error_t err;
+ int *p;
+ void *rpcbuf;
+ struct node *np;
+ size_t amt, thisamt, trans_len;
+ void *data;
+ off_t offset;
+
+ np = pager->np;
+
+ mutex_lock (&np->lock);
+
+ vm_allocate (mach_task_self (), buf, vm_page_size, 1);
+ data = (char *) *buf;
+ amt = vm_page_size;
+ offset = page;
+
+ while (amt)
+ {
+ thisamt = amt;
+ if (thisamt > read_size)
+ thisamt = read_size;
+
+ p = nfs_initialize_rpc (NFSPROC_READ, (struct netcred *)-1, 0,
+ &rpcbuf, np, -1);
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+ *p++ = htonl (offset);
+ *p++ = htonl (vm_page_size);
+ *p++ = 0;
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ err = nfs_error_trans (ntohl (*p++));
+ if (err)
+ {
+ mutex_unlock (&np->lock);
+ free (rpcbuf);
+ vm_deallocate (mach_task_self (), *buf, vm_page_size);
+ return err;
+ }
+
+ p = register_fresh_stat (np, p);
+ trans_len = ntohl (*p++);
+ if (trans_len > thisamt)
+ 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, we're all done. */
+ if (trans_len < thisamt)
+ break;
+ }
+
+ register_new_page (pager->p, page);
+ mutex_unlock (&np->lock);
+ return 0;
+}
+
+
+error_t
+pager_write_page (struct user_pager_info *pager,
+ vm_offset_t page,
+ vm_address_t buf)
+{
+ int *p;
+ void *rpcbuf;
+ error_t err;
+ size_t amt, thisamt;
+ off_t offset;
+ struct node *np;
+ void *data;
+
+ np = pager->np;
+ mutex_lock (&np->lock);
+
+ amt = vm_page_size;
+ offset = page;
+ data = (void *) buf;
+
+ while (amt)
+ {
+ thisamt = amt;
+ if (amt > write_size)
+ amt = write_size;
+
+ p = nfs_initialize_rpc (NFSPROC_WRITE, (struct netcred *) -1,
+ amt, &rpcbuf, np, -1);
+ p = xdr_encode_fhandle (p, &np->nn->handle);
+ *p++ = 0;
+ *p++ = htonl (offset);
+ *p++ = 0;
+ p = xdr_encode_data (p, data, thisamt);
+
+ err = conduct_rpc (&rpcbuf, &p);
+ if (!err)
+ err = nfs_error_trans (ntohl (*p++));
+ if (err)
+ {
+ free (rpcbuf);
+ vm_deallocate (mach_task_self (), buf, vm_page_size);
+ return err;
+ }
+ register_fresh_stat (np, p);
+ free (rpcbuf);
+ amt -= thisamt;
+ data += thisamt;
+ offset += thisamt;
+ }
+
+ vm_deallocate (mach_task_self (), buf, vm_page_size);
+ mutex_unlock (&np->lock);
+ return 0;
+}
+
+error_t
+pager_unlock_page (struct user_pager_info *pager,
+ vm_offset_t address)
+{
+ abort ();
+}
+
+error_t
+pager_report_extent (struct user_pager_info *pager,
+ vm_address_t *offset,
+ vm_size_t *size)
+{
+ struct node *np;
+ error_t err;
+
+ np = pager->np;
+ mutex_lock (&np->lock);
+
+ err = netfs_validate_stat (np, 0);
+ if (!err)
+ *size = round_page (np->nn_stat.st_size);
+ mutex_unlock (&np->lock);
+ return err;
+}
+
+void
+pager_clear_user_data (struct user_pager_info *upi)
+{
+ spin_lock (&node2pagelock);
+ if (upi->np->nn->fileinfo == upi)
+ upi->np->nn->fileinfo = 0;
+ spin_unlock (&node2pagelock);
+ netfs_nrele (upi->np);
+ free (upi);
+}
+
+void
+pager_dropweak (struct user_pager_info *upi)
+{
+ abort ();
+}
+
+mach_port_t
+netfs_get_filemap (struct node *np, vm_prot_t prot)
+{
+ struct user_pager_info *upi;
+ mach_port_t right;
+
+ spin_lock (&node2pagelock);
+ do
+ if (!np->nn->fileinfo)
+ {
+ upi = malloc (sizeof (struct user_pager_info));
+ upi->np = np;
+ netfs_nref (np);
+ upi->max_prot = prot;
+ upi->p = pager_create (upi, pager_bucket, 1, MEMORY_OBJECT_COPY_NONE);
+ np->nn->fileinfo = upi;
+ right = pager_get_port (np->nn->fileinfo->p);
+ ports_port_deref (np->nn->fileinfo->p);
+ }
+ else
+ {
+ np->nn->fileinfo->max_prot |= prot;
+ /* Because NP->dn->fileinfo->p is not a real reference,
+ this might be nearly deallocated. If that's so, then
+ the port right will be null. In that case, clear here
+ and loop. The deallocation will complete separately. */
+ right = pager_get_port (np->nn->fileinfo->p);
+ if (right == MACH_PORT_NULL)
+ np->nn->fileinfo = 0;
+ }
+ while (right == MACH_PORT_NULL);
+
+ spin_unlock (&node2pagelock);
+
+ mach_port_insert_right (mach_task_self (), right, right,
+ MACH_MSG_TYPE_MAKE_SEND);
+ return right;
+}
+
+void
+drop_pager_softrefs (struct node *np)
+{
+ struct user_pager_info *upi;
+
+ spin_lock (&node2pagelock);
+ upi = np->nn->fileinfo;
+ if (upi)
+ ports_port_ref (upi->p);
+ spin_unlock (&node2pagelock);
+
+ if (upi)
+ {
+ pager_change_attributes (upi->p, 0, MEMORY_OBJECT_COPY_NONE, 0);
+ ports_port_deref (upi->p);
+ }
+}
+
+void
+allow_pager_softrefs (struct node *np)
+{
+ struct user_pager_info *upi;
+
+ spin_lock (&node2pagelock);
+ upi = np->nn->fileinfo;
+ if (upi)
+ ports_port_ref (upi->p);
+ spin_unlock (&node2pagelock);
+
+ if (upi)
+ {
+ pager_change_attributes (upi->p, 1, MEMORY_OBJECT_COPY_NONE, 0);
+ ports_port_deref (upi->p);
+ }
+}
+
+void
+block_caching ()
+{
+ error_t block_cache (void *arg)
+ {
+ struct pager *p = arg;
+ pager_change_attributes (p, 0, MEMORY_OBJECT_COPY_NONE, 1);
+ return 0;
+ }
+ ports_bucket_iterate (pager_bucket, block_cache);
+}
+
+void
+enable_caching ()
+{
+ error_t enable_cache (void *arg)
+ {
+ struct pager *p = arg;
+ struct user_pager_info *upi = pager_get_upi (p);
+
+ pager_change_attributes (p, 1, MEMORY_OBJECT_COPY_NONE, 0);
+ return 0;
+ }
+
+ ports_bucket_iterate (pager_bucket, enable_cache);
+}
+
+int
+netfs_pager_users ()
+{
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (!npagers)
+ return 0;
+
+ block_caching ();
+ /* Give it a sec; the kernel doesn't issue the shutdown right away */
+ sleep (1);
+ npagers = ports_count_bucket (pager_bucket);
+ if (!npagers)
+ return 0;
+
+ enable_caching ();
+
+ ports_enable_bucket (pager_bucket);
+}
+
+vm_prot_t
+netfs_max_user_pager_prot ()
+{
+ vm_prot_t max_prot;
+ int npagers = ports_count_bucket (pager_bucket);
+
+ if (npagers)
+ {
+ error_t add_pager_max_prot (void *v_p)
+ {
+ struct pager *p = v_p;
+ struct user_pager_info *upi = pager_get_upi (p);
+ max_prot |= upi->max_prot;
+ return max_prot == (VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE);
+ }
+
+ block_caching ();
+ sleep (1);
+
+ ports_bucket_iterate (pager_bucket, add_pager_max_prot);
+ enable_caching ();
+ }
+
+ ports_enable_bucket (pager_bucket);
+ return max_prot;
+}
+
+void
+netfs_shutdown_pager ()
+{
+ error_t shutdown_one (void *arg)
+ {
+ pager_shutdown ((struct pager *) arg);
+ return 0;
+ }
+
+ ports_bucket_iterate (pager_bucket, shutdown_one);
+}
+
+void
+netfs_sync_everything (int wait)
+{
+ error_t sync_one (void *arg)
+ {
+ pager_sync ((struct pager *) arg, wait);
+ return 0;
+ }
+ ports_bucket_iterate (pager_bucket, sync_one);
+}
+
+void
+pager_initialize (void)
+{
+ pager_bucket = ports_create_bucket ();
+ cthread_detach (cthread_fork (flush_pager_cache_thread, 0));
+
diff --git a/nfs/rpcsvc/mount.h b/nfs/rpcsvc/mount.h
new file mode 100644
index 00000000..2dc3dc88
--- /dev/null
+++ b/nfs/rpcsvc/mount.h
@@ -0,0 +1,81 @@
+#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/nfs/rpcsvc/nfs_prot.h b/nfs/rpcsvc/nfs_prot.h
new file mode 100644
index 00000000..7f974930
--- /dev/null
+++ b/nfs/rpcsvc/nfs_prot.h
@@ -0,0 +1,343 @@
+#define NFS_PORT 2049
+#define NFS_MAXDATA 8192
+#define NFS_MAXPATHLEN 1024
+#define NFS_MAXNAMLEN 255
+#define NFS_FHSIZE 32
+#define NFS_COOKIESIZE 4
+#define NFS_FIFO_DEV -1
+#define NFSMODE_FMT 0170000
+#define NFSMODE_DIR 0040000
+#define NFSMODE_CHR 0020000
+#define NFSMODE_BLK 0060000
+#define NFSMODE_REG 0100000
+#define NFSMODE_LNK 0120000
+#define NFSMODE_SOCK 0140000
+#define NFSMODE_FIFO 0010000
+
+enum nfsstat {
+ NFS_OK = 0,
+ NFSERR_PERM = 1,
+ NFSERR_NOENT = 2,
+ NFSERR_IO = 5,
+ NFSERR_NXIO = 6,
+ NFSERR_ACCES = 13,
+ NFSERR_EXIST = 17,
+ NFSERR_NODEV = 19,
+ NFSERR_NOTDIR = 20,
+ NFSERR_ISDIR = 21,
+ NFSERR_FBIG = 27,
+ NFSERR_NOSPC = 28,
+ NFSERR_ROFS = 30,
+ NFSERR_NAMETOOLONG = 63,
+ NFSERR_NOTEMPTY = 66,
+ NFSERR_DQUOT = 69,
+ NFSERR_STALE = 70,
+ NFSERR_WFLUSH = 99,
+};
+typedef enum nfsstat nfsstat;
+bool_t xdr_nfsstat();
+
+
+enum ftype {
+ NFNON = 0,
+ NFREG = 1,
+ NFDIR = 2,
+ NFBLK = 3,
+ NFCHR = 4,
+ NFLNK = 5,
+ NFSOCK = 6,
+ NFBAD = 7,
+ NFFIFO = 8,
+};
+typedef enum ftype ftype;
+bool_t xdr_ftype();
+
+
+struct nfs_fh {
+ char data[NFS_FHSIZE];
+};
+typedef struct nfs_fh nfs_fh;
+bool_t xdr_nfs_fh();
+
+
+struct nfstime {
+ u_int seconds;
+ u_int useconds;
+};
+typedef struct nfstime nfstime;
+bool_t xdr_nfstime();
+
+
+struct fattr {
+ ftype type;
+ u_int mode;
+ u_int nlink;
+ u_int uid;
+ u_int gid;
+ u_int size;
+ u_int blocksize;
+ u_int rdev;
+ u_int blocks;
+ u_int fsid;
+ u_int fileid;
+ nfstime atime;
+ nfstime mtime;
+ nfstime ctime;
+};
+typedef struct fattr fattr;
+bool_t xdr_fattr();
+
+
+struct sattr {
+ u_int mode;
+ u_int uid;
+ u_int gid;
+ u_int size;
+ nfstime atime;
+ nfstime mtime;
+};
+typedef struct sattr sattr;
+bool_t xdr_sattr();
+
+
+typedef char *filename;
+bool_t xdr_filename();
+
+
+typedef char *nfspath;
+bool_t xdr_nfspath();
+
+
+struct attrstat {
+ nfsstat status;
+ union {
+ fattr attributes;
+ } attrstat_u;
+};
+typedef struct attrstat attrstat;
+bool_t xdr_attrstat();
+
+
+struct sattrargs {
+ nfs_fh file;
+ sattr attributes;
+};
+typedef struct sattrargs sattrargs;
+bool_t xdr_sattrargs();
+
+
+struct diropargs {
+ nfs_fh dir;
+ filename name;
+};
+typedef struct diropargs diropargs;
+bool_t xdr_diropargs();
+
+
+struct diropokres {
+ nfs_fh file;
+ fattr attributes;
+};
+typedef struct diropokres diropokres;
+bool_t xdr_diropokres();
+
+
+struct diropres {
+ nfsstat status;
+ union {
+ diropokres diropres;
+ } diropres_u;
+};
+typedef struct diropres diropres;
+bool_t xdr_diropres();
+
+
+struct readlinkres {
+ nfsstat status;
+ union {
+ nfspath data;
+ } readlinkres_u;
+};
+typedef struct readlinkres readlinkres;
+bool_t xdr_readlinkres();
+
+
+struct readargs {
+ nfs_fh file;
+ u_int offset;
+ u_int count;
+ u_int totalcount;
+};
+typedef struct readargs readargs;
+bool_t xdr_readargs();
+
+
+struct readokres {
+ fattr attributes;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct readokres readokres;
+bool_t xdr_readokres();
+
+
+struct readres {
+ nfsstat status;
+ union {
+ readokres reply;
+ } readres_u;
+};
+typedef struct readres readres;
+bool_t xdr_readres();
+
+
+struct writeargs {
+ nfs_fh file;
+ u_int beginoffset;
+ u_int offset;
+ u_int totalcount;
+ struct {
+ u_int data_len;
+ char *data_val;
+ } data;
+};
+typedef struct writeargs writeargs;
+bool_t xdr_writeargs();
+
+
+struct createargs {
+ diropargs where;
+ sattr attributes;
+};
+typedef struct createargs createargs;
+bool_t xdr_createargs();
+
+
+struct renameargs {
+ diropargs from;
+ diropargs to;
+};
+typedef struct renameargs renameargs;
+bool_t xdr_renameargs();
+
+
+struct linkargs {
+ nfs_fh from;
+ diropargs to;
+};
+typedef struct linkargs linkargs;
+bool_t xdr_linkargs();
+
+
+struct symlinkargs {
+ diropargs from;
+ nfspath to;
+ sattr attributes;
+};
+typedef struct symlinkargs symlinkargs;
+bool_t xdr_symlinkargs();
+
+
+typedef char nfscookie[NFS_COOKIESIZE];
+bool_t xdr_nfscookie();
+
+
+struct readdirargs {
+ nfs_fh dir;
+ nfscookie cookie;
+ u_int count;
+};
+typedef struct readdirargs readdirargs;
+bool_t xdr_readdirargs();
+
+
+struct entry {
+ u_int fileid;
+ filename name;
+ nfscookie cookie;
+ struct entry *nextentry;
+};
+typedef struct entry entry;
+bool_t xdr_entry();
+
+
+struct dirlist {
+ entry *entries;
+ bool_t eof;
+};
+typedef struct dirlist dirlist;
+bool_t xdr_dirlist();
+
+
+struct readdirres {
+ nfsstat status;
+ union {
+ dirlist reply;
+ } readdirres_u;
+};
+typedef struct readdirres readdirres;
+bool_t xdr_readdirres();
+
+
+struct statfsokres {
+ u_int tsize;
+ u_int bsize;
+ u_int blocks;
+ u_int bfree;
+ u_int bavail;
+};
+typedef struct statfsokres statfsokres;
+bool_t xdr_statfsokres();
+
+
+struct statfsres {
+ nfsstat status;
+ union {
+ statfsokres reply;
+ } statfsres_u;
+};
+typedef struct statfsres statfsres;
+bool_t xdr_statfsres();
+
+
+#define NFS_PROGRAM ((u_long)100003)
+#define NFS_VERSION ((u_long)2)
+#define NFSPROC_NULL ((u_long)0)
+extern void *nfsproc_null_2();
+#define NFSPROC_GETATTR ((u_long)1)
+extern attrstat *nfsproc_getattr_2();
+#define NFSPROC_SETATTR ((u_long)2)
+extern attrstat *nfsproc_setattr_2();
+#define NFSPROC_ROOT ((u_long)3)
+extern void *nfsproc_root_2();
+#define NFSPROC_LOOKUP ((u_long)4)
+extern diropres *nfsproc_lookup_2();
+#define NFSPROC_READLINK ((u_long)5)
+extern readlinkres *nfsproc_readlink_2();
+#define NFSPROC_READ ((u_long)6)
+extern readres *nfsproc_read_2();
+#define NFSPROC_WRITECACHE ((u_long)7)
+extern void *nfsproc_writecache_2();
+#define NFSPROC_WRITE ((u_long)8)
+extern attrstat *nfsproc_write_2();
+#define NFSPROC_CREATE ((u_long)9)
+extern diropres *nfsproc_create_2();
+#define NFSPROC_REMOVE ((u_long)10)
+extern nfsstat *nfsproc_remove_2();
+#define NFSPROC_RENAME ((u_long)11)
+extern nfsstat *nfsproc_rename_2();
+#define NFSPROC_LINK ((u_long)12)
+extern nfsstat *nfsproc_link_2();
+#define NFSPROC_SYMLINK ((u_long)13)
+extern nfsstat *nfsproc_symlink_2();
+#define NFSPROC_MKDIR ((u_long)14)
+extern diropres *nfsproc_mkdir_2();
+#define NFSPROC_RMDIR ((u_long)15)
+extern nfsstat *nfsproc_rmdir_2();
+#define NFSPROC_READDIR ((u_long)16)
+extern readdirres *nfsproc_readdir_2();
+#define NFSPROC_STATFS ((u_long)17)
+extern statfsres *nfsproc_statfs_2();
+