add Rick Macklem's compressed NFS
authorKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Tue, 2 Oct 1990 06:17:09 +0000 (22:17 -0800)
committerKirk McKusick <mckusick@ucbvax.Berkeley.EDU>
Tue, 2 Oct 1990 06:17:09 +0000 (22:17 -0800)
SCCS-vsn: sys/nfs/nfs_socket.c 7.19
SCCS-vsn: sys/nfs/nfs_subs.c 7.30
SCCS-vsn: sys/nfs/nfs_syscalls.c 7.19

usr/src/sys/nfs/nfs_socket.c
usr/src/sys/nfs/nfs_subs.c
usr/src/sys/nfs/nfs_syscalls.c

index 764c653..86fa9c9 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_socket.c        7.18 (Berkeley) %G%
+ *     @(#)nfs_socket.c        7.19 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -51,8 +51,29 @@ extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix,
 extern u_long nfs_prog, nfs_vers;
 /* Maybe these should be bits in a u_long ?? */
 extern int nonidempotent[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
 /* Maybe these should be bits in a u_long ?? */
 extern int nonidempotent[NFS_NPROCS];
+static int compressrequest[NFS_NPROCS] = {
+       FALSE,
+       TRUE,
+       TRUE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       FALSE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+};
 int    nfs_sbwait();
 void   nfs_disconnect();
 int    nfs_sbwait();
 void   nfs_disconnect();
+struct mbuf *nfs_compress(), *nfs_uncompress();
 
 int    nfsrv_null(),
        nfsrv_getattr(),
 
 int    nfsrv_null(),
        nfsrv_getattr(),
@@ -333,7 +354,7 @@ nfs_receive(so, aname, mp, rep)
        struct uio auio;
        struct iovec aio;
        register struct mbuf *m;
        struct uio auio;
        struct iovec aio;
        register struct mbuf *m;
-       struct mbuf *m2, *m3, *mnew, **mbp;
+       struct mbuf *m2, *mnew, **mbp;
        caddr_t fcp, tcp;
        u_long len;
        struct mbuf **getnam;
        caddr_t fcp, tcp;
        u_long len;
        struct mbuf **getnam;
@@ -475,47 +496,34 @@ errout:
                /*
                 * All this for something that may never happen.
                 */
                /*
                 * All this for something that may never happen.
                 */
-               if (m->m_len & 0x3) {
+               if (m->m_next && (m->m_len & 0x3)) {
                        printf("nfs_rcv odd length!\n");
                        printf("nfs_rcv odd length!\n");
-                       fcp = mtod(m, caddr_t);
-                       mnew = m2 = (struct mbuf *)0;
-#ifdef lint
-                       m3 = (struct mbuf *)0;
                        mlen = 0;
                        mlen = 0;
-#endif /* lint */
                        while (m) {
                        while (m) {
-                               if (m2 == NULL || mlen == 0) {
-                                       MGET(m2, M_WAIT, MT_DATA);
-                                       if (len > MINCLSIZE)
-                                               MCLGET(m2, M_WAIT);
-                                       m2->m_len = 0;
-                                       mlen = M_TRAILINGSPACE(m2);
-                                       tcp = mtod(m2, caddr_t);
-                                       if (mnew) {
-                                               m3->m_next = m2;
-                                               m3 = m2;
-                                       } else
-                                               mnew = m3 = m2;
-                               }
-                               siz = (mlen > m->m_len) ? m->m_len : mlen;
-                               bcopy(fcp, tcp, siz);
-                               m2->m_len += siz;
-                               mlen -= siz;
-                               len -= siz;
-                               tcp += siz;
-                               m->m_len -= siz;
-                               fcp += siz;
-                               if (m->m_len == 0) {
-                                       do {
-                                               m = m->m_next;
-                                       } while (m && m->m_len == 0);
-                                       if (m)
-                                               fcp = mtod(m, caddr_t);
+                               fcp = mtod(m, caddr_t);
+                               while (m->m_len > 0) {
+                                       if (mlen == 0) {
+                                               MGET(m2, M_WAIT, MT_DATA);
+                                               if (len >= MINCLSIZE)
+                                                       MCLGET(m2, M_WAIT);
+                                               m2->m_len = 0;
+                                               mlen = M_TRAILINGSPACE(m2);
+                                               tcp = mtod(m2, caddr_t);
+                                               *mbp = m2;
+                                               mbp = &m2->m_next;
+                                       }
+                                       siz = MIN(mlen, m->m_len);
+                                       bcopy(fcp, tcp, siz);
+                                       m2->m_len += siz;
+                                       mlen -= siz;
+                                       len -= siz;
+                                       tcp += siz;
+                                       m->m_len -= siz;
+                                       fcp += siz;
                                }
                                }
+                               MFREE(m, mnew);
+                               m = mnew;
                        }
                        }
-                       m = *mbp;
-                       *mbp = mnew;
-                       m_freem(m);
                        break;
                }
                len -= m->m_len;
                        break;
                }
                len -= m->m_len;
@@ -525,11 +533,6 @@ errout:
        return (error);
 }
 
        return (error);
 }
 
-struct rpc_replyhead {
-       u_long  r_xid;
-       u_long  r_rep;
-};
-
 /*
  * Implement receipt of reply on a socket.
  * We must search through the list of received datagrams matching them
 /*
  * Implement receipt of reply on a socket.
  * We must search through the list of received datagrams matching them
@@ -543,7 +546,7 @@ nfs_reply(nmp, myrep)
        register struct mbuf *m;
        register struct nfsreq *rep;
        register int error = 0;
        register struct mbuf *m;
        register struct nfsreq *rep;
        register int error = 0;
-       struct rpc_replyhead replyh;
+       u_long rxid;
        struct mbuf *mp, *nam;
        char *cp;
        int cnt, xfer;
        struct mbuf *mp, *nam;
        char *cp;
        int cnt, xfer;
@@ -596,30 +599,15 @@ nfs_reply(nmp, myrep)
                 * Get the xid and check that it is an rpc reply
                 */
                m = mp;
                 * Get the xid and check that it is an rpc reply
                 */
                m = mp;
-               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 (m && cnt > 0) {
-                               if (m->m_len > 0) {
-                                       xfer = (m->m_len >= cnt) ? cnt :
-                                               m->m_len;
-                                       bcopy(mtod(m, caddr_t), cp, xfer);
-                                       cnt -= xfer;
-                                       cp += xfer;
-                               }
-                               if (cnt > 0)
-                                       m = m->m_next;
-                       }
-               }
-               if (replyh.r_rep != rpc_reply || m == NULL) {
+               while (m && m->m_len == 0)
+                       m = m->m_next;
+               if (m == NULL) {
                        nfsstats.rpcinvalid++;
                        m_freem(mp);
                        nfs_sounlock(&nmp->nm_flag);
                        continue;
                }
                        nfsstats.rpcinvalid++;
                        m_freem(mp);
                        nfs_sounlock(&nmp->nm_flag);
                        continue;
                }
+               bcopy(mtod(m, caddr_t), (caddr_t)&rxid, NFSX_UNSIGNED);
                /*
                 * Loop through the request list to match up the reply
                 * Iff no match, just drop the datagram
                /*
                 * Loop through the request list to match up the reply
                 * Iff no match, just drop the datagram
@@ -627,7 +615,7 @@ nfs_reply(nmp, myrep)
                m = mp;
                rep = nfsreqh.r_next;
                while (rep != &nfsreqh) {
                m = mp;
                rep = nfsreqh.r_next;
                while (rep != &nfsreqh) {
-                       if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid) {
+                       if (rep->r_mrep == NULL && rxid == rep->r_xid) {
                                /* Found it.. */
                                rep->r_mrep = m;
                                /*
                                /* Found it.. */
                                rep->r_mrep = m;
                                /*
@@ -693,7 +681,7 @@ nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
        caddr_t dpos;
        char *cp2;
        int t1;
        caddr_t dpos;
        char *cp2;
        int t1;
-       int s;
+       int s, compressed;
        int error = 0;
 
        nmp = VFSTONFS(mp);
        int error = 0;
 
        nmp = VFSTONFS(mp);
@@ -732,6 +720,15 @@ nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
        }
        mreq->m_pkthdr.len = len;
        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
        }
        mreq->m_pkthdr.len = len;
        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
+       compressed = 0;
+       m = mreq;
+       if ((nmp->nm_flag & NFSMNT_COMPRESS) && compressrequest[procnum]) {
+               mreq = nfs_compress(mreq);
+               if (mreq != m) {
+                       len = mreq->m_pkthdr.len;
+                       compressed++;
+               }
+       }
        /*
         * For non-atomic protocols, insert a Sun RPC Record Mark.
         */
        /*
         * For non-atomic protocols, insert a Sun RPC Record Mark.
         */
