Add the support of IPv6 in the NFS client.

Signed-off-by: Gilles Quillard <gilles.quillard@bull.net>
---

diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/callback.c linux-2.6.9-cel5-gq-03/fs/nfs/callback.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/callback.c	2004-12-13 14:36:31.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/fs/nfs/callback.c	2005-01-21 17:06:06.000000000 +0100
@@ -63,8 +63,8 @@
 					__FUNCTION__, -err);
 			break;
 		}
-		dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
-				NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
+		dprintk("%s: request from %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+				__FUNCTION__, NIP6(rqstp->rq_addr.sin6_addr));
 		svc_process(serv, rqstp);
 	}
 
@@ -141,14 +141,14 @@
 
 static int nfs_callback_set_client(struct svc_rqst *rqstp)
 {
-	struct in_addr *addr = &rqstp->rq_addr.sin_addr;
+	struct in6_addr *addr = &rqstp->rq_addr.sin6_addr;
 	struct nfs4_client *clp;
 
 	/* Don't talk to strangers */
 	clp = nfs4_find_client(addr);
 	if (clp == NULL)
 		return SVC_DROP;
-	dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr));
+	dprintk("%s: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x NFSv4 callback!\n", __FUNCTION__, NIP6(*addr));
 	nfs4_put_client(clp);
 	switch (rqstp->rq_authop->flavour) {
 		case RPC_AUTH_NULL:
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/callback.h linux-2.6.9-cel5-gq-03/fs/nfs/callback.h
--- linux-2.6.9-cel5-gq-02/fs/nfs/callback.h	2004-10-18 23:54:55.000000000 +0200
+++ linux-2.6.9-cel5-gq-03/fs/nfs/callback.h	2005-01-21 17:06:06.000000000 +0100
@@ -38,7 +38,7 @@
 };
 
 struct cb_getattrargs {
-	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr;
 	struct nfs_fh fh;
 	uint32_t bitmap[2];
 };
@@ -53,7 +53,7 @@
 };
 
 struct cb_recallargs {
-	struct sockaddr_in *addr;
+	struct sockaddr_in6 *addr;
 	struct nfs_fh fh;
 	nfs4_stateid stateid;
 	uint32_t truncate;
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/callback_proc.c linux-2.6.9-cel5-gq-03/fs/nfs/callback_proc.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/callback_proc.c	2004-10-18 23:55:36.000000000 +0200
+++ linux-2.6.9-cel5-gq-03/fs/nfs/callback_proc.c	2005-01-21 17:06:06.000000000 +0100
@@ -22,7 +22,7 @@
 	
 	res->bitmap[0] = res->bitmap[1] = 0;
 	res->status = htonl(NFS4ERR_BADHANDLE);
-	clp = nfs4_find_client(&args->addr->sin_addr);
+	clp = nfs4_find_client(&args->addr->sin6_addr);
 	if (clp == NULL)
 		goto out;
 	inode = nfs_delegation_find_inode(clp, &args->fh);
@@ -59,7 +59,7 @@
 	unsigned res;
 	
 	res = htonl(NFS4ERR_BADHANDLE);
-	clp = nfs4_find_client(&args->addr->sin_addr);
+	clp = nfs4_find_client(&args->addr->sin6_addr);
 	if (clp == NULL)
 		goto out;
 	inode = nfs_delegation_find_inode(clp, &args->fh);
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/delegation.c linux-2.6.9-cel5-gq-03/fs/nfs/delegation.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/delegation.c	2004-10-18 23:54:40.000000000 +0200
+++ linux-2.6.9-cel5-gq-03/fs/nfs/delegation.c	2005-01-21 17:06:06.000000000 +0100
@@ -104,8 +104,8 @@
 		if (memcmp(&delegation->stateid, &nfsi->delegation->stateid,
 					sizeof(delegation->stateid)) != 0 ||
 				delegation->type != nfsi->delegation->type) {
-			printk("%s: server %u.%u.%u.%u, handed out a duplicate delegation!\n",
-					__FUNCTION__, NIPQUAD(clp->cl_addr));
+			printk("%s: server %x:%x:%x:%x:%x:%x:%x:%x, handed out a duplicate delegation!\n",
+					__FUNCTION__, NIP6(clp->cl_addr));
 			status = -EIO;
 		}
 	}
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/inode.c linux-2.6.9-cel5-gq-03/fs/nfs/inode.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/inode.c	2005-01-21 17:09:02.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/fs/nfs/inode.c	2005-01-24 11:21:55.000000000 +0100
@@ -45,6 +45,13 @@
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
+#define IS_ADDR6_ANY(a) \
+	(((uint32_t *) (a))[0] == 0                       \
+	 && ((uint32_t *) (a))[1] == 0                    \
+	 && (((uint32_t *) (a))[2] == 0                   \
+	     || ((uint32_t *) (a))[2] == htonl(0xffff))   \
+	 && ((uint32_t *) (a))[3] == 0)
+
 /* Maximum number of readahead requests
  * FIXME: this should really be a sysctl so that users may tune it to suit
  *        their needs. People that do NFS over a slow network, might for
@@ -1391,9 +1398,9 @@
 	struct nfs_server *server = data;
 	struct nfs_server *old = NFS_SB(sb);
 
-	if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
+	if (memcmp(&old->addr.sin6_addr, &server->addr.sin6_addr, sizeof(struct in6_addr)))
 		return 0;
-	if (old->addr.sin_port != server->addr.sin_port)
+	if (old->addr.sin6_port != server->addr.sin6_port)
 		return 0;
 	return !nfs_compare_fh(&old->fh, &server->fh);
 }
@@ -1448,12 +1455,17 @@
 	memcpy(root->data, data->root.data, root->size);
 
 	/* We now require that the mount process passes the remote address */
