mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read
@ 2014-02-07 21:28 Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 02/11] nfs: fix mount prog version in portmap lookup Uwe Kleine-König
                   ` (10 more replies)
  0 siblings, 11 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

On some architectures (e.g. alpha, amd64, arm64, ia64, s390x, mips64)
sizeof(ulong) is 8 which made net_read_uint32 actually read too much and
even returned the wrong value on big endian machines.
(Note the second issue isn't that critical though, because the only
architecture from the list above that uses big endian byte order is s390x
...)

Also change the argument to void * because the pointer is not necessarily
properly aligned.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 include/net.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/net.h b/include/net.h
index a4cfec712374..8388e2f12ebe 100644
--- a/include/net.h
+++ b/include/net.h
@@ -269,11 +269,11 @@ static inline IPaddr_t net_read_ip(void *from)
 }
 
 /* return uint32 *in network byteorder* */
-static inline uint32_t net_read_uint32(uint32_t *from)
+static inline uint32_t net_read_uint32(void *from)
 {
-	ulong l;
-	memcpy((void*)&l, (void*)from, sizeof(l));
-	return l;
+	uint32_t tmp;
+	memcpy(&tmp, from, sizeof(tmp));
+	return tmp;
 }
 
 /* write IP *in network byteorder* */
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 02/11] nfs: fix mount prog version in portmap lookup
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 03/11] nfs: skip over stale rpc packets Uwe Kleine-König
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

We're speaking rpc mount version 2 (i.e. the same version as the
implemented nfs protocol), so also specify that in the lookup.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---

Notes:
    new in v2

 fs/nfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 717326435189..6582bae7db31 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -1010,7 +1010,7 @@ static int nfs_probe(struct device_d *dev)
 	/* Need a priviliged source port */
 	net_udp_bind(npriv->con, 1000);
 
-	ret = rpc_lookup_req(npriv, PROG_MOUNT, 1);
+	ret = rpc_lookup_req(npriv, PROG_MOUNT, 2);
 	if (ret) {
 		printf("lookup mount port failed with %d\n", ret);
 		goto err2;
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 03/11] nfs: skip over stale rpc packets
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 02/11] nfs: fix mount prog version in portmap lookup Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit Uwe Kleine-König
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

When a former transaction was aborted by hitting Ctrl-C the old reply might
still hang in the ethernet controller making all further transactions fail.

So just skip over old replies.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---

Notes:
    Changed in v2:
     - use
    	if (rpc_id - ntohl(rpc.id) == 1)
       instead of
    	if (ntohl(rpc.id) < rpc_id)
       to drop at most a single stale reply and handle overflow properly
    
    An alternative would be to drain the ethernet queue before a new request is
    sent. Don't know how that works and I don't see much benefit, so I didn't
    try to find out :-)

 fs/nfs.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 6582bae7db31..76d8c0595db4 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -275,8 +275,13 @@ static int rpc_check_reply(unsigned char *pkt, int rpc_prog, unsigned long rpc_i
 
 	memcpy(&rpc, pkt, sizeof(rpc));
 
-	if (ntohl(rpc.id) != rpc_id)
+	if (ntohl(rpc.id) != rpc_id) {
+		if (rpc_id - ntohl(rpc.id) == 1)
+			/* stale packet, wait a bit longer */
+			return 0;
+
 		return -EINVAL;
+	}
 
 	if (rpc.rstatus  ||
 	    rpc.verifier ||
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 02/11] nfs: fix mount prog version in portmap lookup Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 03/11] nfs: skip over stale rpc packets Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-08  6:51   ` Jean-Christophe PLAGNIOL-VILLARD
  2014-02-07 21:28 ` [PATCH v2 05/11] nfs: simplify rpc_lookup_req Uwe Kleine-König
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 fs/nfs.c | 26 +++++---------------------
 1 file changed, 5 insertions(+), 21 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 76d8c0595db4..54dda261c0b1 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -224,34 +224,18 @@ out_overflow:
  */
 static uint32_t *rpc_add_credentials(uint32_t *p)
 {
-	int hl;
-	int hostnamelen = 0;
-
 	/*
-	 * Here's the executive summary on authentication requirements of the
-	 * various NFS server implementations:	Linux accepts both AUTH_NONE
-	 * and AUTH_UNIX authentication (also accepts an empty hostname field
-	 * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts
-	 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
-	 * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have
-	 * it (if the BOOTP/DHCP reply didn't give one, just use an empty
-	 * hostname).
+	 * *BSD refuses AUTH_NONE, so use AUTH_UNIX. An empty hostname is OK for
+	 * both Linux and *BSD.
 	 */
 
-	hl = (hostnamelen + 3) & ~3;
-
 	/* Provide an AUTH_UNIX credential.  */
 	*p++ = htonl(1);		/* AUTH_UNIX */
-	*p++ = htonl(hl + 20);		/* auth length */
+	*p++ = htonl(20);		/* auth length: 20 + strlen(hostname) */
 	*p++ = htonl(0);		/* stamp */
-	*p++ = htonl(hostnamelen);	/* hostname string */
-
-	if (hostnamelen & 3)
-		*(p + hostnamelen / 4) = 0; /* add zero padding */
-
-	/* memcpy(p, hostname, hostnamelen); */ /* empty hostname */
+	*p++ = htonl(0);		/* hostname string length */
+	/* memcpy(p, "", 0); p += 0; <- empty host name */
 
-	p += hl / 4;
 	*p++ = 0;			/* uid */
 	*p++ = 0;			/* gid */
 	*p++ = 0;			/* auxiliary gid list */
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 05/11] nfs: simplify rpc_lookup_req
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (2 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 06/11] nfs: drop an unneeded variable from nfs_do_open() Uwe Kleine-König
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

Instead of letting rpc_lookup_req set mount_port and nfs_port, let it
return the port found and let the caller use that information.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 fs/nfs.c | 24 ++++++------------------
 1 file changed, 6 insertions(+), 18 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 54dda261c0b1..761bfd626716 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -374,22 +374,8 @@ static int rpc_lookup_req(struct nfs_priv *npriv, int prog, int ver)
 	if (ret)
 		return ret;
 
-	port = net_read_uint32((uint32_t *)(nfs_packet + sizeof(struct rpc_reply)));
-
-	switch (prog) {
-	case PROG_MOUNT:
-		npriv->mount_port = ntohl(port);
-		debug("mount port: %d\n", npriv->mount_port);
-		break;
-	case PROG_NFS:
-		npriv->nfs_port = ntohl(port);
-		debug("nfs port: %d\n", npriv->nfs_port);
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	return 0;
+	port = ntohl(net_read_uint32(nfs_packet + sizeof(struct rpc_reply)));
+	return port;
 }
 
 /*
@@ -1000,16 +986,18 @@ static int nfs_probe(struct device_d *dev)
 	net_udp_bind(npriv->con, 1000);
 
 	ret = rpc_lookup_req(npriv, PROG_MOUNT, 2);
-	if (ret) {
+	if (ret < 0) {
 		printf("lookup mount port failed with %d\n", ret);
 		goto err2;
 	}
+	npriv->mount_port = ret;
 
 	ret = rpc_lookup_req(npriv, PROG_NFS, 2);
-	if (ret) {
+	if (ret < 0) {
 		printf("lookup nfs port failed with %d\n", ret);
 		goto err2;
 	}
+	npriv->nfs_port = ret;
 
 	ret = nfs_mount_req(npriv);
 	if (ret) {
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 06/11] nfs: drop an unneeded variable from nfs_do_open()
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (3 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 05/11] nfs: simplify rpc_lookup_req Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 07/11] net: new function net_read_uint64 Uwe Kleine-König
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

While at it also fix the type of flen holding a string length
(int -> size_t).

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 fs/nfs.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 761bfd626716..79df6a8e4f7a 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -616,7 +616,7 @@ static struct file_priv *nfs_do_open(struct device_d *dev, const char *filename)
 	struct file_priv *priv;
 	struct nfs_priv *npriv = dev->priv;
 	int ret;
-	const char *fname, *tok;
+	const char *tok;
 
 	priv = xzalloc(sizeof(*priv));
 
@@ -629,25 +629,23 @@ static struct file_priv *nfs_do_open(struct device_d *dev, const char *filename)
 
 	filename++;
 
-	fname = filename;
-
 	memcpy(priv->filefh, npriv->rootfh, NFS_FHSIZE);
 
-	while (*fname) {
-		int flen;
+	while (*filename) {
+		size_t flen;
 
-		tok = strchr(fname, '/');
+		tok = strchr(filename, '/');
 		if (tok)
-			flen = tok - fname;
+			flen = tok - filename;
 		else
-			flen = strlen(fname);
+			flen = strlen(filename);
 
-		ret = nfs_lookup_req(priv, fname, flen);
+		ret = nfs_lookup_req(priv, filename, flen);
 		if (ret)
 			goto out;
 
 		if (tok)
-			fname += flen + 1;
+			filename += flen + 1;
 		else
 			break;
 	}
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 07/11] net: new function net_read_uint64
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (4 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 06/11] nfs: drop an unneeded variable from nfs_do_open() Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 08/11] net: provide alternatives to {ntoh, hton}[sl] funtions with cleaner semantics Uwe Kleine-König
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

This is needed for nfs3 support as some types became bigger compared to
nfs2.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 include/net.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/include/net.h b/include/net.h
index 8388e2f12ebe..6c86947d9ca3 100644
--- a/include/net.h
+++ b/include/net.h
@@ -276,6 +276,13 @@ static inline uint32_t net_read_uint32(void *from)
 	return tmp;
 }
 
+static inline uint64_t net_read_uint64(void *from)
+{
+	uint64_t tmp;
+	memcpy(&tmp, from, sizeof(tmp));
+	return tmp;
+}
+
 /* write IP *in network byteorder* */
 static inline void net_write_ip(void *to, IPaddr_t ip)
 {
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 08/11] net: provide alternatives to {ntoh, hton}[sl] funtions with cleaner semantics
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (5 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 07/11] net: new function net_read_uint64 Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 09/11] nfs: switch to nfs3 Uwe Kleine-König
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

ntohl always converts 32 bits even on archs where sizeof(long) == 8.
"ntoh32" is a much more intuitive name here. Also the name of the 64 bit
variant that is also added isn't questionable.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---

Notes:
    new in v2

 include/byteorder.h | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 include/byteorder.h

diff --git a/include/byteorder.h b/include/byteorder.h
new file mode 100644
index 000000000000..4b255a5fab9b
--- /dev/null
+++ b/include/byteorder.h
@@ -0,0 +1,24 @@
+#ifndef __BYTEORDER_H__
+#define __BYTEORDER_H__
+
+/*
+ * The standard macros for converting between host and network byte order are
+ * badly named. So ntohl converts 32 bits even on architectures where a long is
+ * 64 bit wide although the 'l' suffix suggests that it's working on longs.
+ *
+ * So this file introduces variants that use the bitcount as suffix instead of
+ * 's' or 'l'.
+ */
+
+#include <asm/byteorder.h>
+
+#define ntoh16(x)	__be16_to_cpu(x)
+#define hton16(x)	__cpu_to_be16(x)
+
+#define ntoh32(x)	__be32_to_cpu(x)
+#define hton32(x)	__cpu_to_be32(x)
+
+#define ntoh64(x)	__be64_to_cpu(x)
+#define hton64(x)	__cpu_to_be64(x)
+
+#endif /* __BYTEORDER_H__ */
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 09/11] nfs: switch to nfs3
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (6 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 08/11] net: provide alternatives to {ntoh, hton}[sl] funtions with cleaner semantics Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 10/11] mount: support filesystem options passed via -o Uwe Kleine-König
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

This was tested against nfs-kernel-server and unfs3.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---

Notes:
    Changes since implicit v1:
    - fix PROG_MOUNT version to 3
    - add empty line as requested by Jean-Christophe
    - use {hton,ntoh}{16,32,64}

 fs/nfs.c | 894 ++++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 625 insertions(+), 269 deletions(-)

diff --git a/fs/nfs.c b/fs/nfs.c
index 79df6a8e4f7a..ab33c91ef0a9 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -1,10 +1,12 @@
 /*
  * nfs.c - barebox NFS driver
  *
+ * Copyright (c) 2014 Uwe Kleine-König, Pengutronix
  * Copyright (c) 2012 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
  * Copyright (c) Masami Komiya <mkomiya@sonare.it> 2004
  *
- * Based on U-Boot NFS code which is based on NetBSD code
+ * Based on U-Boot NFS code which is based on NetBSD code with
+ * major changes to support nfs3.
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -17,7 +19,6 @@
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- *
  */
 
 #include <common.h>
@@ -33,6 +34,7 @@
 #include <linux/err.h>
 #include <kfifo.h>
 #include <sizes.h>
+#include <byteorder.h>
 
 #define SUNRPC_PORT     111
 
@@ -48,34 +50,54 @@
 #define MOUNT_ADDENTRY	1
 #define MOUNT_UMOUNT	3
 
-#define NFS_GETATTR     1
-#define NFS_LOOKUP      4
-#define NFS_READLINK    5
-#define NFS_READ        6
-#define NFS_READDIR	16
-
-#define NFS_FHSIZE      32
-
-enum nfs_stat {
-	NFS_OK		= 0,
-	NFSERR_PERM	= 1,
-	NFSERR_NOENT	= 2,
-	NFSERR_IO	= 5,
-	NFSERR_NXIO	= 6,
-	NFSERR_ACCES	= 13,
-	NFSERR_EXIST	= 17,
-	NFSERR_NODEV	= 19,
-	NFSERR_NOTDIR	= 20,
-	NFSERR_ISDIR	= 21,
-	NFSERR_FBIG	= 27,
-	NFSERR_NOSPC	= 28,
-	NFSERR_ROFS	= 30,
-	NFSERR_NAMETOOLONG=63,
-	NFSERR_NOTEMPTY	= 66,
-	NFSERR_DQUOT	= 69,
-	NFSERR_STALE	= 70,
-	NFSERR_WFLUSH	= 99,
-};
+#define NFSPROC3_GETATTR	1
+#define NFSPROC3_LOOKUP		3
+#define NFSPROC3_READLINK	5
+#define NFSPROC3_READ		6
+#define NFSPROC3_READDIR	16
+
+#define NFS3_FHSIZE      64
+#define NFS3_COOKIEVERFSIZE	8
+
+/* values of enum ftype3 */
+#define NF3REG	1
+#define NF3DIR	2
+#define NF3BLK	3
+#define NF3CHR	4
+#define NF3LNK	5
+#define NF3SOCK	6
+#define NF3FIFO	7
+
+/* values for enum nfsstat3 */
+#define NFS3_OK			    0
+#define NFS3ERR_PERM		    1
+#define NFS3ERR_NOENT		    2
+#define NFS3ERR_IO   		    5
+#define NFS3ERR_NXIO 		    6
+#define NFS3ERR_ACCES		   13
+#define NFS3ERR_EXIST		   17
+#define NFS3ERR_XDEV		   18
+#define NFS3ERR_NODEV		   19
+#define NFS3ERR_NOTDIR		   20
+#define NFS3ERR_ISDIR		   21
+#define NFS3ERR_INVAL		   22
+#define NFS3ERR_FBIG		   27
+#define NFS3ERR_NOSPC		   28
+#define NFS3ERR_ROFS		   30
+#define NFS3ERR_MLINK		   31
+#define NFS3ERR_NAMETOOLONG	   63
+#define NFS3ERR_NOTEMPTY	   66
+#define NFS3ERR_DQUOT		   69
+#define NFS3ERR_STALE		   70
+#define NFS3ERR_REMOTE		   71
+#define NFS3ERR_BADHANDLE 	10001
+#define NFS3ERR_NOT_SYNC	10002
+#define NFS3ERR_BAD_COOKIE	10003
+#define NFS3ERR_NOTSUPP		10004
+#define NFS3ERR_TOOSMALL	10005
+#define NFS3ERR_SERVERFAULT	10006
+#define NFS3ERR_BADTYPE		10007
+#define NFS3ERR_JUKEBOX		10008
 
 static void *nfs_packet;
 static int nfs_len;
@@ -107,51 +129,96 @@ struct nfs_priv {
 	struct net_connection *con;
 	IPaddr_t server;
 	char *path;
-	int mount_port;
-	int nfs_port;
-	unsigned long rpc_id;
-	char rootfh[NFS_FHSIZE];
+	unsigned short mount_port;
+	unsigned short nfs_port;
+	uint32_t rpc_id;
+	uint32_t rootfh_len;
+	char rootfh[NFS3_FHSIZE];
 };
 
 struct file_priv {
 	struct kfifo *fifo;
 	void *buf;
-	char filefh[NFS_FHSIZE];
+	uint32_t filefh_len;
+	char filefh[NFS3_FHSIZE];
 	struct nfs_priv *npriv;
 };
 
 static uint64_t nfs_timer_start;
 
-static int	nfs_state;
+static int nfs_state;
 #define STATE_DONE			1
 #define STATE_START			2
 
-enum ftype {
-	NFNON = 0,
-	NFREG = 1,
-	NFDIR = 2,
-	NFBLK = 3,
-	NFCHR = 4,
-	NFLNK = 5
-};
-
-struct fattr {
-	uint32_t type;
-	uint32_t mode;
-	uint32_t nlink;
-	uint32_t uid;
-	uint32_t gid;
-	uint32_t size;
-	uint32_t blocksize;
-	uint32_t rdev;
-	uint32_t blocks;
-};
-
-struct readdirargs {
-	char filefh[NFS_FHSIZE];
-	uint32_t cookie;
-	uint32_t count;
-};
+/*
+ * common types used in more than one request:
+ *
+ * typedef uint32 count3;
+ * typedef uint32 gid3;
+ * typedef uint32 mode3;
+ * typedef uint32 uid3;
+ *
+ * typedef uint64 cookie3;
+ * typedef uint64 fileid3;
+ * typedef uint64 size3;
+ *
+ * typedef string filename3<>;
+ * typedef string nfspath3<>;
+ *
+ * typedef opaque cookieverf3[NFS3_COOKIEVERFSIZE];
+ *
+ * enum ftype3 {
+ * 	NF3REG = 1,
+ * 	NF3DIR = 2,
+ * 	NF3BLK = 3,
+ * 	NF3CHR = 4,
+ * 	NF3LNK = 5,
+ * 	NF3SOCK = 6,
+ * 	NF3FIFO = 7
+ * };
+ *
+ * struct specdata3 {
+ * 	uint32 specdata1;
+ * 	uint32 specdata2;
+ * };
+ *
+ * struct nfs_fh3 {
+ * 	opaque data<NFS3_FHSIZE>;
+ * }
+ *
+ * struct nfstime3 {
+ * 	uint32 seconds;
+ * 	uint32 nseconds;
+ * };
+ *
+ * struct fattr3 {
+ * 	ftype3 type;
+ * 	mode3 mode;
+ * 	uint32_t nlink;
+ * 	uid3 uid;
+ * 	gid3 gid;
+ * 	size3 size;
+ * 	size3 used;
+ * 	specdata3 rdev;
+ * 	uint64_t fsid;
+ * 	fileid3 fileid;
+ * 	nfstime3 atime;
+ * 	nfstime3 mtime;
+ * 	nfstime3 ctime;
+ * };
+ *
+ * struct diropargs3 {
+ * 	nfs_fh3 dir;
+ * 	filename3 name;
+ * }
+ *
+ * union post_op_attr switch (bool attributes_follow) {
+ * case TRUE:
+ * 	fattr3 attributes;
+ * case FALSE:
+ * 	void;
+ * };
+ */
 
 struct xdr_stream {
 	__be32 *p;
@@ -162,6 +229,20 @@ struct xdr_stream {
 #define xdr_zero 0
 #define XDR_QUADLEN(l)		(((l) + 3) >> 2)
 
+struct nfs_dir {
+	DIR dir;
+
+	/*
+	 * stream points to the next entry3 in the reply member of READDIR3res
+	 * (if any, to the end indicator otherwise).
+	 */
+	struct xdr_stream stream;
+	struct dirent ent;
+	struct file_priv *priv;
+	uint64_t cookie;
+	char cookieverf[NFS3_COOKIEVERFSIZE];
+};
+
 static void xdr_init(struct xdr_stream *stream, void *buf, int len)
 {
 	stream->p = stream->buf = buf;
@@ -192,8 +273,10 @@ static __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
 	return p;
 }
 
-static int decode_filename(struct xdr_stream *xdr,
-		char *name, u32 *length)
+/*
+ * name is expected to point to a buffer with a size of at least 256 bytes.
+ */
+static int decode_filename(struct xdr_stream *xdr, char *name, u32 *length)
 {
 	__be32 *p;
 	u32 count;
@@ -201,7 +284,7 @@ static int decode_filename(struct xdr_stream *xdr,
 	p = xdr_inline_decode(xdr, 4);
 	if (!p)
 		goto out_overflow;
-	count = be32_to_cpup(p);
+	count = ntoh32(net_read_uint32(p));
 	if (count > 255)
 		goto out_nametoolong;
 	p = xdr_inline_decode(xdr, count);
@@ -211,11 +294,13 @@ static int decode_filename(struct xdr_stream *xdr,
 	name[count] = 0;
 	*length = count;
 	return 0;
+
 out_nametoolong:
-	printk("NFS: returned filename too long: %u\n", count);
+	printf("%s: returned a too long filename: %u\n", __func__, count);
 	return -ENAMETOOLONG;
+
 out_overflow:
-	printf("%s overflow\n",__func__);
+	printf("%s: premature end of packet\n", __func__);
 	return -EIO;
 }
 
@@ -230,10 +315,10 @@ static uint32_t *rpc_add_credentials(uint32_t *p)
 	 */
 
 	/* Provide an AUTH_UNIX credential.  */
-	*p++ = htonl(1);		/* AUTH_UNIX */
-	*p++ = htonl(20);		/* auth length: 20 + strlen(hostname) */
-	*p++ = htonl(0);		/* stamp */
-	*p++ = htonl(0);		/* hostname string length */
+	*p++ = hton32(1);		/* AUTH_UNIX */
+	*p++ = hton32(20);		/* auth length: 20 + strlen(hostname) */
+	*p++ = hton32(0);		/* stamp */
+	*p++ = hton32(0);		/* hostname string length */
 	/* memcpy(p, "", 0); p += 0; <- empty host name */
 
 	*p++ = 0;			/* uid */
@@ -247,7 +332,8 @@ static uint32_t *rpc_add_credentials(uint32_t *p)
 	return p;
 }
 
-static int rpc_check_reply(unsigned char *pkt, int rpc_prog, unsigned long rpc_id, int *nfserr)
+static int rpc_check_reply(unsigned char *pkt,
+		int rpc_prog, uint32_t rpc_id, int *nfserr)
 {
 	uint32_t *data;
 	struct rpc_reply rpc;
@@ -259,8 +345,8 @@ static int rpc_check_reply(unsigned char *pkt, int rpc_prog, unsigned long rpc_i
 
 	memcpy(&rpc, pkt, sizeof(rpc));
 
-	if (ntohl(rpc.id) != rpc_id) {
-		if (rpc_id - ntohl(rpc.id) == 1)
+	if (ntoh32(rpc.id) != rpc_id) {
+		if (rpc_id - ntoh32(rpc.id) == 1)
 			/* stale packet, wait a bit longer */
 			return 0;
 
@@ -277,7 +363,7 @@ static int rpc_check_reply(unsigned char *pkt, int rpc_prog, unsigned long rpc_i
 		return 0;
 
 	data = (uint32_t *)(pkt + sizeof(struct rpc_reply));
-	*nfserr = ntohl(net_read_uint32(data));
+	*nfserr = ntoh32(net_read_uint32(data));
 	*nfserr = -*nfserr;
 
 	debug("%s: state: %d, err %d\n", __func__, nfs_state, *nfserr);
@@ -292,37 +378,41 @@ static int rpc_req(struct nfs_priv *npriv, int rpc_prog, int rpc_proc,
 		uint32_t *data, int datalen)
 {
 	struct rpc_call pkt;
-	unsigned long id;
-	int dport;
+	unsigned short dport;
 	int ret;
 	unsigned char *payload = net_udp_get_payload(npriv->con);
 	int nfserr;
 	int tries = 0;
 
 	npriv->rpc_id++;
-	id = npriv->rpc_id;
 
-	pkt.id = htonl(id);
-	pkt.type = htonl(MSG_CALL);
-	pkt.rpcvers = htonl(2);	/* use RPC version 2 */
-	pkt.prog = htonl(rpc_prog);
-	pkt.vers = htonl(2);	/* portmapper is version 2 */
-	pkt.proc = htonl(rpc_proc);
+	pkt.id = hton32(npriv->rpc_id);
+	pkt.type = hton32(MSG_CALL);
+	pkt.rpcvers = hton32(2);	/* use RPC version 2 */
+	pkt.prog = hton32(rpc_prog);
+	pkt.proc = hton32(rpc_proc);
 
-	memcpy(payload, &pkt, sizeof(pkt));
-	memcpy(payload + sizeof(pkt), data, datalen * sizeof(uint32_t));
+	debug("%s: prog: %d, proc: %d\n", __func__, rpc_prog, rpc_proc);
 
-	if (rpc_prog == PROG_PORTMAP)
+	if (rpc_prog == PROG_PORTMAP) {
 		dport = SUNRPC_PORT;
-	else if (rpc_prog == PROG_MOUNT)
+		pkt.vers = hton32(2);
+	} else if (rpc_prog == PROG_MOUNT) {
 		dport = npriv->mount_port;
-	else
+		pkt.vers = hton32(3);
+	} else {
 		dport = npriv->nfs_port;
+		pkt.vers = hton32(3);
+	}
+
+	memcpy(payload, &pkt, sizeof(pkt));
+	memcpy(payload + sizeof(pkt), data, datalen * sizeof(uint32_t));
 
-	npriv->con->udp->uh_dport = htons(dport);
+	npriv->con->udp->uh_dport = hton16(dport);
 
 again:
-	ret = net_udp_send(npriv->con, sizeof(pkt) + datalen * sizeof(uint32_t));
+	ret = net_udp_send(npriv->con,
+			sizeof(pkt) + datalen * sizeof(uint32_t));
 
 	nfs_timer_start = get_time_ns();
 
@@ -357,7 +447,7 @@ again:
 /*
  * rpc_lookup_req - Lookup RPC Port numbers
  */
-static int rpc_lookup_req(struct nfs_priv *npriv, int prog, int ver)
+static int rpc_lookup_req(struct nfs_priv *npriv, uint32_t prog, uint32_t ver)
 {
 	uint32_t data[16];
 	int ret;
@@ -365,19 +455,149 @@ static int rpc_lookup_req(struct nfs_priv *npriv, int prog, int ver)
 
 	data[0] = 0; data[1] = 0;	/* auth credential */
 	data[2] = 0; data[3] = 0;	/* auth verifier */
-	data[4] = htonl(prog);
-	data[5] = htonl(ver);
-	data[6] = htonl(17);	/* IP_UDP */
+	data[4] = hton32(prog);
+	data[5] = hton32(ver);
+	data[6] = hton32(17);	/* IP_UDP */
 	data[7] = 0;
 
 	ret = rpc_req(npriv, PROG_PORTMAP, PORTMAP_GETPORT, data, 8);
 	if (ret)
 		return ret;
 
-	port = ntohl(net_read_uint32(nfs_packet + sizeof(struct rpc_reply)));
+	port = ntoh32(net_read_uint32(nfs_packet + sizeof(struct rpc_reply)));
 	return port;
 }
 
+static uint32_t *nfs_add_uint32(uint32_t *p, uint32_t val)
+{
+	*p++ = hton32(val);
+	return p;
+}
+
+static uint32_t *nfs_add_uint64(uint32_t *p, uint64_t val)
+{
+	uint64_t nval = hton64(val);
+
+	memcpy(p, &nval, 8);
+	return p + 2;
+}
+
+static uint32_t *nfs_add_fh3(uint32_t *p, unsigned fh_len, const char *fh)
+{
+	*p++ = hton32(fh_len);
+
+	/* zero padding */
+	if (fh_len & 3)
+		p[fh_len / 4] = 0;
+
+	memcpy(p, fh, fh_len);
+	p += DIV_ROUND_UP(fh_len, 4);
+	return p;
+}
+
+static uint32_t *nfs_add_filename(uint32_t *p,
+		uint32_t filename_len, const char *filename)
+{
+	*p++ = hton32(filename_len);
+
+	/* zero padding */
+	if (filename_len & 3)
+		p[filename_len / 4] = 0;
+
+	memcpy(p, filename, filename_len);
+	p += DIV_ROUND_UP(filename_len, 4);
+	return p;
+}
+
+/* This is a 1:1 mapping for Linux, the compiler optimizes it out */
+static const struct {
+	uint32_t nfsmode;
+	unsigned short statmode;
+} nfs3_mode_bits[] = {
+	{ 0x00001, S_IXOTH },
+	{ 0x00002, S_IWOTH },
+	{ 0x00004, S_IROTH },
+	{ 0x00008, S_IXGRP },
+	{ 0x00010, S_IWGRP },
+	{ 0x00020, S_IRGRP },
+	{ 0x00040, S_IXUSR },
+	{ 0x00080, S_IWUSR },
+	{ 0x00100, S_IRUSR },
+	{ 0x00200, S_ISVTX },
+	{ 0x00400, S_ISGID },
+	{ 0x00800, S_ISUID },
+};
+
+static int nfs_fattr3_to_stat(uint32_t *p, struct stat *s)
+{
+	uint32_t mode;
+	size_t i;
+
+	/* offsetof(struct fattr3, type) = 0 */
+	switch (ntoh32(net_read_uint32(p + 0))) {
+	case NF3REG:
+		s->st_mode = S_IFREG;
+		break;
+	case NF3DIR:
+		s->st_mode = S_IFDIR;
+		break;
+	case NF3BLK:
+		s->st_mode = S_IFBLK;
+		break;
+	case NF3CHR:
+		s->st_mode = S_IFCHR;
+		break;
+	case NF3LNK:
+		s->st_mode = S_IFLNK;
+		break;
+	case NF3SOCK:
+		s->st_mode = S_IFSOCK;
+		break;
+	case NF3FIFO:
+		s->st_mode = S_IFIFO;
+		break;
+	default:
+		printf("%s: invalid mode %x\n",
+				__func__, ntoh32(net_read_uint32(p + 0)));
+		return -EIO;
+	}
+
+	/* offsetof(struct fattr3, mode) = 4 */
+	mode = ntoh32(net_read_uint32(p + 1));
+	for (i = 0; i < ARRAY_SIZE(nfs3_mode_bits); ++i) {
+		if (mode & nfs3_mode_bits[i].nfsmode)
+			s->st_mode |= nfs3_mode_bits[i].statmode;
+	}
+
+	/* offsetof(struct fattr3, size) = 20 */
+	s->st_size = ntoh64(net_read_uint64(p + 5));
+
+	return 0;
+}
+
+static uint32_t *nfs_read_post_op_attr(uint32_t *p, struct stat **s)
+{
+	struct stat dummy;
+	/*
+	 * union post_op_attr switch (bool attributes_follow) {
+	 * case TRUE:
+	 * 	fattr3 attributes;
+	 * case FALSE:
+	 * 	void;
+	 * };
+	 */
+
+	if (ntoh32(net_read_uint32(p++))) {
+		nfs_fattr3_to_stat(p, s ? *s : &dummy);
+		p += 21;
+	} else if (s) {
+		/* no attributes available */
+		*s = NULL;
+	}
+
+	return p;
+}
+
 /*
  * nfs_mount_req - Mount an NFS Filesystem
  */
@@ -396,7 +616,7 @@ static int nfs_mount_req(struct nfs_priv *npriv)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	*p++ = htonl(pathlen);
+	*p++ = hton32(pathlen);
 	if (pathlen & 3)
 		*(p + pathlen / 4) = 0;
 
@@ -409,7 +629,16 @@ static int nfs_mount_req(struct nfs_priv *npriv)
 	if (ret)
 		return ret;
 
-	memcpy(npriv->rootfh, nfs_packet + sizeof(struct rpc_reply) + 4, NFS_FHSIZE);
+	p = nfs_packet + sizeof(struct rpc_reply) + 4;
+
+	npriv->rootfh_len = ntoh32(net_read_uint32(p++));
+	if (npriv->rootfh_len > NFS3_FHSIZE) {
+		printf("%s: file handle too big: %lu\n", __func__,
+				(unsigned long)npriv->rootfh_len);
+		return -EIO;
+	}
+	memcpy(npriv->rootfh, p, npriv->rootfh_len);
+	p += DIV_ROUND_UP(npriv->rootfh_len, 4);
 
 	return 0;
 }
@@ -429,12 +658,7 @@ static void nfs_umount_req(struct nfs_priv *npriv)
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	*p++ = htonl(pathlen);
-	if (pathlen & 3)
-		*(p + pathlen / 4) = 0;
-
-	memcpy (p, npriv->path, pathlen);
-	p += (pathlen + 3) / 4;
+	p = nfs_add_filename(p, pathlen, npriv->path);
 
 	len = p - &(data[0]);
 
@@ -443,36 +667,68 @@ static void nfs_umount_req(struct nfs_priv *npriv)
 
 /*
  * nfs_lookup_req - Lookup Pathname
+ *
+ * *s is set to NULL if LOOKUP3resok doesn't contain obj_attributes.
  */
-static int nfs_lookup_req(struct file_priv *priv, const char *filename,
-		int fnamelen)
+static int nfs_lookup_req(struct file_priv *priv,
+		uint32_t filename_len, const char *filename, struct stat **s)
 {
 	uint32_t data[1024];
 	uint32_t *p;
 	int len;
 	int ret;
 
+	/*
+	 * struct LOOKUP3args {
+	 * 	diropargs3 what;
+	 * };
+	 *
+	 * struct LOOKUP3resok {
+	 * 	nfs_fh3 object;
+	 * 	post_op_attr obj_attributes;
+	 * 	post_op_attr dir_attributes;
+	 * };
+	 *
+	 * struct LOOKUP3resfail {
+	 * 	post_op_attr dir_attributes;
+	 * };
+	 *
+	 * union LOOKUP3res switch (nfsstat3 status) {
+	 * case NFS3_OK:
+	 * 	LOOKUP3resok resok;
+	 * default:
+	 * 	LOOKUP3resfail resfail;
+	 * };
+	 */
+
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, priv->filefh, NFS_FHSIZE);
-
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(fnamelen);
+	/* what.dir */
+	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
 
-	if (fnamelen & 3)
-		*(p + fnamelen / 4) = 0;
-
-	memcpy(p, filename, fnamelen);
-	p += (fnamelen + 3) / 4;
+	/* what.name */
+	p = nfs_add_filename(p, filename_len, filename);
 
 	len = p - &(data[0]);
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFS_LOOKUP, data, len);
+	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_LOOKUP, data, len);
 	if (ret)
 		return ret;
 
-	memcpy(priv->filefh, nfs_packet + sizeof(struct rpc_reply) + 4, NFS_FHSIZE);
+	p = nfs_packet + sizeof(struct rpc_reply) + 4;
+
+	priv->filefh_len = ntoh32(net_read_uint32(p++));
+	if (priv->filefh_len > NFS3_FHSIZE) {
+		debug("%s: file handle too big: %lu\n", __func__,
+				(unsigned long)priv->filefh_len);
+		return -EIO;
+	}
+	memcpy(priv->filefh, p, priv->filefh_len);
+	p += DIV_ROUND_UP(priv->filefh_len, 4);
+
+	if (s)
+		nfs_read_post_op_attr(p, s);
 
 	return 0;
 }
@@ -483,33 +739,48 @@ static int nfs_attr_req(struct file_priv *priv, struct stat *s)
 	uint32_t *p;
 	int len;
 	int ret;
-	struct fattr *fattr;
-	uint32_t type;
+
+	/*
+	 * struct GETATTR3args {
+	 * 	nfs_fh3 object;
+	 * }
+	 *
+	 * struct GETATTR3resok {
+	 * 	fattr3 obj_attributes;
+	 * };
+	 *
+	 * union GETATTR3res switch (nfsstat3 status) {
+	 * case NFS3_OK:
+	 * 	GETATTR3resok resok;
+	 * default:
+	 * 	void;
+	 * }
+	 */
 
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, priv->filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = 0;
+	/* object */
+	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
 
 	len = p - &(data[0]);
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFS_GETATTR, data, len);
+	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_GETATTR, data, len);
 	if (ret)
 		return ret;
 
-	fattr = nfs_packet + sizeof(struct rpc_reply) + 4;
-
-	type = ntohl(net_read_uint32(&fattr->type));
+	p = nfs_packet + sizeof(struct rpc_reply) + 4;
 
-	s->st_size = ntohl(net_read_uint32(&fattr->size));
-	s->st_mode = ntohl(net_read_uint32(&fattr->mode));
+	nfs_fattr3_to_stat(p, s);
 
 	return 0;
 }
 
-static void *nfs_readdirattr_req(struct file_priv *priv, int *plen, uint32_t cookie)
+/*
+ * returns with dir->stream pointing to the first entry
+ * of dirlist3 res.resok.reply
+ */
+static void *nfs_readdirattr_req(struct file_priv *priv, struct nfs_dir *dir)
 {
 	uint32_t data[1024];
 	uint32_t *p;
@@ -517,26 +788,79 @@ static void *nfs_readdirattr_req(struct file_priv *priv, int *plen, uint32_t coo
 	int ret;
 	void *buf;
 
+	/*
+	 * struct READDIR3args {
+	 * 	nfs_fh3 dir;
+	 * 	cookie3 cookie;
+	 * 	cookieverf3 cookieverf;
+	 * 	count3 count;
+	 * };
+	 *
+	 * struct entry3 {
+	 * 	fileid3 fileid;
+	 * 	filename3 name;
+	 * 	cookie3 cookie;
+	 * 	entry3 *nextentry;
+	 * };
+	 *
+	 * struct dirlist3 {
+	 * 	entry3 *entries;
+	 * 	bool eof;
+	 * };
+	 *
+	 * struct READDIR3resok {
+	 * 	post_op_attr dir_attributes;
+	 * 	cookieverf3 cookieverf;
+	 * 	dirlist3 reply;
+	 * };
+	 *
+	 * struct READDIR3resfail {
+	 * 	post_op_attr dir_attributes;
+	 * };
+	 *
+	 * union READDIR3res switch (nfsstat3 status) {
+	 * case NFS3_OK:
+	 * 	READDIR3resok resok;
+	 * default:
+	 * 	READDIR3resfail resfail;
+	 * };
+	 */
+
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, priv->filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(cookie); /* cookie */
-	*p++ = htonl(1024); /* count */
-	*p++ = 0;
+	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+	p = nfs_add_uint64(p, dir->cookie);
 
-	len = p - &(data[0]);
+	memcpy(p, dir->cookieverf, NFS3_COOKIEVERFSIZE);
+	p += NFS3_COOKIEVERFSIZE / 4;
+
+	p = nfs_add_uint32(p, 1024); /* count */
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFS_READDIR, data, len);
+	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READDIR, data, p - data);
 	if (ret)
 		return NULL;
 
-	*plen = nfs_len - sizeof(struct rpc_reply) + 4;
+	p = nfs_packet + sizeof(struct rpc_reply) + 4;
+	p = nfs_read_post_op_attr(p, NULL);
 
-	buf = xzalloc(*plen);
+	/* update cookieverf */
+	memcpy(dir->cookieverf, p, NFS3_COOKIEVERFSIZE);
+	p += NFS3_COOKIEVERFSIZE / 4;
 
-	memcpy(buf, nfs_packet + sizeof(struct rpc_reply) + 4, *plen);
+	len = nfs_packet + nfs_len - (void *)p;
+	if (!len) {
+		printf("%s: huh, no payload left\n", __func__);
+		return NULL;
+	}
+
+	buf = xzalloc(len);
+
+	memcpy(buf, p, len);
+
+	xdr_init(&dir->stream, buf, len);
+
+	/* now xdr points to dirlist3 res.resok.reply */
 
 	return buf;
 }
@@ -544,35 +868,74 @@ static void *nfs_readdirattr_req(struct file_priv *priv, int *plen, uint32_t coo
 /*
  * nfs_read_req - Read File on NFS Server
  */
-static int nfs_read_req(struct file_priv *priv, int offset, int readlen)
+static int nfs_read_req(struct file_priv *priv, uint64_t offset,
+		uint32_t readlen)
 {
 	uint32_t data[1024];
 	uint32_t *p;
-	uint32_t *filedata;
 	int len;
 	int ret;
-	int rlen;
+	uint32_t rlen, eof;
 
+	/*
+	 * struct READ3args {
+	 * 	nfs_fh3 file;
+	 * 	offset3 offset;
+	 * 	count3 count;
+	 * };
+	 *
+	 * struct READ3resok {
+	 * 	post_op_attr file_attributes;
+	 * 	count3 count;
+	 * 	bool eof;
+	 * 	opaque data<>;
+	 * };
+	 *
+	 * struct READ3resfail {
+	 * 	post_op_attr file_attributes;
+	 * };
+	 *
+	 * union READ3res switch (nfsstat3 status) {
+	 * case NFS3_OK:
+	 * 	READ3resok resok;
+	 * default:
+	 * 	READ3resfail resfail;
+	 * };
+	 */
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy (p, priv->filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
-	*p++ = htonl(offset);
-	*p++ = htonl(readlen);
-	*p++ = 0;
+	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
+	p = nfs_add_uint64(p, offset);
+	p = nfs_add_uint32(p, readlen);
 
 	len = p - &(data[0]);
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFS_READ, data, len);
+	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READ, data, len);
 	if (ret)
 		return ret;
 
-	filedata = (uint32_t *)(nfs_packet + sizeof(struct rpc_reply));
+	p = nfs_packet + sizeof(struct rpc_reply) + 4;
+
+	p = nfs_read_post_op_attr(p, NULL);
+
+	rlen = ntoh32(net_read_uint32(p));
+
+	/* skip over count */
+	p += 1;
 
-	rlen = ntohl(net_read_uint32(filedata + 18));
+	eof = ntoh32(net_read_uint32(p));
 
-	kfifo_put(priv->fifo, (char *)(filedata + 19), rlen);
+	/*
+	 * skip over eof and count embedded in the representation of data
+	 * assuming it equals rlen above.
+	 */
+	p += 2;
+
+	if (readlen && !rlen && !eof)
+		return -EIO;
+
+	kfifo_put(priv->fifo, (char *)p, rlen);
 
 	return 0;
 }
@@ -611,25 +974,29 @@ static int nfs_truncate(struct device_d *dev, FILE *f, ulong size)
 	return -ENOSYS;
 }
 
-static struct file_priv *nfs_do_open(struct device_d *dev, const char *filename)
+static struct file_priv *nfs_do_open(struct device_d *dev,
+		const char *filename, struct stat **s)
 {
 	struct file_priv *priv;
 	struct nfs_priv *npriv = dev->priv;
 	int ret;
 	const char *tok;
 
+	debug("%s: filename = %s\n", __func__, filename);
 	priv = xzalloc(sizeof(*priv));
 
 	priv->npriv = npriv;
 
 	if (!*filename) {
-		memcpy(priv->filefh, npriv->rootfh, NFS_FHSIZE);
+		priv->filefh_len = npriv->rootfh_len;
+		memcpy(priv->filefh, npriv->rootfh, npriv->rootfh_len);
 		return priv;
 	}
 
 	filename++;
 
-	memcpy(priv->filefh, npriv->rootfh, NFS_FHSIZE);
+	priv->filefh_len = npriv->rootfh_len;
+	memcpy(priv->filefh, npriv->rootfh, NFS3_FHSIZE);
 
 	while (*filename) {
 		size_t flen;
@@ -640,7 +1007,7 @@ static struct file_priv *nfs_do_open(struct device_d *dev, const char *filename)
 		else
 			flen = strlen(filename);
 
-		ret = nfs_lookup_req(priv, filename, flen);
+		ret = nfs_lookup_req(priv, flen, filename, s);
 		if (ret)
 			goto out;
 
@@ -666,19 +1033,28 @@ static void nfs_do_close(struct file_priv *priv)
 	free(priv);
 }
 
-static struct file_priv *nfs_do_stat(struct device_d *dev, const char *filename, struct stat *s)
+static struct file_priv *nfs_do_stat(struct device_d *dev,
+		const char *filename, struct stat *s)
 {
 	struct file_priv *priv;
 	int ret;
+	struct stat **sptr = &s;
 
-	priv = nfs_do_open(dev, filename);
+	debug("%s: filename = %s\n", __func__, filename);
+	priv = nfs_do_open(dev, filename, sptr);
 	if (IS_ERR(priv))
 		return priv;
 
-	ret = nfs_attr_req(priv, s);
-	if (ret) {
-		nfs_do_close(priv);
-		return ERR_PTR(ret);
+	if (!*sptr) {
+		/*
+		 * The nfs server didn't provide obj_attributes in the lookup
+		 * reply, so ask for them explicitly.
+		 */
+		ret = nfs_attr_req(priv, s);
+		if (ret) {
+			nfs_do_close(priv);
+			return ERR_PTR(ret);
+		}
 	}
 
 	return priv;
@@ -688,35 +1064,52 @@ static int nfs_readlink_req(struct file_priv *priv, char* buf, size_t size)
 {
 	uint32_t data[1024];
 	uint32_t *p;
-	int len;
+	uint32_t len;
 	int ret;
-	char *path;
-	uint32_t *filedata;
 
+	/*
+	 * struct READLINK3args {
+	 * 	nfs_fh3 symlink;
+	 * };
+	 *
+	 * struct READLINK3resok {
+	 * 	post_op_attr symlink_attributes;
+	 * 	nfspath3 data;
+	 * };
+	 *
+	 * struct READLINK3resfail {
+	 * 	post_op_attr symlink_attributes;
+	 * }
+	 *
+	 * union READLINK3res switch (nfsstat3 status) {
+	 * case NFS3_OK:
+	 * 	READLINK3resok resok;
+	 * default:
+	 * 	READLINK3resfail resfail;
+	 * };
+	 */
 	p = &(data[0]);
 	p = rpc_add_credentials(p);
 
-	memcpy(p, priv->filefh, NFS_FHSIZE);
-	p += (NFS_FHSIZE / 4);
+	p = nfs_add_fh3(p, priv->filefh_len, priv->filefh);
 
 	len = p - &(data[0]);
 
-	ret = rpc_req(priv->npriv, PROG_NFS, NFS_READLINK, data, len);
+	ret = rpc_req(priv->npriv, PROG_NFS, NFSPROC3_READLINK, data, len);
 	if (ret)
 		return ret;
 
-	filedata = nfs_packet + sizeof(struct rpc_reply);
-	filedata++;
+	p = nfs_packet + sizeof(struct rpc_reply) + 4;
 
-	len = ntohl(net_read_uint32(filedata)); /* new path length */
-	filedata++;
+	p = nfs_read_post_op_attr(p, NULL);
 
-	path = (char *)filedata;
+	len = ntoh32(net_read_uint32(p)); /* new path length */
+	p++;
 
 	if (len > size)
-		len = size;
+		return -ENOMEM;
 
-	memcpy(buf, path, len);
+	memcpy(buf, p, len);
 
 	return 0;
 }
@@ -726,9 +1119,8 @@ static int nfs_readlink(struct device_d *dev, const char *filename,
 {
 	struct file_priv *priv;
 	int ret;
-	struct stat s;
 
-	priv = nfs_do_stat(dev, filename, &s);
+	priv = nfs_do_open(dev, filename, NULL);
 	if (IS_ERR(priv))
 		return PTR_ERR(priv);
 
@@ -780,32 +1172,17 @@ static int nfs_write(struct device_d *_dev, FILE *file, const void *inbuf,
 static int nfs_read(struct device_d *dev, FILE *file, void *buf, size_t insize)
 {
 	struct file_priv *priv = file->inode;
-	int now, outsize = 0, ret, pos = file->pos;
-
-	while (insize) {
-		now = kfifo_get(priv->fifo, buf, insize);
-		outsize += now;
-		buf += now;
-		insize -= now;
-
-		if (insize) {
-			/* do not use min as insize is a size_t */
-			if (insize < 1024)
-				now = insize;
-			else
-				now = 1024;
-
-			if (pos + now > file->size)
-				now = file->size - pos;
-
-			ret = nfs_read_req(priv, pos, now);
-			if (ret)
-				return ret;
-			pos += now;
-		}
+
+	if (insize > 1024)
+		insize = 1024;
+
+	if (insize && !kfifo_len(priv->fifo)) {
+		int ret = nfs_read_req(priv, file->pos, insize);
+		if (ret)
+			return ret;
 	}
 
-	return outsize;
+	return kfifo_get(priv->fifo, buf, insize);
 }
 
 static loff_t nfs_lseek(struct device_d *dev, FILE *file, loff_t pos)
@@ -818,110 +1195,89 @@ static loff_t nfs_lseek(struct device_d *dev, FILE *file, loff_t pos)
 	return file->pos;
 }
 
-struct nfs_dir {
-	DIR dir;
-	struct xdr_stream stream;
-	struct dirent ent;
-	struct file_priv *priv;
-	uint32_t cookie;
-};
-
 static DIR *nfs_opendir(struct device_d *dev, const char *pathname)
 {
 	struct file_priv *priv;
-	struct stat s;
-	int ret;
-	void *buf;
+	void *buf = NULL;
 	struct nfs_dir *dir;
-	int len;
 
-	priv = nfs_do_open(dev, pathname);
+	priv = nfs_do_open(dev, pathname, NULL);
 	if (IS_ERR(priv))
 		return NULL;
 
-	ret = nfs_attr_req(priv, &s);
-	if (ret)
-		return NULL;
-
-	if (!S_ISDIR(s.st_mode))
-		return NULL;
-
 	dir = xzalloc(sizeof(*dir));
 	dir->priv = priv;
 
-	buf = nfs_readdirattr_req(priv, &len, 0);
-	if (!buf)
-		return NULL;
-
-	xdr_init(&dir->stream, buf, len);
+	/* cookie == 0 and cookieverf == 0 means start of dir */
+	buf = nfs_readdirattr_req(priv, dir);
+	if (!buf) {
+		debug("%s: nfs_readdirattr_req failed\n", __func__);
+		goto err;
+	}
 
 	return &dir->dir;
+
+err:
+	free(buf);
+	free(dir);
+	nfs_do_close(priv);
+	return NULL;
 }
 
 static struct dirent *nfs_readdir(struct device_d *dev, DIR *dir)
 {
-	struct nfs_dir *ndir = (void *)dir;
-	__be32 *p;
+	struct nfs_dir *ndir = container_of(dir, struct nfs_dir, dir);
+	uint32_t *p;
 	int ret;
 	int len;
 	struct xdr_stream *xdr = &ndir->stream;
 
 again:
 	p = xdr_inline_decode(xdr, 4);
-	if (!p)
-		goto out_overflow;
+	if (!p) {
+		printf("%s: premature end of packet\n", __func__);
+		return NULL;
+	}
 
-	if (*p++ == xdr_zero) {
+	if (!net_read_uint32(p)) {
+		/* eof? */
 		p = xdr_inline_decode(xdr, 4);
-		if (!p)
-			goto out_overflow;
-		if (*p++ == xdr_zero) {
-			void *buf;
-			int len;
-
-			/*
-			 * End of current entries, read next chunk.
-			 */
+		if (!p) {
+			printf("%s: premature end of packet\n", __func__);
+			return NULL;
+		}
+		if (net_read_uint32(p))
+			return NULL;
 
-			free(ndir->stream.buf);
+		if (!nfs_readdirattr_req(ndir->priv, ndir)) {
+			printf("%s: nfs_readdirattr_req failed\n", __func__);
+			return NULL;
+		}
 
-			buf = nfs_readdirattr_req(ndir->priv, &len, ndir->cookie);
-			if (!buf)
-				return NULL;
+		goto again;
+	}
 
-			xdr_init(&ndir->stream, buf, len);
+	/* there is another entry available in the last reply */
 
-			goto again;
-		}
-		return NULL; /* -EINVAL */
+	/* skip over fileid */
+	p = xdr_inline_decode(xdr, 8);
+	if (!p) {
+		printf("%s: premature end of packet\n", __func__);
+		return NULL;
 	}
 
-	p = xdr_inline_decode(xdr, 4);
-	if (!p)
-		goto out_overflow;
-
 	ret = decode_filename(xdr, ndir->ent.d_name, &len);
 	if (ret)
 		return NULL;
 
-	/*
-	 * The type (size and byte order) of nfscookie isn't defined in
-	 * RFC 1094.  This implementation assumes that it's an XDR uint32.
-	 */
-	p = xdr_inline_decode(xdr, 4);
-	if (!p)
-		goto out_overflow;
-
-	ndir->cookie = be32_to_cpup(p);
+	p = xdr_inline_decode(xdr, 8);
+	if (!p) {
+		printf("%s: premature end of packet\n", __func__);
+		return NULL;
+	}
+	ndir->cookie = ntoh64(net_read_uint64(p));
 
 	return &ndir->ent;
-
-out_overflow:
-
-	printf("nfs: overflow error\n");
-
-	return NULL;
-
 }
 
 static int nfs_closedir(struct device_d *dev, DIR *dir)
@@ -983,14 +1339,14 @@ static int nfs_probe(struct device_d *dev)
 	/* Need a priviliged source port */
 	net_udp_bind(npriv->con, 1000);
 
-	ret = rpc_lookup_req(npriv, PROG_MOUNT, 2);
+	ret = rpc_lookup_req(npriv, PROG_MOUNT, 3);
 	if (ret < 0) {
 		printf("lookup mount port failed with %d\n", ret);
 		goto err2;
 	}
 	npriv->mount_port = ret;
 
-	ret = rpc_lookup_req(npriv, PROG_NFS, 2);
+	ret = rpc_lookup_req(npriv, PROG_NFS, 3);
 	if (ret < 0) {
 		printf("lookup nfs port failed with %d\n", ret);
 		goto err2;
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 10/11] mount: support filesystem options passed via -o
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (7 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 09/11] nfs: switch to nfs3 Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-07 21:28 ` [PATCH v2 11/11] nfs: parse nfsport and mount port from file system options Uwe Kleine-König
  2014-02-10  8:02 ` [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Sascha Hauer
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

Similar to mount(8) the barebox command mount now supports passing a string
to the file system driver via -o.

This is used in the next commit to let the user specify port numbers for
nfs mounts.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 arch/arm/boards/raspberry-pi/rpi.c |  2 +-
 arch/arm/mach-omap/omap_generic.c  |  2 +-
 arch/arm/mach-omap/xload.c         |  4 ++--
 arch/arm/mach-socfpga/generic.c    |  2 +-
 commands/mount.c                   | 19 ++++++++++++-------
 commands/tftp.c                    |  2 +-
 common/blspec.c                    |  2 +-
 common/startup.c                   |  4 ++--
 fs/fs.c                            | 19 +++++++++++++------
 include/fs.h                       |  6 ++++--
 lib/bootstrap/disk.c               |  2 +-
 11 files changed, 39 insertions(+), 25 deletions(-)

diff --git a/arch/arm/boards/raspberry-pi/rpi.c b/arch/arm/boards/raspberry-pi/rpi.c
index 0997124c01ec..03a16d75619d 100644
--- a/arch/arm/boards/raspberry-pi/rpi.c
+++ b/arch/arm/boards/raspberry-pi/rpi.c
@@ -126,7 +126,7 @@ static int rpi_env_init(void)
 	}
 
 	mkdir("/boot", 0666);
-	ret = mount(diskdev, "fat", "/boot");
+	ret = mount(diskdev, "fat", "/boot", NULL);
 	if (ret) {
 		printf("failed to mount %s\n", diskdev);
 		return 0;
diff --git a/arch/arm/mach-omap/omap_generic.c b/arch/arm/mach-omap/omap_generic.c
index bedb4d8d2618..060c59277f4e 100644
--- a/arch/arm/mach-omap/omap_generic.c
+++ b/arch/arm/mach-omap/omap_generic.c
@@ -136,7 +136,7 @@ static int omap_env_init(void)
 	}
 
 	mkdir("/boot", 0666);
-	ret = mount(diskdev, "fat", "/boot");
+	ret = mount(diskdev, "fat", "/boot", NULL);
 	if (ret) {
 		printf("failed to mount %s\n", diskdev);
 		return 0;
diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c
index 69e3e42df69d..a30945010990 100644
--- a/arch/arm/mach-omap/xload.c
+++ b/arch/arm/mach-omap/xload.c
@@ -110,7 +110,7 @@ static void *omap_xload_boot_mmc(void)
 
 	partname = asprintf("%s.0", diskdev);
 
-	ret = mount(partname, "fat", "/");
+	ret = mount(partname, "fat", "/", NULL);
 
 	free(partname);
 
@@ -170,7 +170,7 @@ static void *omap4_xload_boot_usb(void){
 	void *buf;
 	int len;
 
-	ret = mount("omap4_usbboot", "omap4_usbbootfs", "/");
+	ret = mount("omap4_usbboot", "omap4_usbbootfs", "/", NULL);
 	if (ret) {
 		printf("Unable to mount omap4_usbbootfs (%d)\n", ret);
 		return NULL;
diff --git a/arch/arm/mach-socfpga/generic.c b/arch/arm/mach-socfpga/generic.c
index 0d958d23af60..62593549d6e4 100644
--- a/arch/arm/mach-socfpga/generic.c
+++ b/arch/arm/mach-socfpga/generic.c
@@ -97,7 +97,7 @@ static int socfpga_env_init(void)
 	}
 
 	mkdir("/boot", 0666);
-	ret = mount(partname, "fat", "/boot");
+	ret = mount(partname, "fat", "/boot", NULL);
 	if (ret) {
 		printf("failed to mount %s\n", diskdev);
 		goto out_free;
diff --git a/commands/mount.c b/commands/mount.c
index 2e9d4bef5e3f..691bc2911e8f 100644
--- a/commands/mount.c
+++ b/commands/mount.c
@@ -33,26 +33,31 @@ static int do_mount(int argc, char *argv[])
 {
 	int opt;
 	int ret = 0, verbose = 0;
-	struct fs_device_d *fsdev;
 	struct driver_d *drv;
 	const char *type = NULL;
 	const char *mountpoint, *dev;
+	const char *fsoptions = NULL;
 
-	while ((opt = getopt(argc, argv, "t:va")) > 0) {
+	while ((opt = getopt(argc, argv, "ao:t:v")) > 0) {
 		switch (opt) {
+		case 'a':
+			mount_all();
+			break;
 		case 't':
 			type = optarg;
 			break;
+		case 'o':
+			fsoptions = optarg;
+			break;
 		case 'v':
 			verbose++;
 			break;
-		case 'a':
-			mount_all();
-			break;
 		}
 	}
 
 	if (argc == optind) {
+		struct fs_device_d *fsdev;
+
 		for_each_fs_device(fsdev) {
 			printf("%s on %s type %s\n",
 				fsdev->backingstore ? fsdev->backingstore : "none",
@@ -84,7 +89,7 @@ static int do_mount(int argc, char *argv[])
 		if (!cdev)
 			return -ENOENT;
 
-		path = cdev_mount_default(cdev);
+		path = cdev_mount_default(cdev, fsoptions);
 		if (IS_ERR(path))
 			return PTR_ERR(path);
 
@@ -108,7 +113,7 @@ static int do_mount(int argc, char *argv[])
 		mountpoint = argv[optind + 1];
 	}
 
-	if ((ret = mount(dev, type, mountpoint))) {
+	if ((ret = mount(dev, type, mountpoint, fsoptions))) {
 		perror("mount");
 		return 1;
 	}
diff --git a/commands/tftp.c b/commands/tftp.c
index c83d1740e2f0..64cab2f0451d 100644
--- a/commands/tftp.c
+++ b/commands/tftp.c
@@ -72,7 +72,7 @@ static int do_tftpb(int argc, char *argv[])
 		goto err_free;
 
 	ip = net_get_serverip();
-	ret = mount(ip_to_string(ip), "tftp", TFTP_MOUNT_PATH);
+	ret = mount(ip_to_string(ip), "tftp", TFTP_MOUNT_PATH, NULL);
 	if (ret)
 		goto err_rmdir;
 
diff --git a/common/blspec.c b/common/blspec.c
index 2244d5a8a868..df3c9c3c65da 100644
--- a/common/blspec.c
+++ b/common/blspec.c
@@ -276,7 +276,7 @@ static int blspec_scan_cdev(struct blspec *blspec, struct cdev *cdev)
 	if (type == filetype_mbr || type == filetype_gpt)
 		return -EINVAL;
 
-	rootpath = cdev_mount_default(cdev);
+	rootpath = cdev_mount_default(cdev, NULL);
 	if (IS_ERR(rootpath))
 		return PTR_ERR(rootpath);
 
diff --git a/common/startup.c b/common/startup.c
index e8b9ea0216fe..0b5fe46adb50 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -89,9 +89,9 @@ device_initcall(register_default_env);
 #if defined CONFIG_FS_RAMFS && defined CONFIG_FS_DEVFS
 static int mount_root(void)
 {
-	mount("none", "ramfs", "/");
+	mount("none", "ramfs", "/", NULL);
 	mkdir("/dev", 0);
-	mount("none", "devfs", "/dev");
+	mount("none", "devfs", "/dev", NULL);
 	return 0;
 }
 fs_initcall(mount_root);
diff --git a/fs/fs.c b/fs/fs.c
index 32dba8cf0abe..7a57bc0670bc 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -1242,6 +1242,7 @@ static void fs_remove(struct device_d *dev)
 	}
 
 	free(fsdev->path);
+	free(fsdev->options);
 
 	if (fsdev == fs_dev_root)
 		fs_dev_root = NULL;
@@ -1316,13 +1317,18 @@ int fsdev_open_cdev(struct fs_device_d *fsdev)
  * We do this by registering a new device on which the filesystem
  * driver will match.
  */
-int mount(const char *device, const char *fsname, const char *_path)
+int mount(const char *device, const char *fsname, const char *_path,
+		const char *fsoptions)
 {
 	struct fs_device_d *fsdev;
 	int ret;
 	char *path = normalise_path(_path);
 
-	debug("mount: %s on %s type %s\n", device, path, fsname);
+	if (!fsoptions)
+		fsoptions = "";
+
+	debug("mount: %s on %s type %s, options=%s\n",
+			device, path, fsname, fsoptions);
 
 	if (fs_dev_root) {
 		fsdev = get_fsdevice_by_path(path);
@@ -1354,6 +1360,7 @@ int mount(const char *device, const char *fsname, const char *_path)
 	fsdev->dev.id = get_free_deviceid(fsdev->dev.name);
 	fsdev->path = xstrdup(path);
 	fsdev->dev.bus = &fs_bus;
+	fsdev->options = xstrdup(fsoptions);
 
 	ret = register_device(&fsdev->dev);
 	if (ret)
@@ -1711,7 +1718,7 @@ const char *cdev_get_mount_path(struct cdev *cdev)
  * mount it to /mnt/<cdevname> and return the path. Returns an error pointer
  * on failure.
  */
-const char *cdev_mount_default(struct cdev *cdev)
+const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions)
 {
 	const char *path;
 	char *newpath, *devpath;
@@ -1720,7 +1727,7 @@ const char *cdev_mount_default(struct cdev *cdev)
 	/*
 	 * If this cdev is already mounted somewhere use this path
 	 * instead of mounting it again to avoid corruption on the
-	 * filesystem.
+	 * filesystem. Note this ignores eventual fsoptions though.
 	 */
 	path = cdev_get_mount_path(cdev);
 	if (path)
@@ -1731,7 +1738,7 @@ const char *cdev_mount_default(struct cdev *cdev)
 
 	devpath = asprintf("/dev/%s", cdev->name);
 
-	ret = mount(devpath, NULL, newpath);
+	ret = mount(devpath, NULL, newpath, fsoptions);
 
 	free(devpath);
 
@@ -1761,6 +1768,6 @@ void mount_all(void)
 		struct cdev *cdev = &bdev->cdev;
 
 		list_for_each_entry(cdev, &bdev->dev->cdevs, devices_list)
-			cdev_mount_default(cdev);
+			cdev_mount_default(cdev, NULL);
 	}
 }
diff --git a/include/fs.h b/include/fs.h
index 856e00abb043..073641c74746 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -99,6 +99,7 @@ struct fs_device_d {
 	char *path;
 	struct device_d *parent_device;
 	struct list_head list;
+	char *options;
 };
 
 #define drv_to_fs_driver(d) container_of(d, struct fs_driver_d, drv)
@@ -140,7 +141,8 @@ int closedir(DIR *dir);
 int symlink(const char *pathname, const char *newpath);
 int readlink(const char *path, char *buf, size_t bufsiz);
 
-int mount (const char *device, const char *fsname, const char *path);
+int mount (const char *device, const char *fsname, const char *path,
+		const char *fsoptions);
 int umount(const char *pathname);
 
 /* not-so-standard functions */
@@ -197,7 +199,7 @@ int unlink_recursive(const char *path, char **failedpath);
 
 int fsdev_open_cdev(struct fs_device_d *fsdev);
 const char *cdev_get_mount_path(struct cdev *cdev);
-const char *cdev_mount_default(struct cdev *cdev);
+const char *cdev_mount_default(struct cdev *cdev, const char *fsoptions);
 void mount_all(void);
 
 #endif /* __FS_H */
diff --git a/lib/bootstrap/disk.c b/lib/bootstrap/disk.c
index 879d3315e8e3..527e4308979c 100644
--- a/lib/bootstrap/disk.c
+++ b/lib/bootstrap/disk.c
@@ -20,7 +20,7 @@ void* bootstrap_read_disk(char *dev, char *fstype)
 	int len;
 	char *path = "/";
 
-	ret = mount(dev, fstype, path);
+	ret = mount(dev, fstype, path, NULL);
 	if (ret) {
 		bootstrap_err("mounting %s failed with %d\n", dev, ret);
 		return NULL;
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH v2 11/11] nfs: parse nfsport and mount port from file system options
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (8 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 10/11] mount: support filesystem options passed via -o Uwe Kleine-König
@ 2014-02-07 21:28 ` Uwe Kleine-König
  2014-02-10  8:02 ` [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Sascha Hauer
  10 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-07 21:28 UTC (permalink / raw)
  To: barebox

This allows to use unfs3 on the server side which doesn't integrate into
portmap/rpcbind which results in the port not being impossible to lookup
via rpc calls to the portmap program.

Use it like:

	mount -t nfs -o port=2703,mountport=2703 192.168.77.157:/root /mnt/nfs

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---

Notes:
    move parseopt_hu into a seperate file. For now compile it depending on
    CONFIG_FS_NFS.

 fs/Makefile   |  2 +-
 fs/nfs.c      | 32 +++++++++++++++++++++-----------
 fs/parseopt.c | 34 ++++++++++++++++++++++++++++++++++
 fs/parseopt.h |  1 +
 4 files changed, 57 insertions(+), 12 deletions(-)
 create mode 100644 fs/parseopt.c
 create mode 100644 fs/parseopt.h

diff --git a/fs/Makefile b/fs/Makefile
index e8347bd6705f..d3465edfa595 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -8,6 +8,6 @@ obj-y	+= fs.o
 obj-$(CONFIG_FS_UBIFS)	+= ubifs/
 obj-$(CONFIG_FS_TFTP)	+= tftp.o
 obj-$(CONFIG_FS_OMAP4_USBBOOT)	+= omap4_usbbootfs.o
-obj-$(CONFIG_FS_NFS)	+= nfs.o
+obj-$(CONFIG_FS_NFS)	+= nfs.o parseopt.o
 obj-$(CONFIG_FS_BPKFS) += bpkfs.o
 obj-$(CONFIG_FS_UIMAGEFS)	+= uimagefs.o
diff --git a/fs/nfs.c b/fs/nfs.c
index ab33c91ef0a9..046cd4d76c9a 100644
--- a/fs/nfs.c
+++ b/fs/nfs.c
@@ -36,6 +36,8 @@
 #include <sizes.h>
 #include <byteorder.h>
 
+#include "parseopt.h"
+
 #define SUNRPC_PORT     111
 
 #define PROG_PORTMAP    100000
@@ -1339,19 +1341,27 @@ static int nfs_probe(struct device_d *dev)
 	/* Need a priviliged source port */
 	net_udp_bind(npriv->con, 1000);
 
-	ret = rpc_lookup_req(npriv, PROG_MOUNT, 3);
-	if (ret < 0) {
-		printf("lookup mount port failed with %d\n", ret);
-		goto err2;
+	parseopt_hu(fsdev->options, "mountport", &npriv->mount_port);
+	if (!npriv->mount_port) {
+		ret = rpc_lookup_req(npriv, PROG_MOUNT, 3);
+		if (ret < 0) {
+			printf("lookup mount port failed with %d\n", ret);
+			goto err2;
+		}
+		npriv->mount_port = ret;
 	}
-	npriv->mount_port = ret;
-
-	ret = rpc_lookup_req(npriv, PROG_NFS, 3);
-	if (ret < 0) {
-		printf("lookup nfs port failed with %d\n", ret);
-		goto err2;
+	debug("mount port: %hu\n", npriv->mount_port);
+
+	parseopt_hu(fsdev->options, "port", &npriv->nfs_port);
+	if (!npriv->nfs_port) {
+		ret = rpc_lookup_req(npriv, PROG_NFS, 3);
+		if (ret < 0) {
+			printf("lookup nfs port failed with %d\n", ret);
+			goto err2;
+		}
+		npriv->nfs_port = ret;
 	}
-	npriv->nfs_port = ret;
+	debug("nfs port: %d\n", npriv->nfs_port);
 
 	ret = nfs_mount_req(npriv);
 	if (ret) {
diff --git a/fs/parseopt.c b/fs/parseopt.c
new file mode 100644
index 000000000000..fbe53cfb02c4
--- /dev/null
+++ b/fs/parseopt.c
@@ -0,0 +1,34 @@
+#include <common.h>
+
+#include "parseopt.h"
+
+void parseopt_hu(const char *options, const char *opt, unsigned short *val)
+{
+	const char *start;
+	size_t optlen = strlen(opt);
+	ulong v;
+	char *endp;
+
+again:
+	start = strstr(options, opt);
+
+	if (!start)
+		return;
+
+	if (start > options && start[-1] != ',') {
+		options = start;
+		goto again;
+	}
+
+	if (start[optlen] != '=') {
+		options = start;
+		goto again;
+	}
+
+	v = simple_strtoul(start + optlen + 1, &endp, 0);
+	if (v > USHORT_MAX)
+		return;
+
+	if (*endp == ',' || *endp == '\0')
+		*val = v;
+}
diff --git a/fs/parseopt.h b/fs/parseopt.h
new file mode 100644
index 000000000000..a8523b6a10ae
--- /dev/null
+++ b/fs/parseopt.h
@@ -0,0 +1 @@
+void parseopt_hu(const char *options, const char *opt, unsigned short *val);
-- 
1.8.5.2


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit
  2014-02-07 21:28 ` [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit Uwe Kleine-König
@ 2014-02-08  6:51   ` Jean-Christophe PLAGNIOL-VILLARD
  2014-02-08 15:11     ` Uwe Kleine-König
  0 siblings, 1 reply; 14+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2014-02-08  6:51 UTC (permalink / raw)
  To: Uwe Kleine-K??nig; +Cc: barebox

On 22:28 Fri 07 Feb     , Uwe Kleine-K??nig wrote:
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

keep the hostname I use it on nfs for export filter

Best Regards,
J.
> ---
>  fs/nfs.c | 26 +++++---------------------
>  1 file changed, 5 insertions(+), 21 deletions(-)
> 
> diff --git a/fs/nfs.c b/fs/nfs.c
> index 76d8c0595db4..54dda261c0b1 100644
> --- a/fs/nfs.c
> +++ b/fs/nfs.c
> @@ -224,34 +224,18 @@ out_overflow:
>   */
>  static uint32_t *rpc_add_credentials(uint32_t *p)
>  {
> -	int hl;
> -	int hostnamelen = 0;
> -
>  	/*
> -	 * Here's the executive summary on authentication requirements of the
> -	 * various NFS server implementations:	Linux accepts both AUTH_NONE
> -	 * and AUTH_UNIX authentication (also accepts an empty hostname field
> -	 * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts
> -	 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
> -	 * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have
> -	 * it (if the BOOTP/DHCP reply didn't give one, just use an empty
> -	 * hostname).
> +	 * *BSD refuses AUTH_NONE, so use AUTH_UNIX. An empty hostname is OK for
> +	 * both Linux and *BSD.
>  	 */
>  
> -	hl = (hostnamelen + 3) & ~3;
> -
>  	/* Provide an AUTH_UNIX credential.  */
>  	*p++ = htonl(1);		/* AUTH_UNIX */
> -	*p++ = htonl(hl + 20);		/* auth length */
> +	*p++ = htonl(20);		/* auth length: 20 + strlen(hostname) */
>  	*p++ = htonl(0);		/* stamp */
> -	*p++ = htonl(hostnamelen);	/* hostname string */
> -
> -	if (hostnamelen & 3)
> -		*(p + hostnamelen / 4) = 0; /* add zero padding */
> -
> -	/* memcpy(p, hostname, hostnamelen); */ /* empty hostname */
> +	*p++ = htonl(0);		/* hostname string length */
> +	/* memcpy(p, "", 0); p += 0; <- empty host name */
>  
> -	p += hl / 4;
>  	*p++ = 0;			/* uid */
>  	*p++ = 0;			/* gid */
>  	*p++ = 0;			/* auxiliary gid list */
> -- 
> 1.8.5.2
> 

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit
  2014-02-08  6:51   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2014-02-08 15:11     ` Uwe Kleine-König
  0 siblings, 0 replies; 14+ messages in thread
From: Uwe Kleine-König @ 2014-02-08 15:11 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

On Sat, Feb 08, 2014 at 07:51:28AM +0100, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 22:28 Fri 07 Feb     , Uwe Kleine-K??nig wrote:
> > Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> 
> keep the hostname I use it on nfs for export filter
Which hostname? There is only one "used" in code that is commented out.

Best regards
Uwe
 
> Best Regards,
> J.
> > ---
> >  fs/nfs.c | 26 +++++---------------------
> >  1 file changed, 5 insertions(+), 21 deletions(-)
> > 
> > diff --git a/fs/nfs.c b/fs/nfs.c
> > index 76d8c0595db4..54dda261c0b1 100644
> > --- a/fs/nfs.c
> > +++ b/fs/nfs.c
> > @@ -224,34 +224,18 @@ out_overflow:
> >   */
> >  static uint32_t *rpc_add_credentials(uint32_t *p)
> >  {
> > -	int hl;
> > -	int hostnamelen = 0;
> > -
> >  	/*
> > -	 * Here's the executive summary on authentication requirements of the
> > -	 * various NFS server implementations:	Linux accepts both AUTH_NONE
> > -	 * and AUTH_UNIX authentication (also accepts an empty hostname field
> > -	 * in the AUTH_UNIX scheme).  *BSD refuses AUTH_NONE, but accepts
> > -	 * AUTH_UNIX (also accepts an empty hostname field in the AUTH_UNIX
> > -	 * scheme).  To be safe, use AUTH_UNIX and pass the hostname if we have
> > -	 * it (if the BOOTP/DHCP reply didn't give one, just use an empty
> > -	 * hostname).
> > +	 * *BSD refuses AUTH_NONE, so use AUTH_UNIX. An empty hostname is OK for
> > +	 * both Linux and *BSD.
> >  	 */
> >  
> > -	hl = (hostnamelen + 3) & ~3;
> > -
> >  	/* Provide an AUTH_UNIX credential.  */
> >  	*p++ = htonl(1);		/* AUTH_UNIX */
> > -	*p++ = htonl(hl + 20);		/* auth length */
> > +	*p++ = htonl(20);		/* auth length: 20 + strlen(hostname) */
> >  	*p++ = htonl(0);		/* stamp */
> > -	*p++ = htonl(hostnamelen);	/* hostname string */
> > -
> > -	if (hostnamelen & 3)
> > -		*(p + hostnamelen / 4) = 0; /* add zero padding */
> > -
> > -	/* memcpy(p, hostname, hostnamelen); */ /* empty hostname */
> > +	*p++ = htonl(0);		/* hostname string length */
> > +	/* memcpy(p, "", 0); p += 0; <- empty host name */
> >  
> > -	p += hl / 4;
> >  	*p++ = 0;			/* uid */
> >  	*p++ = 0;			/* gid */
> >  	*p++ = 0;			/* auxiliary gid list */
> > -- 
> > 1.8.5.2
> > 
> 

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read
  2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
                   ` (9 preceding siblings ...)
  2014-02-07 21:28 ` [PATCH v2 11/11] nfs: parse nfsport and mount port from file system options Uwe Kleine-König
@ 2014-02-10  8:02 ` Sascha Hauer
  10 siblings, 0 replies; 14+ messages in thread
From: Sascha Hauer @ 2014-02-10  8:02 UTC (permalink / raw)
  To: Uwe Kleine-König; +Cc: barebox

On Fri, Feb 07, 2014 at 10:28:03PM +0100, Uwe Kleine-König wrote:
> On some architectures (e.g. alpha, amd64, arm64, ia64, s390x, mips64)
> sizeof(ulong) is 8 which made net_read_uint32 actually read too much and
> even returned the wrong value on big endian machines.
> (Note the second issue isn't that critical though, because the only
> architecture from the list above that uses big endian byte order is s390x
> ...)
> 
> Also change the argument to void * because the pointer is not necessarily
> properly aligned.
> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>

Applied this series, thanks

Sascha

> ---
>  include/net.h | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/include/net.h b/include/net.h
> index a4cfec712374..8388e2f12ebe 100644
> --- a/include/net.h
> +++ b/include/net.h
> @@ -269,11 +269,11 @@ static inline IPaddr_t net_read_ip(void *from)
>  }
>  
>  /* return uint32 *in network byteorder* */
> -static inline uint32_t net_read_uint32(uint32_t *from)
> +static inline uint32_t net_read_uint32(void *from)
>  {
> -	ulong l;
> -	memcpy((void*)&l, (void*)from, sizeof(l));
> -	return l;
> +	uint32_t tmp;
> +	memcpy(&tmp, from, sizeof(tmp));
> +	return tmp;
>  }
>  
>  /* write IP *in network byteorder* */
> -- 
> 1.8.5.2
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2014-02-10  8:03 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-02-07 21:28 [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 02/11] nfs: fix mount prog version in portmap lookup Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 03/11] nfs: skip over stale rpc packets Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 04/11] nfs: shorten and simplify rpc_add_credentials a bit Uwe Kleine-König
2014-02-08  6:51   ` Jean-Christophe PLAGNIOL-VILLARD
2014-02-08 15:11     ` Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 05/11] nfs: simplify rpc_lookup_req Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 06/11] nfs: drop an unneeded variable from nfs_do_open() Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 07/11] net: new function net_read_uint64 Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 08/11] net: provide alternatives to {ntoh, hton}[sl] funtions with cleaner semantics Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 09/11] nfs: switch to nfs3 Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 10/11] mount: support filesystem options passed via -o Uwe Kleine-König
2014-02-07 21:28 ` [PATCH v2 11/11] nfs: parse nfsport and mount port from file system options Uwe Kleine-König
2014-02-10  8:02 ` [PATCH v2 01/11] net: net_read_uint32: assert that only 32 bit are read Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox