Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

NFS server: Import various fixes from FreeBSD.

* Rev 228520: Honor NFSv3 commit call when count = 0. (delphij)

* Rev 228185: Enhance sequential access heuristic used for readahead
              and reuse it for writes as well.
        * Use a prime number for sequential detection table
        * Factor our sequential detection code
        * Ramp up sequential heurstic quickly based on IO size.

        This patch differs from the FreeBSD version in that we rapidly
        decay the sequential heuristic as in the original code and don't
        attempt to deal with reordered RPCs.

* Rev 159871: Size the NFS server dupreq cache on the basis of nmbclusters.
	This patch differs from the FreeBSD version in that we don't
	alter the desired cache size based on nmbcluster change events.

* Rev 116789: Bug in nfsrv_read() that caused the replies to certain NFSv3
short read operations at the end of a file to not have the "eof"
flag set. (iedowse)
  • Loading branch information...
commit a084b5c3be79264af0d0802982069fbab7309989 1 parent 3532d24
@vsrinivas vsrinivas authored
View
139 sys/vfs/nfs/nfs_serv.c
@@ -103,14 +103,14 @@
#define MAX_COMMIT_COUNT (1024 * 1024)
-#define NUM_HEURISTIC 1017
+#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];
@@ -144,6 +144,64 @@ static void nfsrvw_coalesce (struct nfsrv_descript *,
struct nfsrv_descript *);
/*
+ * Heuristic to detect sequential operation.
+ */
+static struct nfsheur *
+nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp, int writeop)
+{
+ 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
+ *
+ * See vfs_vnops.c:sequential_heuristic().
+ */
+ if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
+ uio->uio_offset == nh->nh_nextoff) {
+ nh->nh_seqcount += howmany(uio->uio_resid, 16384);
+ 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;
+ return (nh);
+}
+
+/*
* nfs v3 access service
*/
int
@@ -825,61 +883,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;
- }
-
NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
NFSX_POSTOPORFATTR(info.v3) +
3 * NFSX_UNSIGNED + nfsm_rndup(cnt),
@@ -938,9 +941,13 @@ 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, 0);
+ 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) {
+ off = uiop->uio_offset;
+ nh->nh_nextoff = off;
+ }
kfree((caddr_t)iv2, M_TEMP);
if (error || (getret = VOP_GETATTR(vp, vap))) {
if (!error)
@@ -969,7 +976,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
nfsm_adj(info.mb, len - tlen, tlen - cnt);
if (info.v3) {
*tl++ = txdr_unsigned(cnt);
- if (len < reqlen)
+ if (cnt < reqlen)
*tl++ = nfs_true;
else
*tl++ = nfs_false;
@@ -1004,6 +1011,7 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
int stable = NFSV3WRITE_FILESYNC;
struct vnode *vp = NULL;
struct mount *mp = NULL;
+ struct nfsheur *nh;
nfsfh_t nfh;
fhandle_t *fhp;
struct uio io, *uiop = &io;
@@ -1142,7 +1150,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, 1);
+ ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
error = VOP_WRITE(vp, uiop, ioflags, cred);
+ if (error == 0)
+ nh->nh_nextoff = uiop->uio_offset;
nfsstats.srvvop_writes++;
kfree((caddr_t)iv, M_TEMP);
}
@@ -3550,7 +3562,12 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
}
for_ret = VOP_GETATTR(vp, &bfor);
- if (cnt > MAX_COMMIT_COUNT) {
+ /*
+ * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of
+ * file is done. At this time VOP_FSYNC does not accept offset and
+ * byte count parameters, so call VOP_FSYNC the whole file for now.
+ */
+ if (cnt == 0 || cnt > MAX_COMMIT_COUNT) {
/*
* Give up and do the whole thing
*/
View
16 sys/vfs/nfs/nfs_srvcache.c
@@ -58,7 +58,7 @@
#ifndef NFS_NOSERVER
static long numnfsrvcache;
-static long desirednfsrvcache = NFSRVCACHESIZ;
+static long desirednfsrvcache;
#define NFSRCHASH(xid) \
(&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
@@ -129,11 +129,25 @@ static int nfsv2_repstat[NFS_NPROCS] = {
};
/*
+ * Size the NFS server's duplicate request cache at 1/2 the nmbclusters,
+ * within a (64, 2048) range. This is to prevent all mbuf clusters being
+ * tied up in the NFS dupreq cache for small values of nmbclusters.
+ */
+static void
+nfsrvcache_size_change(void)
+{
+ desirednfsrvcache = nmbclusters / 2;
+ desirednfsrvcache = MIN(desirednfsrvcache, NFSRVCACHE_MAX_SIZE);
+ desirednfsrvcache = MAX(desirednfsrvcache, NFSRVCACHE_MIN_SIZE);
+}
+
+/*
* Initialize the server request cache list
*/
void
nfsrv_initcache(void)
{
+ nfsrvcache_size_change();
nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash);
TAILQ_INIT(&nfsrvlruhead);
}
View
3  sys/vfs/nfs/nfsrvcache.h
@@ -48,7 +48,8 @@
* Definitions for the server recent request cache
*/
-#define NFSRVCACHESIZ 64
+#define NFSRVCACHE_MAX_SIZE (2048)
+#define NFSRVCACHE_MIN_SIZE (64)
struct nfsrvcache {
TAILQ_ENTRY(nfsrvcache) rc_lru; /* LRU chain */
Please sign in to comment.
Something went wrong with that request. Please try again.