-	memcpy(&server->addr, &data->addr, sizeof(server->addr));
-	if (server->addr.sin_addr.s_addr == INADDR_ANY) {
-		printk("NFS: mount program didn't pass remote address!\n");
-		kfree(server);
-		return ERR_PTR(-EINVAL);
-	}
+	if (data->addr.sin_addr.s_addr == INADDR_ANY) {
+	    printk("NFS: mount program didn't pass remote address!\n");
+	    kfree(server);
+	    return ERR_PTR(-EINVAL);
+	}
+	server->addr.sin6_family = AF_INET6;
+	server->addr.sin6_port = data->addr.sin_port;
+	server->addr.sin6_addr.s6_addr32[0] = 0;
+	server->addr.sin6_addr.s6_addr32[1] = 0;
+	server->addr.sin6_addr.s6_addr32[2] = htonl(0xffff);
+	server->addr.sin6_addr.s6_addr32[3] = data->addr.sin_addr.s_addr;
 
 	s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
 
@@ -1665,7 +1677,7 @@
 		return -EINVAL;
 	}
 
-	clp = nfs4_get_client(&server->addr.sin_addr);
+	clp = nfs4_get_client(&server->addr.sin6_addr);
 	if (!clp) {
 		printk(KERN_WARNING "NFS: failed to create NFS4 client.\n");
 		return -EIO;
@@ -1835,22 +1847,43 @@
 		goto out_err;
 
 	/* We now require that the mount process passes the remote address */
-	if (data->host_addrlen != sizeof(server->addr)) {
+	if (data->host_addrlen == sizeof(struct sockaddr_in)) {
+		struct sockaddr_in saddr;
+		if (copy_from_user(&saddr, data->host_addr,
+			    sizeof(struct sockaddr_in))) {
+			printk(KERN_ERR "NFS: memory fault while copying mount data!\n");
+			s = ERR_PTR(-EFAULT);
+		        goto out_free;
+		}
+		if (saddr.sin_family != AF_INET || 
+		    saddr.sin_addr.s_addr == INADDR_ANY) {
+			printk(KERN_ERR "NFS: mount program didn't pass remote IP address!\n");
+			s = ERR_PTR(-EINVAL);
+			goto out_free;
+		}
+		server->addr.sin6_family = AF_INET6;
+		server->addr.sin6_port = saddr.sin_port;
+		server->addr.sin6_addr.s6_addr32[0] = 0;
+		server->addr.sin6_addr.s6_addr32[1] = 0;
+		server->addr.sin6_addr.s6_addr32[2] = htonl(0xffff);
+		server->addr.sin6_addr.s6_addr32[3] = saddr.sin_addr.s_addr;
+	} else if (data->host_addrlen == sizeof(struct sockaddr_in6)) {
+		if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
+			printk(KERN_ERR "NFS: memory fault while copying mount data!\n");
+			s = ERR_PTR(-EFAULT);
+			goto out_free;
+		}
+		if (server->addr.sin6_family != AF_INET6 ||
+	    	    IS_ADDR6_ANY(server->addr.sin6_addr.s6_addr32)) {
+			printk(KERN_ERR "NFS: mount program didn't pass remote IP address!\n");
+			s = ERR_PTR(-EINVAL);
+			goto out_free;
+		}
+	} else {
 		printk(KERN_ERR "NFS: mount program didn't pass remote IP address!\n");
 		s = ERR_PTR(-EINVAL);
 		goto out_free;
 	}
-	if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
-		printk(KERN_ERR "NFS: memory fault while copying mount data!\n");
-		s = ERR_PTR(-EFAULT);
-		goto out_free;
-	}
-	if (server->addr.sin_family != AF_INET ||
-	    server->addr.sin_addr.s_addr == INADDR_ANY) {
-		printk(KERN_ERR "NFS: mount program passed bogus remote IP address!\n");
-		s = ERR_PTR(-EINVAL);
-		goto out_free;
-	}
 
 	s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
 
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/nfs4proc.c linux-2.6.9-cel5-gq-03/fs/nfs/nfs4proc.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/nfs4proc.c	2004-12-13 14:36:38.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/fs/nfs/nfs4proc.c	2005-01-21 17:06:06.000000000 +0100
@@ -2348,8 +2348,9 @@
 		*p = htonl((u32)boot_time.tv_nsec);
 	}
 	setclientid.sc_name_len = scnprintf(setclientid.sc_name,
-			sizeof(setclientid.sc_name), "%s/%u.%u.%u.%u",
-			clp->cl_ipaddr, NIPQUAD(clp->cl_addr.s_addr));
+			sizeof(setclientid.sc_name),
+			"%s/%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+			clp->cl_ipaddr, NIP6(clp->cl_addr));
 	setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
 			sizeof(setclientid.sc_netid), "tcp");
 	setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/nfs4state.c linux-2.6.9-cel5-gq-03/fs/nfs/nfs4state.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/nfs4state.c	2004-12-13 14:36:18.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/fs/nfs/nfs4state.c	2005-01-21 17:06:06.000000000 +0100
