All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot]  [PATCH] net: NFS: Add NFSv3 support
@ 2016-06-20 19:27 Guillaume GARDET
  2016-06-20 19:31 ` Guillaume Gardet
  2016-06-23  9:10 ` [U-Boot] [PATCH V2] " Guillaume GARDET
  0 siblings, 2 replies; 13+ messages in thread
From: Guillaume GARDET @ 2016-06-20 19:27 UTC (permalink / raw)
  To: u-boot

This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.

Tested on iMX6 sabrelite with 4 Linux NFS servers:
  * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
  * NFSv2 + NFSv3 server: use NFSv3 protocol
  * NFSv3 + NFSv4 server: use NFSv3 protocol
  * NFSv3 server: use NFSv3 protocol

Signed-off-by: Guillaume GARDET <guillaume.gardet@free.fr>
Cc: Tom Rini <trini@konsulko.com>
Cc: joe.hershberger at ni.com

---
 net/nfs.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 net/nfs.h |  15 +++-
 2 files changed, 246 insertions(+), 50 deletions(-)

diff --git a/net/nfs.c b/net/nfs.c
index 0ed47c9..1e920c1 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -22,6 +22,10 @@
  * possible, maximum 16 steps). There is no clearing of ".."'s inside the
  * path, so please DON'T DO THAT. thx. */
 
+/* NOTE 4: NFSv3 support added by Guillaume GARDET.
+ * NFSv2 is still used by default. But if server does not support NFSv2, then
+ * NFSv3 is used, if available on NFS server. */
+
 #include <common.h>
 #include <command.h>
 #include <net.h>
@@ -47,8 +51,11 @@ static int nfs_offset = -1;
 static int nfs_len;
 static ulong nfs_timeout = NFS_TIMEOUT;
 
-static char dirfh[NFS_FHSIZE];	/* file handle of directory */
-static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
+static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
+static char filefh[NFS_FHSIZE]; /* NFSv2 file handle */
+
+static char filefh3[NFS3_FHSIZE];	/* NFSv3 file handle  */
+static int filefh3_length;	/* (variable) length of filefh3 */
 
 static enum net_loop_state nfs_download_state;
 static struct in_addr nfs_server_ip;
@@ -70,6 +77,10 @@ static char *nfs_filename;
 static char *nfs_path;
 static char nfs_path_buff[2048];
 
+#define NFSV2_FLAG 1
+#define NFSV3_FLAG 1 << 1
+static char supported_nfs_versions = NFSV2_FLAG | NFSV3_FLAG;
+
 static inline int store_block(uchar *src, unsigned offset, unsigned len)
 {
 	ulong newsize = offset + len;
@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
 	pkt.u.call.type = htonl(MSG_CALL);
 	pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
 	pkt.u.call.prog = htonl(rpc_prog);
-	pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	switch (rpc_prog) {
+	case PROG_NFS:
+		if (supported_nfs_versions & NFSV2_FLAG)
+			pkt.u.call.vers = htonl(2);	/* NFS v2 */
+		else /* NFSV3_FLAG */
+			pkt.u.call.vers = htonl(3);	/* NFS v3 */
+		break;
+	case PROG_PORTMAP:
+	case PROG_MOUNT:
+	default:
+		pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	}
 	pkt.u.call.proc = htonl(rpc_proc);
 	p = (uint32_t *)&(pkt.u.call.data);
 
@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver)
 	data[5] = htonl(ver);
 	data[6] = htonl(17);	/* IP_UDP */
 	data[7] = 0;
-
 	rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
 }
 
@@ -291,8 +312,14 @@ static void nfs_readlink_req(void)
 	p = &(data[0]);
 	p = (uint32_t *)rpc_add_credentials((long *)p);
 
-	memcpy(p, filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, filefh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+	} else { /* NFSV3_FLAG */
+		*p++ = htonl(filefh3_length);
+		memcpy(p, filefh3, filefh3_length);
+		p += (filefh3_length / 4);
+	}
 
 	len = (uint32_t *)p - (uint32_t *)&(data[0]);
 
@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname)
 	p = &(data[0]);
 	p = (uint32_t *)rpc_add_credentials((long *)p);
 
-	memcpy(p, dirfh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(fnamelen);
-	if (fnamelen & 3)
-		*(p + fnamelen / 4) = 0;
-	memcpy(p, fname, fnamelen);
-	p += (fnamelen + 3) / 4;
-
-	len = (uint32_t *)p - (uint32_t *)&(data[0]);
-
-	rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, dirfh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(fnamelen);
+		if (fnamelen & 3)
+			*(p + fnamelen / 4) = 0;
+		memcpy(p, fname, fnamelen);
+		p += (fnamelen + 3) / 4;
+
+		len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+	} else {  /* NFSV3_FLAG */
+		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
+		memcpy(p, dirfh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(fnamelen);
+		if (fnamelen & 3)
+			*(p + fnamelen / 4) = 0;
+		memcpy(p, fname, fnamelen);
+		p += (fnamelen + 3) / 4;
+
+		len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+		rpc_req(PROG_NFS, NFS3PROC_LOOKUP, data, len);
+	}
 }
 
 /**************************************************************************
@@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen)
 	p = &(data[0]);
 	p = (uint32_t *)rpc_add_credentials((long *)p);
 
-	memcpy(p, filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(offset);
-	*p++ = htonl(readlen);
-	*p++ = 0;
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, filefh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(offset);
+		*p++ = htonl(readlen);
+		*p++ = 0;
+	} else { /* NFSV3_FLAG */
+		*p++ = htonl(filefh3_length);
+		memcpy(p, filefh3, filefh3_length);
+		p += (filefh3_length / 4);
+		*p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */
+		*p++ = htonl(offset);
+		*p++ = htonl(readlen);
+		*p++ = 0;
+	}
 
 	len = (uint32_t *)p - (uint32_t *)&(data[0]);
 
@@ -359,10 +411,16 @@ static void nfs_send(void)
 
 	switch (nfs_state) {
 	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
-		rpc_lookup_req(PROG_MOUNT, 1);
+		if (supported_nfs_versions & NFSV2_FLAG)
+			rpc_lookup_req(PROG_MOUNT, 1);
+		else  /* NFSV3_FLAG */
+			rpc_lookup_req(PROG_MOUNT, 3);
 		break;
 	case STATE_PRCLOOKUP_PROG_NFS_REQ:
-		rpc_lookup_req(PROG_NFS, 2);
+		if (supported_nfs_versions & NFSV2_FLAG)
+			rpc_lookup_req(PROG_NFS, 2);
+		else  /* NFSV3_FLAG */
+			rpc_lookup_req(PROG_NFS, 3);
 		break;
 	case STATE_MOUNT_REQ:
 		nfs_mount_req(nfs_path);
@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)
 		return -1;
 
 	fs_mounted = 1;
+	/*  NFSv2 and NFSv3 use same structure */
 	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
 
 	return 0;
@@ -481,24 +540,51 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
 	if (rpc_pkt.u.reply.rstatus  ||
 	    rpc_pkt.u.reply.verifier ||
 	    rpc_pkt.u.reply.astatus  ||
-	    rpc_pkt.u.reply.data[0]){
-		switch(ntohl(rpc_pkt.u.reply.astatus)){
-		case 0: /* Not an error */
+	    rpc_pkt.u.reply.data[0]) {
+		switch (ntohl(rpc_pkt.u.reply.astatus)) {
+		case NFS_RPC_SUCCESS: /* Not an error */
 			break;
-		case 2: /* Remote can't support NFS version */
-			printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n", 
-				2, 
-				ntohl(rpc_pkt.u.reply.data[0]), 
-				ntohl(rpc_pkt.u.reply.data[1]));
+		case NFS_RPC_PROG_MISMATCH:
+			/* Remote can't support requested NFS version */
+			switch (ntohl(rpc_pkt.u.reply.data[0])) {
+			/* Minimal supported NFS version */
+			case 3:
+				debug("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
+				      (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
+				      ntohl(rpc_pkt.u.reply.data[0]),
+				      ntohl(rpc_pkt.u.reply.data[1]));
+				debug("Will retry with NFSv3\n");
+				/* Clear NFSV2_FLAG from supported versions */
+				supported_nfs_versions = supported_nfs_versions & ~NFSV2_FLAG;
+				return -NFS_RPC_PROG_MISMATCH;
+			case 4:
+			default:
+				printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
+				       (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
+				       ntohl(rpc_pkt.u.reply.data[0]),
+				       ntohl(rpc_pkt.u.reply.data[1]));
+			}
 			break;
+		case NFS_RPC_PROG_UNAVAIL:
+		case NFS_RPC_PROC_UNAVAIL:
+		case NFS_RPC_GARBAGE_ARGS:
+		case NFS_RPC_SYSTEM_ERR:
 		default: /* Unknown error on 'accept state' flag */
-			printf("*** ERROR: accept state error (%d)\n", ntohl(rpc_pkt.u.reply.astatus));
+			printf("*** ERROR: accept state error (%d)\n",
+			       ntohl(rpc_pkt.u.reply.astatus));
 			break;
 		}
 		return -1;
 	}
 
-	memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	} else {  /* NFSV3_FLAG */
+		filefh3_length = ntohl(rpc_pkt.u.reply.data[1]);
+		if (filefh3_length > NFS3_FHSIZE)
+			filefh3_length  = NFS3_FHSIZE;
+		memcpy(filefh3, rpc_pkt.u.reply.data + 2, filefh3_length);
+	}
 
 	return 0;
 }
@@ -523,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len)
 	    rpc_pkt.u.reply.data[0])
 		return -1;
 
-	rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+	if (supported_nfs_versions & NFSV2_FLAG) {
 
-	if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
-		int pathlen;
-		strcat(nfs_path, "/");
-		pathlen = strlen(nfs_path);
-		memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]),
-		       rlen);
-		nfs_path[pathlen + rlen] = 0;
-	} else {
-		memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
-		nfs_path[rlen] = 0;
+		rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+
+		if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
+			int pathlen;
+			strcat(nfs_path, "/");
+			pathlen = strlen(nfs_path);
+			memcpy(nfs_path + pathlen,
+			       (uchar *)&(rpc_pkt.u.reply.data[2]),
+			       rlen);
+			nfs_path[pathlen + rlen] = 0;
+		} else {
+			memcpy(nfs_path,
+			       (uchar *)&(rpc_pkt.u.reply.data[2]),
+			       rlen);
+			nfs_path[rlen] = 0;
+		}
+	} else {  /* NFSV3_FLAG */
+		int nfsv3_data_offset = 0;
+		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
+			/* 'attributes_follow' flag is TRUE,
+			 * so we have attributes on 21 bytes */
+			/* Skip unused values :
+				type;	32 bits value,
+				mode;	32 bits value,
+				nlink;	32 bits value,
+				uid;	32 bits value,
+				gid;	32 bits value,
+				size;	64 bits value,
+				used;	64 bits value,
+				rdev;	64 bits value,
+				fsid;	64 bits value,
+				fileid;	64 bits value,
+				atime;	64 bits value,
+				mtime;	64 bits value,
+				ctime;	64 bits value,
+			*/
+			nfsv3_data_offset = 22;
+		} else {
+			/* 'attributes_follow' flag is FALSE,
+			 * so we don't have any attributes */
+			nfsv3_data_offset = 1;
+		}
+
+		/* new path length */
+		rlen = ntohl(rpc_pkt.u.reply.data[1+nfsv3_data_offset]);
+
+		if (*((char *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset])) != '/') {
+			int pathlen;
+			strcat(nfs_path, "/");
+			pathlen = strlen(nfs_path);
+			memcpy(nfs_path + pathlen,
+			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
+			       rlen);
+			nfs_path[pathlen + rlen] = 0;
+		} else {
+			memcpy(nfs_path,
+			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
+			       rlen);
+			nfs_path[rlen] = 0;
+		}
 	}
 	return 0;
 }
@@ -543,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
 {
 	struct rpc_t rpc_pkt;
 	int rlen;
+	uchar *data_ptr;
 
 	debug("%s\n", __func__);
 
@@ -570,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
 	if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
 		putc('#');
 
-	rlen = ntohl(rpc_pkt.u.reply.data[18]);
-	if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply),
-			nfs_offset, rlen))
-		return -9999;
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		rlen = ntohl(rpc_pkt.u.reply.data[18]);
+		data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
+	} else {  /* NFSV3_FLAG */
+		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
+			/* 'attributes_follow' is TRUE,
+			 * so we have attributes on 21 bytes */
+			/* Skip unused values :
+				type;	32 bits value,
+				mode;	32 bits value,
+				nlink;	32 bits value,
+				uid;	32 bits value,
+				gid;	32 bits value,
+				size;	64 bits value,
+				used;	64 bits value,
+				rdev;	64 bits value,
+				fsid;	64 bits value,
+				fileid;	64 bits value,
+				atime;	64 bits value,
+				mtime;	64 bits value,
+				ctime;	64 bits value,
+			*/
+			rlen = ntohl(rpc_pkt.u.reply.data[23]); /* count value */
+			/* Skip unused values :
+				EOF:		32 bits value,
+				data_size:	32 bits value,
+			*/
+			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26]);
+		} else {
+			/* attributes_follow is FALSE, so we don't have any attributes */
+			rlen = ntohl(rpc_pkt.u.reply.data[2]); /* count value */
+			/* Skip unused values :
+				EOF:		32 bits value,
+				data_size:	32 bits value,
+			*/
+			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5]);
+		}
+	}
+
+	if (store_block(data_ptr, nfs_offset, rlen))
+			return -9999;
 
 	return rlen;
 }
@@ -657,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 			puts("*** ERROR: File lookup fail\n");
 			nfs_state = STATE_UMOUNT_REQ;
 			nfs_send();
+		} else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions != 0) {
+			/* umount */
+			nfs_state = STATE_UMOUNT_REQ;
+			nfs_send();
+			/* And retry with another supported version */
+			nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
+			nfs_send();
 		} else {
 			nfs_state = STATE_READ_REQ;
 			nfs_offset = 0;
@@ -696,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 		} else {
 			if (!rlen)
 				nfs_download_state = NETLOOP_SUCCESS;
+			if (rlen < 0)
+				printf("NFS READ error (%d)\n", rlen);
 			nfs_state = STATE_UMOUNT_REQ;
 			nfs_send();
 		}
diff --git a/net/nfs.h b/net/nfs.h
index d69b422..f65d14d 100644
--- a/net/nfs.h
+++ b/net/nfs.h
@@ -25,7 +25,10 @@
 #define NFS_READLINK    5
 #define NFS_READ        6
 
+#define NFS3PROC_LOOKUP 3
+
 #define NFS_FHSIZE      32
+#define NFS3_FHSIZE     64
 
 #define NFSERR_PERM     1
 #define NFSERR_NOENT    2
@@ -46,6 +49,16 @@
 
 #define NFS_MAXLINKDEPTH 16
 
+/* Values for Accept State flag on RPC answers (See: rfc1831) */
+enum rpc_accept_stat {
+	NFS_RPC_SUCCESS = 0,	/* RPC executed successfully */
+	NFS_RPC_PROG_UNAVAIL = 1,	/* remote hasn't exported program */
+	NFS_RPC_PROG_MISMATCH = 2,	/* remote can't support version # */
+	NFS_RPC_PROC_UNAVAIL = 3,	/* program can't support procedure */
+	NFS_RPC_GARBAGE_ARGS = 4,	/* procedure can't decode params */
+	NFS_RPC_SYSTEM_ERR = 5	/* errors like memory allocation failure */
+};
+
 struct rpc_t {
 	union {
 		uint8_t data[2048];
@@ -65,7 +78,7 @@ struct rpc_t {
 			uint32_t verifier;
 			uint32_t v2;
 			uint32_t astatus;
-			uint32_t data[19];
+			uint32_t data[NFS_READ_SIZE];
 		} reply;
 	} u;
 };
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] net: NFS: Add NFSv3 support
  2016-06-20 19:27 [U-Boot] [PATCH] net: NFS: Add NFSv3 support Guillaume GARDET
@ 2016-06-20 19:31 ` Guillaume Gardet
  2016-06-20 21:43   ` Joe Hershberger
  2016-06-23  9:10 ` [U-Boot] [PATCH V2] " Guillaume GARDET
  1 sibling, 1 reply; 13+ messages in thread
From: Guillaume Gardet @ 2016-06-20 19:31 UTC (permalink / raw)
  To: u-boot

Please note that, this patch applies on top of this one:
     NFS: Add error message when U-Boot NFS version (V2) is not supported by NFS server
     https://patchwork.ozlabs.org/patch/630898/

It would be nice if people could test it on other boards and with other NFS servers.


Guillaume


Le 20/06/2016 21:27, Guillaume GARDET a ?crit :
> This patch enables NFSv3 support.
> If NFSv2 is available use it as usual.
> If NFSv2 is not available, but NFSv3 is available, use NFSv3.
> If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
>
> Tested on iMX6 sabrelite with 4 Linux NFS servers:
>    * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
>    * NFSv2 + NFSv3 server: use NFSv3 protocol
>    * NFSv3 + NFSv4 server: use NFSv3 protocol
>    * NFSv3 server: use NFSv3 protocol
>
> Signed-off-by: Guillaume GARDET <guillaume.gardet@free.fr>
> Cc: Tom Rini <trini@konsulko.com>
> Cc: joe.hershberger at ni.com
>
> ---
>   net/nfs.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
>   net/nfs.h |  15 +++-
>   2 files changed, 246 insertions(+), 50 deletions(-)
>
> diff --git a/net/nfs.c b/net/nfs.c
> index 0ed47c9..1e920c1 100644
> --- a/net/nfs.c
> +++ b/net/nfs.c
> @@ -22,6 +22,10 @@
>    * possible, maximum 16 steps). There is no clearing of ".."'s inside the
>    * path, so please DON'T DO THAT. thx. */
>   
> +/* NOTE 4: NFSv3 support added by Guillaume GARDET.
> + * NFSv2 is still used by default. But if server does not support NFSv2, then
> + * NFSv3 is used, if available on NFS server. */
> +
>   #include <common.h>
>   #include <command.h>
>   #include <net.h>
> @@ -47,8 +51,11 @@ static int nfs_offset = -1;
>   static int nfs_len;
>   static ulong nfs_timeout = NFS_TIMEOUT;
>   
> -static char dirfh[NFS_FHSIZE];	/* file handle of directory */
> -static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
> +static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
> +static char filefh[NFS_FHSIZE]; /* NFSv2 file handle */
> +
> +static char filefh3[NFS3_FHSIZE];	/* NFSv3 file handle  */
> +static int filefh3_length;	/* (variable) length of filefh3 */
>   
>   static enum net_loop_state nfs_download_state;
>   static struct in_addr nfs_server_ip;
> @@ -70,6 +77,10 @@ static char *nfs_filename;
>   static char *nfs_path;
>   static char nfs_path_buff[2048];
>   
> +#define NFSV2_FLAG 1
> +#define NFSV3_FLAG 1 << 1
> +static char supported_nfs_versions = NFSV2_FLAG | NFSV3_FLAG;
> +
>   static inline int store_block(uchar *src, unsigned offset, unsigned len)
>   {
>   	ulong newsize = offset + len;
> @@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
>   	pkt.u.call.type = htonl(MSG_CALL);
>   	pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
>   	pkt.u.call.prog = htonl(rpc_prog);
> -	pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
> +	switch (rpc_prog) {
> +	case PROG_NFS:
> +		if (supported_nfs_versions & NFSV2_FLAG)
> +			pkt.u.call.vers = htonl(2);	/* NFS v2 */
> +		else /* NFSV3_FLAG */
> +			pkt.u.call.vers = htonl(3);	/* NFS v3 */
> +		break;
> +	case PROG_PORTMAP:
> +	case PROG_MOUNT:
> +	default:
> +		pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
> +	}
>   	pkt.u.call.proc = htonl(rpc_proc);
>   	p = (uint32_t *)&(pkt.u.call.data);
>   
> @@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver)
>   	data[5] = htonl(ver);
>   	data[6] = htonl(17);	/* IP_UDP */
>   	data[7] = 0;
> -
>   	rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
>   }
>   
> @@ -291,8 +312,14 @@ static void nfs_readlink_req(void)
>   	p = &(data[0]);
>   	p = (uint32_t *)rpc_add_credentials((long *)p);
>   
> -	memcpy(p, filefh, NFS_FHSIZE);
> -	p += (NFS_FHSIZE / 4);
> +	if (supported_nfs_versions & NFSV2_FLAG) {
> +		memcpy(p, filefh, NFS_FHSIZE);
> +		p += (NFS_FHSIZE / 4);
> +	} else { /* NFSV3_FLAG */
> +		*p++ = htonl(filefh3_length);
> +		memcpy(p, filefh3, filefh3_length);
> +		p += (filefh3_length / 4);
> +	}
>   
>   	len = (uint32_t *)p - (uint32_t *)&(data[0]);
>   
> @@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname)
>   	p = &(data[0]);
>   	p = (uint32_t *)rpc_add_credentials((long *)p);
>   
> -	memcpy(p, dirfh, NFS_FHSIZE);
> -	p += (NFS_FHSIZE / 4);
> -	*p++ = htonl(fnamelen);
> -	if (fnamelen & 3)
> -		*(p + fnamelen / 4) = 0;
> -	memcpy(p, fname, fnamelen);
> -	p += (fnamelen + 3) / 4;
> -
> -	len = (uint32_t *)p - (uint32_t *)&(data[0]);
> -
> -	rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
> +	if (supported_nfs_versions & NFSV2_FLAG) {
> +		memcpy(p, dirfh, NFS_FHSIZE);
> +		p += (NFS_FHSIZE / 4);
> +		*p++ = htonl(fnamelen);
> +		if (fnamelen & 3)
> +			*(p + fnamelen / 4) = 0;
> +		memcpy(p, fname, fnamelen);
> +		p += (fnamelen + 3) / 4;
> +
> +		len = (uint32_t *)p - (uint32_t *)&(data[0]);
> +
> +		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
> +	} else {  /* NFSV3_FLAG */
> +		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
> +		memcpy(p, dirfh, NFS_FHSIZE);
> +		p += (NFS_FHSIZE / 4);
> +		*p++ = htonl(fnamelen);
> +		if (fnamelen & 3)
> +			*(p + fnamelen / 4) = 0;
> +		memcpy(p, fname, fnamelen);
> +		p += (fnamelen + 3) / 4;
> +
> +		len = (uint32_t *)p - (uint32_t *)&(data[0]);
> +
> +		rpc_req(PROG_NFS, NFS3PROC_LOOKUP, data, len);
> +	}
>   }
>   
>   /**************************************************************************
> @@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen)
>   	p = &(data[0]);
>   	p = (uint32_t *)rpc_add_credentials((long *)p);
>   
> -	memcpy(p, filefh, NFS_FHSIZE);
> -	p += (NFS_FHSIZE / 4);
> -	*p++ = htonl(offset);
> -	*p++ = htonl(readlen);
> -	*p++ = 0;
> +	if (supported_nfs_versions & NFSV2_FLAG) {
> +		memcpy(p, filefh, NFS_FHSIZE);
> +		p += (NFS_FHSIZE / 4);
> +		*p++ = htonl(offset);
> +		*p++ = htonl(readlen);
> +		*p++ = 0;
> +	} else { /* NFSV3_FLAG */
> +		*p++ = htonl(filefh3_length);
> +		memcpy(p, filefh3, filefh3_length);
> +		p += (filefh3_length / 4);
> +		*p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */
> +		*p++ = htonl(offset);
> +		*p++ = htonl(readlen);
> +		*p++ = 0;
> +	}
>   
>   	len = (uint32_t *)p - (uint32_t *)&(data[0]);
>   
> @@ -359,10 +411,16 @@ static void nfs_send(void)
>   
>   	switch (nfs_state) {
>   	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
> -		rpc_lookup_req(PROG_MOUNT, 1);
> +		if (supported_nfs_versions & NFSV2_FLAG)
> +			rpc_lookup_req(PROG_MOUNT, 1);
> +		else  /* NFSV3_FLAG */
> +			rpc_lookup_req(PROG_MOUNT, 3);
>   		break;
>   	case STATE_PRCLOOKUP_PROG_NFS_REQ:
> -		rpc_lookup_req(PROG_NFS, 2);
> +		if (supported_nfs_versions & NFSV2_FLAG)
> +			rpc_lookup_req(PROG_NFS, 2);
> +		else  /* NFSV3_FLAG */
> +			rpc_lookup_req(PROG_NFS, 3);
>   		break;
>   	case STATE_MOUNT_REQ:
>   		nfs_mount_req(nfs_path);
> @@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)
>   		return -1;
>   
>   	fs_mounted = 1;
> +	/*  NFSv2 and NFSv3 use same structure */
>   	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
>   
>   	return 0;
> @@ -481,24 +540,51 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
>   	if (rpc_pkt.u.reply.rstatus  ||
>   	    rpc_pkt.u.reply.verifier ||
>   	    rpc_pkt.u.reply.astatus  ||
> -	    rpc_pkt.u.reply.data[0]){
> -		switch(ntohl(rpc_pkt.u.reply.astatus)){
> -		case 0: /* Not an error */
> +	    rpc_pkt.u.reply.data[0]) {
> +		switch (ntohl(rpc_pkt.u.reply.astatus)) {
> +		case NFS_RPC_SUCCESS: /* Not an error */
>   			break;
> -		case 2: /* Remote can't support NFS version */
> -			printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
> -				2,
> -				ntohl(rpc_pkt.u.reply.data[0]),
> -				ntohl(rpc_pkt.u.reply.data[1]));
> +		case NFS_RPC_PROG_MISMATCH:
> +			/* Remote can't support requested NFS version */
> +			switch (ntohl(rpc_pkt.u.reply.data[0])) {
> +			/* Minimal supported NFS version */
> +			case 3:
> +				debug("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
> +				      (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
> +				      ntohl(rpc_pkt.u.reply.data[0]),
> +				      ntohl(rpc_pkt.u.reply.data[1]));
> +				debug("Will retry with NFSv3\n");
> +				/* Clear NFSV2_FLAG from supported versions */
> +				supported_nfs_versions = supported_nfs_versions & ~NFSV2_FLAG;
> +				return -NFS_RPC_PROG_MISMATCH;
> +			case 4:
> +			default:
> +				printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
> +				       (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
> +				       ntohl(rpc_pkt.u.reply.data[0]),
> +				       ntohl(rpc_pkt.u.reply.data[1]));
> +			}
>   			break;
> +		case NFS_RPC_PROG_UNAVAIL:
> +		case NFS_RPC_PROC_UNAVAIL:
> +		case NFS_RPC_GARBAGE_ARGS:
> +		case NFS_RPC_SYSTEM_ERR:
>   		default: /* Unknown error on 'accept state' flag */
> -			printf("*** ERROR: accept state error (%d)\n", ntohl(rpc_pkt.u.reply.astatus));
> +			printf("*** ERROR: accept state error (%d)\n",
> +			       ntohl(rpc_pkt.u.reply.astatus));
>   			break;
>   		}
>   		return -1;
>   	}
>   
> -	memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
> +	if (supported_nfs_versions & NFSV2_FLAG) {
> +		memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
> +	} else {  /* NFSV3_FLAG */
> +		filefh3_length = ntohl(rpc_pkt.u.reply.data[1]);
> +		if (filefh3_length > NFS3_FHSIZE)
> +			filefh3_length  = NFS3_FHSIZE;
> +		memcpy(filefh3, rpc_pkt.u.reply.data + 2, filefh3_length);
> +	}
>   
>   	return 0;
>   }
> @@ -523,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len)
>   	    rpc_pkt.u.reply.data[0])
>   		return -1;
>   
> -	rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
> +	if (supported_nfs_versions & NFSV2_FLAG) {
>   
> -	if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
> -		int pathlen;
> -		strcat(nfs_path, "/");
> -		pathlen = strlen(nfs_path);
> -		memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]),
> -		       rlen);
> -		nfs_path[pathlen + rlen] = 0;
> -	} else {
> -		memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
> -		nfs_path[rlen] = 0;
> +		rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
> +
> +		if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
> +			int pathlen;
> +			strcat(nfs_path, "/");
> +			pathlen = strlen(nfs_path);
> +			memcpy(nfs_path + pathlen,
> +			       (uchar *)&(rpc_pkt.u.reply.data[2]),
> +			       rlen);
> +			nfs_path[pathlen + rlen] = 0;
> +		} else {
> +			memcpy(nfs_path,
> +			       (uchar *)&(rpc_pkt.u.reply.data[2]),
> +			       rlen);
> +			nfs_path[rlen] = 0;
> +		}
> +	} else {  /* NFSV3_FLAG */
> +		int nfsv3_data_offset = 0;
> +		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
> +			/* 'attributes_follow' flag is TRUE,
> +			 * so we have attributes on 21 bytes */
> +			/* Skip unused values :
> +				type;	32 bits value,
> +				mode;	32 bits value,
> +				nlink;	32 bits value,
> +				uid;	32 bits value,
> +				gid;	32 bits value,
> +				size;	64 bits value,
> +				used;	64 bits value,
> +				rdev;	64 bits value,
> +				fsid;	64 bits value,
> +				fileid;	64 bits value,
> +				atime;	64 bits value,
> +				mtime;	64 bits value,
> +				ctime;	64 bits value,
> +			*/
> +			nfsv3_data_offset = 22;
> +		} else {
> +			/* 'attributes_follow' flag is FALSE,
> +			 * so we don't have any attributes */
> +			nfsv3_data_offset = 1;
> +		}
> +
> +		/* new path length */
> +		rlen = ntohl(rpc_pkt.u.reply.data[1+nfsv3_data_offset]);
> +
> +		if (*((char *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset])) != '/') {
> +			int pathlen;
> +			strcat(nfs_path, "/");
> +			pathlen = strlen(nfs_path);
> +			memcpy(nfs_path + pathlen,
> +			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
> +			       rlen);
> +			nfs_path[pathlen + rlen] = 0;
> +		} else {
> +			memcpy(nfs_path,
> +			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
> +			       rlen);
> +			nfs_path[rlen] = 0;
> +		}
>   	}
>   	return 0;
>   }
> @@ -543,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
>   {
>   	struct rpc_t rpc_pkt;
>   	int rlen;
> +	uchar *data_ptr;
>   
>   	debug("%s\n", __func__);
>   
> @@ -570,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
>   	if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
>   		putc('#');
>   
> -	rlen = ntohl(rpc_pkt.u.reply.data[18]);
> -	if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply),
> -			nfs_offset, rlen))
> -		return -9999;
> +	if (supported_nfs_versions & NFSV2_FLAG) {
> +		rlen = ntohl(rpc_pkt.u.reply.data[18]);
> +		data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
> +	} else {  /* NFSV3_FLAG */
> +		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
> +			/* 'attributes_follow' is TRUE,
> +			 * so we have attributes on 21 bytes */
> +			/* Skip unused values :
> +				type;	32 bits value,
> +				mode;	32 bits value,
> +				nlink;	32 bits value,
> +				uid;	32 bits value,
> +				gid;	32 bits value,
> +				size;	64 bits value,
> +				used;	64 bits value,
> +				rdev;	64 bits value,
> +				fsid;	64 bits value,
> +				fileid;	64 bits value,
> +				atime;	64 bits value,
> +				mtime;	64 bits value,
> +				ctime;	64 bits value,
> +			*/
> +			rlen = ntohl(rpc_pkt.u.reply.data[23]); /* count value */
> +			/* Skip unused values :
> +				EOF:		32 bits value,
> +				data_size:	32 bits value,
> +			*/
> +			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26]);
> +		} else {
> +			/* attributes_follow is FALSE, so we don't have any attributes */
> +			rlen = ntohl(rpc_pkt.u.reply.data[2]); /* count value */
> +			/* Skip unused values :
> +				EOF:		32 bits value,
> +				data_size:	32 bits value,
> +			*/
> +			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5]);
> +		}
> +	}
> +
> +	if (store_block(data_ptr, nfs_offset, rlen))
> +			return -9999;
>   
>   	return rlen;
>   }
> @@ -657,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
>   			puts("*** ERROR: File lookup fail\n");
>   			nfs_state = STATE_UMOUNT_REQ;
>   			nfs_send();
> +		} else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions != 0) {
> +			/* umount */
> +			nfs_state = STATE_UMOUNT_REQ;
> +			nfs_send();
> +			/* And retry with another supported version */
> +			nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
> +			nfs_send();
>   		} else {
>   			nfs_state = STATE_READ_REQ;
>   			nfs_offset = 0;
> @@ -696,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
>   		} else {
>   			if (!rlen)
>   				nfs_download_state = NETLOOP_SUCCESS;
> +			if (rlen < 0)
> +				printf("NFS READ error (%d)\n", rlen);
>   			nfs_state = STATE_UMOUNT_REQ;
>   			nfs_send();
>   		}
> diff --git a/net/nfs.h b/net/nfs.h
> index d69b422..f65d14d 100644
> --- a/net/nfs.h
> +++ b/net/nfs.h
> @@ -25,7 +25,10 @@
>   #define NFS_READLINK    5
>   #define NFS_READ        6
>   
> +#define NFS3PROC_LOOKUP 3
> +
>   #define NFS_FHSIZE      32
> +#define NFS3_FHSIZE     64
>   
>   #define NFSERR_PERM     1
>   #define NFSERR_NOENT    2
> @@ -46,6 +49,16 @@
>   
>   #define NFS_MAXLINKDEPTH 16
>   
> +/* Values for Accept State flag on RPC answers (See: rfc1831) */
> +enum rpc_accept_stat {
> +	NFS_RPC_SUCCESS = 0,	/* RPC executed successfully */
> +	NFS_RPC_PROG_UNAVAIL = 1,	/* remote hasn't exported program */
> +	NFS_RPC_PROG_MISMATCH = 2,	/* remote can't support version # */
> +	NFS_RPC_PROC_UNAVAIL = 3,	/* program can't support procedure */
> +	NFS_RPC_GARBAGE_ARGS = 4,	/* procedure can't decode params */
> +	NFS_RPC_SYSTEM_ERR = 5	/* errors like memory allocation failure */
> +};
> +
>   struct rpc_t {
>   	union {
>   		uint8_t data[2048];
> @@ -65,7 +78,7 @@ struct rpc_t {
>   			uint32_t verifier;
>   			uint32_t v2;
>   			uint32_t astatus;
> -			uint32_t data[19];
> +			uint32_t data[NFS_READ_SIZE];
>   		} reply;
>   	} u;
>   };

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] net: NFS: Add NFSv3 support
  2016-06-20 19:31 ` Guillaume Gardet
@ 2016-06-20 21:43   ` Joe Hershberger
  2016-06-21  8:42     ` Guillaume Gardet
  0 siblings, 1 reply; 13+ messages in thread
From: Joe Hershberger @ 2016-06-20 21:43 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 20, 2016 at 2:31 PM, Guillaume Gardet
<guillaume.gardet@free.fr> wrote:
> Please note that, this patch applies on top of this one:
>     NFS: Add error message when U-Boot NFS version (V2) is not supported by
> NFS server
>     https://patchwork.ozlabs.org/patch/630898/

Please make sure to run your patches through scripts/checkpatch.pl.

Thanks,
-Joe

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH] net: NFS: Add NFSv3 support
  2016-06-20 21:43   ` Joe Hershberger
@ 2016-06-21  8:42     ` Guillaume Gardet
  0 siblings, 0 replies; 13+ messages in thread
From: Guillaume Gardet @ 2016-06-21  8:42 UTC (permalink / raw)
  To: u-boot

Hi,

Le 20/06/2016 23:43, Joe Hershberger a ?crit :
> On Mon, Jun 20, 2016 at 2:31 PM, Guillaume Gardet
> <guillaume.gardet@free.fr> wrote:
>> Please note that, this patch applies on top of this one:
>>      NFS: Add error message when U-Boot NFS version (V2) is not supported by
>> NFS server
>>      https://patchwork.ozlabs.org/patch/630898/
> Please make sure to run your patches through scripts/checkpatch.pl.

I did for the NFSv3 patch. There are only a few lines longer than 80 char, but not very easy to wrap.

For the previous patch, do you want a V2? You told me that you will take care to fix it manually.

If you don't want to include the previous patch for 2016.07 release, then you can drop it, and I can rebase this patch. Just tell me.


Guillaume

>
> Thanks,
> -Joe
>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot]  [PATCH V2] net: NFS: Add NFSv3 support
  2016-06-20 19:27 [U-Boot] [PATCH] net: NFS: Add NFSv3 support Guillaume GARDET
  2016-06-20 19:31 ` Guillaume Gardet
@ 2016-06-23  9:10 ` Guillaume GARDET
  2016-06-23 19:08   ` Tom Rini
  1 sibling, 1 reply; 13+ messages in thread
From: Guillaume GARDET @ 2016-06-23  9:10 UTC (permalink / raw)
  To: u-boot

This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.

Tested on iMX6 sabrelite with 4 Linux NFS servers:
  * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
  * NFSv2 + NFSv3 server: use NFSv3 protocol
  * NFSv3 + NFSv4 server: use NFSv3 protocol
  * NFSv3 server: use NFSv3 protocol

Signed-off-by: Guillaume GARDET <guillaume.gardet@free.fr>
Cc: Tom Rini <trini@konsulko.com>
Cc: joe.hershberger at ni.com

---
Changes in V2: 
	* rebase on latest GIT
	* shorten some long lines
	* no functionnal changes

 net/nfs.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 net/nfs.h |  15 +++-
 2 files changed, 242 insertions(+), 47 deletions(-)

diff --git a/net/nfs.c b/net/nfs.c
index f60a037..b5bc414 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -22,6 +22,10 @@
  * possible, maximum 16 steps). There is no clearing of ".."'s inside the
  * path, so please DON'T DO THAT. thx. */
 
+/* NOTE 4: NFSv3 support added by Guillaume GARDET, 2016-June-20.
+ * NFSv2 is still used by default. But if server does not support NFSv2, then
+ * NFSv3 is used, if available on NFS server. */
+
 #include <common.h>
 #include <command.h>
 #include <net.h>
@@ -47,8 +51,11 @@ static int nfs_offset = -1;
 static int nfs_len;
 static ulong nfs_timeout = NFS_TIMEOUT;
 
-static char dirfh[NFS_FHSIZE];	/* file handle of directory */
-static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
+static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
+static char filefh[NFS_FHSIZE]; /* NFSv2 file handle */
+
+static char filefh3[NFS3_FHSIZE];	/* NFSv3 file handle  */
+static int filefh3_length;	/* (variable) length of filefh3 */
 
 static enum net_loop_state nfs_download_state;
 static struct in_addr nfs_server_ip;
@@ -70,6 +77,10 @@ static char *nfs_filename;
 static char *nfs_path;
 static char nfs_path_buff[2048];
 
+#define NFSV2_FLAG 1
+#define NFSV3_FLAG 1 << 1
+static char supported_nfs_versions = NFSV2_FLAG | NFSV3_FLAG;
+
 static inline int store_block(uchar *src, unsigned offset, unsigned len)
 {
 	ulong newsize = offset + len;
@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
 	pkt.u.call.type = htonl(MSG_CALL);
 	pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
 	pkt.u.call.prog = htonl(rpc_prog);
-	pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	switch (rpc_prog) {
+	case PROG_NFS:
+		if (supported_nfs_versions & NFSV2_FLAG)
+			pkt.u.call.vers = htonl(2);	/* NFS v2 */
+		else /* NFSV3_FLAG */
+			pkt.u.call.vers = htonl(3);	/* NFS v3 */
+		break;
+	case PROG_PORTMAP:
+	case PROG_MOUNT:
+	default:
+		pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	}
 	pkt.u.call.proc = htonl(rpc_proc);
 	p = (uint32_t *)&(pkt.u.call.data);
 
@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver)
 	data[5] = htonl(ver);
 	data[6] = htonl(17);	/* IP_UDP */
 	data[7] = 0;
-
 	rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
 }
 
@@ -291,8 +312,14 @@ static void nfs_readlink_req(void)
 	p = &(data[0]);
 	p = (uint32_t *)rpc_add_credentials((long *)p);
 
-	memcpy(p, filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, filefh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+	} else { /* NFSV3_FLAG */
+		*p++ = htonl(filefh3_length);
+		memcpy(p, filefh3, filefh3_length);
+		p += (filefh3_length / 4);
+	}
 
 	len = (uint32_t *)p - (uint32_t *)&(data[0]);
 
@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname)
 	p = &(data[0]);
 	p = (uint32_t *)rpc_add_credentials((long *)p);
 
-	memcpy(p, dirfh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(fnamelen);
-	if (fnamelen & 3)
-		*(p + fnamelen / 4) = 0;
-	memcpy(p, fname, fnamelen);
-	p += (fnamelen + 3) / 4;
-
-	len = (uint32_t *)p - (uint32_t *)&(data[0]);
-
-	rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, dirfh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(fnamelen);
+		if (fnamelen & 3)
+			*(p + fnamelen / 4) = 0;
+		memcpy(p, fname, fnamelen);
+		p += (fnamelen + 3) / 4;
+
+		len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+	} else {  /* NFSV3_FLAG */
+		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
+		memcpy(p, dirfh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(fnamelen);
+		if (fnamelen & 3)
+			*(p + fnamelen / 4) = 0;
+		memcpy(p, fname, fnamelen);
+		p += (fnamelen + 3) / 4;
+
+		len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+		rpc_req(PROG_NFS, NFS3PROC_LOOKUP, data, len);
+	}
 }
 
 /**************************************************************************
@@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen)
 	p = &(data[0]);
 	p = (uint32_t *)rpc_add_credentials((long *)p);
 
-	memcpy(p, filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(offset);
-	*p++ = htonl(readlen);
-	*p++ = 0;
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, filefh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(offset);
+		*p++ = htonl(readlen);
+		*p++ = 0;
+	} else { /* NFSV3_FLAG */
+		*p++ = htonl(filefh3_length);
+		memcpy(p, filefh3, filefh3_length);
+		p += (filefh3_length / 4);
+		*p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */
+		*p++ = htonl(offset);
+		*p++ = htonl(readlen);
+		*p++ = 0;
+	}
 
 	len = (uint32_t *)p - (uint32_t *)&(data[0]);
 
@@ -359,10 +411,16 @@ static void nfs_send(void)
 
 	switch (nfs_state) {
 	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
-		rpc_lookup_req(PROG_MOUNT, 1);
+		if (supported_nfs_versions & NFSV2_FLAG)
+			rpc_lookup_req(PROG_MOUNT, 1);
+		else  /* NFSV3_FLAG */
+			rpc_lookup_req(PROG_MOUNT, 3);
 		break;
 	case STATE_PRCLOOKUP_PROG_NFS_REQ:
-		rpc_lookup_req(PROG_NFS, 2);
+		if (supported_nfs_versions & NFSV2_FLAG)
+			rpc_lookup_req(PROG_NFS, 2);
+		else  /* NFSV3_FLAG */
+			rpc_lookup_req(PROG_NFS, 3);
 		break;
 	case STATE_MOUNT_REQ:
 		nfs_mount_req(nfs_path);
@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)
 		return -1;
 
 	fs_mounted = 1;
+	/*  NFSv2 and NFSv3 use same structure */
 	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
 
 	return 0;
@@ -483,14 +542,33 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
 	    rpc_pkt.u.reply.astatus  ||
 	    rpc_pkt.u.reply.data[0]) {
 		switch (ntohl(rpc_pkt.u.reply.astatus)) {
-		case 0: /* Not an error */
+		case NFS_RPC_SUCCESS: /* Not an error */
 			break;
-		case 2: /* Remote can't support NFS version */
-			printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
-			       2,
-			       ntohl(rpc_pkt.u.reply.data[0]),
-			       ntohl(rpc_pkt.u.reply.data[1]));
+		case NFS_RPC_PROG_MISMATCH:
+			/* Remote can't support NFS version */
+			switch (ntohl(rpc_pkt.u.reply.data[0])) {
+			/* Minimal supported NFS version */
+			case 3:
+				debug("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
+				      (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
+				      ntohl(rpc_pkt.u.reply.data[0]),
+				      ntohl(rpc_pkt.u.reply.data[1]));
+				debug("Will retry with NFSv3\n");
+				/* Clear NFSV2_FLAG from supported versions */
+				supported_nfs_versions &= ~NFSV2_FLAG;
+				return -NFS_RPC_PROG_MISMATCH;
+			case 4:
+			default:
+				printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
+				       (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
+				       ntohl(rpc_pkt.u.reply.data[0]),
+				       ntohl(rpc_pkt.u.reply.data[1]));
+			}
 			break;
+		case NFS_RPC_PROG_UNAVAIL:
+		case NFS_RPC_PROC_UNAVAIL:
+		case NFS_RPC_GARBAGE_ARGS:
+		case NFS_RPC_SYSTEM_ERR:
 		default: /* Unknown error on 'accept state' flag */
 			printf("*** ERROR: accept state error (%d)\n",
 			       ntohl(rpc_pkt.u.reply.astatus));
@@ -499,7 +577,14 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
 		return -1;
 	}
 
-	memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	} else {  /* NFSV3_FLAG */
+		filefh3_length = ntohl(rpc_pkt.u.reply.data[1]);
+		if (filefh3_length > NFS3_FHSIZE)
+			filefh3_length  = NFS3_FHSIZE;
+		memcpy(filefh3, rpc_pkt.u.reply.data + 2, filefh3_length);
+	}
 
 	return 0;
 }
@@ -524,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len)
 	    rpc_pkt.u.reply.data[0])
 		return -1;
 
-	rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+	if (supported_nfs_versions & NFSV2_FLAG) {
 
-	if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
-		int pathlen;
-		strcat(nfs_path, "/");
-		pathlen = strlen(nfs_path);
-		memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]),
-		       rlen);
-		nfs_path[pathlen + rlen] = 0;
-	} else {
-		memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
-		nfs_path[rlen] = 0;
+		rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+
+		if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
+			int pathlen;
+			strcat(nfs_path, "/");
+			pathlen = strlen(nfs_path);
+			memcpy(nfs_path + pathlen,
+			       (uchar *)&(rpc_pkt.u.reply.data[2]),
+			       rlen);
+			nfs_path[pathlen + rlen] = 0;
+		} else {
+			memcpy(nfs_path,
+			       (uchar *)&(rpc_pkt.u.reply.data[2]),
+			       rlen);
+			nfs_path[rlen] = 0;
+		}
+	} else {  /* NFSV3_FLAG */
+		int nfsv3_data_offset = 0;
+		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
+			/* 'attributes_follow' flag is TRUE,
+			 * so we have attributes on 21 bytes */
+			/* Skip unused values :
+				type;	32 bits value,
+				mode;	32 bits value,
+				nlink;	32 bits value,
+				uid;	32 bits value,
+				gid;	32 bits value,
+				size;	64 bits value,
+				used;	64 bits value,
+				rdev;	64 bits value,
+				fsid;	64 bits value,
+				fileid;	64 bits value,
+				atime;	64 bits value,
+				mtime;	64 bits value,
+				ctime;	64 bits value,
+			*/
+			nfsv3_data_offset = 22;
+		} else {
+			/* 'attributes_follow' flag is FALSE,
+			 * so we don't have any attributes */
+			nfsv3_data_offset = 1;
+		}
+
+		/* new path length */
+		rlen = ntohl(rpc_pkt.u.reply.data[1+nfsv3_data_offset]);
+
+		if (*((char *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset])) != '/') {
+			int pathlen;
+			strcat(nfs_path, "/");
+			pathlen = strlen(nfs_path);
+			memcpy(nfs_path + pathlen,
+			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
+			       rlen);
+			nfs_path[pathlen + rlen] = 0;
+		} else {
+			memcpy(nfs_path,
+			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
+			       rlen);
+			nfs_path[rlen] = 0;
+		}
 	}
 	return 0;
 }
@@ -544,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
 {
 	struct rpc_t rpc_pkt;
 	int rlen;
+	uchar *data_ptr;
 
 	debug("%s\n", __func__);
 
@@ -571,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
 	if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
 		putc('#');
 
-	rlen = ntohl(rpc_pkt.u.reply.data[18]);
-	if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply),
-			nfs_offset, rlen))
-		return -9999;
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		rlen = ntohl(rpc_pkt.u.reply.data[18]);
+		data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
+	} else {  /* NFSV3_FLAG */
+		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
+			/* 'attributes_follow' is TRUE,
+			 * so we have attributes on 21 bytes */
+			/* Skip unused values :
+				type;	32 bits value,
+				mode;	32 bits value,
+				nlink;	32 bits value,
+				uid;	32 bits value,
+				gid;	32 bits value,
+				size;	64 bits value,
+				used;	64 bits value,
+				rdev;	64 bits value,
+				fsid;	64 bits value,
+				fileid;	64 bits value,
+				atime;	64 bits value,
+				mtime;	64 bits value,
+				ctime;	64 bits value,
+			*/
+			rlen = ntohl(rpc_pkt.u.reply.data[23]); /* count value */
+			/* Skip unused values :
+				EOF:		32 bits value,
+				data_size:	32 bits value,
+			*/
+			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26]);
+		} else {
+			/* attributes_follow is FALSE, so we don't have any attributes */
+			rlen = ntohl(rpc_pkt.u.reply.data[2]); /* count value */
+			/* Skip unused values :
+				EOF:		32 bits value,
+				data_size:	32 bits value,
+			*/
+			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5]);
+		}
+	}
+
+	if (store_block(data_ptr, nfs_offset, rlen))
+			return -9999;
 
 	return rlen;
 }
@@ -658,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 			puts("*** ERROR: File lookup fail\n");
 			nfs_state = STATE_UMOUNT_REQ;
 			nfs_send();
+		} else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions != 0) {
+			/* umount */
+			nfs_state = STATE_UMOUNT_REQ;
+			nfs_send();
+			/* And retry with another supported version */
+			nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
+			nfs_send();
 		} else {
 			nfs_state = STATE_READ_REQ;
 			nfs_offset = 0;
@@ -697,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 		} else {
 			if (!rlen)
 				nfs_download_state = NETLOOP_SUCCESS;
+			if (rlen < 0)
+				printf("NFS READ error (%d)\n", rlen);
 			nfs_state = STATE_UMOUNT_REQ;
 			nfs_send();
 		}
diff --git a/net/nfs.h b/net/nfs.h
index d69b422..f65d14d 100644
--- a/net/nfs.h
+++ b/net/nfs.h
@@ -25,7 +25,10 @@
 #define NFS_READLINK    5
 #define NFS_READ        6
 
+#define NFS3PROC_LOOKUP 3
+
 #define NFS_FHSIZE      32
+#define NFS3_FHSIZE     64
 
 #define NFSERR_PERM     1
 #define NFSERR_NOENT    2
@@ -46,6 +49,16 @@
 
 #define NFS_MAXLINKDEPTH 16
 
+/* Values for Accept State flag on RPC answers (See: rfc1831) */
+enum rpc_accept_stat {
+	NFS_RPC_SUCCESS = 0,	/* RPC executed successfully */
+	NFS_RPC_PROG_UNAVAIL = 1,	/* remote hasn't exported program */
+	NFS_RPC_PROG_MISMATCH = 2,	/* remote can't support version # */
+	NFS_RPC_PROC_UNAVAIL = 3,	/* program can't support procedure */
+	NFS_RPC_GARBAGE_ARGS = 4,	/* procedure can't decode params */
+	NFS_RPC_SYSTEM_ERR = 5	/* errors like memory allocation failure */
+};
+
 struct rpc_t {
 	union {
 		uint8_t data[2048];
@@ -65,7 +78,7 @@ struct rpc_t {
 			uint32_t verifier;
 			uint32_t v2;
 			uint32_t astatus;
-			uint32_t data[19];
+			uint32_t data[NFS_READ_SIZE];
 		} reply;
 	} u;
 };
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH V2] net: NFS: Add NFSv3 support
  2016-06-23  9:10 ` [U-Boot] [PATCH V2] " Guillaume GARDET
@ 2016-06-23 19:08   ` Tom Rini
  2016-06-24  7:45     ` Guillaume Gardet
  0 siblings, 1 reply; 13+ messages in thread
From: Tom Rini @ 2016-06-23 19:08 UTC (permalink / raw)
  To: u-boot

On Thu, Jun 23, 2016 at 11:10:26AM +0200, Guillaume GARDET wrote:

> This patch enables NFSv3 support.
> If NFSv2 is available use it as usual.
> If NFSv2 is not available, but NFSv3 is available, use NFSv3.
> If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
> 
> Tested on iMX6 sabrelite with 4 Linux NFS servers:
>   * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
>   * NFSv2 + NFSv3 server: use NFSv3 protocol
>   * NFSv3 + NFSv4 server: use NFSv3 protocol
>   * NFSv3 server: use NFSv3 protocol

So, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do
v2+v3 -> v3 and v3+v4 -> v3 ?  We should be consistent in preferring
either v2 over v3 or v3 over v2.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160623/51f14073/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH V2] net: NFS: Add NFSv3 support
  2016-06-23 19:08   ` Tom Rini
@ 2016-06-24  7:45     ` Guillaume Gardet
  2016-06-24 15:03       ` Tom Rini
  0 siblings, 1 reply; 13+ messages in thread
From: Guillaume Gardet @ 2016-06-24  7:45 UTC (permalink / raw)
  To: u-boot



Le 23/06/2016 21:08, Tom Rini a ?crit :
> On Thu, Jun 23, 2016 at 11:10:26AM +0200, Guillaume GARDET wrote:
>
>> This patch enables NFSv3 support.
>> If NFSv2 is available use it as usual.
>> If NFSv2 is not available, but NFSv3 is available, use NFSv3.
>> If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
>>
>> Tested on iMX6 sabrelite with 4 Linux NFS servers:
>>    * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
>>    * NFSv2 + NFSv3 server: use NFSv3 protocol
>>    * NFSv3 + NFSv4 server: use NFSv3 protocol
>>    * NFSv3 server: use NFSv3 protocol
> So, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do
> v2+v3 -> v3 and v3+v4 -> v3 ?  We should be consistent in preferring
> either v2 over v3 or v3 over v2.  Thanks!
>

Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".

As long as NFSv2 is available, we use it. Otherwise, we use v3 if available. As explained above.


Guillaume

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH V2] net: NFS: Add NFSv3 support
  2016-06-24  7:45     ` Guillaume Gardet
@ 2016-06-24 15:03       ` Tom Rini
  2016-06-25 19:26         ` Joe Hershberger
  0 siblings, 1 reply; 13+ messages in thread
From: Tom Rini @ 2016-06-24 15:03 UTC (permalink / raw)
  To: u-boot

On Fri, Jun 24, 2016 at 09:45:38AM +0200, Guillaume Gardet wrote:
> 
> 
> Le 23/06/2016 21:08, Tom Rini a ?crit :
> >On Thu, Jun 23, 2016 at 11:10:26AM +0200, Guillaume GARDET wrote:
> >
> >>This patch enables NFSv3 support.
> >>If NFSv2 is available use it as usual.
> >>If NFSv2 is not available, but NFSv3 is available, use NFSv3.
> >>If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
> >>
> >>Tested on iMX6 sabrelite with 4 Linux NFS servers:
> >>   * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
> >>   * NFSv2 + NFSv3 server: use NFSv3 protocol
> >>   * NFSv3 + NFSv4 server: use NFSv3 protocol
> >>   * NFSv3 server: use NFSv3 protocol
> >So, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do
> >v2+v3 -> v3 and v3+v4 -> v3 ?  We should be consistent in preferring
> >either v2 over v3 or v3 over v2.  Thanks!
> >
> 
> Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
> 
> As long as NFSv2 is available, we use it. Otherwise, we use v3 if
> available. As explained above.

OK, that makes sense, thanks!  Joe, I assume you can just fix that in
the commit message when you pick this up.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20160624/aae1f621/attachment.sig>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH V2] net: NFS: Add NFSv3 support
  2016-06-24 15:03       ` Tom Rini
@ 2016-06-25 19:26         ` Joe Hershberger
  2016-07-20  9:48           ` Guillaume Gardet
  0 siblings, 1 reply; 13+ messages in thread
From: Joe Hershberger @ 2016-06-25 19:26 UTC (permalink / raw)
  To: u-boot

On Fri, Jun 24, 2016 at 10:03 AM, Tom Rini <trini@konsulko.com> wrote:
>
> On Fri, Jun 24, 2016 at 09:45:38AM +0200, Guillaume Gardet wrote:
> >
> >
> > Le 23/06/2016 21:08, Tom Rini a ?crit :
> > >On Thu, Jun 23, 2016 at 11:10:26AM +0200, Guillaume GARDET wrote:
> > >
> > >>This patch enables NFSv3 support.
> > >>If NFSv2 is available use it as usual.
> > >>If NFSv2 is not available, but NFSv3 is available, use NFSv3.
> > >>If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
> > >>
> > >>Tested on iMX6 sabrelite with 4 Linux NFS servers:
> > >>   * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
> > >>   * NFSv2 + NFSv3 server: use NFSv3 protocol
> > >>   * NFSv3 + NFSv4 server: use NFSv3 protocol
> > >>   * NFSv3 server: use NFSv3 protocol
> > >So, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do
> > >v2+v3 -> v3 and v3+v4 -> v3 ?  We should be consistent in preferring
> > >either v2 over v3 or v3 over v2.  Thanks!
> > >
> >
> > Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
> >
> > As long as NFSv2 is available, we use it. Otherwise, we use v3 if
> > available. As explained above.
>
> OK, that makes sense, thanks!  Joe, I assume you can just fix that in
> the commit message when you pick this up.

Yup, no problem.

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH V2] net: NFS: Add NFSv3 support
  2016-06-25 19:26         ` Joe Hershberger
@ 2016-07-20  9:48           ` Guillaume Gardet
  2016-07-29  9:31             ` [U-Boot] [PATCH V3] " Guillaume GARDET
  0 siblings, 1 reply; 13+ messages in thread
From: Guillaume Gardet @ 2016-07-20  9:48 UTC (permalink / raw)
  To: u-boot



Le 25/06/2016 ? 21:26, Joe Hershberger a ?crit :
> On Fri, Jun 24, 2016 at 10:03 AM, Tom Rini <trini@konsulko.com> wrote:
>> On Fri, Jun 24, 2016 at 09:45:38AM +0200, Guillaume Gardet wrote:
>>>
>>> Le 23/06/2016 21:08, Tom Rini a ?crit :
>>>> On Thu, Jun 23, 2016 at 11:10:26AM +0200, Guillaume GARDET wrote:
>>>>
>>>>> This patch enables NFSv3 support.
>>>>> If NFSv2 is available use it as usual.
>>>>> If NFSv2 is not available, but NFSv3 is available, use NFSv3.
>>>>> If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
>>>>>
>>>>> Tested on iMX6 sabrelite with 4 Linux NFS servers:
>>>>>    * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
>>>>>    * NFSv2 + NFSv3 server: use NFSv3 protocol
>>>>>    * NFSv3 + NFSv4 server: use NFSv3 protocol
>>>>>    * NFSv3 server: use NFSv3 protocol
>>>> So, why do we have v2+v3+v4 -> v2 and not v2+v3+v4 -> v3, when we do
>>>> v2+v3 -> v3 and v3+v4 -> v3 ?  We should be consistent in preferring
>>>> either v2 over v3 or v3 over v2.  Thanks!
>>>>
>>> Sorry, it is a typo error. Please read: "NFSv2 + NFSv3 server: use NFSv2 protocol".
>>>
>>> As long as NFSv2 is available, we use it. Otherwise, we use v3 if
>>> available. As explained above.
>> OK, that makes sense, thanks!  Joe, I assume you can just fix that in
>> the commit message when you pick this up.
> Yup, no problem.
>

Just a friendly reminder for this patch. :)


Guillaume

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot]  [PATCH V3] net: NFS: Add NFSv3 support
  2016-07-20  9:48           ` Guillaume Gardet
@ 2016-07-29  9:31             ` Guillaume GARDET
  2016-07-29 14:07               ` Joe Hershberger
  2016-08-23  2:28               ` [U-Boot] " Joe Hershberger
  0 siblings, 2 replies; 13+ messages in thread
From: Guillaume GARDET @ 2016-07-29  9:31 UTC (permalink / raw)
  To: u-boot

This patch enables NFSv3 support.
If NFSv2 is available use it as usual.
If NFSv2 is not available, but NFSv3 is available, use NFSv3.
If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.

Tested on iMX6 sabrelite with 4 Linux NFS servers:
  * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
  * NFSv2 + NFSv3 server: use NFSv2 protocol
  * NFSv3 + NFSv4 server: use NFSv3 protocol
  * NFSv3 server: use NFSv3 protocol

Signed-off-by: Guillaume GARDET <guillaume.gardet@free.fr>
Cc: Tom Rini <trini@konsulko.com>
Cc: joe.hershberger at ni.com
---
Changes in V3:
	* rebase on latest GIT
	* Fix typo in commit mesage

Changes in V2:
	* rebase on latest GIT
	* shorten some long lines
	* no functionnal changes

 net/nfs.c | 274 +++++++++++++++++++++++++++++++++++++++++++++++++++-----------
 net/nfs.h |  15 +++-
 2 files changed, 242 insertions(+), 47 deletions(-)

diff --git a/net/nfs.c b/net/nfs.c
index 4a5a1ab..6ba37d4 100644
--- a/net/nfs.c
+++ b/net/nfs.c
@@ -22,6 +22,10 @@
  * possible, maximum 16 steps). There is no clearing of ".."'s inside the
  * path, so please DON'T DO THAT. thx. */
 
+/* NOTE 4: NFSv3 support added by Guillaume GARDET, 2016-June-20.
+ * NFSv2 is still used by default. But if server does not support NFSv2, then
+ * NFSv3 is used, if available on NFS server. */
+
 #include <common.h>
 #include <command.h>
 #include <net.h>
@@ -47,8 +51,11 @@ static int nfs_offset = -1;
 static int nfs_len;
 static ulong nfs_timeout = NFS_TIMEOUT;
 
-static char dirfh[NFS_FHSIZE];	/* file handle of directory */
-static char filefh[NFS_FHSIZE]; /* file handle of kernel image */
+static char dirfh[NFS_FHSIZE];	/* NFSv2 / NFSv3 file handle of directory */
+static char filefh[NFS_FHSIZE]; /* NFSv2 file handle */
+
+static char filefh3[NFS3_FHSIZE];	/* NFSv3 file handle  */
+static int filefh3_length;	/* (variable) length of filefh3 */
 
 static enum net_loop_state nfs_download_state;
 static struct in_addr nfs_server_ip;
@@ -70,6 +77,10 @@ static char *nfs_filename;
 static char *nfs_path;
 static char nfs_path_buff[2048];
 
+#define NFSV2_FLAG 1
+#define NFSV3_FLAG 1 << 1
+static char supported_nfs_versions = NFSV2_FLAG | NFSV3_FLAG;
+
 static inline int store_block(uchar *src, unsigned offset, unsigned len)
 {
 	ulong newsize = offset + len;
@@ -188,7 +199,18 @@ static void rpc_req(int rpc_prog, int rpc_proc, uint32_t *data, int datalen)
 	pkt.u.call.type = htonl(MSG_CALL);
 	pkt.u.call.rpcvers = htonl(2);	/* use RPC version 2 */
 	pkt.u.call.prog = htonl(rpc_prog);
-	pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	switch (rpc_prog) {
+	case PROG_NFS:
+		if (supported_nfs_versions & NFSV2_FLAG)
+			pkt.u.call.vers = htonl(2);	/* NFS v2 */
+		else /* NFSV3_FLAG */
+			pkt.u.call.vers = htonl(3);	/* NFS v3 */
+		break;
+	case PROG_PORTMAP:
+	case PROG_MOUNT:
+	default:
+		pkt.u.call.vers = htonl(2);	/* portmapper is version 2 */
+	}
 	pkt.u.call.proc = htonl(rpc_proc);
 	p = (uint32_t *)&(pkt.u.call.data);
 
@@ -224,7 +246,6 @@ static void rpc_lookup_req(int prog, int ver)
 	data[5] = htonl(ver);
 	data[6] = htonl(17);	/* IP_UDP */
 	data[7] = 0;
-
 	rpc_req(PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
 }
 
@@ -291,8 +312,14 @@ static void nfs_readlink_req(void)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, filefh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+	} else { /* NFSV3_FLAG */
+		*p++ = htonl(filefh3_length);
+		memcpy(p, filefh3, filefh3_length);
+		p += (filefh3_length / 4);
+	}
 
 	len = (uint32_t *)p - (uint32_t *)&(data[0]);
 
@@ -314,17 +341,32 @@ static void nfs_lookup_req(char *fname)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, dirfh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(fnamelen);
-	if (fnamelen & 3)
-		*(p + fnamelen / 4) = 0;
-	memcpy(p, fname, fnamelen);
-	p += (fnamelen + 3) / 4;
-
-	len = (uint32_t *)p - (uint32_t *)&(data[0]);
-
-	rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, dirfh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(fnamelen);
+		if (fnamelen & 3)
+			*(p + fnamelen / 4) = 0;
+		memcpy(p, fname, fnamelen);
+		p += (fnamelen + 3) / 4;
+
+		len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+		rpc_req(PROG_NFS, NFS_LOOKUP, data, len);
+	} else {  /* NFSV3_FLAG */
+		*p++ = htonl(NFS_FHSIZE);	/* Dir handle length */
+		memcpy(p, dirfh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(fnamelen);
+		if (fnamelen & 3)
+			*(p + fnamelen / 4) = 0;
+		memcpy(p, fname, fnamelen);
+		p += (fnamelen + 3) / 4;
+
+		len = (uint32_t *)p - (uint32_t *)&(data[0]);
+
+		rpc_req(PROG_NFS, NFS3PROC_LOOKUP, data, len);
+	}
 }
 
 /**************************************************************************
@@ -339,11 +381,21 @@ static void nfs_read_req(int offset, int readlen)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(offset);
-	*p++ = htonl(readlen);
-	*p++ = 0;
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(p, filefh, NFS_FHSIZE);
+		p += (NFS_FHSIZE / 4);
+		*p++ = htonl(offset);
+		*p++ = htonl(readlen);
+		*p++ = 0;
+	} else { /* NFSV3_FLAG */
+		*p++ = htonl(filefh3_length);
+		memcpy(p, filefh3, filefh3_length);
+		p += (filefh3_length / 4);
+		*p++ = htonl(0); /* offset is 64-bit long, so fill with 0 */
+		*p++ = htonl(offset);
+		*p++ = htonl(readlen);
+		*p++ = 0;
+	}
 
 	len = (uint32_t *)p - (uint32_t *)&(data[0]);
 
@@ -359,10 +411,16 @@ static void nfs_send(void)
 
 	switch (nfs_state) {
 	case STATE_PRCLOOKUP_PROG_MOUNT_REQ:
-		rpc_lookup_req(PROG_MOUNT, 1);
+		if (supported_nfs_versions & NFSV2_FLAG)
+			rpc_lookup_req(PROG_MOUNT, 1);
+		else  /* NFSV3_FLAG */
+			rpc_lookup_req(PROG_MOUNT, 3);
 		break;
 	case STATE_PRCLOOKUP_PROG_NFS_REQ:
-		rpc_lookup_req(PROG_NFS, 2);
+		if (supported_nfs_versions & NFSV2_FLAG)
+			rpc_lookup_req(PROG_NFS, 2);
+		else  /* NFSV3_FLAG */
+			rpc_lookup_req(PROG_NFS, 3);
 		break;
 	case STATE_MOUNT_REQ:
 		nfs_mount_req(nfs_path);
@@ -436,6 +494,7 @@ static int nfs_mount_reply(uchar *pkt, unsigned len)
 		return -1;
 
 	fs_mounted = 1;
+	/*  NFSv2 and NFSv3 use same structure */
 	memcpy(dirfh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
 
 	return 0;
@@ -483,14 +542,33 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
 	    rpc_pkt.u.reply.astatus  ||
 	    rpc_pkt.u.reply.data[0]) {
 		switch (ntohl(rpc_pkt.u.reply.astatus)) {
-		case 0: /* Not an error */
+		case NFS_RPC_SUCCESS: /* Not an error */
 			break;
-		case 2: /* Remote can't support NFS version */
-			printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
-			       2,
-			       ntohl(rpc_pkt.u.reply.data[0]),
-			       ntohl(rpc_pkt.u.reply.data[1]));
+		case NFS_RPC_PROG_MISMATCH:
+			/* Remote can't support NFS version */
+			switch (ntohl(rpc_pkt.u.reply.data[0])) {
+			/* Minimal supported NFS version */
+			case 3:
+				debug("*** Waring: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
+				      (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
+				      ntohl(rpc_pkt.u.reply.data[0]),
+				      ntohl(rpc_pkt.u.reply.data[1]));
+				debug("Will retry with NFSv3\n");
+				/* Clear NFSV2_FLAG from supported versions */
+				supported_nfs_versions &= ~NFSV2_FLAG;
+				return -NFS_RPC_PROG_MISMATCH;
+			case 4:
+			default:
+				printf("*** ERROR: NFS version not supported: Requested: V%d, accepted: min V%d - max V%d\n",
+				       (supported_nfs_versions & NFSV2_FLAG) ? 2 : 3,
+				       ntohl(rpc_pkt.u.reply.data[0]),
+				       ntohl(rpc_pkt.u.reply.data[1]));
+			}
 			break;
+		case NFS_RPC_PROG_UNAVAIL:
+		case NFS_RPC_PROC_UNAVAIL:
+		case NFS_RPC_GARBAGE_ARGS:
+		case NFS_RPC_SYSTEM_ERR:
 		default: /* Unknown error on 'accept state' flag */
 			printf("*** ERROR: accept state error (%d)\n",
 			       ntohl(rpc_pkt.u.reply.astatus));
@@ -499,7 +577,14 @@ static int nfs_lookup_reply(uchar *pkt, unsigned len)
 		return -1;
 	}
 
-	memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		memcpy(filefh, rpc_pkt.u.reply.data + 1, NFS_FHSIZE);
+	} else {  /* NFSV3_FLAG */
+		filefh3_length = ntohl(rpc_pkt.u.reply.data[1]);
+		if (filefh3_length > NFS3_FHSIZE)
+			filefh3_length  = NFS3_FHSIZE;
+		memcpy(filefh3, rpc_pkt.u.reply.data + 2, filefh3_length);
+	}
 
 	return 0;
 }
@@ -524,18 +609,68 @@ static int nfs_readlink_reply(uchar *pkt, unsigned len)
 	    rpc_pkt.u.reply.data[0])
 		return -1;
 
-	rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+	if (supported_nfs_versions & NFSV2_FLAG) {
 
-	if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
-		int pathlen;
-		strcat(nfs_path, "/");
-		pathlen = strlen(nfs_path);
-		memcpy(nfs_path + pathlen, (uchar *)&(rpc_pkt.u.reply.data[2]),
-		       rlen);
-		nfs_path[pathlen + rlen] = 0;
-	} else {
-		memcpy(nfs_path, (uchar *)&(rpc_pkt.u.reply.data[2]), rlen);
-		nfs_path[rlen] = 0;
+		rlen = ntohl(rpc_pkt.u.reply.data[1]); /* new path length */
+
+		if (*((char *)&(rpc_pkt.u.reply.data[2])) != '/') {
+			int pathlen;
+			strcat(nfs_path, "/");
+			pathlen = strlen(nfs_path);
+			memcpy(nfs_path + pathlen,
+			       (uchar *)&(rpc_pkt.u.reply.data[2]),
+			       rlen);
+			nfs_path[pathlen + rlen] = 0;
+		} else {
+			memcpy(nfs_path,
+			       (uchar *)&(rpc_pkt.u.reply.data[2]),
+			       rlen);
+			nfs_path[rlen] = 0;
+		}
+	} else {  /* NFSV3_FLAG */
+		int nfsv3_data_offset = 0;
+		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
+			/* 'attributes_follow' flag is TRUE,
+			 * so we have attributes on 21 bytes */
+			/* Skip unused values :
+				type;	32 bits value,
+				mode;	32 bits value,
+				nlink;	32 bits value,
+				uid;	32 bits value,
+				gid;	32 bits value,
+				size;	64 bits value,
+				used;	64 bits value,
+				rdev;	64 bits value,
+				fsid;	64 bits value,
+				fileid;	64 bits value,
+				atime;	64 bits value,
+				mtime;	64 bits value,
+				ctime;	64 bits value,
+			*/
+			nfsv3_data_offset = 22;
+		} else {
+			/* 'attributes_follow' flag is FALSE,
+			 * so we don't have any attributes */
+			nfsv3_data_offset = 1;
+		}
+
+		/* new path length */
+		rlen = ntohl(rpc_pkt.u.reply.data[1+nfsv3_data_offset]);
+
+		if (*((char *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset])) != '/') {
+			int pathlen;
+			strcat(nfs_path, "/");
+			pathlen = strlen(nfs_path);
+			memcpy(nfs_path + pathlen,
+			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
+			       rlen);
+			nfs_path[pathlen + rlen] = 0;
+		} else {
+			memcpy(nfs_path,
+			       (uchar *)&(rpc_pkt.u.reply.data[2+nfsv3_data_offset]),
+			       rlen);
+			nfs_path[rlen] = 0;
+		}
 	}
 	return 0;
 }
@@ -544,6 +679,7 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
 {
 	struct rpc_t rpc_pkt;
 	int rlen;
+	uchar *data_ptr;
 
 	debug("%s\n", __func__);
 
@@ -571,10 +707,47 @@ static int nfs_read_reply(uchar *pkt, unsigned len)
 	if (!(nfs_offset % ((NFS_READ_SIZE / 2) * 10)))
 		putc('#');
 
-	rlen = ntohl(rpc_pkt.u.reply.data[18]);
-	if (store_block((uchar *)pkt + sizeof(rpc_pkt.u.reply),
-			nfs_offset, rlen))
-		return -9999;
+	if (supported_nfs_versions & NFSV2_FLAG) {
+		rlen = ntohl(rpc_pkt.u.reply.data[18]);
+		data_ptr = (uchar *)&(rpc_pkt.u.reply.data[19]);
+	} else {  /* NFSV3_FLAG */
+		if (ntohl(rpc_pkt.u.reply.data[1]) != 0) {
+			/* 'attributes_follow' is TRUE,
+			 * so we have attributes on 21 bytes */
+			/* Skip unused values :
+				type;	32 bits value,
+				mode;	32 bits value,
+				nlink;	32 bits value,
+				uid;	32 bits value,
+				gid;	32 bits value,
+				size;	64 bits value,
+				used;	64 bits value,
+				rdev;	64 bits value,
+				fsid;	64 bits value,
+				fileid;	64 bits value,
+				atime;	64 bits value,
+				mtime;	64 bits value,
+				ctime;	64 bits value,
+			*/
+			rlen = ntohl(rpc_pkt.u.reply.data[23]); /* count value */
+			/* Skip unused values :
+				EOF:		32 bits value,
+				data_size:	32 bits value,
+			*/
+			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[26]);
+		} else {
+			/* attributes_follow is FALSE, so we don't have any attributes */
+			rlen = ntohl(rpc_pkt.u.reply.data[2]); /* count value */
+			/* Skip unused values :
+				EOF:		32 bits value,
+				data_size:	32 bits value,
+			*/
+			data_ptr = (uchar *)&(rpc_pkt.u.reply.data[5]);
+		}
+	}
+
+	if (store_block(data_ptr, nfs_offset, rlen))
+			return -9999;
 
 	return rlen;
 }
@@ -658,6 +831,13 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 			puts("*** ERROR: File lookup fail\n");
 			nfs_state = STATE_UMOUNT_REQ;
 			nfs_send();
+		} else if (reply == -NFS_RPC_PROG_MISMATCH && supported_nfs_versions != 0) {
+			/* umount */
+			nfs_state = STATE_UMOUNT_REQ;
+			nfs_send();
+			/* And retry with another supported version */
+			nfs_state = STATE_PRCLOOKUP_PROG_MOUNT_REQ;
+			nfs_send();
 		} else {
 			nfs_state = STATE_READ_REQ;
 			nfs_offset = 0;
@@ -697,6 +877,8 @@ static void nfs_handler(uchar *pkt, unsigned dest, struct in_addr sip,
 		} else {
 			if (!rlen)
 				nfs_download_state = NETLOOP_SUCCESS;
+			if (rlen < 0)
+				printf("NFS READ error (%d)\n", rlen);
 			nfs_state = STATE_UMOUNT_REQ;
 			nfs_send();
 		}
diff --git a/net/nfs.h b/net/nfs.h
index d69b422..f65d14d 100644
--- a/net/nfs.h
+++ b/net/nfs.h
@@ -25,7 +25,10 @@
 #define NFS_READLINK    5
 #define NFS_READ        6
 
+#define NFS3PROC_LOOKUP 3
+
 #define NFS_FHSIZE      32
+#define NFS3_FHSIZE     64
 
 #define NFSERR_PERM     1
 #define NFSERR_NOENT    2
@@ -46,6 +49,16 @@
 
 #define NFS_MAXLINKDEPTH 16
 
+/* Values for Accept State flag on RPC answers (See: rfc1831) */
+enum rpc_accept_stat {
+	NFS_RPC_SUCCESS = 0,	/* RPC executed successfully */
+	NFS_RPC_PROG_UNAVAIL = 1,	/* remote hasn't exported program */
+	NFS_RPC_PROG_MISMATCH = 2,	/* remote can't support version # */
+	NFS_RPC_PROC_UNAVAIL = 3,	/* program can't support procedure */
+	NFS_RPC_GARBAGE_ARGS = 4,	/* procedure can't decode params */
+	NFS_RPC_SYSTEM_ERR = 5	/* errors like memory allocation failure */
+};
+
 struct rpc_t {
 	union {
 		uint8_t data[2048];
@@ -65,7 +78,7 @@ struct rpc_t {
 			uint32_t verifier;
 			uint32_t v2;
 			uint32_t astatus;
-			uint32_t data[19];
+			uint32_t data[NFS_READ_SIZE];
 		} reply;
 	} u;
 };
-- 
1.8.4.5

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [U-Boot] [PATCH V3] net: NFS: Add NFSv3 support
  2016-07-29  9:31             ` [U-Boot] [PATCH V3] " Guillaume GARDET
@ 2016-07-29 14:07               ` Joe Hershberger
  2016-08-23  2:28               ` [U-Boot] " Joe Hershberger
  1 sibling, 0 replies; 13+ messages in thread
From: Joe Hershberger @ 2016-07-29 14:07 UTC (permalink / raw)
  To: u-boot

On Fri, Jul 29, 2016 at 4:31 AM, Guillaume GARDET
<guillaume.gardet@free.fr> wrote:
> This patch enables NFSv3 support.
> If NFSv2 is available use it as usual.
> If NFSv2 is not available, but NFSv3 is available, use NFSv3.
> If NFSv2 and NFSv3 are not available, print an error message since NFSv4 is not supported.
>
> Tested on iMX6 sabrelite with 4 Linux NFS servers:
>   * NFSv2 + NFSv3 + NFSv4 server: use NFSv2 protocol
>   * NFSv2 + NFSv3 server: use NFSv2 protocol
>   * NFSv3 + NFSv4 server: use NFSv3 protocol
>   * NFSv3 server: use NFSv3 protocol
>
> Signed-off-by: Guillaume GARDET <guillaume.gardet@free.fr>
> Cc: Tom Rini <trini@konsulko.com>
> Cc: joe.hershberger at ni.com

Sorry for the delay...

Acked-by: Joe Hershberger <joe.hershberger@ni.com>

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [U-Boot] net: NFS: Add NFSv3 support
  2016-07-29  9:31             ` [U-Boot] [PATCH V3] " Guillaume GARDET
  2016-07-29 14:07               ` Joe Hershberger
@ 2016-08-23  2:28               ` Joe Hershberger
  1 sibling, 0 replies; 13+ messages in thread
From: Joe Hershberger @ 2016-08-23  2:28 UTC (permalink / raw)
  To: u-boot

Hi Guillaume,

https://patchwork.ozlabs.org/patch/654061/ was applied to u-boot-net.git.

Thanks!
-Joe

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2016-08-23  2:28 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-06-20 19:27 [U-Boot] [PATCH] net: NFS: Add NFSv3 support Guillaume GARDET
2016-06-20 19:31 ` Guillaume Gardet
2016-06-20 21:43   ` Joe Hershberger
2016-06-21  8:42     ` Guillaume Gardet
2016-06-23  9:10 ` [U-Boot] [PATCH V2] " Guillaume GARDET
2016-06-23 19:08   ` Tom Rini
2016-06-24  7:45     ` Guillaume Gardet
2016-06-24 15:03       ` Tom Rini
2016-06-25 19:26         ` Joe Hershberger
2016-07-20  9:48           ` Guillaume Gardet
2016-07-29  9:31             ` [U-Boot] [PATCH V3] " Guillaume GARDET
2016-07-29 14:07               ` Joe Hershberger
2016-08-23  2:28               ` [U-Boot] " Joe Hershberger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.