From 4b88dc318984a49382233c54001805fefb6c0487 Mon Sep 17 00:00:00 2001 From: jhb Date: Thu, 5 Jan 2012 18:50:12 +0000 Subject: [PATCH 61/65] 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. git-svn-id: http://svn.freebsd.org/base/stable/9@229617 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f (cherry picked from commit f55a6bbf3c9d5b259a569725e37f2f71322c6891) Signed-off-by: Xin Li --- sys/fs/nfsserver/nfs_nfsdport.c | 121 +++++++++++++++++++++---------------- sys/nfsserver/nfs_serv.c | 129 +++++++++++++++++++++------------------ 2 files changed, 138 insertions(+), 112 deletions(-) diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c index 442bc54..a9a10f4 100644 --- a/sys/fs/nfsserver/nfs_nfsdport.c +++ b/sys/fs/nfsserver/nfs_nfsdport.c @@ -90,20 +90,78 @@ SYSCTL_INT(_vfs_nfsd, OID_AUTO, issue_delegations, CTLFLAG_RW, SYSCTL_INT(_vfs_nfsd, 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 @@ -567,60 +625,11 @@ nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, 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; /* @@ -665,6 +674,8 @@ nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, 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) { @@ -672,6 +683,7 @@ nfsvno_read(struct vnode *vp, off_t off, int cnt, struct ucred *cred, *mpp = NULL; goto out; } + nh->nh_nextoff = uiop->uio_offset; tlen = len - uiop->uio_resid; cnt = cnt < tlen ? cnt : tlen; tlen = NFSM_RNDUP(cnt); @@ -700,6 +712,7 @@ nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int stable, 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); @@ -733,7 +746,11 @@ nfsvno_write(struct vnode *vp, off_t off, int retlen, int cnt, int stable, 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); diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index fd3a1b5..3ee804d 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -107,14 +107,15 @@ FEATURE(nfsserver, "NFS server"); #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]; @@ -187,6 +188,63 @@ nfsrv_lockedpair_nd(int vfs1, struct nameidata *nd) } /* + * 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 @@ -843,7 +901,6 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, /* * Calculate byte count to read */ - if (off >= vap->va_size) cnt = 0; else if ((off + reqlen) > vap->va_size) @@ -851,61 +908,6 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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); @@ -963,9 +965,11 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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) @@ -1030,6 +1034,7 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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; @@ -1170,7 +1175,11 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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); -- 1.7.8.3