@@ -93,7 +93,7 @@
  * bother putting them in a slab cache...
  */
 static struct nfs4_client *
-nfs4_alloc_client(struct in_addr *addr)
+nfs4_alloc_client(struct in6_addr *addr)
 {
 	struct nfs4_client *clp;
 
@@ -142,7 +142,7 @@
 	nfs_callback_down();
 }
 
-static struct nfs4_client *__nfs4_find_client(struct in_addr *addr)
+static struct nfs4_client *__nfs4_find_client(struct in6_addr *addr)
 {
 	struct nfs4_client *clp;
 	list_for_each_entry(clp, &nfs4_clientid_list, cl_servers) {
@@ -154,7 +154,7 @@
 	return NULL;
 }
 
-struct nfs4_client *nfs4_find_client(struct in_addr *addr)
+struct nfs4_client *nfs4_find_client(struct in6_addr *addr)
 {
 	struct nfs4_client *clp;
 	spin_lock(&state_spinlock);
@@ -164,7 +164,7 @@
 }
 
 struct nfs4_client *
-nfs4_get_client(struct in_addr *addr)
+nfs4_get_client(struct in6_addr *addr)
 {
 	struct nfs4_client *clp, *new = NULL;
 
@@ -840,9 +840,12 @@
 	struct reclaimer_args *args = (struct reclaimer_args *)ptr;
 	struct nfs4_client *clp = args->clp;
 	struct nfs4_state_owner *sp;
+	char str[64];
 	int status = 0;
 
-	daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
+	sprintf(str, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
+		  NIP6(clp->cl_addr));
+	daemonize("%s-reclaim", str);
 	allow_signal(SIGKILL);
 
 	atomic_inc(&clp->cl_count);
@@ -884,8 +887,7 @@
 	nfs4_put_client(clp);
 	return 0;
 out_error:
-	printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u with error %d\n",
-				NIPQUAD(clp->cl_addr.s_addr), -status);
+	printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %s\n", str);
 	goto out;
 }
 
