first bootable NFS from Rick Macklem
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Thu, 6 Jul 1989 02:36:01 +0000 (18:36 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Thu, 6 Jul 1989 02:36:01 +0000 (18:36 -0800)
SCCS-vsn: sys/nfs/nfs.h 7.1
SCCS-vsn: sys/nfs/nfs_vnops.c 7.1
SCCS-vsn: sys/nfs/nfs_socket.c 7.1
SCCS-vsn: sys/nfs/nfs_syscalls.c 7.1
SCCS-vsn: sys/nfs/nfs_vfsops.c 7.1
SCCS-vsn: sys/nfs/nfsm_subs.h 7.1
SCCS-vsn: sys/nfs/nfsmount.h 7.1
SCCS-vsn: sys/nfs/nfsnode.h 7.1
SCCS-vsn: sys/nfs/nfsproto.h 7.1
SCCS-vsn: sys/nfs/rpcv2.h 7.1
SCCS-vsn: sys/nfs/xdr_subs.h 7.1
SCCS-vsn: sys/nfs/nfs_node.c 7.1

12 files changed:
usr/src/sys/nfs/nfs.h [new file with mode: 0644]
usr/src/sys/nfs/nfs_node.c [new file with mode: 0644]
usr/src/sys/nfs/nfs_socket.c [new file with mode: 0644]
usr/src/sys/nfs/nfs_syscalls.c [new file with mode: 0644]
usr/src/sys/nfs/nfs_vfsops.c [new file with mode: 0644]
usr/src/sys/nfs/nfs_vnops.c [new file with mode: 0644]
usr/src/sys/nfs/nfsm_subs.h [new file with mode: 0644]
usr/src/sys/nfs/nfsmount.h [new file with mode: 0644]
usr/src/sys/nfs/nfsnode.h [new file with mode: 0644]
usr/src/sys/nfs/nfsproto.h [new file with mode: 0644]
usr/src/sys/nfs/rpcv2.h [new file with mode: 0644]
usr/src/sys/nfs/xdr_subs.h [new file with mode: 0644]

diff --git a/usr/src/sys/nfs/nfs.h b/usr/src/sys/nfs/nfs.h
new file mode 100644 (file)
index 0000000..cd913ef
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfs.h       7.1 (Berkeley) %G%
+ */
+
+/*
+ * Tunable constants for nfs
+ */
+#define        MAX_IOVEC       10
+#define        NFS_TIMEO       10      /* Timeout in .01 sec intervals */
+#define        NFS_ATTRTIMEO   5       /* Attribute cache timeout in sec */
+#define        NFS_RETRANS     10      /* Num of retrans for soft mounts */
+#define        NFS_WSIZE       8196    /* Max. write data size <= 8192 */
+#define        NFS_RSIZE       8196    /* Max. read data size <= 8192 */
+#define        MAX_READDIR     NFS_RSIZE       /* Max. size of directory read */
+
+/*
+ * Nfs outstanding request list element
+ */
+struct nfsreq {
+       struct nfsreq   *r_next;
+       struct nfsreq   *r_prev;
+       struct mbuf     *r_mreq;
+       struct mbuf     *r_mrep;
+       struct nfsmount *r_mntp;
+       struct vnode    *r_vp;
+       int             r_msiz;
+       u_long          r_xid;
+       u_long          r_retry;
+       u_long          r_timeout;
+       u_long          r_timer;
+};
+
+/*
+ * Silly rename structure that hangs off the nfsnode until the name
+ * can be removed by nfs_inactive()
+ */
+struct sillyrename {
+       int     s_flag;
+       nfsv2fh_t s_fh;
+       struct nameidata s_namei;
+};
+
+/* And its flag values */
+#define REMOVE         0
+#define        RMDIR           1
+
+/*
+ * Stats structure
+ */
+struct nfsstats {
+       int     attrcache_hits;
+       int     attrcache_misses;
+       int     lookupcache_hits;
+       int     lookupcache_misses;
+       int     rpccnt[NFS_NPROCS];
+       int     rpcretries;
+       int     srvrpccnt[NFS_NPROCS];
+       int     srvrpc_errs;
+       int     srv_errs;
+};
+
+#ifdef KERNEL
+struct nfsstats nfsstats;
+#endif
diff --git a/usr/src/sys/nfs/nfs_node.c b/usr/src/sys/nfs/nfs_node.c
new file mode 100644 (file)
index 0000000..7325046
--- /dev/null
@@ -0,0 +1,412 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfs_node.c  7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "user.h"
+#include "proc.h"
+#include "mount.h"
+#include "vnode.h"
+#include "dir.h"
+#include "namei.h"
+#include "errno.h"
+#include "nfsv2.h"
+#include "nfs.h"
+#include "nfsnode.h"
+#include "nfsmount.h"
+#include "kernel.h"
+#include "malloc.h"
+
+/* The request list head */
+extern struct nfsreq nfsreqh;
+
+/* Someday this should be dynamically sized like the inode table */
+struct nfsnode nfsnd[2000];
+struct nfsnode *nfsnode = &nfsnd[0];
+struct nfsnode *nfsnodeNNFSNODE = &nfsnd[2000];
+int nnfsnode = 2000;
+
+#define        NFSNOHSZ        512
+#if    ((NFSNOHSZ&(NFSNOHSZ-1)) == 0)
+#define        NFSNOHASH(fhsum)        ((fhsum)&(NFSNOHSZ-1))
+#else
+#define        NFSNOHASH(fhsum)        (((unsigned)(fhsum))%NFSNOHSZ)
+#endif
+
+union nhead {                          /* inode LRU cache, Chris Maltby */
+       union  nhead *nh_head[2];
+       struct nfsnode *nh_chain[2];
+} nhead[NFSNOHSZ];
+
+struct nfsnode *nfreeh, **nfreet;
+
+/*
+ * Initialize hash links for nfsnodes
+ * and build nfsnode free list.
+ */
+nfs_nhinit()
+{
+       register int i;
+       register struct nfsnode *np = nfsnode;
+       register union  nhead *nh = nhead;
+
+       for (i = NFSNOHSZ; --i >= 0; nh++) {
+               nh->nh_head[0] = nh;
+               nh->nh_head[1] = nh;
+       }
+       nfreeh = np;
+       nfreet = &np->n_freef;
+       np->n_freeb = &nfreeh;
+       np->n_forw = np;
+       np->n_back = np;
+       NFSTOV(np)->v_data = (qaddr_t)np;
+       for (i = nnfsnode; --i > 0; ) {
+               ++np;
+               np->n_forw = np;
+               np->n_back = np;
+               NFSTOV(np)->v_data = (qaddr_t)np;
+               *nfreet = np;
+               np->n_freeb = nfreet;
+               nfreet = &np->n_freef;
+       }
+       np->n_freef = NULL;
+}
+
+/*
+ * Look up an vnode/nfsnode by file handle.
+ * Callers must check for mount points!!
+ * In all cases, a pointer to a
+ * nfsnode structure is returned.
+ */
+nfs_nget(mntp, fhp, npp)
+       struct mount *mntp;
+       register nfsv2fh_t *fhp;
+       struct nfsnode **npp;
+{
+       register struct nfsnode *np;
+       register struct vnode *vp;
+       register struct nfsnode *nq;
+       register u_char *fhpp;
+       register u_long fhsum;
+       register int i;
+       union  nhead *nh;
+       int error;
+
+       fhpp = &fhp->fh_bytes[0];
+       fhsum = 0;
+       for (i = 0; i < NFSX_FH; i++)
+               fhsum += *fhpp++;
+loop:
+       nh = &nhead[NFSNOHASH(fhsum)];
+       for (np = nh->nh_chain[0]; np != (struct nfsnode *)nh; np = np->n_forw)
+               if (mntp == NFSTOV(np)->v_mount &&
+                   !bcmp((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH)) {
+                       /*
+                        * Following is essentially an inline expanded
+                        * copy of ngrab(), expanded inline for speed,
+                        * and so that the test for a mounted on nfsnode
+                        * can be deferred until after we are sure that
+                        * the nfsnode isn't busy.
+                        */
+                       if ((np->n_flag & NLOCKED) != 0) {
+                               np->n_flag |= NWANT;
+                               sleep((caddr_t)np, PINOD);
+                               goto loop;
+                       }
+                       vp = NFSTOV(np);
+                       if (vp->v_count == 0) {         /* nfsno on free list */
+                               if (nq = np->n_freef)
+                                       nq->n_freeb = np->n_freeb;
+                               else
+                                       nfreet = np->n_freeb;
+                               *np->n_freeb = nq;
+                               np->n_freef = NULL;
+                               np->n_freeb = NULL;
+                       }
+                       np->n_flag |= NLOCKED;
+                       vp->v_count++;
+                       *npp = np;
+                       return(0);
+               }
+
+       if ((np = nfreeh) == NULL) {
+               tablefull("nfsnode");
+               *npp = 0;
+               return(ENFILE);
+       }
+       vp = NFSTOV(np);
+       if (vp->v_count)
+               panic("free nfsnode isn't");
+       if (nq = np->n_freef)
+               nq->n_freeb = &nfreeh;
+       nfreeh = nq;
+       np->n_freef = NULL;
+       np->n_freeb = NULL;
+       /*
+        * Now to take nfsnode off the hash chain it was on
+        * (initially, or after an nflush, it is on a "hash chain"
+        * consisting entirely of itself, and pointed to by no-one,
+        * but that doesn't matter), and put it on the chain for
+        * its new file handle
+        */
+       remque(np);
+       insque(np, nh);
+       bcopy((caddr_t)fhp, (caddr_t)&np->n_fh, NFSX_FH);
+#ifdef notyet
+       cache_purge(vp);
+#endif
+       np->n_flag = NLOCKED;
+       np->n_attrstamp = 0;
+       np->n_sillyrename = (struct sillyrename *)0;
+       np->n_id = ++nextnfsnodeid;
+       /*
+        * Initialize the associated vnode
+        */
+       vinit(vp, mntp, VNON, &nfsv2_vnodeops);
+       *npp = np;
+       return (0);
+}
+
+/*
+ * Convert a pointer to an nfsnode into a reference to an nfsnode.
+ *
+ * This is basically the internal piece of nget (after the
+ * nfsnode pointer is located) but without the test for mounted
+ * filesystems.  It is caller's responsibility to check that
+ * the nfsnode pointer is valid.
+ */
+nfs_ngrab(np)
+       register struct nfsnode *np;
+{
+       register struct vnode *vp = NFSTOV(np);
+
+       while ((np->n_flag & NLOCKED) != 0) {
+               np->n_flag |= NWANT;
+               sleep((caddr_t)np, PINOD);
+       }
+       if (vp->v_count == 0) {         /* ino on free list */
+               register struct nfsnode *nq;
+
+               if (nq = np->n_freef)
+                       nq->n_freeb = np->n_freeb;
+               else
+                       nfreet = np->n_freeb;
+               *np->n_freeb = nq;
+               np->n_freef = NULL;
+               np->n_freeb = NULL;
+       }
+       vp->v_count++;
+       np->n_flag |= NLOCKED;
+}
+
+nfs_inactive(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np;
+       register struct nameidata *ndp;
+       register struct sillyrename *sp;
+       register struct nfsreq *rep;
+       struct nfsreq *rep2;
+       struct nfsnode *dnp;
+       int s;
+
+       if (vp == NULL)
+               panic("nfs_inactive NULL vp");
+       if (vp->v_count == 0) {
+               np = VTONFS(vp);
+               np->n_flag |= NLOCKED;
+               if (np->n_sillyrename) {
+                       /*
+                        * Remove the silly file that was rename'd earlier
+                        */
+                       sp = np->n_sillyrename;
+                       ndp = &sp->s_namei;
+                       if (!nfs_nget(vp->v_mount, &sp->s_fh, &dnp)) {
+                               ndp->ni_dvp = NFSTOV(dnp);
+                               if (sp->s_flag == REMOVE)
+                                       nfs_removeit(ndp);
+                               else
+                                       nfs_rmdirit(ndp);
+                               nfs_nput(ndp->ni_dvp);
+                       }
+                       crfree(ndp->ni_cred);
+                       free((caddr_t)sp, M_TEMP);
+                       np->n_sillyrename = (struct sillyrename *)0;
+               }
+               nfs_unlock(vp);
+               np->n_flag = 0;
+               /*
+                * Scan the request list for any requests left hanging about
+                */
+               s = splnet();
+               rep = nfsreqh.r_next;
+               while (rep) {
+                       if (rep->r_vp == vp) {
+                               rep->r_prev->r_next = rep2 = rep->r_next;
+                               if (rep->r_next != NULL)
+                                       rep->r_next->r_prev = rep->r_prev;
+                               m_freem(rep->r_mreq);
+                               if (rep->r_mrep != NULL)
+                                       m_freem(rep->r_mrep);
+                               free((caddr_t)rep, M_NFSREQ);
+                               rep = rep2;
+                       } else
+                               rep = rep->r_next;
+               }
+               splx(s);
+               /*
+                * Put the nfsnode on the end of the free list.
+                */
+               if (nfreeh) {
+                       *nfreet = np;
+                       np->n_freeb = nfreet;
+               } else {
+                       nfreeh = np;
+                       np->n_freeb = &nfreeh;
+               }
+               np->n_freef = NULL;
+               nfreet = &np->n_freef;
+       }
+       return (0);
+}
+
+/*
+ * Remove any nfsnodes in the nfsnode cache belonging to mount.
+ *
+ * There should not be any active ones, return error if any are found
+ * (nb: this is a user error, not a system err).
+ */
+nfs_nflush(mntp)
+       struct mount *mntp;
+{
+       register struct nfsnode *np;
+       register struct vnode *vp;
+
+       for (np = nfsnode; np < nfsnodeNNFSNODE; np++) {
+               vp = NFSTOV(np);
+               if (vp->v_mount == mntp)
+                       if (vp->v_count)
+                               return (EBUSY);
+                       else {
+                               remque(np);
+                               np->n_forw = np;
+                               np->n_back = np;
+                               /*
+                                * as v_count == 0, the inode was on the free
+                                * list already, just leave it there, it will
+                                * fall off the bottom eventually. We could
+                                * perhaps move it to the head of the free
+                                * list, but as umounts are done so
+                                * infrequently, we would gain very little,
+                                * while making the code bigger.
+                                */
+                       }
+       }
+       return (0);
+}
+
+/*
+ * Lock an nfsnode
+ */
+nfs_lock(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       if (np->n_flag & NLOCKED)
+               printf("pid %d hit locked nfsnode=0x%x\n",
+                   u.u_procp->p_pid, np);
+       while (np->n_flag & NLOCKED) {
+               np->n_flag |= NWANT;
+               sleep((caddr_t)np, PINOD);
+       }
+       np->n_flag |= NLOCKED;
+}
+
+/*
+ * Unlock an nfsnode
+ */
+nfs_unlock(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       if ((np->n_flag & NLOCKED) == 0) {
+               printf("pid %d unlocking unlocked nfsnode=0x%x ",
+                   u.u_procp->p_pid, np);
+               printf("fh0=0x%x fh1=0x%x fh2=0x%x fh3=0x%x fh4=0x%x fh5=0x%x fh6=0x%x fh7=0x%x\n",
+                       np->n_fh.fh_bytes[0],np->n_fh.fh_bytes[1],
+                       np->n_fh.fh_bytes[2],np->n_fh.fh_bytes[3],
+                       np->n_fh.fh_bytes[4],np->n_fh.fh_bytes[5],
+                       np->n_fh.fh_bytes[6],np->n_fh.fh_bytes[7]);
+       }
+       np->n_flag &= ~NLOCKED;
+       if (np->n_flag & NWANT) {
+               np->n_flag &= ~NWANT;
+               wakeup((caddr_t)np);
+       }
+}
+
+/*
+ * Unlock and vrele()
+ * since I can't decide if dirs. should be locked, I will check for
+ * the lock and be flexible
+ */
+nfs_nput(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       if (np->n_flag & NLOCKED)
+               nfs_unlock(vp);
+       vrele(vp);
+}
+
+nfs_abortop(ndp)
+       register struct nameidata *ndp;
+{
+       register struct nfsnode *np;
+
+       if (ndp->ni_vp != NULL) {
+               np = VTONFS(ndp->ni_vp);
+               if (np->n_flag & NLOCKED)
+                       nfs_unlock(ndp->ni_vp);
+               vrele(ndp->ni_vp);
+       }
+       if (ndp->ni_dvp != NULL) {
+               np = VTONFS(ndp->ni_dvp);
+               if (np->n_flag & NLOCKED)
+                       nfs_unlock(ndp->ni_dvp);
+               vrele(ndp->ni_dvp);
+       }
+}
+
+/*
+ * This is silly, but if you use a macro and try and use it in a file
+ * that has mbuf.h included, m_data --> m_hdr.mh_data and this is not
+ * a good thing
+ */
+struct nfsmount *vfs_to_nfs(mp)
+       struct mount *mp;
+{
+       return ((struct nfsmount *)mp->m_data);
+}
diff --git a/usr/src/sys/nfs/nfs_socket.c b/usr/src/sys/nfs/nfs_socket.c
new file mode 100644 (file)
index 0000000..00a53d1
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfs_socket.c        7.1 (Berkeley) %G%
+ */
+
+/*
+ * Socket operations for use by nfs (similar to uipc_socket.c, but never
+ * with copies to/from a uio vector)
+ * NB: For now, they only work for UDP datagram sockets.
+ * (Use on stream sockets would require some record boundary mark in the
+ *  stream such as Sun's RM (Section 3.2 of the Sun RPC Message Protocol
+ *  manual, in Networking on the Sun Workstation, Part #800-1324-03
+ *  and different versions of send, receive and reply that do not assume
+ *  an atomic protocol
+ */
+
+#include "types.h"
+#include "param.h"
+#include "uio.h"
+#include "user.h"
+#include "mount.h"
+#include "kernel.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "vnode.h"
+#include "domain.h"
+#include "protosw.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "netinet/in.h"
+#include "rpcv2.h"
+#include "nfsv2.h"
+#include "nfs.h"
+#include "xdr_subs.h"
+#include "nfsm_subs.h"
+#include "nfsmount.h"
+
+#define        TRUE    1
+
+/* set lock on sockbuf sb, sleep at neg prio */
+#define nfs_sblock(sb) { \
+       while ((sb)->sb_flags & SB_LOCK) { \
+               (sb)->sb_flags |= SB_WANT; \
+               sleep((caddr_t)&(sb)->sb_flags, PZERO-1); \
+       } \
+       (sb)->sb_flags |= SB_LOCK; \
+}
+
+/*
+ * External data, mostly RPC constants in XDR form
+ */
+extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
+       rpc_msgaccepted, rpc_call;
+extern u_long nfs_prog, nfs_vers;
+int    nfsrv_null(),
+       nfsrv_getattr(),
+       nfsrv_setattr(),
+       nfsrv_lookup(),
+       nfsrv_readlink(),
+       nfsrv_read(),
+       nfsrv_write(),
+       nfsrv_create(),
+       nfsrv_remove(),
+       nfsrv_rename(),
+       nfsrv_link(),
+       nfsrv_symlink(),
+       nfsrv_mkdir(),
+       nfsrv_rmdir(),
+       nfsrv_readdir(),
+       nfsrv_statfs(),
+       nfsrv_noop();
+
+int (*nfsrv_procs[NFS_NPROCS])() = {
+       nfsrv_null,
+       nfsrv_getattr,
+       nfsrv_setattr,
+       nfsrv_noop,
+       nfsrv_lookup,
+       nfsrv_readlink,
+       nfsrv_read,
+       nfsrv_noop,
+       nfsrv_write,
+       nfsrv_create,
+       nfsrv_remove,
+       nfsrv_rename,
+       nfsrv_link,
+       nfsrv_symlink,
+       nfsrv_mkdir,
+       nfsrv_rmdir,
+       nfsrv_readdir,
+       nfsrv_statfs,
+};
+
+
+/*
+ * This is a stripped down version of sosend() specific to
+ * udp/ip and uses the mbuf list provdied
+ */
+nfs_udpsend(so, nam, top, flags, siz)
+       register struct socket *so;
+       struct mbuf *nam;
+       struct mbuf *top;
+       int flags;
+       int siz;
+{
+       register int space;
+       int error = 0, s, dontroute, first = 1;
+
+       dontroute =
+           (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 &&
+           (so->so_proto->pr_flags & PR_ATOMIC);
+#define        snderr(errno)   { error = errno; splx(s); goto release; }
+
+#ifdef MGETHDR
+       top->m_pkthdr.len = siz;
+#endif
+restart:
+       nfs_sblock(&so->so_snd);
+       s = splnet();
+       if (so->so_state & SS_CANTSENDMORE)
+               snderr(EPIPE);
+       if (so->so_error)
+               snderr(so->so_error);
+       space = sbspace(&so->so_snd);
+       if (space < siz) {
+               sbunlock(&so->so_snd);
+               nfs_sbwait(&so->so_snd);
+               splx(s);
+               goto restart;
+       }
+       splx(s);
+       if (dontroute)
+               so->so_options |= SO_DONTROUTE;
+       s = splnet();                                   /* XXX */
+       error = (*so->so_proto->pr_usrreq)(so,
+           PRU_SEND,
+           top, (caddr_t)nam, (struct mbuf *)0, (struct mbuf *)0);
+       splx(s);
+       if (dontroute)
+               so->so_options &= ~SO_DONTROUTE;
+       top = (struct mbuf *)0;
+
+release:
+       sbunlock(&so->so_snd);
+       if (top)
+               m_freem(top);
+       return (error);
+}
+
+/*
+ * This is a stripped down udp specific version of soreceive()
+ */
+nfs_udpreceive(so, aname, mp)
+       register struct socket *so;
+       struct mbuf **aname;
+       struct mbuf **mp;
+{
+       register struct mbuf *m;
+       int s, error = 0;
+       struct protosw *pr = so->so_proto;
+       struct mbuf *nextrecord;
+
+       if (aname)
+               *aname = 0;
+
+restart:
+       sblock(&so->so_rcv);
+       s = splnet();
+
+       if (so->so_rcv.sb_cc == 0) {
+               if (so->so_error) {
+                       error = so->so_error;
+                       so->so_error = 0;
+                       goto release;
+               }
+               if (so->so_state & SS_CANTRCVMORE)
+                       goto release;
+               sbunlock(&so->so_rcv);
+               sbwait(&so->so_rcv);
+               splx(s);
+               goto restart;
+       }
+       m = so->so_rcv.sb_mb;
+       if (m == 0)
+               panic("nfs_receive 1");
+       nextrecord = m->m_nextpkt;
+       if (m->m_type != MT_SONAME)
+               panic("nfs_receive 1a");
+       sbfree(&so->so_rcv, m);
+       if (aname) {
+               *aname = m;
+               so->so_rcv.sb_mb = m->m_next;
+               m->m_next = 0;
+               m = so->so_rcv.sb_mb;
+       } else {
+               MFREE(m, so->so_rcv.sb_mb);
+               m = so->so_rcv.sb_mb;
+       }
+       if (m && m->m_type == MT_RIGHTS)
+               panic("nfs_receive 2");
+       if (m && m->m_type == MT_CONTROL) {
+               sbfree(&so->so_rcv, m);
+               MFREE(m, so->so_rcv.sb_mb);
+               m = so->so_rcv.sb_mb;
+       }
+       *mp = m;
+       while (m) {
+               if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
+                       panic("nfs_receive 3");
+               sbfree(&so->so_rcv, m);
+               m = so->so_rcv.sb_mb = m->m_next;
+       }
+       so->so_rcv.sb_mb = nextrecord;
+       so->so_state &= ~SS_RCVATMARK;  /* Necessary ?? */
+release:
+       sbunlock(&so->so_rcv);
+       splx(s);
+       return (error);
+}
+
+struct nfsreq nfsreqh = {
+       (struct nfsreq *)0,
+       (struct nfsreq *)0,
+       (struct mbuf *)0,
+       (struct mbuf *)0,
+       (struct nfsmount *)0,
+       0, 0, 0, 0, 0,
+};
+
+struct rpc_replyhead {
+       u_long  r_xid;
+       u_long  r_rep;
+};
+
+/*
+ * Implement receipt of reply on a socket.
+ * We depend on the way that records are added to the sockbuf
+ * by sbappend*.  In particular, each record (mbufs linked through m_next)
+ * must begin with an address, followed by optional MT_CONTROL mbuf
+ * and then zero or more mbufs of data.
+ * Although the sockbuf is locked, new data may still be appended,
+ * and thus we must maintain consistency of the sockbuf during that time.
+ * We must search through the list of received datagrams matching them
+ * with outstanding requests using the xid, until ours is found.
+ */
+nfs_udpreply(so, mntp, repl, myrep)
+       register struct socket *so;
+       struct nfsmount *mntp;
+       struct nfsreq *repl, *myrep;
+{
+       register struct mbuf *m;
+       register struct nfsreq *rep;
+       register int error = 0, s;
+       struct protosw *pr = so->so_proto;
+       struct mbuf *nextrecord;
+       struct sockaddr_in *sad, *sad2;
+       struct rpc_replyhead replyh;
+       struct mbuf *mp;
+       char *cp;
+       int cnt, xfer;
+       int found;
+
+restart:
+       /* Already received, bye bye */
+       if (myrep->r_mrep != NULL)
+               return (0);
+       /* If a soft mount and we have run out of retries */
+       if (myrep->r_retry == 0 && myrep->r_timer == 0)
+               return (ETIMEDOUT);
+       nfs_sblock(&so->so_rcv);
+       s = splnet();
+
+       if (so->so_rcv.sb_cc == 0) {
+               if (so->so_error) {
+                       error = so->so_error;
+                       so->so_error = 0;
+                       goto release;
+               }
+               if (so->so_state & SS_CANTRCVMORE)
+                       goto release;
+               sbunlock(&so->so_rcv);
+               nfs_sbwait(&so->so_rcv);
+               splx(s);
+               goto restart;
+       }
+       m = so->so_rcv.sb_mb;
+       if (m == 0)
+               panic("nfs_soreply 1");
+       nextrecord = m->m_nextpkt;
+
+       /*
+        * Take off the address, check for rights and ditch any control
+        * mbufs.
+        */
+       if (m->m_type != MT_SONAME)
+               panic("nfs reply SONAME");
+       sad = mtod(m, struct sockaddr_in *);
+       sad2 = mtod(mntp->nm_sockaddr, struct sockaddr_in *);
+       found = 0;
+       if (sad->sin_addr.s_addr != sad2->sin_addr.s_addr)
+               goto dropit;
+       sbfree(&so->so_rcv, m);
+       MFREE(m, so->so_rcv.sb_mb);
+       m = so->so_rcv.sb_mb;
+       if (m && m->m_type == MT_RIGHTS)
+               panic("nfs reply RIGHTS");
+       if (m && m->m_type == MT_CONTROL) {
+               sbfree(&so->so_rcv, m);
+               MFREE(m, so->so_rcv.sb_mb);
+               m = so->so_rcv.sb_mb;
+       }
+       if (m)
+               m->m_nextpkt = nextrecord;
+       else {
+               sbunlock(&so->so_rcv);
+               splx(s);
+               goto restart;
+       }
+
+       /*
+        * Get the xid and check that it is an rpc reply
+        */
+       mp = m;
+       if (m->m_len >= 2*NFSX_UNSIGNED)
+               bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED);
+       else {
+               cnt = 2*NFSX_UNSIGNED;
+               cp = (caddr_t)&replyh;
+               while (mp && cnt > 0) {
+                       if (mp->m_len > 0) {
+                               xfer = (mp->m_len >= cnt) ? cnt : mp->m_len;
+                               bcopy(mtod(mp, caddr_t), cp, xfer);
+                               cnt -= xfer;
+                               cp += xfer;
+                       }
+                       if (cnt > 0)
+                               mp = mp->m_next;
+               }
+       }
+       if (replyh.r_rep != rpc_reply || mp == NULL)
+               goto dropit;
+       /*
+        * Loop through the request list to match up the reply
+        * Iff no match, just drop the datagram
+        */
+       rep = repl;
+       while (!found && rep) {
+               if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid) {
+                       /* Found it.. */
+                       rep->r_mrep = m;
+                       while (m) {
+                               if (m->m_type != MT_DATA && m->m_type != MT_HEADER)
+                                       panic("nfs_soreply 3");
+                               sbfree(&so->so_rcv, m);
+                               m = so->so_rcv.sb_mb = m->m_next;
+                       }
+                       so->so_rcv.sb_mb = nextrecord;
+                       if (rep == myrep)
+                               goto release;
+                       found++;
+               }
+               rep = rep->r_next;
+       }
+       /* Iff not matched to request, drop it */
+dropit:
+       if (!found)
+               sbdroprecord(&so->so_rcv);
+       sbunlock(&so->so_rcv);
+       splx(s);
+       goto restart;
+release:
+       sbunlock(&so->so_rcv);
+       splx(s);
+       return (error);
+}
+
+/*
+ * nfs_request - goes something like this
+ *     - fill in request struct
+ *     - links it into list
+ *     - calls nfs_sosend() for first transmit
+ *     - calls nfs_soreceive() to get reply
+ *     - break down rpc header and return with nfs reply pointed to
+ *       by mrep or error
+ * nb: always frees up mreq mbuf list
+ */
+nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp)
+       struct vnode *vp;
+       struct mbuf *mreq;
+       u_long xid;
+       struct mount *mp;
+       struct mbuf **mrp;
+       struct mbuf **mdp;
+       caddr_t *dposp;
+{
+       register struct mbuf *m, *mrep;
+       register struct nfsreq *rep;
+       register u_long *p;
+       register int len;
+       struct nfsmount *mntp;
+       struct mbuf *md;
+       caddr_t dpos;
+       char *cp2;
+       int t1;
+       int s;
+       int error;
+
+       mntp = vfs_to_nfs(mp);
+       m = mreq;
+       MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK);
+       rep->r_xid = xid;
+       rep->r_mntp = mntp;
+       rep->r_vp = vp;
+       if (mntp->nm_flag & NFSMNT_SOFT)
+               rep->r_retry = mntp->nm_retrans;
+       else
+               rep->r_retry = VNOVAL;
+       rep->r_mrep = NULL;
+       rep->r_mreq = m;
+       rep->r_timer = rep->r_timeout = mntp->nm_timeo;
+       len = 0;
+       while (m) {
+               len += m->m_len;
+               m = m->m_next;
+       }
+       rep->r_msiz = len;
+       m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT);
+
+       /* Chain it into list of outstanding requests */
+       s = splnet();
+       rep->r_next = nfsreqh.r_next;
+       if (rep->r_next != NULL)
+               rep->r_next->r_prev = rep;
+       nfsreqh.r_next = rep;
+       rep->r_prev = &nfsreqh;
+       splx(s);
+
+       /*
+        * Iff the NFSMCOPY above succeeded, send it off...
+        * otherwise the timer will retransmit later
+        */
+       if (m != NULL)
+               error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len);
+       error = nfs_udpreply(mntp->nm_so, mntp, nfsreqh.r_next, rep);
+
+       s = splnet();
+       rep->r_prev->r_next = rep->r_next;
+       if (rep->r_next != NULL)
+               rep->r_next->r_prev = rep->r_prev;
+       splx(s);
+       m_freem(rep->r_mreq);
+       mrep = md = rep->r_mrep;
+       FREE((caddr_t)rep, M_NFSREQ);
+       if (error)
+               return (error);
+
+       /*
+        * break down the rpc header and check if ok
+        */
+       dpos = mtod(md, caddr_t);
+       nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED);
+       p += 2;
+       if (*p++ == rpc_msgdenied) {
+               if (*p == rpc_mismatch)
+                       error = EOPNOTSUPP;
+               else
+                       error = EACCES;
+               m_freem(mrep);
+               return (error);
+       }
+       /*
+        * skip over the auth_verf, someday we may want to cache auth_short's
+        * for nfs_reqhead(), but for now just dump it
+        */
+       if (*++p != 0) {
+               len = nfsm_rndup(fxdr_unsigned(long, *p));
+               nfsm_adv(len);
+       }
+       nfsm_disect(p, u_long *, NFSX_UNSIGNED);
+       /* 0 == ok */
+       if (*p == 0) {
+               nfsm_disect(p, u_long *, NFSX_UNSIGNED);
+               if (*p != 0) {
+                       error = fxdr_unsigned(int, *p);
+                       m_freem(mrep);
+                       return (error);
+               }
+               *mrp = mrep;
+               *mdp = md;
+               *dposp = dpos;
+               return (0);
+       }
+       m_freem(mrep);
+       return (EPROTONOSUPPORT);
+nfsmout:
+       return (error);
+}
+
+/*
+ * Get a request for the server main loop
+ * - receive a request via. nfs_soreceive()
+ * - verify it
+ * - fill in the cred struct.
+ */
+nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr)
+       struct socket *so;
+       u_long prog;
+       u_long vers;
+       int maxproc;
+       struct mbuf **nam;
+       struct mbuf **mrp;
+       struct mbuf **mdp;
+       caddr_t *dposp;
+       u_long *retxid;
+       u_long *proc;
+       register struct ucred *cr;
+{
+       register int i;
+       register struct mbuf *m;
+       nfsm_vars;
+       int len, len2;
+
+       if (error = nfs_udpreceive(so, nam, &mrep))
+               return (error);
+       md = mrep;
+       dpos = mtod(mrep, caddr_t);
+       nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED);
+       *retxid = *p++;
+       if (*p++ != rpc_call) {
+               m_freem(mrep);
+               return (ERPCMISMATCH);
+       }
+       if (*p++ != rpc_vers) {
+               m_freem(mrep);
+               return (ERPCMISMATCH);
+       }
+       if (*p++ != prog) {
+               m_freem(mrep);
+               return (EPROGUNAVAIL);
+       }
+       if (*p++ != vers) {
+               m_freem(mrep);
+               return (EPROGMISMATCH);
+       }
+       *proc = fxdr_unsigned(u_long, *p++);
+       if (*proc == NFSPROC_NULL) {
+               *mrp = mrep;
+               return (0);
+       }
+       if (*proc > maxproc || *p++ != rpc_auth_unix) {
+               m_freem(mrep);
+               return (EPROCUNAVAIL);
+       }
+       len = fxdr_unsigned(int, *p++);
+       len2 = fxdr_unsigned(int, *++p);
+       nfsm_adv(nfsm_rndup(len2));
+       nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED);
+       cr->cr_uid = fxdr_unsigned(uid_t, *p++);
+       cr->cr_gid = fxdr_unsigned(gid_t, *p++);
+       len2 = fxdr_unsigned(int, *p);
+       if (len2 > 10) {
+               m_freem(mrep);
+               return (EBADRPC);
+       }
+       nfsm_disect(p, u_long *, (len2+2)*NFSX_UNSIGNED);
+       for (i = 1; i <= len2; i++)
+               cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++);
+       cr->cr_ngroups = len2+1;
+       /*
+        * Do we have any use for the verifier.
+        * According to the "Remote Procedure Call Protocol Spec." it
+        * should be AUTH_NULL, but some clients make it AUTH_UNIX?
+        * For now, just skip over it
+        */
+       len2 = fxdr_unsigned(int, *++p);
+       if (len2 > 0)
+               nfsm_adv(nfsm_rndup(len2));
+       *mrp = mrep;
+       *mdp = md;
+       *dposp = dpos;
+       return (0);
+nfsmout:
+       return (error);
+}
+
+/*
+ * Generate the rpc reply header
+ * siz arg. is used to decide if adding a cluster is worthwhile
+ */
+nfs_rephead(siz, retxid, err, mrq, mbp, bposp)
+       int siz;
+       u_long retxid;
+       int err;
+       struct mbuf **mrq;
+       struct mbuf **mbp;
+       caddr_t *bposp;
+{
+       nfsm_vars;
+
+       NFSMGETHDR(mreq);
+       mb = mreq;
+       if ((siz+RPC_REPLYSIZ) > MHLEN)
+               NFSMCLGET(mreq, M_WAIT);
+       p = mtod(mreq, u_long *);
+       mreq->m_len = 6*NFSX_UNSIGNED;
+       bpos = ((caddr_t)p)+mreq->m_len;
+       *p++ = retxid;
+       *p++ = rpc_reply;
+       if (err == ERPCMISMATCH) {
+               *p++ = rpc_msgdenied;
+               *p++ = rpc_mismatch;
+               *p++ = txdr_unsigned(2);
+               *p = txdr_unsigned(2);
+       } else {
+               *p++ = rpc_msgaccepted;
+               *p++ = 0;
+               *p++ = 0;
+               switch (err) {
+               case EPROGUNAVAIL:
+                       *p = txdr_unsigned(RPC_PROGUNAVAIL);
+                       break;
+               case EPROGMISMATCH:
+                       *p = txdr_unsigned(RPC_PROGMISMATCH);
+                       nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
+                       *p++ = txdr_unsigned(2);
+                       *p = txdr_unsigned(2);  /* someday 3 */
+                       break;
+               case EPROCUNAVAIL:
+                       *p = txdr_unsigned(RPC_PROCUNAVAIL);
+                       break;
+               default:
+                       *p = 0;
+                       if (err != VNOVAL) {
+                               nfsm_build(p, u_long *, NFSX_UNSIGNED);
+                               *p = txdr_unsigned(err);
+                       }
+                       break;
+               };
+       }
+       *mrq = mreq;
+       *mbp = mb;
+       *bposp = bpos;
+       if (err != 0 && err != VNOVAL)
+               nfsstats.srvrpc_errs++;
+       return (0);
+}
+
+/*
+ * Nfs timer routine
+ * Scan the nfsreq list and retranmit any requests that have timed out
+ * To avoid retransmission attempts on STREAM sockets (in the future) make
+ * sure to set the r_retry field to 0.
+ */
+nfs_timer()
+{
+       register struct nfsreq *rep;
+       register struct mbuf *m;
+       register struct socket *so;
+       int s, len;
+
+       s = splnet();
+       rep = nfsreqh.r_next;
+       while (rep != NULL) {
+               if (rep->r_timer > 0)
+                       rep->r_timer--;
+               else if (rep->r_mrep == NULL && rep->r_retry > 0) {
+                       so = rep->r_mntp->nm_so;
+                       if ((so->so_state & SS_CANTSENDMORE) == 0 &&
+                           !so->so_error &&
+                           sbspace(&so->so_snd) >= rep->r_msiz) {
+                               m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT);
+                               if (m != NULL) {
+                                       nfsstats.rpcretries++;
+                                       rep->r_timer = rep->r_timeout;
+                                       if (rep->r_retry != VNOVAL)
+                                               rep->r_retry--;
+#ifdef MGETHDR
+                                       m->m_pkthdr.len = rep->r_msiz;
+#endif
+                                       (*so->so_proto->pr_usrreq)(so, PRU_SEND,
+                                               m, (caddr_t)0, (struct mbuf *)0,
+                                               (struct mbuf *)0);
+                               }
+                       }
+               }
+               rep = rep->r_next;
+       }
+       splx(s);
+       timeout(nfs_timer, (caddr_t)0, hz);
+}
+
+/*
+ * nfs_sbwait() is simply sbwait() but at a negative priority so that it
+ * can not be interrupted by a signal.
+ */
+nfs_sbwait(sb)
+       struct sockbuf *sb;
+{
+       sb->sb_flags |= SB_WAIT;
+       sleep((caddr_t)&sb->sb_cc, PZERO-1);
+}
diff --git a/usr/src/sys/nfs/nfs_syscalls.c b/usr/src/sys/nfs/nfs_syscalls.c
new file mode 100644 (file)
index 0000000..1ad338f
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfs_syscalls.c      7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "systm.h"
+#include "user.h"
+#include "kernel.h"
+#include "file.h"
+#include "stat.h"
+#include "vnode.h"
+#include "mount.h"
+#include "proc.h"
+#include "uio.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "socket.h"
+#include "socketvar.h"
+#include "nfsv2.h"
+#include "nfs.h"
+
+/* Global defs. */
+extern u_long nfs_prog, nfs_vers;
+extern int (*nfsrv_procs[NFS_NPROCS])();
+struct file *getsock();
+
+/*
+ * NFS server system calls
+ * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
+ */
+#define RETURN(value)  { u.u_error = (value); return; }
+
+/*
+ * Get file handle system call
+ */
+getfh()
+{
+       register struct a {
+               char    *fname;
+               fhandle_t *fhp;
+       } *uap = (struct a *)u.u_ap;
+       register struct nameidata *ndp = &u.u_nd;
+       register struct vnode *vp;
+       fhandle_t fh;
+       int error;
+
+       /*
+        * Must be super user
+        */
+       if (error = suser(u.u_cred, &u.u_acflag))
+               RETURN (error);
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = uap->fname;
+       if (error = namei(ndp))
+               RETURN (error);
+       vp = ndp->ni_vp;
+       bzero((caddr_t)&fh, sizeof(fh));
+       fh.fh_fsid = vp->v_mount->m_fsid;
+       error = VFS_VPTOFH(vp, &fh.fh_fid);
+       vput(vp);
+       if (error)
+               RETURN (error);
+       error = copyout((caddr_t)&fh, (caddr_t)uap->fhp, sizeof (fh));
+       RETURN (error);
+}
+
+/*
+ * Mark a mount point in the filesystem exported
+ */
+exportfs()
+{
+       register struct a {
+               char    *fname;
+               int     rootuid;
+               int     exflags;
+       } *uap = (struct a *)u.u_ap;
+       register struct nameidata *ndp = &u.u_nd;
+       register struct vnode *vp;
+       register struct mount *mp;
+       int error;
+
+       /*
+        * Must be super user
+        */
+       if (error = suser(u.u_cred, &u.u_acflag))
+               RETURN (error);
+       ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;   /* Or NOFOLLOW ?? */
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = uap->fname;
+       if (error = namei(ndp))
+               RETURN (error);
+       vp = ndp->ni_vp;
+       if (vp->v_type != VDIR) {
+               vput(vp);
+               RETURN (ENOENT);
+       }
+       mp = vp->v_mount;
+
+       /*
+        * If the filesystem has already been exported, just relax
+        * security as required.
+        * Otherwise export it with the given security
+        */
+       if (mp->m_flag & M_EXPORTED) {
+               if (uap->rootuid == 0)
+                       mp->m_exroot = 0;
+               if ((uap->exflags & M_EXRDONLY) == 0)
+                       mp->m_flag &= ~M_EXRDONLY;
+       } else {
+               mp->m_exroot = uap->rootuid;
+               if (uap->exflags & M_EXRDONLY)
+                       mp->m_flag |= M_EXRDONLY;
+               mp->m_flag |= M_EXPORTED;
+       }
+       vput(vp);
+       RETURN (0);
+}
+
+/*
+ * Nfs server psuedo system call for the nfsd's
+ * Never returns unless it fails or gets killed
+ */
+nfssvc()
+{
+       register struct a {
+               int s;
+       } *uap = (struct a *)u.u_ap;
+       register struct mbuf *m;
+       register int siz;
+       register struct ucred *cr;
+       struct file *fp;
+       struct mbuf *mreq, *mrep, *nam, *md;
+       struct socket *so;
+       caddr_t dpos;
+       int proc;
+       u_long retxid;
+       int error;
+
+       /*
+        * Must be super user
+        */
+       if (error = suser(u.u_cred, &u.u_acflag))
+               RETURN (error);
+       fp = getsock(uap->s);
+       if (fp == 0)
+               return;
+       so = (struct socket *)fp->f_data;
+       cr = u.u_cred = crcopy(u.u_cred);       /* Copy it so others don't see changes */
+       /*
+        * Just loop arround doin our stuff until SIGKILL
+        */
+       for (;;) {
+               if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
+                       &nam, &mrep, &md, &dpos, &retxid, &proc, cr)) {
+                       m_freem(nam);
+                       continue;
+               }
+               if (error = (*(nfsrv_procs[proc]))(mrep, md, dpos,
+                       cr, retxid, &mreq)) {
+                       m_freem(nam);
+                       nfsstats.srv_errs++;
+                       continue;
+               } else
+                       nfsstats.srvrpccnt[proc]++;
+               m = mreq;
+               siz = 0;
+               while (m) {
+                       siz += m->m_len;
+                       m = m->m_next;
+               }
+               if (siz <= 0 || siz > 9216) {
+                       printf("mbuf siz=%d\n",siz);
+                       panic("Bad nfs svc reply");
+               }
+               error = nfs_udpsend(so, nam, mreq, 0, siz);
+               m_freem(nam);
+       }
+}
diff --git a/usr/src/sys/nfs/nfs_vfsops.c b/usr/src/sys/nfs/nfs_vfsops.c
new file mode 100644 (file)
index 0000000..4e09a8b
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfs_vfsops.c        7.1 (Berkeley) %G%
+ */
+
+#include "param.h"
+#include "signal.h"
+#include "user.h"
+#include "proc.h"
+#include "uio.h"
+#include "ucred.h"
+#include "dir.h"
+#include "namei.h"
+#include "vnode.h"
+#include "mount.h"
+#include "errno.h"
+#include "malloc.h"
+#include "mbuf.h"
+#undef m_data
+#include "socket.h"
+#include "socketvar.h"
+#include "../netinet/in.h"
+#include "nfsv2.h"
+#include "nfsnode.h"
+#include "nfsmount.h"
+#include "nfs.h"
+
+#ifndef shouldbe
+#include "conf.h"
+#endif
+
+/*
+ * nfs vfs operations.
+ */
+int nfs_mount();
+int nfs_unmount();
+int nfs_root();
+extern int nfs_statfs();
+int nfs_sync();
+int nfs_fhtovp();
+int nfs_vptofh();
+
+struct vfsops nfs_vfsops = {
+       nfs_mount,
+       nfs_unmount,
+       nfs_root,
+       nfs_statfs,
+       nfs_sync,
+       nfs_fhtovp,
+       nfs_vptofh,
+};
+
+extern struct nfsreq nfsreqh;
+static long nfs_mntid;
+
+/*
+ * Called by vfs_mountroot when nfs is going to be mounted as root
+ * Not Yet (By a LONG shot)
+ */
+nfs_mountroot()
+{
+       return (ENODEV);
+}
+
+/*
+ * VFS Operations.
+ *
+ * mount system call
+ * It seems a bit dumb to copyinstr() the host and path here and then
+ * bcopy() them in mountnfs(), but I wanted to detect errors before
+ * doing the sockargs() call because sockargs() allocates an mbuf and
+ * an error after that means that I have to release the mbuf.
+ */
+nfs_mount(mp, path, data, ndp)
+       struct mount *mp;
+       char *path;
+       caddr_t data;
+       struct nameidata *ndp;
+{
+       int error;
+       struct nfs_args args;
+       struct mbuf *saddr;
+       char pth[MNAMELEN], hst[MNAMELEN];
+       int len;
+       nfsv2fh_t nfh;
+
+       if (error = copyin(data, (caddr_t)&args, sizeof (struct nfs_args)))
+               return (error);
+       if (error=copyin((caddr_t)args.fh, (caddr_t)&nfh, sizeof (nfsv2fh_t)))
+               return (error);
+       if (error = copyinstr(path, pth, MNAMELEN-1, &len))
+               return (error);
+       bzero(&pth[len], MNAMELEN-len);
+       if (error = copyinstr(args.hostname, hst, MNAMELEN-1, &len))
+               return (error);
+       bzero(&hst[len], MNAMELEN-len);
+       /* sockargs() call must be after above copyin() calls */
+       if (error = sockargs(&saddr, (caddr_t)args.addr,
+               sizeof (struct sockaddr_in), MT_SONAME))
+               return (error);
+       args.fh = &nfh;
+       error = mountnfs(&args, mp, saddr, pth, hst);
+       return (error);
+}
+
+/*
+ * Common code for mount and mountroot
+ */
+mountnfs(argp, mp, saddr, pth, hst)
+       register struct nfs_args *argp;
+       register struct mount *mp;
+       register struct mbuf *saddr;
+       char *pth, *hst;
+{
+       register struct nfsmount *nmp;
+       struct nfsnode *np;
+       struct statfs statf, *sbp;
+       int error;
+
+       nmp = (struct nfsmount *)malloc(sizeof (struct nfsmount), M_NFSMNT,
+           M_WAITOK);
+       mp->m_data = (qaddr_t)nmp;
+       mp->m_fsid.val[0] = ++nfs_mntid;
+       mp->m_fsid.val[1] = MOUNT_NFS;
+       nmp->nm_mountp = mp;
+       nmp->nm_flag = argp->flags;
+       nmp->nm_sockaddr = saddr;
+       /* Set up the sockets */
+       if (error = socreate(AF_INET, &nmp->nm_so, SOCK_DGRAM, 0))
+               goto bad;
+       if (error = soconnect(nmp->nm_so, saddr))
+               goto bad;
+       if ((argp->flags & NFSMNT_TIMEO) && argp->timeo >= 1)
+               nmp->nm_timeo = argp->timeo;
+       else
+               nmp->nm_timeo = NFS_TIMEO;
+       if ((argp->flags & NFSMNT_RETRANS) && argp->retrans > 0)
+               nmp->nm_retrans = argp->retrans;
+       else
+               nmp->nm_retrans = NFS_RETRANS;
+       if ((argp->flags & NFSMNT_WSIZE) &&
+           argp->wsize <= NFS_MAXDATA && argp->wsize > 0 &&
+          (argp->wsize & 0x1ff) == 0)
+               nmp->nm_wsize = argp->wsize;
+       else
+               nmp->nm_wsize = NFS_WSIZE;
+       if ((argp->flags & NFSMNT_RSIZE) &&
+           argp->rsize <= NFS_MAXDATA && argp->rsize > 0 &&
+          (argp->rsize & 0x1ff) == 0)
+               nmp->nm_rsize = argp->rsize;
+       else
+               nmp->nm_rsize = NFS_RSIZE;
+       bcopy((caddr_t)argp->fh, (caddr_t)&nmp->nm_fh, sizeof(nfsv2fh_t));
+       bcopy(pth, nmp->nm_path, MNAMELEN);
+       bcopy(hst, nmp->nm_host, MNAMELEN);
+       sbp = &statf;
+       /*
+        * Kludge City...
+        * To do an interruptable hard mount, turn it into a soft mount
+        * with a retry limit of one and then repeat it so long as it
+        * times out and there is no pending signal for the process.
+        * It is tempting to just let nfs_statfs() sleep at positive
+        * prio, but then you would long jump out without taking the
+        * mount structure back out of the list.
+        * NB: NFSMNT_INT must NEVER be set for nfs_mountroot(), since
+        * the process context is not yet built!!
+        */
+       if ((argp->flags && NFSMNT_INT) && (argp->flags & NFSMNT_SOFT) == 0) {
+               int savretrans;
+
+               nmp->nm_flag |= NFSMNT_SOFT;
+               savretrans = nmp->nm_retrans;
+               nmp->nm_retrans = 1;
+               do {
+                       error = nfs_statfs(mp, sbp);
+               } while (error == ETIMEDOUT && (u.u_procp->p_sig &
+                       (sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM)|
+                        sigmask(SIGKILL))) == 0);
+               nmp->nm_retrans = savretrans;
+               nmp->nm_flag &= ~NFSMNT_SOFT;
+               if (error)
+                       goto bad;
+       } else if (error = nfs_statfs(mp, sbp))
+               goto bad;
+       mp->m_fsize = sbp->f_fsize;
+
+       /*
+        * If the block size is not an exact multiple of CLBYTES
+        * use CLBYTES so that paging in ZMAGIC executables doesn't
+        * get sick. (It is used by vinitfod())
+        */
+       if (sbp->f_bsize >= CLBYTES && claligned(sbp->f_bsize))
+               mp->m_bsize = sbp->f_bsize;
+       else
+               mp->m_bsize = CLBYTES;
+       return (0);
+bad:
+       m_freem(saddr);
+       free((caddr_t)nmp, M_NFSMNT);
+       return (error);
+}
+
+/*
+ * unmount system call
+ */
+nfs_unmount(mp, flags)
+       struct mount *mp;
+       int flags;
+{
+       register struct nfsmount *nmp;
+       register struct nfsreq *rep;
+       struct nfsreq *rep2;
+       int error;
+       int s;
+
+       if (flags & MNT_FORCE)
+               return (EINVAL);
+       nmp = vfs_to_nfs(mp);
+       /*
+        * Goes something like this..
+        * - Call nfs_nflush() to clear out the nfsnode table
+        * - Flush out lookup cache
+        * - Close the socket
+        * - Free up the data structures
+        */
+       if (error = nfs_nflush(mp)) {
+               return (error);
+       }
+       /*
+        * Scan the request list for any requests left hanging about
+        */
+       s = splnet();
+       rep = nfsreqh.r_next;
+       while (rep) {
+               if (rep->r_mntp == nmp) {
+                       rep->r_prev->r_next = rep2 = rep->r_next;
+                       if (rep->r_next != NULL)
+                               rep->r_next->r_prev = rep->r_prev;
+                       m_freem(rep->r_mreq);
+                       if (rep->r_mrep != NULL)
+                               m_freem(rep->r_mrep);
+                       free((caddr_t)rep, M_NFSREQ);
+                       rep = rep2;
+               } else
+                       rep = rep->r_next;
+       }
+       splx(s);
+       soclose(nmp->nm_so);
+       m_freem(nmp->nm_sockaddr);
+       free((caddr_t)nmp, M_NFSMNT);
+       return (0);
+}
+
+/*
+ * Return root of a filesystem
+ */
+nfs_root(mp, vpp)
+       struct mount *mp;
+       struct vnode **vpp;
+{
+       register struct vnode *vp;
+       struct nfsmount *nmp;
+       struct nfsnode *np;
+       int error;
+
+       nmp = vfs_to_nfs(mp);
+       if (error = nfs_nget(mp, &nmp->nm_fh, &np))
+               return (error);
+       vp = NFSTOV(np);
+       vp->v_type = VDIR;
+       vp->v_flag = VROOT;
+       *vpp = vp;
+       return (0);
+}
+
+/*
+ * Since writes are synchronous, I think this is a no-op
+ * Maybe write cache on nfs version 3 will require something ??
+ */
+nfs_sync(mp, waitfor)
+       struct mount *mp;
+       int waitfor;
+{
+       return (0);
+}
+
+/*
+ * At this point, this should never happen
+ */
+nfs_fhtovp(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+       return (EINVAL);
+}
+
+/*
+ * Vnode pointer to File handle, should never happen either
+ */
+nfs_vptofh(mp, fhp, vpp)
+       struct mount *mp;
+       struct fid *fhp;
+       struct vnode **vpp;
+{
+       return (EINVAL);
+}
diff --git a/usr/src/sys/nfs/nfs_vnops.c b/usr/src/sys/nfs/nfs_vnops.c
new file mode 100644 (file)
index 0000000..a85dfda
--- /dev/null
@@ -0,0 +1,1216 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfs_vnops.c 7.1 (Berkeley) %G%
+ */
+
+/*
+ * vnode op calls for sun nfs version 2
+ */
+
+#include "machine/pte.h"
+#include "machine/mtpr.h"
+#include "strings.h"
+#include "param.h"
+#include "user.h"
+#include "proc.h"
+#include "mount.h"
+#include "buf.h"
+#include "vm.h"
+#include "dir.h"
+#include "malloc.h"
+#include "mbuf.h"
+#include "uio.h"
+#include "ucred.h"
+#include "namei.h"
+#include "errno.h"
+#include "file.h"
+#include "conf.h"
+#include "vnode.h"
+#include "../ufs/inode.h"
+#include "nfsv2.h"
+#include "nfs.h"
+#include "nfsnode.h"
+#include "nfsmount.h"
+#include "xdr_subs.h"
+#include "nfsm_subs.h"
+
+/* Defs */
+#define        TRUE    1
+#define        FALSE   0
+
+/* Global vars */
+int    nfs_lookup(),
+       nfs_create(),
+       nfs_open(),
+       nfs_close(),
+       nfs_access(),
+       nfs_getattr(),
+       nfs_setattr(),
+       nfs_read(),
+       nfs_write(),
+       vfs_noop(),
+       vfs_nullop(),
+       nfs_remove(),
+       nfs_link(),
+       nfs_rename(),
+       nfs_mkdir(),
+       nfs_rmdir(),
+       nfs_symlink(),
+       nfs_readdir(),
+       nfs_readlink(),
+       nfs_abortop(),
+       nfs_lock(),
+       nfs_unlock(),
+       nfs_bmap(),
+       nfs_strategy(),
+       nfs_inactive();
+
+struct vnodeops nfsv2_vnodeops = {
+       nfs_lookup,
+       nfs_create,
+       vfs_noop,
+       nfs_open,
+       nfs_close,
+       nfs_access,
+       nfs_getattr,
+       nfs_setattr,
+       nfs_read,
+       nfs_write,
+       vfs_noop,
+       vfs_noop,
+       vfs_noop,
+       vfs_nullop,
+       vfs_noop,
+       nfs_remove,
+       nfs_link,
+       nfs_rename,
+       nfs_mkdir,
+       nfs_rmdir,
+       nfs_symlink,
+       nfs_readdir,
+       nfs_readlink,
+       nfs_abortop,
+       nfs_inactive,
+       nfs_lock,
+       nfs_unlock,
+       nfs_bmap,
+       nfs_strategy,
+};
+
+/* Special device vnode ops */
+int    blk_open(),
+       blk_read(),
+       blk_write(),
+       blk_ioctl(),
+       blk_select(),
+       ufs_bmap(),
+       blk_strategy();
+
+struct vnodeops nfsv2chr_vnodeops = {
+       vfs_noop,
+       vfs_noop,
+       vfs_noop,
+       blk_open,
+       nfs_close,
+       nfs_access,
+       nfs_getattr,
+       nfs_setattr,
+       blk_read,
+       blk_write,
+       blk_ioctl,
+       blk_select,
+       vfs_noop,
+       vfs_nullop,
+       vfs_noop,
+       nfs_remove,
+       nfs_link,
+       nfs_rename,
+       vfs_noop,
+       vfs_noop,
+       nfs_symlink,
+       vfs_noop,
+       vfs_noop,
+       nfs_abortop,
+       nfs_inactive,
+       nfs_lock,
+       nfs_unlock,
+       ufs_bmap,
+       blk_strategy,
+};
+
+extern u_long nfs_procids[NFS_NPROCS];
+extern u_long nfs_prog, nfs_vers;
+extern struct vnode *cache_lookup();
+extern char nfsiobuf[MAXPHYS+NBPG];
+enum vtype v_type[NFLNK+1];
+
+/*
+ * nfs null call from vfs.
+ */
+nfs_null(vp, cred)
+       struct vnode *vp;
+       struct ucred *cred;
+{
+       nfsm_vars;
+       
+       nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
+       nfsm_request(vp);
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs access vnode op.
+ * Essentially just get vattr and then imitate iaccess()
+ */
+nfs_access(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       register struct ucred *cred;
+{
+       register struct vattr *vap;
+       register gid_t *gp;
+       struct vattr vattr;
+       register int i;
+       int error;
+
+       /*
+        * If you're the super-user,
+        * you always get access.
+        */
+       if (cred->cr_uid == 0)
+               return (0);
+       vap = &vattr;
+       if (nfs_getattrcache(vp, vap)) {
+               if (error = nfs_getattr(vp, vap, cred))
+                       return (error);
+       }
+       /*
+        * Access check is based on only one of owner, group, public.
+        * If not owner, then check group. If not a member of the
+        * group, then check public access.
+        */
+       if (cred->cr_uid != vap->va_uid) {
+               mode >>= 3;
+               gp = cred->cr_groups;
+               for (i = 0; i < cred->cr_ngroups; i++, gp++)
+                       if (vap->va_gid == *gp)
+                               goto found;
+               mode >>= 3;
+found:
+               ;
+       }
+       if ((vap->va_mode & mode) != 0)
+               return (0);
+       return (EACCES);
+}
+
+/*
+ * nfs open vnode op
+ * Just check to see if the type is ok
+ */
+nfs_open(vp, mode, cred)
+       struct vnode *vp;
+       int mode;
+       struct ucred *cred;
+{
+       register enum vtype vtyp;
+
+       vtyp = vp->v_type;
+       if (vtyp == VREG || vtyp == VDIR || vtyp == VLNK)
+               return (0);
+       else
+               return (EACCES);
+}
+
+/*
+ * nfs close vnode op
+ * Nothin to do unless its a VCHR
+ */
+nfs_close(vp, fflags, cred)
+       register struct vnode *vp;
+       int fflags;
+       struct ucred *cred;
+{
+       dev_t dev;
+       int error;
+
+       if (vp->v_type != VCHR || vp->v_count > 1)
+               return (0);
+       dev = vp->v_rdev;
+       /* XXX what is this doing below the vnode op call */
+       if (setjmp(&u.u_qsave)) {
+               /*
+                * If device close routine is interrupted,
+                * must return so closef can clean up.
+                */
+               error = EINTR;
+       } else
+               error = (*cdevsw[major(dev)].d_close)(dev, fflags, IFCHR);
+       /*
+        * Most device close routines don't return errors,
+        * and dup2() doesn't work right on error.
+        */
+       error = 0;              /* XXX */
+       return (error);
+}
+
+/*
+ * nfs getattr call from vfs.
+ */
+nfs_getattr(vp, vap, cred)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
+{
+       nfsm_vars;
+       
+       /* First look in the cache.. */
+       if (nfs_getattrcache(vp, vap) == 0)
+               return (0);
+       nfsstats.rpccnt[NFSPROC_GETATTR]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
+       nfsm_fhtom(vp);
+       nfsm_request(vp);
+       nfsm_loadattr(vp, vap);
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs setattr call.
+ */
+nfs_setattr(vp, vap, cred)
+       struct vnode *vp;
+       register struct vattr *vap;
+       struct ucred *cred;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_SETATTR]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_SETATTR], cred, NFSX_FH+NFSX_SATTR);
+       nfsm_fhtom(vp);
+       nfsm_build(p, u_long *, NFSX_SATTR);
+       if (vap->va_mode == 0xffff)
+               *p++ = VNOVAL;
+       else
+               *p++ = vtonfs_mode(vp->v_type, vap->va_mode);
+       if (vap->va_uid == 0xffff)
+               *p++ = VNOVAL;
+       else
+               *p++ = txdr_unsigned(vap->va_uid);
+       if (vap->va_gid == 0xffff)
+               *p++ = VNOVAL;
+       else
+               *p++ = txdr_unsigned(vap->va_gid);
+       *p++ = txdr_unsigned(vap->va_size);
+       txdr_time(&(vap->va_atime), p);
+       p += 2;
+       txdr_time(&(vap->va_mtime), p);
+       nfsm_request(vp);
+       nfsm_loadattr(vp, (struct vattr *)0);
+       /* should we fill in any vap fields ?? */
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs lookup call, one step at a time...
+ * First look in cache
+ * If not found, unlock the directory nfsnode and do the rpc
+ */
+nfs_lookup(vp, ndp)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
+{
+       register struct vnode *vdp;
+       nfsm_vars;
+       struct vnode *newvp;
+       long len;
+       nfsv2fh_t *fhp;
+       struct nfsnode *np;
+       int lockparent, wantparent, flag;
+       dev_t rdev;
+
+       ndp->ni_dvp = vp;
+       ndp->ni_vp = NULL;
+       if (vp->v_type != VDIR)
+               return (ENOTDIR);
+       lockparent = ndp->ni_nameiop & LOCKPARENT;
+       flag = ndp->ni_nameiop & OPFLAG;
+       wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
+#ifdef notyet
+       if (vdp = cache_lookup(ndp)) {
+               nfsstats.lookupcache_hits++;
+               /*
+                * Get the next vnode in the path.
+                * See comment above `IUNLOCK' code for
+                * an explaination of the locking protocol.
+                */
+               if (vp == vdp) {
+                       vdp->v_count++;
+               } else if (ndp->ni_isdotdot) {
+                       nfs_unlock(vp);
+                       nfs_ngrab(VTONFS(vdp));
+               } else {
+                       nfs_ngrab(VTONFS(vdp));
+                       nfs_unlock(vp);
+               }
+               ndp->ni_vp = vdp;
+               return (0);
+       }
+       nfsstats.lookupcache_misses++;
+#endif notyet
+       nfsstats.rpccnt[NFSPROC_LOOKUP]++;
+       len = ndp->ni_namelen;
+       nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
+       nfsm_fhtom(vp);
+       nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
+       nfsm_request(vp);
+nfsmout:
+       if (error) {
+               if ((flag == CREATE || flag == RENAME) &&
+                       *ndp->ni_next == 0) {
+                       if (!lockparent)
+                               nfs_unlock(vp);
+               }
+               return (ENOENT);
+       }
+       nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
+
+       /*
+        * Handle DELETE and RENAME cases...
+        */
+       if (flag == DELETE && *ndp->ni_next == 0) {
+               if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+                       vp->v_count++;
+                       newvp = vp;
+                       np = VTONFS(vp);
+               } else {
+                       if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                               m_freem(mrep);
+                               return (error);
+                       }
+                       newvp = NFSTOV(np);
+               }
+               if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
+                       if (newvp != vp)
+                               nfs_nput(newvp);
+                       else
+                               vp->v_count--;
+                       m_freem(mrep);
+                       return (error);
+               }
+               newvp->v_type = np->n_vattr.va_type;
+               ndp->ni_vp = newvp;
+               if (!lockparent)
+                       nfs_unlock(vp);
+               m_freem(mrep);
+               return (0);
+       }
+
+       if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
+               if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+                       m_freem(mrep);
+                       return (EISDIR);
+               }
+               if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                       m_freem(mrep);
+                       return (error);
+               }
+               newvp = NFSTOV(np);
+               if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
+                       if (newvp != vp)
+                               nfs_nput(newvp);
+                       else
+                               vp->v_count--;
+                       m_freem(mrep);
+                       return (error);
+               }
+               ndp->ni_vp = newvp;
+               if (!lockparent)
+                       nfs_unlock(vp);
+               return (0);
+       }
+
+       if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+               vp->v_count++;
+               newvp = vp;
+               np = VTONFS(vp);
+       } else if (ndp->ni_isdotdot) {
+               nfs_unlock(vp);
+               if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                       nfs_lock(vp);
+                       m_freem(mrep);
+                       return (error);
+               }
+               nfs_lock(vp);
+               newvp = NFSTOV(np);
+       } else {
+               if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                       m_freem(mrep);
+                       return (error);
+               }
+               newvp = NFSTOV(np);
+       }
+       if (error = nfs_loadattrcache(newvp, &md, &dpos, (struct vattr *)0)) {
+               if (newvp != vp)
+                       nfs_nput(newvp);
+               else
+                       vp->v_count--;
+               m_freem(mrep);
+               return (error);
+       }
+       m_freem(mrep);
+       newvp->v_type = np->n_vattr.va_type;
+
+       /*
+        * Handling special files...
+        * For VCHR, use the nfs_node, but with the nfsv2chr_vnodeops
+        * that are a mix of nfs and blk vnode ops.
+        * For VBLK, get a block dev. inode using bdevvp() and release
+        * the nfs_node. This means that ufs_inactive() had better know
+        * how to release inodes that do not have an underlying ufs.
+        * (i_fs == 0)
+        * Also, returns right away to avoid loading the name cache
+        */
+       if (newvp->v_type == VCHR) {
+               newvp->v_rdev = np->n_vattr.va_rdev;
+               newvp->v_op = &nfsv2chr_vnodeops;
+       } else if (newvp->v_type == VBLK) {
+               rdev = np->n_vattr.va_rdev;
+               nfs_nput(newvp);
+               if (error = bdevvp(rdev, &newvp))
+                       return (error);
+       }
+       if (vp != newvp && (!lockparent || *ndp->ni_next != '\0'))
+               nfs_unlock(vp);
+       ndp->ni_vp = newvp;
+#ifdef notyet
+       if (error == 0 && ndp->ni_makeentry)
+               cache_enter(ndp);
+#endif notyet
+       return (error);
+}
+
+/*
+ * nfs readlink call
+ */
+nfs_readlink(vp, uiop, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       struct ucred *cred;
+{
+       nfsm_vars;
+       long len;
+
+       nfsstats.rpccnt[NFSPROC_READLINK]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
+       nfsm_fhtom(vp);
+       nfsm_request(vp);
+       nfsm_strsiz(len, NFS_MAXPATHLEN);
+       nfsm_mtouio(uiop, len);
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs read call
+ */
+nfs_read(vp, uiop, offp, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       off_t *offp;
+       int ioflag;
+       struct ucred *cred;
+{
+       nfsm_vars;
+       struct nfsmount *nmp;
+       long len, retlen, tsiz;
+
+       nmp = vfs_to_nfs(vp->v_mount);
+       tsiz = uiop->uio_resid;
+       if (!(ioflag & IO_NODELOCKED))
+               nfs_lock(vp);
+       while (tsiz > 0) {
+               nfsstats.rpccnt[NFSPROC_READ]++;
+               len = (tsiz > nmp->nm_rsize) ? nmp->nm_rsize : tsiz;
+               nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
+               nfsm_fhtom(vp);
+               nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
+               *p++ = txdr_unsigned(*offp);
+               *p++ = txdr_unsigned(len);
+               *p = 0;
+               nfsm_request(vp);
+               nfsm_loadattr(vp, (struct vattr *)0);
+               nfsm_strsiz(retlen, nmp->nm_rsize);
+               nfsm_mtouio(uiop, retlen);
+               m_freem(mrep);
+               *offp += retlen;
+               if (retlen < len)
+                       tsiz = 0;
+               else
+                       tsiz -= len;
+       }
+nfsmout:
+       if (!(ioflag & IO_NODELOCKED))
+               nfs_unlock(vp);
+       return (error);
+}
+
+/*
+ * nfs write call
+ */
+nfs_write(vp, uiop, offp, ioflag, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       off_t *offp;
+       int ioflag;
+       struct ucred *cred;
+{
+       nfsm_vars;
+       struct nfsmount *nmp;
+       long len, tsiz;
+       u_long osize;
+       off_t ooff;
+       struct vattr va;
+
+       nmp = vfs_to_nfs(vp->v_mount);
+       tsiz = uiop->uio_resid;
+       if (!(ioflag & IO_NODELOCKED))
+               nfs_lock(vp);
+       if ((ioflag&IO_UNIT) || (vp->v_type == VREG && (ioflag&IO_APPEND))) {
+               if (error = nfs_getattr(vp, &va, cred))
+                       goto nfsmout;
+               osize = va.va_size;
+               if (vp->v_type == VREG && (ioflag & IO_APPEND))
+                       *offp = osize;
+               ooff = *offp;
+       }
+       while (tsiz > 0) {
+               nfsstats.rpccnt[NFSPROC_WRITE]++;
+               len = (tsiz > nmp->nm_wsize) ? nmp->nm_wsize : tsiz;
+               nfsm_reqhead(nfs_procids[NFSPROC_WRITE], cred,
+                       NFSX_FH+NFSX_UNSIGNED*4);
+               nfsm_fhtom(vp);
+               nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
+               *(p+1) = txdr_unsigned(*offp);
+               *(p+3) = txdr_unsigned(len);
+               nfsm_uiotom(uiop, len);
+               nfsm_request(vp);
+               nfsm_loadattr(vp, (struct vattr *)0);
+               m_freem(mrep);
+               tsiz -= len;
+               *offp += len;
+       }
+nfsmout:
+       if (error && (ioflag & IO_UNIT)) {
+               vattr_null(&va);
+               va.va_size = osize;
+               nfs_setattr(vp, &va, cred);
+               *offp = ooff;
+       }
+       if (!(ioflag & IO_NODELOCKED))
+               nfs_unlock(vp);
+       return (error);
+}
+
+/*
+ * nfs file create call
+ */
+nfs_create(ndp, vap)
+       register struct nameidata *ndp;
+       register struct vattr *vap;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_CREATE]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
+         NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
+       nfsm_fhtom(ndp->ni_dvp);
+       nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+       nfsm_build(p, u_long *, NFSX_UNSIGNED*8);
+       *p++ = vtonfs_mode(VREG, vap->va_mode);
+       *p++ = txdr_unsigned(ndp->ni_cred->cr_uid);
+       *p++ = txdr_unsigned(ndp->ni_cred->cr_gid);
+       *p++ = txdr_unsigned(0);
+       /* or should these be VNOVAL ?? */
+       txdr_time(&(vap->va_atime), p);
+       txdr_time(&(vap->va_mtime), p+2);
+       nfsm_request(ndp->ni_dvp);
+       nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
+       nfsm_reqdone;
+       nfs_nput(ndp->ni_dvp);
+       return (error);
+}
+
+/*
+ * nfs file remove call
+ */
+nfs_remove(ndp)
+       register struct nameidata *ndp;
+{
+       nfsm_vars;
+
+       if (ndp->ni_vp->v_count > 1)
+               error = nfs_sillyrename(ndp, REMOVE);
+       else {
+               nfsstats.rpccnt[NFSPROC_REMOVE]++;
+               nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
+                       NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
+               nfsm_fhtom(ndp->ni_dvp);
+               nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+               nfsm_request(ndp->ni_dvp);
+               nfsm_reqdone;
+       }
+       if (ndp->ni_dvp == ndp->ni_vp)
+               vrele(ndp->ni_dvp);
+       else
+               nfs_nput(ndp->ni_dvp);
+       nfs_nput(ndp->ni_vp);
+       return (error);
+}
+
+/*
+ * nfs file remove rpc called from nfs_inactive
+ */
+nfs_removeit(ndp)
+       register struct nameidata *ndp;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_REMOVE]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
+               NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
+       nfsm_fhtom(ndp->ni_dvp);
+       nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+       nfsm_request(ndp->ni_dvp);
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs file rename call
+ */
+nfs_rename(sndp, tndp)
+       register struct nameidata *sndp, *tndp;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_RENAME]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
+               (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
+               nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
+       nfsm_fhtom(sndp->ni_dvp);
+       nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
+       nfsm_fhtom(tndp->ni_dvp);
+       nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
+       nfsm_request(sndp->ni_dvp);
+       nfsm_reqdone;
+#ifdef notyet
+       if (sndp->ni_vp->v_type == VDIR) {
+               if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
+                       cache_purge(tndp->ni_dvp);
+               cache_purge(sndp->ni_dvp);
+       }
+#endif
+       nfs_abortop(sndp);
+       nfs_abortop(tndp);
+       return (error);
+}
+
+/*
+ * nfs file rename rpc called from above
+ */
+nfs_renameit(sndp, tndp)
+       register struct nameidata *sndp, *tndp;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_RENAME]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
+               (NFSX_FH+NFSX_UNSIGNED)*2+nfsm_rndup(sndp->ni_dent.d_namlen)+
+               nfsm_rndup(tndp->ni_dent.d_namlen)); /* or sndp->ni_cred?*/
+       nfsm_fhtom(sndp->ni_dvp);
+       nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
+       nfsm_fhtom(tndp->ni_dvp);
+       nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
+       nfsm_request(sndp->ni_dvp);
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs hard link create call
+ */
+nfs_link(vp, ndp)
+       struct vnode *vp;
+       register struct nameidata *ndp;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_LINK]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_LINK], ndp->ni_cred,
+               NFSX_FH*2+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
+       nfsm_fhtom(vp);
+       nfsm_fhtom(ndp->ni_dvp);
+       nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+       nfsm_request(vp);
+       nfsm_reqdone;
+       nfs_nput(ndp->ni_dvp);
+       return (error);
+}
+
+/*
+ * nfs symbolic link create call
+ */
+nfs_symlink(ndp, vap, nm)
+       struct nameidata *ndp;
+       struct vattr *vap;
+       char *nm;               /* is this the path ?? */
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_SYMLINK]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
+       NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_UNSIGNED);
+       nfsm_fhtom(ndp->ni_dvp);
+       nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+       nfsm_strtom(nm, strlen(nm), NFS_MAXPATHLEN);
+       nfsm_build(p, u_long *, NFSX_SATTR);
+       *p++ = vtonfs_mode(VLNK, vap->va_mode);
+       *p++ = txdr_unsigned(ndp->ni_cred->cr_uid);
+       *p++ = txdr_unsigned(ndp->ni_cred->cr_gid);
+       *p++ = txdr_unsigned(VNOVAL);
+       txdr_time(&(vap->va_atime), p);         /* or VNOVAL ?? */
+       txdr_time(&(vap->va_mtime), p+2);       /* or VNOVAL ?? */
+       nfsm_request(ndp->ni_dvp);
+       nfsm_reqdone;
+       nfs_nput(ndp->ni_dvp);
+       return (error);
+}
+
+/*
+ * nfs make dir call
+ */
+nfs_mkdir(ndp, vap)
+       struct nameidata *ndp;
+       struct vattr *vap;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_MKDIR]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
+         NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen)+NFSX_SATTR);
+       nfsm_fhtom(ndp->ni_dvp);
+       nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+       nfsm_build(p, u_long *, NFSX_SATTR);
+       *p++ = vtonfs_mode(VDIR, vap->va_mode);
+       *p++ = txdr_unsigned(ndp->ni_cred->cr_uid);
+       *p++ = txdr_unsigned(ndp->ni_cred->cr_gid);
+       *p++ = txdr_unsigned(VNOVAL);
+       txdr_time(&(vap->va_atime), p);         /* or VNOVAL ?? */
+       txdr_time(&(vap->va_mtime), p+2);       /* or VNOVAL ?? */
+       nfsm_request(ndp->ni_dvp);
+       nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
+       nfsm_reqdone;
+       if (error)
+               nfs_nput(ndp->ni_vp);
+       nfs_nput(ndp->ni_dvp);
+       return (error);
+}
+
+/*
+ * nfs remove directory call
+ */
+nfs_rmdir(ndp)
+       register struct nameidata *ndp;
+{
+       nfsm_vars;
+
+       if (ndp->ni_dvp == ndp->ni_vp) {
+               vrele(ndp->ni_dvp);
+               nfs_nput(ndp->ni_dvp);
+               return (EINVAL);
+       }
+       if (ndp->ni_vp->v_count > 1)
+               error = nfs_sillyrename(ndp, RMDIR);
+       else {
+               nfsstats.rpccnt[NFSPROC_RMDIR]++;
+               nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
+                       NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
+               nfsm_fhtom(ndp->ni_dvp);
+               nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+               nfsm_request(ndp->ni_dvp);
+               nfsm_reqdone;
+       }
+#ifdef notyet
+       cache_purge(ndp->ni_dvp);
+       cache_purge(ndp->ni_vp);
+#endif
+       nfs_nput(ndp->ni_vp);
+       nfs_nput(ndp->ni_dvp);
+       return (error);
+}
+
+/*
+ * nfs remove dir rpc called from above
+ */
+nfs_rmdirit(ndp)
+       register struct nameidata *ndp;
+{
+       nfsm_vars;
+
+       nfsstats.rpccnt[NFSPROC_RMDIR]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_RMDIR], ndp->ni_cred,
+               NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
+       nfsm_fhtom(ndp->ni_dvp);
+       nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
+       nfsm_request(ndp->ni_dvp);
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * nfs readdir call
+ * Although cookie is defined as opaque, I translate it to/from net byte
+ * order so that it looks more sensible. This appears consistent with the
+ * Ultrix implementation of NFS.
+ */
+nfs_readdir(vp, uiop, offp, cred)
+       struct vnode *vp;
+       struct uio *uiop;
+       off_t *offp;
+       struct ucred *cred;
+{
+       register long len;
+       register struct direct *dp;
+       nfsm_vars;
+       struct mbuf *md2;
+       caddr_t dpos2;
+       int siz;
+       int more_dirs, eofflg;
+       off_t off, savoff;
+       struct direct *savdp;
+
+       nfs_lock(vp);
+       nfsstats.rpccnt[NFSPROC_READDIR]++;
+       nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
+       nfsm_fhtom(vp);
+       nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
+       off = *offp;
+       *p++ = txdr_unsigned(off);
+       *p = txdr_unsigned(uiop->uio_resid);
+       nfsm_request(vp);
+       siz = 0;
+       nfsm_disect(p, u_long *, NFSX_UNSIGNED);
+       more_dirs = fxdr_unsigned(int, *p);
+
+       /* Save the position so that we can do nfsm_mtouio() later */
+       dpos2 = dpos;
+       md2 = md;
+
+       /* loop thru the dir entries, doctoring them to 4bsd form */
+       while (more_dirs && siz < uiop->uio_resid) {
+               savoff = off;           /* Hold onto offset and dp */
+               savdp = dp;
+               nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
+               dp = (struct direct *)p;
+               dp->d_ino = fxdr_unsigned(u_long, *p++);
+               len = fxdr_unsigned(int, *p);
+               if (len <= 0 || len > NFS_MAXNAMLEN) {
+                       error = EBADRPC;
+                       m_freem(mrep);
+                       goto nfsmout;
+               }
+               dp->d_namlen = (u_short)len;
+               len = nfsm_rndup(len);
+               nfsm_adv(len);
+               nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
+               off = fxdr_unsigned(off_t, *p);
+               *p++ = 0;               /* Ensures null termination of name */
+               more_dirs = fxdr_unsigned(int, *p);
+               dp->d_reclen = len+4*NFSX_UNSIGNED;
+               siz += dp->d_reclen;
+       }
+       /*
+        * If at end of rpc data, get the eof boolean
+        */
+       if (!more_dirs) {
+               nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
+               eofflg = fxdr_unsigned(long, *p);
+       }
+       /*
+        * If there is too much to fit in the data buffer, use savoff and
+        * savdp to trim off the last record.
+        * --> we are not at eof
+        */
+       if (siz > uiop->uio_resid) {
+               eofflg = FALSE;
+               off = savoff;
+               siz -= dp->d_reclen;
+               dp = savdp;
+       }
+       if (siz > 0) {
+#ifdef notdef
+               if (!eofflg)
+                       dp->d_reclen += (uiop->uio_resid-siz);
+#endif
+               md = md2;
+               dpos = dpos2;
+               nfsm_mtouio(uiop, siz);
+#ifdef notdef
+               if (!eofflg)
+                       uiop->uio_resid = 0;
+#endif
+               *offp = off;
+       }
+       nfsm_reqdone;
+       nfs_unlock(vp);
+       return (error);
+}
+
+/*
+ * nfs statfs call
+ * (Actually a vfsop, not a vnode op)
+ */
+nfs_statfs(mp, sbp)
+       struct mount *mp;
+       register struct statfs *sbp;
+{
+       register struct nfsmount *nmp;
+       nfsm_vars;
+       struct ucred *cred;
+       struct nfsnode *np;
+       struct vnode *vp;
+
+       nmp = vfs_to_nfs(mp);
+       if (error = nfs_nget(mp, &nmp->nm_fh, &np))
+               return (error);
+       vp = NFSTOV(np);
+       nfsstats.rpccnt[NFSPROC_STATFS]++;
+       cred = crget();
+       cred->cr_ngroups = 1;
+       nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
+       nfsm_fhtom(vp);
+       nfsm_request(vp);
+       nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED);
+       sbp->f_type = MOUNT_NFS;
+       sbp->f_flags = nmp->nm_flag;
+       sbp->f_bsize = fxdr_unsigned(long, *p++);
+       sbp->f_fsize = fxdr_unsigned(long, *p++);
+       sbp->f_blocks = fxdr_unsigned(long, *p++);
+       sbp->f_bfree = fxdr_unsigned(long, *p++);
+       sbp->f_bavail = fxdr_unsigned(long, *p);
+       sbp->f_files = 0x7fffffff;
+       sbp->f_ffree = 0x7fffffff;
+       sbp->f_fsid.val[0] = mp->m_fsid.val[0];
+       sbp->f_fsid.val[1] = mp->m_fsid.val[1];
+       bcopy(nmp->nm_path, sbp->f_mntonname, MNAMELEN);
+       bcopy(nmp->nm_host, sbp->f_mntfromname, MNAMELEN);
+       nfsm_reqdone;
+       nfs_nput(vp);
+       crfree(cred);
+       return (error);
+}
+
+#define        HEXTOASC(x)     "0123456789abcdef"[x]
+
+/*
+ * Silly rename. To make the NFS filesystem that is stateless look a little
+ * more like the "ufs" a remove of an active vnode is translated to a rename
+ * to a funny looking filename that is removed by nfs_inactive on the
+ * nfsnode. There is the potential for another process on a different client
+ * to create the same funny name between the nfs_lookitup() fails and the
+ * nfs_rename() completes, but...
+ */
+nfs_sillyrename(ndp, flag)
+       struct nameidata *ndp;
+       int flag;
+{
+       register struct nfsnode *np;
+       register struct sillyrename *sp;
+       register struct nameidata *tndp;
+       int error;
+       short pid;
+
+       np = VTONFS(ndp->ni_dvp);
+       MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
+               M_WAITOK, M_TEMP);
+       sp->s_flag = flag;
+       bcopy((caddr_t)&np->n_fh, (caddr_t)&sp->s_fh, NFSX_FH);
+       np = VTONFS(ndp->ni_vp);
+       tndp = &sp->s_namei;
+       tndp->ni_cred = crdup(ndp->ni_cred);
+
+       /* Fudge together a funny name */
+       pid = u.u_procp->p_pid;
+       bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13);
+       tndp->ni_dent.d_namlen = 12;
+       tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf);
+       tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf);
+       tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf);
+       tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf);
+
+       /* Try lookitups until we get one that isn't there */
+       while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) {
+               tndp->ni_dent.d_name[4]++;
+               if (tndp->ni_dent.d_name[4] > 'z') {
+                       error = EINVAL;
+                       goto bad;
+               }
+       }
+       if (error = nfs_renameit(ndp, tndp))
+               goto bad;
+       nfs_lookitup(ndp->ni_dvp, tndp, &np->n_fh);
+       np->n_sillyrename = sp;
+       return (0);
+bad:
+       crfree(ndp->ni_cred);
+       free((caddr_t)sp, M_TEMP);
+       return (error);
+}
+
+/*
+ * Look up a file name for silly rename stuff.
+ * Just like nfs_lookup() except that it doesn't load returned values
+ * into the nfsnode table.
+ * If fhp != NULL it copies the returned file handle out
+ */
+nfs_lookitup(vp, ndp, fhp)
+       register struct vnode *vp;
+       register struct nameidata *ndp;
+       nfsv2fh_t *fhp;
+{
+       nfsm_vars;
+       long len;
+
+       nfsstats.rpccnt[NFSPROC_LOOKUP]++;
+       ndp->ni_dvp = vp;
+       ndp->ni_vp = NULL;
+       len = ndp->ni_dent.d_namlen;
+       nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
+       nfsm_fhtom(vp);
+       nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN);
+       nfsm_request(vp);
+       if (fhp != NULL) {
+               nfsm_disect(cp, caddr_t, NFSX_FH);
+               bcopy(cp, (caddr_t)fhp, NFSX_FH);
+       }
+       nfsm_reqdone;
+       return (error);
+}
+
+/*
+ * Kludge City..
+ * - make nfs_bmap() essentially a no-op that does no translation
+ * - do nfs_strategy() by faking physical I/O with nfs_readit/nfs_writeit
+ *   after mapping the physical addresses into Kernel Virtual space in the
+ *   nfsiobuf area.
+ *   (Maybe I could use the process's page mapping, but I was concerned that
+ *    Kernel Write might not be enabled and also figured copyout() would do
+ *    a lot more work than bcopy() and also it currently happens in the
+ *    context of the swapper process (2).
+ */
+nfs_bmap(vp, bn, vpp, bnp)
+       struct vnode *vp;
+       daddr_t bn;
+       struct vnode **vpp;
+       daddr_t *bnp;
+{
+       if (vpp != NULL)
+               *vpp = vp;
+       if (bnp != NULL)
+               *bnp = bn * btodb(vp->v_mount->m_bsize);
+       return (0);
+}
+
+/*
+ * Fun and games with phys i/o
+ */
+nfs_strategy(bp)
+       register struct buf *bp;
+{
+       register struct pte *pte, *ppte;
+       register caddr_t vaddr;
+       register struct uio *uiop;
+       register struct ucred *cr;
+       register struct vnode *vp;
+       int npf;
+       unsigned v;
+       struct proc *rp;
+       int o, error;
+       off_t off;
+       struct uio uio;
+       struct iovec io;
+
+       vp = bp->b_vp;
+       cr = crget();
+       cr->cr_gid = 10;        /* Pick anything ?? */
+       cr->cr_ngroups = 1;
+       uiop = &uio;
+       uiop->uio_iov = &io;
+       uiop->uio_iovcnt = 1;
+       io.iov_len = uiop->uio_resid = bp->b_bcount;
+       uiop->uio_segflg = UIO_SYSSPACE;
+       uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE;
+       o = (int)bp->b_un.b_addr & PGOFSET;
+       npf = btoc(bp->b_bcount + o);
+       rp = bp->b_flags&B_DIRTY ? &proc[2] : bp->b_proc;
+       cr->cr_uid = rp->p_uid;
+       if ((bp->b_flags & B_PHYS) == 0)
+               panic("nfs strategy Not PHYS IO");
+       if (bp->b_flags & B_PAGET)
+               pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
+       else {
+               v = btop(bp->b_un.b_addr);
+               if (bp->b_flags & B_UAREA)
+                       pte = &rp->p_addr[v];
+               else
+                       pte = vtopte(rp, v);
+       }
+       /*
+        * Play vmaccess() but with the Nfsiomap page table
+        */
+       ppte = &Nfsiomap[0];
+       vaddr = nfsiobuf;
+       while (npf != 0) {
+               mapin(ppte, (u_int)vaddr, pte->pg_pfnum, (int)(PG_V|PG_KW));
+#if defined(tahoe)
+               mtpr(P1DC, vaddr);
+#endif
+               ppte++;
+               pte++;
+               vaddr += NBPG;
+               --npf;
+       }
+       io.iov_base = nfsiobuf+o;
+       if (bp->b_flags & B_READ) {
+               uiop->uio_rw = UIO_READ;
+               bp->b_error = error = nfs_read(vp, uiop, &off, 0, cr);
+       } else {
+               uiop->uio_rw = UIO_WRITE;
+               bp->b_error = error = nfs_write(vp, uiop, &off, 0, cr);
+       }
+       bp->b_resid = uiop->uio_resid;
+       biodone(bp);
+       crfree(cr);
+       return (error);
+}
diff --git a/usr/src/sys/nfs/nfsm_subs.h b/usr/src/sys/nfs/nfsm_subs.h
new file mode 100644 (file)
index 0000000..6eb8723
--- /dev/null
@@ -0,0 +1,295 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfsm_subs.h 7.1 (Berkeley) %G%
+ */
+
+/*
+ * These macros do strange and peculiar things to mbuf chains for
+ * the assistance of the nfs code. To attempt to use them for any
+ * other purpose will be dangerous. (they make weird assumptions)
+ */
+
+/*
+ * First define what the actual subs. return
+ */
+struct mbuf *nfsm_reqh();
+struct vnode *nfs_fhtovp();
+
+/*
+ * To try and deal with different variants of mbuf.h, I have used the
+ * following defs. If M_HASCL is not defined in an older the 4.4bsd mbuf.h,
+ * you will have to use a different ifdef
+ */
+#ifdef M_HASCL
+#define        NFSMCLGET(m, w) MCLGET(m)
+#define        NFSMGETHDR(m)   MGET(m, M_WAIT, MT_DATA)
+#define        MHLEN           MLEN
+#define        NFSMINOFF(m) \
+               if (M_HASCL(m)) \
+                       (m)->m_off = ((int)MTOCL(m))-(int)(m); \
+               else \
+                       (m)->m_off = MMINOFF
+#define        NFSMADV(m, s)   (m)->m_off += (s)
+#define        NFSMSIZ(m)      ((M_HASCL(m))?MCLBYTES:MLEN)
+#define        m_nextpkt       m_act
+#define        NFSMCOPY(m, o, l, w)    m_copy((m), (o), (l))
+#else
+#define        M_HASCL(m)      ((m)->m_flags & M_EXT)
+#define        NFSMCLGET       MCLGET
+#define        NFSMGETHDR(m) \
+               MGETHDR(m, M_WAIT, MT_DATA); \
+               (m)->m_pkthdr.len = 0; \
+               (m)->m_pkthdr.rcvif = (struct ifnet *)0
+#define        NFSMINOFF(m) \
+               if (M_HASCL(m)) \
+                       (m)->m_data = (m)->m_ext.ext_buf; \
+               else \
+                       (m)->m_data = (m)->m_dat
+#define        NFSMADV(m, s)   (m)->m_data += (s)
+#define        NFSMSIZ(m)      ((M_HASCL(m))?(MCLBYTES-max_hdr): \
+                               (((m)->m_flags & M_PKTHDR)?MHLEN:MLEN))
+#define        NFSMCOPY        m_copym
+#endif
+
+#ifndef MCLBYTES
+#define        MCLBYTES        CLBYTES
+#endif
+
+#ifndef MT_CONTROL
+#define        MT_CONTROL      MT_RIGHTS
+#endif
+
+/*
+ * Now for the macros that do the simple stuff and call the functions
+ * for the hard stuff.
+ * These macros use several vars. declared in nfsm_reqhead and these
+ * vars. must not be used elsewhere unless you are careful not to corrupt
+ * them. The vars. starting with pN and tN (N=1,2,3,..) are temporaries
+ * that may be used so long as the value is not expected to retained
+ * after a macro.
+ * I know, this is kind of dorkey, but it makes the actual op functions
+ * fairly clean and deals with the mess caused by the xdr discriminating
+ * unions.
+ */
+
+#define        nfsm_build(a,c,s) \
+               t1 = NFSMSIZ(mb); \
+               if ((s) > (t1-mb->m_len)) { \
+                       MGET(mb2, M_WAIT, MT_DATA); \
+                       if ((s) > MLEN) \
+                               panic("build > MLEN"); \
+                       mb->m_next = mb2; \
+                       mb = mb2; \
+                       mb->m_len = 0; \
+                       bpos = mtod(mb, caddr_t); \
+               } \
+               (a) = (c)(bpos); \
+               mb->m_len += (s); \
+               bpos += (s)
+
+#define        nfsm_disect(a,c,s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+               if (t1 >= (s)) { \
+                       (a) = (c)(dpos); \
+                       dpos += (s); \
+               } else if (error = nfsm_disct(&md, &dpos, (s), t1, TRUE, &cp2)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } else { \
+                       (a) = (c)cp2; \
+               }
+
+#define        nfsm_disecton(a,c,s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+               if (t1 >= (s)) { \
+                       (a) = (c)(dpos); \
+                       dpos += (s); \
+               } else if (error = nfsm_disct(&md, &dpos, (s), t1, FALSE, &cp2)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } else { \
+                       (a) = (c)cp2; \
+               }
+
+#define nfsm_fhtom(v) \
+               nfsm_build(cp,caddr_t,NFSX_FH); \
+               bcopy((caddr_t)&(VTONFS(v)->n_fh), cp, NFSX_FH)
+
+#define nfsm_srvfhtom(f) \
+               nfsm_build(cp,caddr_t,NFSX_FH); \
+               bcopy((caddr_t)(f), cp, NFSX_FH)
+
+#define nfsm_mtofh(d,v) \
+               { struct nfsnode *np; nfsv2fh_t *fhp; \
+               nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH); \
+               if (error = nfs_nget((d)->v_mount, fhp, &np)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               } \
+               (v) = NFSTOV(np); \
+               nfsm_loadattr(v, (struct vattr *)0); \
+               (v)->v_type = np->n_vattr.va_type; \
+               }
+
+#define        nfsm_loadattr(v,a) \
+               if (error = nfs_loadattrcache((v), &md, &dpos, (a))) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_strsiz(s,m) \
+               nfsm_disect(p,u_long *,NFSX_UNSIGNED); \
+               if (((s) = fxdr_unsigned(long,*p)) > (m)) { \
+                       m_freem(mrep); \
+                       error = EBADRPC; \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_srvstrsiz(s,m) \
+               nfsm_disect(p,u_long *,NFSX_UNSIGNED); \
+               if (((s) = fxdr_unsigned(long,*p)) > (m) || (s) <= 0) { \
+                       error = EBADRPC; \
+                       nfsm_reply(0); \
+               }
+
+#define        nfsm_srvstrsizon(s,m) \
+               nfsm_disecton(p,u_long *,NFSX_UNSIGNED); \
+               if (((s) = fxdr_unsigned(long,*p)) > (m)) { \
+                       error = EBADRPC; \
+                       nfsm_reply(0); \
+               }
+
+#define nfsm_mtouio(p,s) \
+               if ((s) > 0 && \
+                  (error = nfsm_mbuftouio(&md,(p),(s),&dpos))) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               }
+
+#define nfsm_uiotom(p,s) \
+               if (error = nfsm_uiotombuf((p),&mb,(s),&bpos)) { \
+                       m_freem(mreq); \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_reqhead(a,c,s) \
+               if ((mreq = nfsm_reqh(nfs_prog,nfs_vers,(a),(c),(s),&bpos,&mb,&xid)) == NULL) { \
+                       error = ENOBUFS; \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_vars \
+               register u_long *p; \
+               register caddr_t cp; \
+               register long t1, t2; \
+               caddr_t bpos, dpos, cp2; \
+               u_long xid; \
+               int error = 0; \
+               long offs = 0; \
+               struct mbuf *mreq, *mrep, *md, *mb, *mb2
+
+#define nfsm_reqdone   m_freem(mrep); \
+               nfsmout: 
+
+#define nfsm_rndup(a)  (((a)+3)&(~0x3))
+
+#define        nfsm_request(v) \
+               if (error = nfs_request((v), mreq, xid, \
+                  (v)->v_mount, &mrep, &md, &dpos)) \
+                       goto nfsmout
+
+#define        nfsm_strtom(a,s,m) \
+               if ((s) > (m)) { \
+                       m_freem(mreq); \
+                       error = ENAMETOOLONG; \
+                       goto nfsmout; \
+               } \
+               t2 = nfsm_rndup(s)+NFSX_UNSIGNED; \
+               if(t2<=(NFSMSIZ(mb)-mb->m_len)){ \
+                       nfsm_build(p,u_long *,t2); \
+                       *p++ = txdr_unsigned(s); \
+                       *(p+((t2>>2)-2)) = 0; \
+                       bcopy((caddr_t)(a), (caddr_t)p, (s)); \
+               } else if (error = nfsm_strtmbuf(&mb, &bpos, (a), (s))) { \
+                       m_freem(mreq); \
+                       goto nfsmout; \
+               }
+
+#define        nfsm_srverr \
+               { \
+                       m_freem(mrep); \
+                       return(ENOBUFS); \
+               }
+
+#define        nfsm_srvars \
+               register caddr_t cp; \
+               register u_long *p; \
+               register long t1, t2; \
+               caddr_t bpos; \
+               long offs = 0; \
+               int error = 0; \
+               char *cp2; \
+               struct mbuf *mb, *mb2, *mreq
+
+#define        nfsm_srvdone \
+               nfsmout: \
+               return(error)
+
+#define        nfsm_reply(s) \
+               { \
+               if (error) \
+                       nfs_rephead(0, xid, error, mrq, &mb, &bpos); \
+               else \
+                       nfs_rephead((s), xid, error, mrq, &mb, &bpos); \
+               m_freem(mrep); \
+               mreq = *mrq; \
+               if (error) \
+                       return(0); \
+               }
+
+#define        nfsm_adv(s) \
+               t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+               if (t1 >= (s)) { \
+                       dpos += (s); \
+               } else if (error = nfs_adv(&md, &dpos, (s), t1)) { \
+                       m_freem(mrep); \
+                       goto nfsmout; \
+               }
+
+#define nfsm_srvmtofh(f) \
+               nfsm_disecton(p, u_long *, NFSX_FH); \
+               bcopy((caddr_t)p, (caddr_t)f, NFSX_FH)
+
+#define        nfsm_clget \
+               if (bp >= be) { \
+                       MGET(mp, M_WAIT, MT_DATA); \
+                       NFSMCLGET(mp, M_WAIT); \
+                       mp->m_len = NFSMSIZ(mp); \
+                       if (mp3 == NULL) \
+                               mp3 = mp2 = mp; \
+                       else { \
+                               mp2->m_next = mp; \
+                               mp2 = mp; \
+                       } \
+                       bp = mtod(mp, caddr_t); \
+                       be = bp+mp->m_len; \
+               } \
+               p = (u_long *)bp
+
diff --git a/usr/src/sys/nfs/nfsmount.h b/usr/src/sys/nfs/nfsmount.h
new file mode 100644 (file)
index 0000000..3641134
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfsmount.h  7.1 (Berkeley) %G%
+ */
+
+/*
+ * Mount structure.
+ * One allocated on every nfs mount.
+ * Holds nfs specific info for mount (sockets...)
+ */
+struct nfsmount {
+       int     nm_flag;                /* Flags for soft/hard... */
+       struct  mount *nm_mountp;       /* vfs structure for this filesystem */
+       nfsv2fh_t nm_fh;                /* File handle of root dir */
+       struct  mbuf *nm_sockaddr;      /* Address of server */
+       struct  socket  *nm_so;         /* rpc socket */
+       int     nm_timeo;               /* Timeout interval */
+       int     nm_retrans;             /* # of retransmits */
+       int     nm_rsize;               /* Max size of read rpc */
+       int     nm_wsize;               /* Max size of write rpc */
+       char    nm_path[MNAMELEN];      /* Path mounted on */
+       char    nm_host[MNAMELEN];      /* Remote host name */
+};
+
+struct nfsmount *vfs_to_nfs();
diff --git a/usr/src/sys/nfs/nfsnode.h b/usr/src/sys/nfs/nfsnode.h
new file mode 100644 (file)
index 0000000..ecf964e
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfsnode.h   7.1 (Berkeley) %G%
+ */
+
+/*
+ * The nfsnode is the nfs equivalent to ufs's inode. Any similarity
+ * is purely coincidental.
+ * There is a unique nfsnode allocated for each active file,
+ * each current directory, each mounted-on file, text file, and the root.
+ * An nfsnode is 'named' by its file handle. (nget/nfs_node.c)
+ */
+
+struct nfsnode {
+       struct  nfsnode *n_chain[2];    /* must be first */
+       nfsv2fh_t n_fh;                 /* NFS File Handle */
+       long    n_flag;                 /* Flag for locking.. */
+       long    n_id;           /* unique identifier */
+       struct  vnode n_vnode;  /* vnode associated with this nfsnode */
+       long    n_attrstamp;    /* Time stamp (sec) for attributes */
+       struct  vattr n_vattr;  /* Vnode attribute cache */
+       struct  sillyrename *n_sillyrename;     /* Ptr to silly rename struct */
+       struct nfsnode  *n_freef;       /* free list forward */
+       struct nfsnode **n_freeb;       /* free list back */
+};
+
+#define        n_forw          n_chain[0]
+#define        n_back          n_chain[1]
+
+#ifdef KERNEL
+struct nfsnode *nfsnode;               /* the nfsnode table itself */
+struct nfsnode *nfsnodeNNFSNODE;       /* the end of the nfsnode table */
+int    nnfsnode;                       /* number of slots in the table */
+long   nextnfsnodeid;          /* unique id generator */
+
+extern struct vnodeops nfsv2_vnodeops; /* vnode operations for nfsv2 */
+extern struct vnodeops nfsv2chr_vnodeops; /* vnode operations for chr devices */
+
+/*
+ * Convert between nfsnode pointers and vnode pointers
+ */
+#define VTONFS(vp)     ((struct nfsnode *)(vp)->v_data)
+#define NFSTOV(np)     ((struct vnode *)&(np)->n_vnode)
+#endif
+/*
+ * Flags for n_flag
+ */
+#define        NLOCKED         0x1
+#define        NWANT           0x2
diff --git a/usr/src/sys/nfs/nfsproto.h b/usr/src/sys/nfs/nfsproto.h
new file mode 100644 (file)
index 0000000..1d4fdf8
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)nfsproto.h  7.1 (Berkeley) %G%
+ */
+
+/*
+ * nfs definitions as per the version 2 specs
+ */
+
+/*
+ * Constants as defined in the Sun NFS Version 2 spec.
+ * "Network File System Protocol Specification" in the
+ * Manual "Networking on the Sun Workstation", Part #800-1324-03, Rev B
+ */
+
+#define NFS_PORT       2049
+#define        NFS_PROG        100003
+#define NFS_VER2       2
+#define        NFS_MAXDATA     8192
+#define        NFS_MAXPATHLEN  1024
+#define        NFS_MAXNAMLEN   255
+#define        NFS_FHSIZE      32
+#define        NFS_NPROCS      18
+
+/* Stat numbers for rpc returns */
+#define        NFS_OK          0
+#define        NFSERR_PERM     1
+#define        NFSERR_NOENT    2
+#define        NFSERR_IO       5
+#define        NFSERR_NXIO     6
+#define        NFSERR_ACCES    13
+#define        NFSERR_EXIST    17
+#define        NFSERR_NODEV    19
+#define        NFSERR_NOTDIR   20
+#define        NFSERR_ISDIR    21
+#define        NFSERR_FBIG     27
+#define        NFSERR_NOSPC    28
+#define        NFSERR_ROFS     30
+#define        NFSERR_NAMETOOLONG      63
+#define        NFSERR_NOTEMPTY 66
+#define        NFSERR_DQUOT    69
+#define        NFSERR_STALE    70
+#define        NFSERR_WFLUSH   99
+
+/* Sizes in bytes of various nfs rpc components */
+#define        NFSX_FH         32
+#define        NFSX_UNSIGNED   4
+#define        NFSX_FATTR      68
+#define        NFSX_SATTR      32
+#define        NFSX_COOKIE     4
+#define NFSX_STATFS    20
+
+/* nfs rpc procedure numbers */
+#define        NFSPROC_NULL            0
+#define        NFSPROC_GETATTR         1
+#define        NFSPROC_SETATTR         2
+#define        NFSPROC_ROOT            3               /* Obsolete */
+#define        NFSPROC_LOOKUP          4
+#define        NFSPROC_READLINK        5
+#define        NFSPROC_READ            6
+#define        NFSPROC_WRITECACHE      7               /* Obsolete */
+#define        NFSPROC_WRITE           8
+#define        NFSPROC_CREATE          9
+#define        NFSPROC_REMOVE          10
+#define        NFSPROC_RENAME          11
+#define        NFSPROC_LINK            12
+#define        NFSPROC_SYMLINK         13
+#define        NFSPROC_MKDIR           14
+#define        NFSPROC_RMDIR           15
+#define        NFSPROC_READDIR         16
+#define        NFSPROC_STATFS          17
+
+/* Conversion macros */
+#define        vtonfs_mode(t,m) txdr_unsigned(MAKEIMODE(t,m))
+#define        nfstov_mode(a)  (fxdr_unsigned(u_short, (a))&07777)
+#define        vtonfs_type(a)  txdr_unsigned(nfs_type[((long)(a))])
+#define        nfstov_type(a)  v_type[fxdr_unsigned(u_long, (a))]
+
+/* File types */
+typedef enum { NFNON=0, NFREG=1, NFDIR=2, NFBLK=3, NFCHR=4, NFLNK=5 } nfstype;
diff --git a/usr/src/sys/nfs/rpcv2.h b/usr/src/sys/nfs/rpcv2.h
new file mode 100644 (file)
index 0000000..870e862
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)rpcv2.h     7.1 (Berkeley) %G%
+ */
+
+/*
+ * Definitions for Sun RPC Version 2, from
+ * "Remote Procedure Call Protocol Specification" in the manual
+ * "Networking on the Sun Workstation", Part #800-1324-03 Rev. B
+ */
+
+/* Version # */
+#define        RPC_VER2        2
+
+/* Authentication Flavours */
+#define        RPCAUTH_NULL    0
+#define        RPCAUTH_UNIX    1
+#define        RPCAUTH_SHORT   2
+
+/* Rpc Constants */
+#define        RPC_CALL        0
+#define        RPC_REPLY       1
+#define        RPC_MSGACCEPTED 0
+#define        RPC_MSGDENIED   1
+#define        RPC_PROGUNAVAIL 1
+#define        RPC_PROGMISMATCH        2
+#define        RPC_PROCUNAVAIL 3
+#define        RPC_GARBAGE     4               /* I like this one */
+#define        RPC_MISMATCH    0
+#define        RPC_AUTHFAIL    1
+
+/* Authentication failures */
+#define        AUTH_BADCRED    1
+#define        AUTH_REJECTCRED 2
+#define        AUTH_BADVERF    3
+#define        AUTH_REJECTVERF 4
+#define        AUTH_TOOWEAK    5               /* Give em wheaties */
+
+/* Sizes of rpc header parts */
+#define        RPC_SIZ         24
+#define        RPC_REPLYSIZ    28
+
+/* RPC Prog definitions */
+#define        RPCPROG_MNT     100005
+#define        RPCMNT_VER1     1
+#define        RPCMNT_MOUNT    1
+#define        RPCMNT_DUMP     2
+#define        RPCMNT_UMOUNT   3
+#define        RPCMNT_UMNTALL  4
+#define        RPCMNT_EXPORT   5
+#define        RPCMNT_NAMELEN  255
+#define        RPCMNT_PATHLEN  1024
+#define        RPCPROG_NFS     100003
diff --git a/usr/src/sys/nfs/xdr_subs.h b/usr/src/sys/nfs/xdr_subs.h
new file mode 100644 (file)
index 0000000..199873c
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley.  The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ *     @(#)xdr_subs.h  7.1 (Berkeley) %G%
+ */
+
+/*
+ * Macros used for conversion to/from xdr representation by nfs...
+ * These use the MACHINE DEPENDENT routines ntohl, htonl
+ */
+/* From xdr to machine */
+#define fxdr_unsigned(t, v)    ((t)ntohl((long)(v)))
+#define        fxdr_time(f, t)         {((struct timeval *)(t))->tv_sec=ntohl( \
+                               ((struct timeval *)(f))->tv_sec); \
+                               ((struct timeval *)(t))->tv_usec=ntohl( \
+                               ((struct timeval *)(f))->tv_usec);}
+
+/* from machine to xdr */
+#define        txdr_unsigned(v)        (htonl((long)(v)))
+#define        txdr_time(f, t)         {((struct timeval *)(t))->tv_sec=htonl( \
+                               ((struct timeval *)(f))->tv_sec); \
+                               ((struct timeval *)(t))->tv_usec=htonl( \
+                               ((struct timeval *)(f))->tv_usec);}
+