NFS: Support raw IPv6 address hostnames during NFS mount operation

Traditionally the mount command has looked for a ":" to separate the
server's hostname from the export path in the mounted on device name,
like this:

	mount server:/export /mounted/on/dir

The server's hostname is "server" and the export path is "/export".

You can also substitute a specific IPv4 network address for the server
hostname, like this:

	mount 192.168.0.55:/export /mounted/on/dir

Raw IPv6 addresses present a problem, however, because they look
something like this:

	fe80::200:5aff:fe00:30b

Note the use of colons.

To get around the presence of colons, copy the Solaris convention used for
mounting IPv6 servers by address: wrap a raw IPv6 address with square
brackets.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
Chuck Lever 2008-06-23 12:36:45 -04:00 committed by Trond Myklebust
parent dc04589827
commit d1aa082573
1 changed files with 82 additions and 8 deletions

View File

@ -1195,12 +1195,7 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
return status;
}
/*
* Split "dev_name" into "hostname:export_path".
*
* Note: caller frees hostname and export path, even on error.
*/
static int nfs_parse_devname(const char *dev_name,
static int nfs_parse_simple_hostname(const char *dev_name,
char **hostname, size_t maxnamlen,
char **export_path, size_t maxpathlen)
{
@ -1256,6 +1251,85 @@ out_path:
return -ENAMETOOLONG;
}
/*
* Hostname has square brackets around it because it contains one or
* more colons. We look for the first closing square bracket, and a
* colon must follow it.
*/
static int nfs_parse_protected_hostname(const char *dev_name,
char **hostname, size_t maxnamlen,
char **export_path, size_t maxpathlen)
{
size_t len;
char *start, *end;
start = (char *)(dev_name + 1);
end = strchr(start, ']');
if (end == NULL)
goto out_bad_devname;
if (*(end + 1) != ':')
goto out_bad_devname;
len = end - start;
if (len > maxnamlen)
goto out_hostname;
/* N.B. caller will free nfs_server.hostname in all cases */
*hostname = kstrndup(start, len, GFP_KERNEL);
if (*hostname == NULL)
goto out_nomem;
end += 2;
len = strlen(end);
if (len > maxpathlen)
goto out_path;
*export_path = kstrndup(end, len, GFP_KERNEL);
if (!*export_path)
goto out_nomem;
return 0;
out_bad_devname:
dfprintk(MOUNT, "NFS: device name not in host:path format\n");
return -EINVAL;
out_nomem:
dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
return -ENOMEM;
out_hostname:
dfprintk(MOUNT, "NFS: server hostname too long\n");
return -ENAMETOOLONG;
out_path:
dfprintk(MOUNT, "NFS: export pathname too long\n");
return -ENAMETOOLONG;
}
/*
* Split "dev_name" into "hostname:export_path".
*
* The leftmost colon demarks the split between the server's hostname
* and the export path. If the hostname starts with a left square
* bracket, then it may contain colons.
*
* Note: caller frees hostname and export path, even on error.
*/
static int nfs_parse_devname(const char *dev_name,
char **hostname, size_t maxnamlen,
char **export_path, size_t maxpathlen)
{
if (*dev_name == '[')
return nfs_parse_protected_hostname(dev_name,
hostname, maxnamlen,
export_path, maxpathlen);
return nfs_parse_simple_hostname(dev_name,
hostname, maxnamlen,
export_path, maxpathlen);
}
/*
* Validate the NFS2/NFS3 mount data
* - fills in the mount root filehandle