diff -Nru linux-2.6.9-cel5-gq-02/fs/nfs/nfs4xdr.c linux-2.6.9-cel5-gq-03/fs/nfs/nfs4xdr.c
--- linux-2.6.9-cel5-gq-02/fs/nfs/nfs4xdr.c	2004-12-13 14:36:38.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/fs/nfs/nfs4xdr.c	2005-01-21 17:06:06.000000000 +0100
@@ -99,9 +99,9 @@
 #define decode_renew_maxsz	(op_decode_hdr_maxsz)
 #define encode_setclientid_maxsz \
 				(op_encode_hdr_maxsz + \
-				4 /*server->ip_addr*/ + \
+				16 /*server->ip_addr*/ + \
 				1 /*Netid*/ + \
-				6 /*uaddr*/ + \
+				12 /*uaddr*/ + \
 				6 + (NFS4_VERIFIER_SIZE >> 2))
 #define decode_setclientid_maxsz \
 				(op_decode_hdr_maxsz + \
diff -Nru linux-2.6.9-cel5-gq-02/include/linux/nfs_fs.h linux-2.6.9-cel5-gq-03/include/linux/nfs_fs.h
--- linux-2.6.9-cel5-gq-02/include/linux/nfs_fs.h	2004-12-13 14:36:38.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/include/linux/nfs_fs.h	2005-01-21 17:06:06.000000000 +0100
@@ -11,6 +11,7 @@
 
 #include <linux/config.h>
 #include <linux/in.h>
+#include <linux/in6.h>
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/rwsem.h>
@@ -30,6 +31,7 @@
 #include <linux/nfs_xdr.h>
 #include <linux/rwsem.h>
 #include <linux/workqueue.h>
+#include <linux/spinlock.h>
 #include <linux/mempool.h>
 
 /*
@@ -584,7 +586,7 @@
  */
 struct nfs4_client {
 	struct list_head	cl_servers;	/* Global list of servers */
-	struct in_addr		cl_addr;	/* Server identifier */
+	struct in6_addr		cl_addr;	/* Server identifier */
 	u64			cl_clientid;	/* constant */
 	nfs4_verifier		cl_confirm;
 	unsigned long		cl_state;
@@ -623,7 +625,7 @@
 	/* Our own IP address, as a null-terminated string.
 	 * This is used to generate the clientid, and the callback address.
 	 */
-	char			cl_ipaddr[16];
+	char			cl_ipaddr[40];
 };
 
 /*
@@ -737,10 +739,10 @@
 /* nfs4state.c */
 extern void init_nfsv4_state(struct nfs_server *);
 extern void destroy_nfsv4_state(struct nfs_server *);
-extern struct nfs4_client *nfs4_get_client(struct in_addr *);
+extern struct nfs4_client *nfs4_get_client(struct in6_addr *);
 extern void nfs4_put_client(struct nfs4_client *clp);
 extern int nfs4_init_client(struct nfs4_client *clp);
-extern struct nfs4_client *nfs4_find_client(struct in_addr *);
+extern struct nfs4_client *nfs4_find_client(struct in6_addr *);
 extern u32 nfs4_alloc_lockowner_id(struct nfs4_client *);
 
 extern struct nfs4_state_owner * nfs4_get_state_owner(struct nfs_server *, struct rpc_cred *);
diff -Nru linux-2.6.9-cel5-gq-02/include/linux/nfs_fs_sb.h linux-2.6.9-cel5-gq-03/include/linux/nfs_fs_sb.h
--- linux-2.6.9-cel5-gq-02/include/linux/nfs_fs_sb.h	2004-12-13 14:36:38.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/include/linux/nfs_fs_sb.h	2005-01-21 17:06:06.000000000 +0100
@@ -30,13 +30,13 @@
 	unsigned int		namelen;
 	char *			hostname;	/* remote hostname */
 	struct nfs_fh		fh;
-	struct sockaddr_in	addr;
+	struct sockaddr_in6	addr;
 	struct nfs_iostats *	io_stats;	/* I/O statistics */
 #ifdef CONFIG_NFS_V4
 	/* Our own IP address, as a null-terminated string.
 	 * This is used to generate the clientid, and the callback address.
 	 */
-	char			ip_addr[16];
+	char			ip_addr[40];
 	char *			mnt_path;
 	struct nfs4_client *	nfs4_state;	/* all NFSv4 state starts here */
 	struct list_head	nfs4_siblings;	/* List of other nfs_server structs
diff -Nru linux-2.6.9-cel5-gq-02/include/linux/nfs_xdr.h linux-2.6.9-cel5-gq-03/include/linux/nfs_xdr.h
--- linux-2.6.9-cel5-gq-02/include/linux/nfs_xdr.h	2004-12-13 14:36:38.000000000 +0100
+++ linux-2.6.9-cel5-gq-03/include/linux/nfs_xdr.h	2005-01-21 17:06:06.000000000 +0100
@@ -621,12 +621,12 @@
 struct nfs4_setclientid {
 	const nfs4_verifier *		sc_verifier;      /* request */
 	unsigned int			sc_name_len;
-	char				sc_name[32];	  /* request */
+	char				sc_name[80];	  /* request */
 	u32				sc_prog;          /* request */
 	unsigned int			sc_netid_len;
 	char				sc_netid[4];	  /* request */
 	unsigned int			sc_uaddr_len;
-	char				sc_uaddr[24];     /* request */
+	char				sc_uaddr[48];     /* request */
 	u32				sc_cb_ident;      /* request */
 };
 
