Patchwork [U-Boot] net: nfs: Fixing error when mounting with time outs

login
register
mail settings
Submitter Matthias Brugger
Date Dec. 6, 2012, 10:11 a.m.
Message ID <1354788710-15238-1-git-send-email-matthias.bgg@gmail.com>
Download mbox | patch
Permalink /patch/204211/
State Superseded
Delegated to: Joe Hershberger
Headers show

Comments

Matthias Brugger - Dec. 6, 2012, 10:11 a.m.
When reading more then one file via nfs and in the mount/unmountall process
occurs a time out the boot process will be aborted, although eventually the
respons from the NFS server arrives.

This patch does not increment the rpc_id for the communication with the server
when we resend a command timed out previously.
Apart if we receive responses from the server with an old RPC ID (smaller then
in the u-boot state machine) we don't interpret that as an error but just drop
the message and wait for the response corresponding to the last message sent.

Signed-off-by: Matthias Brugger <matthias.bgg@gmail.com>
---
 net/nfs.c |  107 ++++++++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 70 insertions(+), 37 deletions(-)

Patch

diff --git a/net/nfs.c b/net/nfs.c
index 7f2393f..756d4d3 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -37,8 +37,11 @@ 
 # define NFS_TIMEOUT CONFIG_NFS_TIMEOUT
 #endif
 
+#define NFS_RPC_ERR	1
+#define NFS_RPC_DROP	124
+
 static int fs_mounted;
-static unsigned long rpc_id;
+static unsigned long rpc_id = 1;
 static int nfs_offset = -1;
 static int nfs_len;
 
@@ -179,7 +182,7 @@  rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
 	int pktlen;
 	int sport;
 
-	id = ++rpc_id;
+	id = rpc_id;
 	pkt.u.call.id = htonl(id);
 	pkt.u.call.type = htonl(MSG_CALL);
 	pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
@@ -357,10 +360,13 @@  RPC request dispatcher
 **************************************************************************/
 
 static void
-NfsSend(void)
+NfsSend(uint8_t resend)
 {
 	debug("%s\n", __func__);
 
+	if (resend == 0)
+		rpc_id++;
+
 	switch (NfsState) {
 	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
 		rpc_lookup_req(PROG_MOUNT, 1);
@@ -399,8 +405,10 @@  rpc_lookup_reply(int prog, uchar *pkt, unsigned len)
 
 	debug("%s\n", __func__);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -428,8 +436,10 @@  nfs_mount_reply(uchar *pkt, unsigned len)
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -452,13 +462,15 @@  nfs_umountall_reply(uchar *pkt, unsigned len)
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
 	    rpc_pkt.u.reply.astatus)
-		return -1;
+		return -NFS_RPC_ERR;
 
 	fs_mounted = 0;
 	memset(dirfh, 0, sizeof(dirfh));
@@ -475,14 +487,16 @@  nfs_lookup_reply(uchar *pkt, unsigned len)
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
 	    rpc_pkt.u.reply.astatus  ||
 	    rpc_pkt.u.reply.data[0])
-		return -1;
+		return -NFS_RPC_ERR;
 
 	memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
 
@@ -499,14 +513,16 @@  nfs_readlink_reply(uchar *pkt, unsigned len)
 
 	memcpy((unsigned char *)&rpc_pkt, pkt, len);
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
 	    rpc_pkt.u.reply.astatus  ||
 	    rpc_pkt.u.reply.data[0])
-		return -1;
+		return -NFS_RPC_ERR;
 
 	rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
 
@@ -534,8 +550,10 @@  nfs_read_reply(uchar *pkt, unsigned len)
 
 	memcpy((uchar *)&rpc_pkt, pkt, sizeof(rpc_pkt.u.reply));
 
-	if (ntohl(rpc_pkt.u.reply.id) != rpc_id)
-		return -1;
+	if (ntohl(rpc_pkt.u.reply.id) > rpc_id)
+		return -NFS_RPC_ERR;
+	else if (ntohl(rpc_pkt.u.reply.id) < rpc_id)
+		return -NFS_RPC_DROP;
 
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
@@ -575,7 +593,7 @@  NfsTimeout(void)
 	} else {
 		puts("T ");
 		NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
-		NfsSend();
+		NfsSend(1);
 	}
 }
 
@@ -583,6 +601,7 @@  static void
 NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 {
 	int rlen;
+	int reply;
 
 	debug("%s\n", __func__);
 
@@ -591,31 +610,39 @@  NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 
 	switch (NfsState) {
 	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
-		rpc_lookup_reply(PROG_MOUNT, pkt, len);
+		if (rpc_lookup_reply(PROG_MOUNT, pkt, len) == -NFS_RPC_DROP)
+			break;
 		NfsState = STATE_PRCLOOKUP_PROG_NFS_REQ;
-		NfsSend();
+		NfsSend(0);
 		break;
 
 	case STATE_PRCLOOKUP_PROG_NFS_REQ:
-		rpc_lookup_reply(PROG_NFS, pkt, len);
+		if (rpc_lookup_reply(PROG_NFS, pkt, len) == -NFS_RPC_DROP)
+			break;
 		NfsState = STATE_MOUNT_REQ;
-		NfsSend();
+		NfsSend(0);
 		break;
 
 	case STATE_MOUNT_REQ:
-		if (nfs_mount_reply(pkt, len)) {
+		reply = nfs_mount_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: Cannot mount\n");
 			/* just to be sure... */
 			NfsState = STATE_UMOUNT_REQ;
-			NfsSend();
+			NfsSend(0);
 		} else {
 			NfsState = STATE_LOOKUP_REQ;
-			NfsSend();
+			NfsSend(0);
 		}
 		break;
 
 	case STATE_UMOUNT_REQ:
-		if (nfs_umountall_reply(pkt, len)) {
+		reply = nfs_umountall_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: Cannot umount\n");
 			net_set_state(NETLOOP_FAIL);
 		} else {
@@ -625,30 +652,36 @@  NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 		break;
 
 	case STATE_LOOKUP_REQ:
-		if (nfs_lookup_reply(pkt, len)) {
+		reply = nfs_lookup_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: File lookup fail\n");
 			NfsState = STATE_UMOUNT_REQ;
-			NfsSend();
+			NfsSend(0);
 		} else {
 			NfsState = STATE_READ_REQ;
 			nfs_offset = 0;
 			nfs_len = NFS_READ_SIZE;
-			NfsSend();
+			NfsSend(0);
 		}
 		break;
 
 	case STATE_READLINK_REQ:
-		if (nfs_readlink_reply(pkt, len)) {
+		reply = nfs_readlink_reply(pkt, len);
+		if (reply == -NFS_RPC_DROP)
+			break;
+		else if (reply == -NFS_RPC_ERR) {
 			puts("*** ERROR: Symlink fail\n");
 			NfsState = STATE_UMOUNT_REQ;
-			NfsSend();
+			NfsSend(0);
 		} else {
 			debug("Symlink --> %s\n", nfs_path);
 			nfs_filename = basename(nfs_path);
 			nfs_path     = dirname(nfs_path);
 
 			NfsState = STATE_MOUNT_REQ;
-			NfsSend();
+			NfsSend(0);
 		}
 		break;
 
@@ -657,16 +690,16 @@  NfsHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, unsigned len)
 		NetSetTimeout(NFS_TIMEOUT, NfsTimeout);
 		if (rlen > 0) {
 			nfs_offset += rlen;
-			NfsSend();
+			NfsSend(0);
 		} else if ((rlen == -NFSERR_ISDIR) || (rlen == -NFSERR_INVAL)) {
 			/* symbolic link */
 			NfsState = STATE_READLINK_REQ;
-			NfsSend();
+			NfsSend(0);
 		} else {
 			if (!rlen)
 				nfs_download_state = NETLOOP_SUCCESS;
 			NfsState = STATE_UMOUNT_REQ;
-			NfsSend();
+			NfsSend(0);
 		}
 		break;
 	}
@@ -751,5 +784,5 @@  NfsStart(void)
 	/* zero out server ether in case the server ip has changed */
 	memset(NetServerEther, 0, 6);
 
-	NfsSend();
+	NfsSend(0);
 }