summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsserver/nfs_nfsdport.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsserver/nfs_nfsdport.c')
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c121
1 files changed, 69 insertions, 52 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index f30d051..9fdb569 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);
OpenPOWER on IntegriCloud