Author: jhb
Date: Thu Jan  5 18:50:37 2012
New Revision: 229618
URL: http://svn.freebsd.org/changeset/base/229618

Log:
  MFC 228185:
  Enhance the sequential access heuristic used to perform readahead in the
  NFS server and reuse it for writes as well to allow writes to the backing
  store to be clustered.

Modified:
  stable/8/sys/fs/nfsserver/nfs_nfsdport.c
  stable/8/sys/nfsserver/nfs_serv.c
Directory Properties:
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)

Modified: stable/8/sys/fs/nfsserver/nfs_nfsdport.c
==============================================================================
--- stable/8/sys/fs/nfsserver/nfs_nfsdport.c    Thu Jan  5 18:50:12 2012        
(r229617)
+++ stable/8/sys/fs/nfsserver/nfs_nfsdport.c    Thu Jan  5 18:50:37 2012        
(r229618)
@@ -86,20 +86,78 @@ SYSCTL_INT(_vfs_newnfs, OID_AUTO, issue_
 SYSCTL_INT(_vfs_newnfs, OID_AUTO, enable_locallocks, CTLFLAG_RW,
     &nfsrv_dolocallocks, 0, "Enable nfsd to acquire local locks on files");
 
-#define        NUM_HEURISTIC           1017
+#define        MAX_REORDERED_RPC       16
+#define        NUM_HEURISTIC           1031
 #define        NHUSE_INIT              64
 #define        NHUSE_INC               16
 #define        NHUSE_MAX               2048
 
 static struct nfsheur {
        struct vnode *nh_vp;    /* vp to match (unreferenced pointer) */
-       off_t nh_nextr;         /* next offset for sequential detection */
+       off_t nh_nextoff;       /* next offset for sequential detection */
        int nh_use;             /* use count for selection */
        int nh_seqcount;        /* heuristic */
 } nfsheur[NUM_HEURISTIC];
 
 
 /*
+ * Heuristic to detect sequential operation.
+ */
+static struct nfsheur *
+nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp)
+{
+       struct nfsheur *nh;
+       int hi, try;
+
+       /* Locate best candidate. */
+       try = 32;
+       hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
+       nh = &nfsheur[hi];
+       while (try--) {
+               if (nfsheur[hi].nh_vp == vp) {
+                       nh = &nfsheur[hi];
+                       break;
+               }
+               if (nfsheur[hi].nh_use > 0)
+                       --nfsheur[hi].nh_use;
+               hi = (hi + 1) % NUM_HEURISTIC;
+               if (nfsheur[hi].nh_use < nh->nh_use)
+                       nh = &nfsheur[hi];
+       }
+
+       /* Initialize hint if this is a new file. */
+       if (nh->nh_vp != vp) {
+               nh->nh_vp = vp;
+               nh->nh_nextoff = uio->uio_offset;
+               nh->nh_use = NHUSE_INIT;
+               if (uio->uio_offset == 0)
+                       nh->nh_seqcount = 4;
+               else
+                       nh->nh_seqcount = 1;
+       }
+
+       /* Calculate heuristic. */
+       if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
+           uio->uio_offset == nh->nh_nextoff) {
+               /* See comments in vfs_vnops.c:sequential_heuristic(). */
+               nh->nh_seqcount += howmany(uio->uio_resid, 16384);
+               if (nh->nh_seqcount > IO_SEQMAX)
+                       nh->nh_seqcount = IO_SEQMAX;
+       } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
+           imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
+               /* Probably a reordered RPC, leave seqcount alone. */
+       } else if (nh->nh_seqcount > 1) {
+               nh->nh_seqcount /= 2;
+       } else {
+               nh->nh_seqcount = 0;
+       }
+       nh->nh_use += NHUSE_INC;
+       if (nh->nh_use > NHUSE_MAX)
+               nh->nh_use = NHUSE_MAX;
+       return (nh);
+}
+
+/*
  * Get attributes into nfsvattr structure.
  */
 int
@@ -562,60 +620,11 @@ nfsvno_read(struct vnode *vp, off_t off,
        int i;
        struct iovec *iv;
        struct iovec *iv2;
-       int error = 0, len, left, siz, tlen, ioflag = 0, hi, try = 32;
+       int error = 0, len, left, siz, tlen, ioflag = 0;
        struct mbuf *m2 = NULL, *m3;
        struct uio io, *uiop = &io;
        struct nfsheur *nh;
 
-       /*
-        * Calculate seqcount for heuristic
-        */
-       /*
-        * Locate best candidate
-        */
-
-       hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
-       nh = &nfsheur[hi];
-
-       while (try--) {
-               if (nfsheur[hi].nh_vp == vp) {
-                       nh = &nfsheur[hi];
-                       break;
-               }
-               if (nfsheur[hi].nh_use > 0)
-                       --nfsheur[hi].nh_use;
-               hi = (hi + 1) % NUM_HEURISTIC;
-               if (nfsheur[hi].nh_use < nh->nh_use)
-                       nh = &nfsheur[hi];
-       }
-
-       if (nh->nh_vp != vp) {
-               nh->nh_vp = vp;
-               nh->nh_nextr = off;
-               nh->nh_use = NHUSE_INIT;
-               if (off == 0)
-                       nh->nh_seqcount = 4;
-               else
-                       nh->nh_seqcount = 1;
-       }
-
-       /*
-        * Calculate heuristic
-        */
-
-       if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) {
-               if (++nh->nh_seqcount > IO_SEQMAX)
-                       nh->nh_seqcount = IO_SEQMAX;
-       } else if (nh->nh_seqcount > 1) {
-               nh->nh_seqcount = 1;
-       } else {
-               nh->nh_seqcount = 0;
-       }
-       nh->nh_use += NHUSE_INC;
-       if (nh->nh_use > NHUSE_MAX)
-               nh->nh_use = NHUSE_MAX;
-       ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
-
        len = left = NFSM_RNDUP(cnt);
        m3 = NULL;
        /*
@@ -660,6 +669,8 @@ nfsvno_read(struct vnode *vp, off_t off,
        uiop->uio_resid = len;
        uiop->uio_rw = UIO_READ;
        uiop->uio_segflg = UIO_SYSSPACE;
+       nh = nfsrv_sequential_heuristic(uiop, vp);
+       ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
        error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
        FREE((caddr_t)iv2, M_TEMP);
        if (error) {
@@ -667,6 +678,7 @@ nfsvno_read(struct vnode *vp, off_t off,
                *mpp = NULL;
                goto out;
        }
+       nh->nh_nextoff = uiop->uio_offset;
        tlen = len - uiop->uio_resid;
        cnt = cnt < tlen ? cnt : tlen;
        tlen = NFSM_RNDUP(cnt);
@@ -695,6 +707,7 @@ nfsvno_write(struct vnode *vp, off_t off
        struct iovec *iv;
        int ioflags, error;
        struct uio io, *uiop = &io;
+       struct nfsheur *nh;
 
        MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
            M_WAITOK);
@@ -728,7 +741,11 @@ nfsvno_write(struct vnode *vp, off_t off
        uiop->uio_segflg = UIO_SYSSPACE;
        NFSUIOPROC(uiop, p);
        uiop->uio_offset = off;
+       nh = nfsrv_sequential_heuristic(uiop, vp);
+       ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
        error = VOP_WRITE(vp, uiop, ioflags, cred);
+       if (error == 0)
+               nh->nh_nextoff = uiop->uio_offset;
        FREE((caddr_t)iv, M_TEMP);
 
        NFSEXITCODE(error);

Modified: stable/8/sys/nfsserver/nfs_serv.c
==============================================================================
--- stable/8/sys/nfsserver/nfs_serv.c   Thu Jan  5 18:50:12 2012        
(r229617)
+++ stable/8/sys/nfsserver/nfs_serv.c   Thu Jan  5 18:50:37 2012        
(r229618)
@@ -105,14 +105,15 @@ __FBSDID("$FreeBSD$");
 
 #define MAX_COMMIT_COUNT       (1024 * 1024)
 
-#define NUM_HEURISTIC          1017
+#define        MAX_REORDERED_RPC       16
+#define NUM_HEURISTIC          1031
 #define NHUSE_INIT             64
 #define NHUSE_INC              16
 #define NHUSE_MAX              2048
 
 static struct nfsheur {
        struct vnode *nh_vp;    /* vp to match (unreferenced pointer) */
-       off_t nh_nextr;         /* next offset for sequential detection */
+       off_t nh_nextoff;       /* next offset for sequential detection */
        int nh_use;             /* use count for selection */
        int nh_seqcount;        /* heuristic */
 } nfsheur[NUM_HEURISTIC];
@@ -184,6 +185,63 @@ nfsrv_lockedpair_nd(int vfs1, struct nam
 }
 
 /*
+ * Heuristic to detect sequential operation.
+ */
+static struct nfsheur *
+nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp)
+{
+       struct nfsheur *nh;
+       int hi, try;
+
+       /* Locate best candidate. */
+       try = 32;
+       hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
+       nh = &nfsheur[hi];
+       while (try--) {
+               if (nfsheur[hi].nh_vp == vp) {
+                       nh = &nfsheur[hi];
+                       break;
+               }
+               if (nfsheur[hi].nh_use > 0)
+                       --nfsheur[hi].nh_use;
+               hi = (hi + 1) % NUM_HEURISTIC;
+               if (nfsheur[hi].nh_use < nh->nh_use)
+                       nh = &nfsheur[hi];
+       }
+
+       /* Initialize hint if this is a new file. */
+       if (nh->nh_vp != vp) {
+               nh->nh_vp = vp;
+               nh->nh_nextoff = uio->uio_offset;
+               nh->nh_use = NHUSE_INIT;
+               if (uio->uio_offset == 0)
+                       nh->nh_seqcount = 4;
+               else
+                       nh->nh_seqcount = 1;
+       }
+
+       /* Calculate heuristic. */
+       if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
+           uio->uio_offset == nh->nh_nextoff) {
+               /* See comments in vfs_vnops.c:sequential_heuristic(). */
+               nh->nh_seqcount += howmany(uio->uio_resid, 16384);
+               if (nh->nh_seqcount > IO_SEQMAX)
+                       nh->nh_seqcount = IO_SEQMAX;
+       } else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
+           imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
+               /* Probably a reordered RPC, leave seqcount alone. */
+       } else if (nh->nh_seqcount > 1) {
+               nh->nh_seqcount /= 2;
+       } else {
+               nh->nh_seqcount = 0;
+       }
+       nh->nh_use += NHUSE_INC;
+       if (nh->nh_use > NHUSE_MAX)
+               nh->nh_use = NHUSE_MAX;
+       return (nh);
+}
+
+/*
  * nfs v3 access service
  */
 int
@@ -840,7 +898,6 @@ nfsrv_read(struct nfsrv_descript *nfsd, 
        /*
         * Calculate byte count to read
         */
-
        if (off >= vap->va_size)
                cnt = 0;
        else if ((off + reqlen) > vap->va_size)
@@ -848,61 +905,6 @@ nfsrv_read(struct nfsrv_descript *nfsd, 
        else
                cnt = reqlen;
 
-       /*
-        * Calculate seqcount for heuristic
-        */
-
-       {
-               int hi;
-               int try = 32;
-
-               /*
-                * Locate best candidate
-                */
-
-               hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % 
NUM_HEURISTIC;
-               nh = &nfsheur[hi];
-
-               while (try--) {
-                       if (nfsheur[hi].nh_vp == vp) {
-                               nh = &nfsheur[hi];
-                               break;
-                       }
-                       if (nfsheur[hi].nh_use > 0)
-                               --nfsheur[hi].nh_use;
-                       hi = (hi + 1) % NUM_HEURISTIC;
-                       if (nfsheur[hi].nh_use < nh->nh_use)
-                               nh = &nfsheur[hi];
-               }
-
-               if (nh->nh_vp != vp) {
-                       nh->nh_vp = vp;
-                       nh->nh_nextr = off;
-                       nh->nh_use = NHUSE_INIT;
-                       if (off == 0)
-                               nh->nh_seqcount = 4;
-                       else
-                               nh->nh_seqcount = 1;
-               }
-
-               /*
-                * Calculate heuristic
-                */
-
-               if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) {
-                       if (++nh->nh_seqcount > IO_SEQMAX)
-                               nh->nh_seqcount = IO_SEQMAX;
-               } else if (nh->nh_seqcount > 1) {
-                       nh->nh_seqcount = 1;
-               } else {
-                       nh->nh_seqcount = 0;
-               }
-               nh->nh_use += NHUSE_INC;
-               if (nh->nh_use > NHUSE_MAX)
-                       nh->nh_use = NHUSE_MAX;
-               ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
-        }
-
        nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
        if (v3) {
                tl = nfsm_build(u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
@@ -960,9 +962,11 @@ nfsrv_read(struct nfsrv_descript *nfsd, 
                uiop->uio_resid = len;
                uiop->uio_rw = UIO_READ;
                uiop->uio_segflg = UIO_SYSSPACE;
+               nh = nfsrv_sequential_heuristic(uiop, vp);
+               ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
                error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
-               off = uiop->uio_offset;
-               nh->nh_nextr = off;
+               if (error == 0)
+                       nh->nh_nextoff = uiop->uio_offset;
                free((caddr_t)iv2, M_TEMP);
                if (error || (getret = VOP_GETATTR(vp, vap, cred))) {
                        if (!error)
@@ -1027,6 +1031,7 @@ nfsrv_write(struct nfsrv_descript *nfsd,
        int v3 = (nfsd->nd_flag & ND_NFSV3);
        struct mbuf *mb, *mreq;
        struct vnode *vp = NULL;
+       struct nfsheur *nh;
        nfsfh_t nfh;
        fhandle_t *fhp;
        struct uio io, *uiop = &io;
@@ -1167,7 +1172,11 @@ nfsrv_write(struct nfsrv_descript *nfsd,
            uiop->uio_segflg = UIO_SYSSPACE;
            uiop->uio_td = NULL;
            uiop->uio_offset = off;
+           nh = nfsrv_sequential_heuristic(uiop, vp);
+           ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
            error = VOP_WRITE(vp, uiop, ioflags, cred);
+           if (error == 0)
+                   nh->nh_nextoff = uiop->uio_offset;
            /* Unlocked write. */
            nfsrvstats.srvvop_writes++;
            free((caddr_t)iv, M_TEMP);
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to