summaryrefslogtreecommitdiffstats
path: root/sys/nfs/nfs_serv.c
diff options
context:
space:
mode:
authordillon <dillon@FreeBSD.org>1999-12-13 17:34:45 +0000
committerdillon <dillon@FreeBSD.org>1999-12-13 17:34:45 +0000
commitbab004e7294b9a4e8172382b0cb3c56e712c7dee (patch)
treee58f124699f778dea87aafa11777502c37675990 /sys/nfs/nfs_serv.c
parent0a7cf7b8591f3e931974448e2634431df25c3c30 (diff)
downloadFreeBSD-src-bab004e7294b9a4e8172382b0cb3c56e712c7dee.zip
FreeBSD-src-bab004e7294b9a4e8172382b0cb3c56e712c7dee.tar.gz
Add a readahead heuristic to the NFS server side code. While the server
cannot unilaterally pass data to a client it can reduce the physical disk transaction overhead by reading larger blocks. This results in better pipelining of requests/responses over the network and an almost 100% increase in cpu efficiency on the server. On a 100BaseTX network NFS read performance increases from 8.5 MBytes/sec to 10 MB/sec (maxed out), and cpu efficiency increases from 72% idle to 80% idle on the server. Reviewed by: Alfred Perlstein <bright@wintelcom.net>
Diffstat (limited to 'sys/nfs/nfs_serv.c')
-rw-r--r--sys/nfs/nfs_serv.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/sys/nfs/nfs_serv.c b/sys/nfs/nfs_serv.c
index e0aa5ab..ffaeea7 100644
--- a/sys/nfs/nfs_serv.c
+++ b/sys/nfs/nfs_serv.c
@@ -115,6 +115,18 @@
#define MAX_COMMIT_COUNT (1024 * 1024)
+#define NUM_HEURISTIC 64
+#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 */
+ int nh_use; /* use count for selection */
+ int nh_seqcount; /* heuristic */
+} nfsheur[NUM_HEURISTIC];
+
nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
NFFIFO, NFNON };
#ifndef NFS_NOSERVER
@@ -780,7 +792,9 @@ nfsrv_read(nfsd, slp, procp, mrq)
fhandle_t *fhp;
struct uio io, *uiop = &io;
struct vattr va, *vap = &va;
+ struct nfsheur *nh;
off_t off;
+ int ioflag = 0;
u_quad_t frev;
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
@@ -833,12 +847,73 @@ nfsrv_read(nfsd, slp, procp, mrq)
error = 0;
goto nfsmout;
}
+
+ /*
+ * Calculate byte count to read
+ */
+
if (off >= vap->va_size)
cnt = 0;
else if ((off + reqlen) > vap->va_size)
cnt = vap->va_size - off;
else
cnt = reqlen;
+
+ /*
+ * Calculate seqcount for heuristic
+ */
+
+ {
+ int hi;
+ int try = 4;
+
+ /*
+ * Locate best candidate
+ */
+
+ hi = ((int)vp / sizeof(struct vnode)) & (NUM_HEURISTIC - 1);
+ 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 - 1);
+ 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 > 127)
+ nh->nh_seqcount = 127;
+ } 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 << 16;
+ }
+
nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
if (v3) {
nfsm_build(tl, u_int32_t *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
@@ -896,8 +971,9 @@ nfsrv_read(nfsd, slp, procp, mrq)
uiop->uio_resid = len;
uiop->uio_rw = UIO_READ;
uiop->uio_segflg = UIO_SYSSPACE;
- error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
+ error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
off = uiop->uio_offset;
+ nh->nh_nextr = off;
FREE((caddr_t)iv2, M_TEMP);
if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
if (!error)
OpenPOWER on IntegriCloud