Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Venkatesh Srinivas authored December 24, 2011
139  sys/vfs/nfs/nfs_serv.c
@@ -103,14 +103,14 @@
103 103
 
104 104
 #define MAX_COMMIT_COUNT	(1024 * 1024)
105 105
 
106  
-#define NUM_HEURISTIC		1017
  106
+#define NUM_HEURISTIC		1031
107 107
 #define NHUSE_INIT		64
108 108
 #define NHUSE_INC		16
109 109
 #define NHUSE_MAX		2048
110 110
 
111 111
 static struct nfsheur {
112 112
     struct vnode *nh_vp;	/* vp to match (unreferenced pointer) */
113  
-    off_t nh_nextr;		/* next offset for sequential detection */
  113
+    off_t nh_nextoff;		/* next offset for sequential detection */
114 114
     int nh_use;			/* use count for selection */
115 115
     int nh_seqcount;		/* heuristic */
116 116
 } nfsheur[NUM_HEURISTIC];
@@ -144,6 +144,64 @@ static void nfsrvw_coalesce (struct nfsrv_descript *,
144 144
 		struct nfsrv_descript *);
145 145
 
146 146
 /*
  147
+ * Heuristic to detect sequential operation.
  148
+ */
  149
+static struct nfsheur *
  150
+nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp, int writeop)
  151
+{
  152
+	struct nfsheur *nh;
  153
+	int hi, try;
  154
+
  155
+	/* Locate best candidate */
  156
+	try = 32;
  157
+	hi = ((int)(vm_offset_t) vp / sizeof(struct vnode)) % NUM_HEURISTIC;
  158
+	nh = &nfsheur[hi];
  159
+
  160
+	while (try--) {
  161
+		if (nfsheur[hi].nh_vp == vp) {
  162
+			nh = &nfsheur[hi];
  163
+			break;
  164
+		}
  165
+		if (nfsheur[hi].nh_use > 0)
  166
+			--nfsheur[hi].nh_use;
  167
+		hi = (hi + 1) % NUM_HEURISTIC;
  168
+		if (nfsheur[hi].nh_use < nh->nh_use)
  169
+			nh = &nfsheur[hi];
  170
+	}
  171
+
  172
+	/* Initialize hint if this is a new file */
  173
+	if (nh->nh_vp != vp) {
  174
+		nh->nh_vp = vp;
  175
+		nh->nh_nextoff = uio->uio_offset;
  176
+		nh->nh_use = NHUSE_INIT;
  177
+		if (uio->uio_offset == 0)
  178
+			nh->nh_seqcount = 4;
  179
+		else
  180
+			nh->nh_seqcount = 1;
  181
+	}
  182
+
  183
+	/*
  184
+	 * Calculate heuristic
  185
+	 *
  186
+	 * See vfs_vnops.c:sequential_heuristic().
  187
+	 */
  188
+	if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
  189
+	    uio->uio_offset == nh->nh_nextoff) {
  190
+		nh->nh_seqcount += howmany(uio->uio_resid, 16384);
  191
+		if (nh->nh_seqcount > IO_SEQMAX)
  192
+			nh->nh_seqcount = IO_SEQMAX;
  193
+	} else if (nh->nh_seqcount > 1) {
  194
+		nh->nh_seqcount = 1;
  195
+	} else {
  196
+		nh->nh_seqcount = 0;
  197
+	}
  198
+	nh->nh_use += NHUSE_INC;
  199
+	if (nh->nh_use > NHUSE_MAX)
  200
+		nh->nh_use = NHUSE_MAX;
  201
+	return (nh);
  202
+}
  203
+
  204
+/*
147 205
  * nfs v3 access service
148 206
  */
149 207
 int
@@ -825,61 +883,6 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
825 883
 	else
826 884
 		cnt = reqlen;
827 885
 
828  
-	/*
829  
-	 * Calculate seqcount for heuristic
830  
-	 */
831  
-
832  
-	{
833  
-		int hi;
834  
-		int try = 32;
835  
-
836  
-		/*
837  
-		 * Locate best candidate
838  
-		 */
839  
-
840  
-		hi = ((int)(vm_offset_t)vp / sizeof(struct vnode)) % NUM_HEURISTIC;
841  
-		nh = &nfsheur[hi];
842  
-
843  
-		while (try--) {
844  
-			if (nfsheur[hi].nh_vp == vp) {
845  
-				nh = &nfsheur[hi];
846  
-				break;
847  
-			}
848  
-			if (nfsheur[hi].nh_use > 0)
849  
-				--nfsheur[hi].nh_use;
850  
-			hi = (hi + 1) % NUM_HEURISTIC;
851  
-			if (nfsheur[hi].nh_use < nh->nh_use)
852  
-				nh = &nfsheur[hi];
853  
-		}
854  
-
855  
-		if (nh->nh_vp != vp) {
856  
-			nh->nh_vp = vp;
857  
-			nh->nh_nextr = off;
858  
-			nh->nh_use = NHUSE_INIT;
859  
-			if (off == 0)
860  
-				nh->nh_seqcount = 4;
861  
-			else
862  
-				nh->nh_seqcount = 1;
863  
-		}
864  
-
865  
-		/*
866  
-		 * Calculate heuristic
867  
-		 */
868  
-
869  
-		if ((off == 0 && nh->nh_seqcount > 0) || off == nh->nh_nextr) {
870  
-			if (++nh->nh_seqcount > IO_SEQMAX)
871  
-				nh->nh_seqcount = IO_SEQMAX;
872  
-		} else if (nh->nh_seqcount > 1) {
873  
-			nh->nh_seqcount = 1;
874  
-		} else {
875  
-			nh->nh_seqcount = 0;
876  
-		}
877  
-		nh->nh_use += NHUSE_INC;
878  
-		if (nh->nh_use > NHUSE_MAX)
879  
-			nh->nh_use = NHUSE_MAX;
880  
-		ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
881  
-        }
882  
-
883 886
 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
