Re: [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]

 



On Thu, 05 Mar 2009 16:33:31 -0500
Chuck Lever <chuck.lever@xxxxxxxxxx> wrote:

> 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
> 

I like the basic idea here -- moving these helpers into common code.
That said, I don't like the fact that this common code ends up in the
base kernel. IMO, a better solution would be a new module
(nfs_common.ko maybe?) that contains this code and any other common
code that's needed in the future...

> 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
> 


-- 
Jeff Layton <jlayton@xxxxxxxxxx>
--
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