Change the interface with the mount command for NFSv2 and v3 in order
to allow the use of non-IPv4 addresses.
The 'nfs_mount_data' structure is extended with the fields host_addrlen (int)
and host_addr (sockaddr *) to carry addresses which may be other than IPv4
addresses. The mount version number is incremented to 7 to assume the
compatibility with previous versions.
So according to the mount version, the server address will be retrieved from the
addr or host_addr field.

Signed-off-by: Gilles Quillard <Gilles.Quillard@bull.net>
Signed-off-by: Aurelien Charbon <Aurelien.Charbon@ext.bull.net>

---

 fs/nfs/inode.c            |   57 ++++++++++++++++++++++++++++++----------------
 include/linux/nfs_mount.h |    4 ++-
 2 files changed, 41 insertions(+), 20 deletions(-)

---

diff -Nru linux-2.6.11-04/fs/nfs/inode.c linux-2.6.11-05/fs/nfs/inode.c
--- linux-2.6.11-04/fs/nfs/inode.c	2005-03-15 11:03:28.000000000 +0100
+++ linux-2.6.11-05/fs/nfs/inode.c	2005-03-15 11:14:01.000000000 +0100
@@ -1782,36 +1782,49 @@
 		root->size = NFS2_FHSIZE;
 	if (root->size > sizeof(root->data)) {
 		printk("nfs_get_sb: invalid root filehandle\n");
-		kfree(server);
-		return ERR_PTR(-EINVAL);
+		s = ERR_PTR(-EINVAL);
+		goto out_free;
 	}
 	memcpy(root->data, data->root.data, root->size);
 
 	/* We now require that the mount process passes the remote address */
-	server->addrlen = sizeof(struct sockaddr_in);
-	server->addr = kmalloc(server->addrlen, GFP_KERNEL);
-	if (!server->addr) {
-		kfree(server);
-		return = ERR_PTR(-ENOMEM);
+	if (data->version < 7) {
+		server->addrlen = sizeof(struct sockaddr_in);
+		server->addr = kmalloc(server->addrlen, GFP_KERNEL);
+		if (!server->addr) {
+			s = ERR_PTR(-ENOMEM);
+			goto out_free;
+		}
+		memcpy(server->addr, &data->addr, server->addrlen);
+	} else {
+		if (data->host_addrlen > sizeof(struct sockaddr_storage)) {
+			s = ERR_PTR(-EINVAL);
+			goto out_free;
+		}
+		server->addrlen = data->host_addrlen;
+		server->addr = kmalloc(server->addrlen, GFP_KERNEL);
+		if (!server->addr) {
+			s = ERR_PTR(-ENOMEM);
+			goto out_free;
+		}
+		if (copy_from_user(server->addr, data->host_addr, server->addrlen)) {
+			s = ERR_PTR(-EFAULT);
+			goto out_free;
+		}
 	}
-	memcpy(server->addr, &data->addr, server->addrlen);
 
 	s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
 
-	if (IS_ERR(s) || s->s_root) {
-		kfree(server->addr);
-		kfree(server);
-		return s;
-	}
+	if (IS_ERR(s) || s->s_root)
+		goto out_free;
 
 	s->s_flags = flags;
 
 	/* Fire up rpciod if not yet running */
 	if (rpciod_up() != 0) {
 		printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
-		kfree(server->addr);
-		kfree(server);
-		return ERR_PTR(-EIO);
+		s = ERR_PTR(-EIO);
+		goto out_free;
 	}
 
 	error = nfs_fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
@@ -1822,6 +1835,11 @@
 	}
 	s->s_flags |= MS_ACTIVE;
 	return s;
+out_free:
+	if (server->addr)
+		kfree(server->addr);
+	kfree(server);
+	return s;
 }
 
 static void nfs_kill_super(struct super_block *s)
@@ -1843,6 +1861,8 @@
 	if (server->hostname != NULL)
 		kfree(server->hostname);
 	nfs_free_iostats(server->io_stats);
+	if (server->addr)
+		kfree(server->addr);
 	kfree(server);
 	nfs_release_automount_timer();
 }
@@ -2355,11 +2375,10 @@
 	if (server->hostname == NULL)
 		goto free_server;
 	memcpy(server->hostname, parent->hostname, len);
-	len = strlen(parent->addrlen) + 1;
-	server->addr = kmalloc(len, GFP_KERNEL);
+	server->addr = kmalloc(parent->addrlen, GFP_KERNEL);
 	if (server->addr == NULL)
 		goto free_hostname;
-	memcpy(server->addr, parent->addr, len);
+	memcpy(server->addr, parent->addr, parent->addrlen);
 	server->fsid = data->fattr->fsid;
 	nfs_copy_fh(&server->fh, data->fh);
 	if (rpciod_up() != 0)
diff -Nru linux-2.6.11-04/include/linux/nfs_mount.h linux-2.6.11-05/include/linux/nfs_mount.h
--- linux-2.6.11-04/include/linux/nfs_mount.h	2005-03-15 11:02:05.000000000 +0100
+++ linux-2.6.11-05/include/linux/nfs_mount.h	2005-03-15 11:03:29.000000000 +0100
@@ -20,7 +20,7 @@
  * mount-to-kernel version compatibility.  Some of these aren't used yet
  * but here they are anyway.
  */
-#define NFS_MOUNT_VERSION	6
+#define NFS_MOUNT_VERSION	7
 #define NFS_MAX_CONTEXT_LEN	256
 
 struct nfs_mount_data {
@@ -43,6 +43,8 @@
 	struct nfs3_fh	root;			/* 4 */
 	int		pseudoflavor;		/* 5 */
 	char		context[NFS_MAX_CONTEXT_LEN + 1];	/* 6 */
+	unsigned int host_addrlen;		/* 7 */
+	struct sockaddr __user * host_addr;	/* 7 */
 
 };
 