@@ -808,11 +805,14 @@ nfs_request(vp, mreq, xid, procnum, procp, tryhard, mp, mrp, mdp, dposp)
                                rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
        }
        m_freem(rep->r_mreq);
                                rep->r_nmp->nm_mountp->mnt_stat.f_mntfromname);
        }
        m_freem(rep->r_mreq);
-       mrep = md = rep->r_mrep;
+       mrep = rep->r_mrep;
        FREE((caddr_t)rep, M_NFSREQ);
        if (error)
                return (error);
 
        FREE((caddr_t)rep, M_NFSREQ);
        if (error)
                return (error);
 
+       if (compressed)
+               mrep = nfs_uncompress(mrep);
+       md = mrep;
        /*
         * break down the rpc header and check if ok
         */
        /*
         * break down the rpc header and check if ok
         */
@@ -862,7 +862,7 @@ nfsmout:
  * - fill in the cred struct.
  */
 nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
  * - fill in the cred struct.
  */
 nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
-       msk, mtch)
+       msk, mtch, wascomp)
        struct socket *so;
        u_long prog;
        u_long vers;
        struct socket *so;
        u_long prog;
        u_long vers;
@@ -875,6 +875,7 @@ nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
        u_long *procnum;
        register struct ucred *cr;
        struct mbuf *msk, *mtch;
        u_long *procnum;
        register struct ucred *cr;
        struct mbuf *msk, *mtch;
+       int *wascomp;
 {
        register int i;
        register u_long *p;
 {
        register int i;
        register u_long *p;
@@ -899,6 +900,12 @@ nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, procnum, cr,
        if (error)
                return (error);
        md = mrep;
        if (error)
                return (error);
        md = mrep;
+       mrep = nfs_uncompress(mrep);
+       if (mrep != md) {
+               *wascomp = 1;
+               md = mrep;
+       } else
+               *wascomp = 0;
        dpos = mtod(mrep, caddr_t);
        nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED);
        *retxid = *p++;
        dpos = mtod(mrep, caddr_t);
        nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED);
        *retxid = *p++;
index 9480c57..85c0b9a 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_subs.c  7.29 (Berkeley) %G%
+ *     @(#)nfs_subs.c  7.30 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
@@ -33,6 +33,7 @@
 #include "nfsiom.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 #include "nfsiom.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
+#include "nfscompress.h"
 
 #define TRUE   1
 #define        FALSE   0
 
 #define TRUE   1
 #define        FALSE   0
@@ -878,3 +879,203 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred)
                VOP_UNLOCK(*vpp);
        return (0);
 }
                VOP_UNLOCK(*vpp);
        return (0);
 }
