[PATCH 17/23] NFS: Move NFS client's IP address parser to nfs_common/

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The kernel's NFS server also needs to parse presentation format IP
addresses.  Since both the client and the server can reside in their own
modules, move the parser logic to nfs_common, which can be used by either.

I expect other common IPv4/IPv6 helpers to be moved in here at some
later point.

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---

 fs/nfs/internal.h              |    3 -
 fs/nfs/nfs4namespace.c         |    2 +
 fs/nfs/super.c                 |  121 --------------------------------
 fs/nfs_common/Makefile         |    1 
 fs/nfs_common/nfs_addr_parse.c |  151 ++++++++++++++++++++++++++++++++++++++++
 include/linux/nfs_addr_parse.h |   29 ++++++++
 6 files changed, 184 insertions(+), 123 deletions(-)
 create mode 100644 fs/nfs_common/nfs_addr_parse.c
 create mode 100644 include/linux/nfs_addr_parse.h

diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 4da6bbd..82d899f 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -167,7 +167,6 @@ extern void nfs4_clear_inode(struct inode *);
 void nfs_zap_acl_cache(struct inode *inode);
 
 /* super.c */
-void nfs_parse_ip_address(char *, size_t, struct sockaddr *, size_t *);
 extern struct file_system_type nfs_xdev_fs_type;
 #ifdef CONFIG_NFS_V4
 extern struct file_system_type nfs4_xdev_fs_type;
@@ -291,8 +290,6 @@ unsigned int nfs_page_array_len(unsigned int base, size_t len)
 		PAGE_SIZE - 1) >> PAGE_SHIFT;
 }
 