884 887
 			      NFSX_POSTOPORFATTR(info.v3) +
885 888
 			      3 * NFSX_UNSIGNED + nfsm_rndup(cnt),
@@ -938,9 +941,13 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
938 941
 		uiop->uio_resid = len;
939 942
 		uiop->uio_rw = UIO_READ;
940 943
 		uiop->uio_segflg = UIO_SYSSPACE;
  944
+		nh = nfsrv_sequential_heuristic(uiop, vp, 0);
  945
+		ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
941 946
 		error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
942  
-		off = uiop->uio_offset;
943  
-		nh->nh_nextr = off;
  947
+		if (error == 0) {
  948
+			off = uiop->uio_offset;
  949
+			nh->nh_nextoff = off;
  950
+		}
944 951
 		kfree((caddr_t)iv2, M_TEMP);
945 952
 		if (error || (getret = VOP_GETATTR(vp, vap))) {
946 953
 			if (!error)
@@ -969,7 +976,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
969 976
 		nfsm_adj(info.mb, len - tlen, tlen - cnt);
970 977
 	if (info.v3) {
971 978
 		*tl++ = txdr_unsigned(cnt);
972  
-		if (len < reqlen)
  979
+		if (cnt < reqlen)
973 980
 			*tl++ = nfs_true;
974 981
 		else
975 982
 			*tl++ = nfs_false;
@@ -1004,6 +1011,7 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1004 1011
 	int stable = NFSV3WRITE_FILESYNC;
1005 1012
 	struct vnode *vp = NULL;
1006 1013
 	struct mount *mp = NULL;
  1014
+	struct nfsheur *nh;
1007 1015
 	nfsfh_t nfh;
1008 1016
 	fhandle_t *fhp;
1009 1017
 	struct uio io, *uiop = &io;
@@ -1142,7 +1150,11 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1142 1150
 	    uiop->uio_segflg = UIO_SYSSPACE;
1143 1151
 	    uiop->uio_td = NULL;
1144 1152
 	    uiop->uio_offset = off;
  1153
+	    nh = nfsrv_sequential_heuristic(uiop, vp, 1);
  1154
+	    ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
1145 1155
 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
  1156
+	    if (error == 0)
  1157
+		nh->nh_nextoff = uiop->uio_offset;
1146 1158
 	    nfsstats.srvvop_writes++;
1147 1159
 	    kfree((caddr_t)iv, M_TEMP);
1148 1160
 	}
@@ -3550,7 +3562,12 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3550 3562
 	}
3551 3563
 	for_ret = VOP_GETATTR(vp, &bfor);
3552 3564
 
3553  
-	if (cnt > MAX_COMMIT_COUNT) {
  3565
+	/*
  3566
+	 * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of
  3567
+	 * file is done. At this time VOP_FSYNC does not accept offset and
  3568
+	 * byte count parameters, so call VOP_FSYNC the whole file for now.
  3569
+	 */
  3570
+	if (cnt == 0 || cnt > MAX_COMMIT_COUNT) {
3554 3571
 		/*
3555 3572
 		 * Give up and do the whole thing
3556 3573
 		 */
16  sys/vfs/nfs/nfs_srvcache.c
@@ -58,7 +58,7 @@
58 58
 
59 59
 #ifndef NFS_NOSERVER 
60 60
 static long numnfsrvcache;
61  
-static long desirednfsrvcache = NFSRVCACHESIZ;
  61
+static long desirednfsrvcache;
62 62
 
63 63
 #define	NFSRCHASH(xid) \
64 64
 	(&nfsrvhashtbl[((xid) + ((xid) >> 24)) & nfsrvhash])
@@ -129,11 +129,25 @@ static int nfsv2_repstat[NFS_NPROCS] = {
129 129
 };
130 130
 
131 131
 /*
  132
+ * Size the NFS server's duplicate request cache at 1/2 the nmbclusters,
  133
+ * within a (64, 2048) range. This is to prevent all mbuf clusters being
  134
+ * tied up in the NFS dupreq cache for small values of nmbclusters.
  135
+ */
  136
+static void
  137
+nfsrvcache_size_change(void)
  138
+{
  139
+	desirednfsrvcache = nmbclusters / 2;
  140
+	desirednfsrvcache = MIN(desirednfsrvcache, NFSRVCACHE_MAX_SIZE);
  141
+	desirednfsrvcache = MAX(desirednfsrvcache, NFSRVCACHE_MIN_SIZE);
  142
+}
  143
+
  144
+/*
132 145
  * Initialize the server request cache list
133 146
  */
134 147
 void
135 148
 nfsrv_initcache(void)
136 149
 {
  150
+	nfsrvcache_size_change();
137 151
 	nfsrvhashtbl = hashinit(desirednfsrvcache, M_NFSD, &nfsrvhash);
138 152
 	TAILQ_INIT(&nfsrvlruhead);
139 153
 }
3  sys/vfs/nfs/nfsrvcache.h
@@ -48,7 +48,8 @@
48 48
  * Definitions for the server recent request cache
49 49
  */
50 50
 
51  
-#define	NFSRVCACHESIZ	64
  51
+#define NFSRVCACHE_MAX_SIZE	(2048)
  52
+#define NFSRVCACHE_MIN_SIZE	(64)
52 53
 
53 54
 struct nfsrvcache {
54 55
 	TAILQ_ENTRY(nfsrvcache) rc_lru;		/* LRU chain */

0 notes on commit a084b5c

Please sign in to comment.
Something went wrong with that request. Please try again.