+
+/*
+ * These two functions implement nfs rpc compression.
+ * The algorithm is a trivial run length encoding of '\0' bytes. The high
+ * order nibble of hex "e" is or'd with the number of zeroes - 2 in four
+ * bits. (2 - 17 zeros) Any data byte with a high order nibble of hex "e"
+ * is byte stuffed.
+ * The compressed data is padded with 0x0 bytes to an even multiple of
+ * 4 bytes in length to avoid any weird long pointer alignments.
+ * If compression/uncompression is unsuccessful, the original mbuf list
+ * is returned.
+ * The first four bytes (the XID) are left uncompressed and the fifth
+ * byte is set to 0x1 for request and 0x2 for reply.
+ * An uncompressed RPC will always have the fifth byte == 0x0.
+ */
+struct mbuf *
+nfs_compress(m0)
+       struct mbuf *m0;
+{
+       register u_char ch, nextch;
+       register int i, rlelast;
+       register u_char *ip, *op;
+       register int ileft, oleft, noteof;
+       register struct mbuf *m, *om;
+       struct mbuf **mp, *retm;
+       int olen, clget;
+
+       i = rlelast = 0;
+       noteof = 1;
+       m = m0;
+       if (m->m_len < 12)
+               return (m0);
+       if (m->m_pkthdr.len >= MINCLSIZE)
+               clget = 1;
+       else
+               clget = 0;
+       ileft = m->m_len - 9;
+       ip = mtod(m, u_char *);
+       MGETHDR(om, MT_DATA, M_WAIT);
+       if (clget)
+               MCLGET(om, M_WAIT);
+       retm = om;
+       mp = &om->m_next;
+       olen = om->m_len = 5;
+       oleft = M_TRAILINGSPACE(om);
+       op = mtod(om, u_char *);
+       *((u_long *)op) = *((u_long *)ip);
+       ip += 7;
+       op += 4;
+       *op++ = *ip++ + 1;
+       nextch = *ip++;
+       while (noteof) {
+               ch = nextch;
+               if (ileft == 0) {
+                       do {
+                               m = m->m_next;
+                       } while (m && m->m_len == 0);
+                       if (m) {
+                               ileft = m->m_len;
+                               ip = mtod(m, u_char *);
+                       } else {
+                               noteof = 0;
+                               nextch = 0x1;
+                               goto doit;
+                       }
+               }
+               nextch = *ip++;
+               ileft--;
+doit:
+               if (ch == '\0') {
+                       if (++i == NFSC_MAX || nextch != '\0') {
+                               if (i < 2) {
+                                       nfscput('\0');
+                               } else {
+                                       if (rlelast == i) {
+                                               nfscput('\0');
+                                               i--;
+                                       }
+                                       if (NFSCRLE(i) == (nextch & 0xff)) {
+                                               i--;
+                                               if (i < 2) {
+                                                       nfscput('\0');
+                                               } else {
+                                                       nfscput(NFSCRLE(i));
+                                               }
+                                               nfscput('\0');
+                                               rlelast = 0;
+                                       } else {
+                                               nfscput(NFSCRLE(i));
+                                               rlelast = i;
+                                       }
+                               }
+                               i = 0;
+                       }
+               } else {
+                       if ((ch & NFSCRL) == NFSCRL) {
+                               nfscput(ch);
+                       }
+                       nfscput(ch);
+                       i = rlelast = 0;
+               }
+       }
+       if (olen < m0->m_pkthdr.len) {
+               m_freem(m0);
+               if (i = (olen & 0x3)) {
+                       i = 4 - i;
+                       while (i-- > 0)
+                               nfscput('\0');
+               }
+               retm->m_pkthdr.len = olen;
+               return (retm);
+       } else {
+               m_freem(retm);
+               return (m0);
+       }
+}
+
+struct mbuf *
+nfs_uncompress(m0)
+       struct mbuf *m0;
+{
+       register u_char cp, nextcp, *ip, *op;
+       register struct mbuf *m, *om;
+       struct mbuf *retm, **mp;
+       int i, j, noteof, clget, ileft, oleft, olen;
+
+       m = m0;
+       if (m->m_pkthdr.len < 6)
+               return (m0);
+       if (m->m_pkthdr.len >= MINCLSIZE)
+               clget = 1;
+       else
+               clget = 0;
+       MGETHDR(om, MT_DATA, M_WAIT);
+       if (clget)
+               MCLGET(om, M_WAIT);
+       olen = om->m_len = 8;
+       oleft = M_TRAILINGSPACE(om);
+       op = mtod(om, u_char *);
+       retm = om;
+       mp = &om->m_next;
+       if (m->m_len >= 6) {
+               ileft = m->m_len - 6;
+               ip = mtod(m, u_char *);
+               *((u_long *)op) = *((u_long *)ip);
+               bzero(op + 4, 3);
+               ip += 4;
+               op += 7;
+               if (*ip == '\0') {
+                       m_freem(om);
+                       return (m0);
+               }
+               *op++ = *ip++ - 1;
+               cp = *ip++;
+       } else {
+               ileft = m->m_len;
+               ip = mtod(m, u_char *);
+               nfscget(*op++);
+               nfscget(*op++);
+               nfscget(*op++);
+               nfscget(*op++);
+               bzero(op, 3);
+               op += 3;
+               nfscget(*op);
+               if (*op == '\0') {
+                       m_freem(om);
+                       return (m0);
+               }
+               (*op)--;
+               op++;
+               nfscget(cp);
+       }
+       noteof = 1;
+       while (noteof) {
+               if ((cp & NFSCRL) == NFSCRL) {
+                       nfscget(nextcp);
+                       if (cp == nextcp) {
+                               nfscput(cp);
+                               goto readit;
+                       } else {
+                               i = (cp & 0xf) + 2;
+                               for (j = 0; j < i; j++) {
+                                       nfscput('\0');
+                               }
+                               cp = nextcp;
+                       }
+               } else {
+                       nfscput(cp);
+readit:
+                       nfscget(cp);
+               }
+       }
+       m_freem(m0);
+       if (i = (olen & 0x3)) {
+               olen -= i;
+               om->m_len -= i;
+       }
+       retm->m_pkthdr.len = olen;
+       return (retm);
+}
index f659d7a..662391e 100644 (file)
@@ -7,7 +7,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)nfs_syscalls.c      7.18 (Berkeley) %G%
+ *     @(#)nfs_syscalls.c      7.19 (Berkeley) %G%
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -41,10 +41,31 @@ extern int nfs_asyncdaemons;
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 extern int nfs_tcpnodelay;
 struct file *getsock();
 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
 extern int nfs_tcpnodelay;
 struct file *getsock();
+struct mbuf *nfs_compress();
 
 #define        TRUE    1
 #define        FALSE   0
 
 
 #define        TRUE    1
 #define        FALSE   0
 
+static int compressreply[NFS_NPROCS] = {
+       FALSE,
+       TRUE,
+       TRUE,
+       FALSE,
+       TRUE,
+       TRUE,
+       FALSE,
+       FALSE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+       TRUE,
+};
 /*
  * NFS server system calls
  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
 /*
  * NFS server system calls
  * getfh() lives here too, but maybe should move to kern/vfs_syscalls.c
@@ -112,7 +133,7 @@ nfssvc(p, uap, retval)
        struct mbuf msk, mtch;
        struct socket *so;
        caddr_t dpos;
        struct mbuf msk, mtch;
        struct socket *so;
        caddr_t dpos;
-       int procid, repstat, error, cacherep;
+       int procid, repstat, error, cacherep, wascomp;
        u_long retxid;
 
        /*
        u_long retxid;
 
        /*
@@ -174,7 +195,7 @@ nfssvc(p, uap, retval)
        for (;;) {
                if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
                   &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
        for (;;) {
                if (error = nfs_getreq(so, nfs_prog, nfs_vers, NFS_NPROCS-1,
                   &nam, &mrep, &md, &dpos, &retxid, &procid, cr,
-                  &msk, &mtch)) {
+                  &msk, &mtch, &wascomp)) {
                        if (nam)
                                m_freem(nam);
                        if (error == EPIPE || error == EINTR ||
                        if (nam)
                                m_freem(nam);
                        if (error == EPIPE || error == EINTR ||
@@ -220,6 +241,10 @@ nfssvc(p, uap, retval)
                        }
                        mreq->m_pkthdr.len = siz;
                        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
                        }
                        mreq->m_pkthdr.len = siz;
                        mreq->m_pkthdr.rcvif = (struct ifnet *)0;
+                       if (wascomp && compressreply[procid]) {
+                               m = nfs_compress(m);
+                               siz = m->m_pkthdr.len;
+                       }
                        /*
                         * For non-atomic protocols, prepend a Sun RPC
                         * Record Mark.
                        /*
                         * For non-atomic protocols, prepend a Sun RPC
                         * Record Mark.