-#define IPV6_SCOPE_DELIMITER	'%'
-
 /*
  * Set the port number in an address.  Be agnostic about the address
  * family.
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 30befc3..660fc36 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -15,6 +15,8 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/vfs.h>
 #include <linux/inet.h>
+#include <linux/nfs_addr_parse.h>
+
 #include "internal.h"
 #include "nfs4_fs.h"
 
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 520fe6f..bf55e23 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -51,6 +51,7 @@
 #include <linux/nfs_xdr.h>
 #include <linux/magic.h>
 #include <linux/parser.h>
+#include <linux/nfs_addr_parse.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -697,126 +698,6 @@ static int nfs_verify_server_address(struct sockaddr *addr)
 	return 0;
 }
 
-static void nfs_parse_ipv4_address(char *string, size_t str_len,
-				   struct sockaddr *sap, size_t *addr_len)
-{
-	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
-	u8 *addr = (u8 *)&sin->sin_addr.s_addr;
-
-	if (str_len <= INET_ADDRSTRLEN) {
-		dfprintk(MOUNT, "NFS: parsing IPv4 address %*s\n",
-				(int)str_len, string);
-
-		sin->sin_family = AF_INET;
-		*addr_len = sizeof(*sin);
-		if (in4_pton(string, str_len, addr, '\0', NULL))
-			return;
-	}
-
-	sap->sa_family = AF_UNSPEC;
-	*addr_len = 0;
-}
-
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-static int nfs_parse_ipv6_scope_id(const char *string, const size_t str_len,
-				   const char *delim,
-				   struct sockaddr_in6 *sin6)
-{
-	char *p;
-	size_t len;
-
-	if ((string + str_len) == delim)
-		return 1;
-
-	if (*delim != IPV6_SCOPE_DELIMITER)
-		return 0;
-
-	if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
-		return 0;
-
-	len = (string + str_len) - delim - 1;
-	p = kstrndup(delim + 1, len, GFP_KERNEL);
-	if (p) {
-		unsigned long scope_id = 0;
-		struct net_device *dev;
-
-		dev = dev_get_by_name(&init_net, p);
-		if (dev != NULL) {
-			scope_id = dev->ifindex;
-			dev_put(dev);
-		} else {
-			if (strict_strtoul(p, 10, &scope_id) == 0) {
-				kfree(p);
-				return 0;
-			}
-		}
-
-		kfree(p);
-
-		sin6->sin6_scope_id = scope_id;
-		dfprintk(MOUNT, "NFS: IPv6 scope ID = %lu\n", scope_id);
-		return 1;
-	}
-
-	return 0;
-}
-
-static void nfs_parse_ipv6_address(char *string, size_t str_len,
-				   struct sockaddr *sap, size_t *addr_len)
-{
-	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
-	u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
-	const char *delim;
-
-	if (str_len <= INET6_ADDRSTRLEN) {
-		dfprintk(MOUNT, "NFS: parsing IPv6 address %*s\n",
-				(int)str_len, string);
-
-		sin6->sin6_family = AF_INET6;
-		*addr_len = sizeof(*sin6);
-		if (in6_pton(string, str_len, addr,
-					IPV6_SCOPE_DELIMITER, &delim) != 0) {
-			if (nfs_parse_ipv6_scope_id(string, str_len,
-							delim, sin6) != 0)
-				return;
-		}
-	}
-
-	sap->sa_family = AF_UNSPEC;
-	*addr_len = 0;
-}
-#else
-static void nfs_parse_ipv6_address(char *string, size_t str_len,
-				   struct sockaddr *sap, size_t *addr_len)
-{
-	sap->sa_family = AF_UNSPEC;
-	*addr_len = 0;
-}
-#endif
-
-/*
- * Construct a sockaddr based on the contents of a string that contains
- * an IP address in presentation format.
- *
- * If there is a problem constructing the new sockaddr, set the address
- * family to AF_UNSPEC.
- */
-void nfs_parse_ip_address(char *string, size_t str_len,
-				 struct sockaddr *sap, size_t *addr_len)
-{
-	unsigned int i, colons;
-
-	colons = 0;
-	for (i = 0; i < str_len; i++)
-		if (string[i] == ':')
-			colons++;
-
-	if (colons >= 2)
-		nfs_parse_ipv6_address(string, str_len, sap, addr_len);
-	else
-		nfs_parse_ipv4_address(string, str_len, sap, addr_len);
-}
-
 /*
  * Sanity check the NFS transport protocol.
  *
diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile
index f689ed8..032b4c5 100644
--- a/fs/nfs_common/Makefile
+++ b/fs/nfs_common/Makefile
@@ -2,6 +2,7 @@
 # Makefile for Linux filesystem routines that are shared by client and server.
 #
 
+obj-$(CONFIG_NFS_COMMON) += nfs_addr_parse.o
 obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o
 
 nfs_acl-objs := nfsacl.o
diff --git a/fs/nfs_common/nfs_addr_parse.c b/fs/nfs_common/nfs_addr_parse.c
new file mode 100644
index 0000000..529b407
--- /dev/null
+++ b/fs/nfs_common/nfs_addr_parse.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008 Oracle Corporation.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/unistd.h>
+
+#include <linux/inet.h>
+#include <linux/in6.h>
+#include <net/ipv6.h>
+#include <linux/netdevice.h>
+
+#include <linux/nfs_addr_parse.h>
+
+static void nfs_parse_ipv4_address(const char *buf, const size_t buflen,
+				   struct sockaddr *sap, size_t *salenp)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in *)sap;
+	u8 *addr = (u8 *)&sin->sin_addr.s_addr;
+
+	if (buflen <= INET_ADDRSTRLEN) {
+		sin->sin_family = AF_INET;
+		*salenp = sizeof(*sin);
+		if (in4_pton(buf, buflen, addr, '\0', NULL))
+			return;
+	}
+
+	sap->sa_family = AF_UNSPEC;
+	*salenp = 0;
+}
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static int nfs_parse_ipv6_scope_id(const char *buf, const size_t buflen,
+				   const char *delim,
+				   struct sockaddr_in6 *sin6)
+{
+	char *p;
+	size_t len;
+
+	if ((buf + buflen) == delim)
+		return 1;
+
+	if (*delim != IPV6_SCOPE_DELIMITER)
+		return 0;
+
+	if (!(ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL))
+		return 0;
+
+	len = (buf + buflen) - delim - 1;
+	p = kstrndup(delim + 1, len, GFP_KERNEL);
+	if (p) {
+		unsigned long scope_id = 0;
+		struct net_device *dev;
+
+		dev = dev_get_by_name(&init_net, p);
+		if (dev != NULL) {
+			scope_id = dev->ifindex;
+			dev_put(dev);
+		} else {
+			if (strict_strtoul(p, 10, &scope_id) == 0) {
+				kfree(p);
+				return 0;
+			}
+		}
+
+		kfree(p);
+
+		sin6->sin6_scope_id = scope_id;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void nfs_parse_ipv6_address(const char *buf, const size_t buflen,
+				   struct sockaddr *sap, size_t *salenp)
+{
+	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
+	u8 *addr = (u8 *)&sin6->sin6_addr.in6_u;
+	const char *delim;
+
+	if (buflen <= INET6_ADDRSTRLEN) {
+		sin6->sin6_family = AF_INET6;
+		*salenp = sizeof(*sin6);
+		if (in6_pton(buf, buflen, addr,
+					IPV6_SCOPE_DELIMITER, &delim) != 0) {
+			if (nfs_parse_ipv6_scope_id(buf, buflen,
+							delim, sin6) != 0)
+				return;
+		}
+	}
+
+	sap->sa_family = AF_UNSPEC;
+	*salenp = 0;
+}
+#else	/* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
+static void nfs_parse_ipv6_address(const char *buf, const size_t buflen,
+				   struct sockaddr *sap, size_t *salenp)
+{
+	sap->sa_family = AF_UNSPEC;
+	*salenp = 0;
+}
+#endif	/* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
+
+/**
+ * nfs_parse_ip_address - convert IP address string to sockaddr
+ * @buf: C string containing presentation format IP address
+ * @buflen: length of @buf in bytes
+ * @sap: pointer to buffer in which to construct sockaddr
+ * @salenp: IN: length of buffer in bytes
+ *	      OUT: size of address in bytes
+ *
+ * Construct a sockaddr based on the contents of a string that contains
+ * an IP address in presentation format.
+ *
+ * If there is a problem constructing the new sockaddr, set the address
+ * family to AF_UNSPEC.
+ */
+void nfs_parse_ip_address(const char *buf, const size_t buflen,
+			  struct sockaddr *sap, size_t *salenp)
+{
+	unsigned int i, colons;
+
+	colons = 0;
+	for (i = 0; i < buflen; i++)
+		if (buf[i] == ':')
+			colons++;
+
+	if (colons >= 2)
+		nfs_parse_ipv6_address(buf, buflen, sap, salenp);
+	else
+		nfs_parse_ipv4_address(buf, buflen, sap, salenp);
+}
+EXPORT_SYMBOL_GPL(nfs_parse_ip_address);
diff --git a/include/linux/nfs_addr_parse.h b/include/linux/nfs_addr_parse.h
new file mode 100644
index 0000000..193c71c
--- /dev/null
+++ b/include/linux/nfs_addr_parse.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 Oracle Corporation.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ *
+ */
+
+#ifndef __LINUX_NFS_ADDR_PARSE_H
+#define __LINUX_NFS_ADDR_PARSE_H
+
+#define IPV6_SCOPE_DELIMITER	'%'
+
+void	nfs_parse_ip_address(const char *buf, const size_t buflen,
+				struct sockaddr *sap, size_t *salenp);
+
+#endif	/* !__LINUX_NFS_ADDR_PARSE_H */

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux