Commit dc045898 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust

NFS: Use common device name parsing logic for NFSv4 and NFSv2/v3

To support passing a raw IPv6 address as a server hostname, we need to
expand the logic that handles splitting the passed-in device name into
a server hostname and export path

Start by pulling device name parsing out of the mount option validation
functions and into separate helper functions.
Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent cd100725
...@@ -1195,6 +1195,67 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args, ...@@ -1195,6 +1195,67 @@ static int nfs_try_mount(struct nfs_parsed_mount_data *args,
return status; 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,
char **hostname, size_t maxnamlen,
char **export_path, size_t maxpathlen)
{
size_t len;
char *colon, *comma;
colon = strchr(dev_name, ':');
if (colon == NULL)
goto out_bad_devname;
len = colon - dev_name;
if (len > maxnamlen)
goto out_hostname;
/* N.B. caller will free nfs_server.hostname in all cases */
*hostname = kstrndup(dev_name, len, GFP_KERNEL);
if (!*hostname)
goto out_nomem;
/* kill possible hostname list: not supported */
comma = strchr(*hostname, ',');
if (comma != NULL) {
if (comma == *hostname)
goto out_bad_devname;
*comma = '\0';
}
colon++;
len = strlen(colon);
if (len > maxpathlen)
goto out_path;
*export_path = kstrndup(colon, len, GFP_KERNEL);
if (!*export_path)
goto out_nomem;
dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
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;
}
/* /*
* Validate the NFS2/NFS3 mount data * Validate the NFS2/NFS3 mount data
* - fills in the mount root filehandle * - fills in the mount root filehandle
...@@ -1323,8 +1384,6 @@ static int nfs_validate_mount_data(void *options, ...@@ -1323,8 +1384,6 @@ static int nfs_validate_mount_data(void *options,
break; break;
default: { default: {
unsigned int len;
char *c;
int status; int status;
if (nfs_parse_mount_options((char *)options, args) == 0) if (nfs_parse_mount_options((char *)options, args) == 0)
...@@ -1334,21 +1393,17 @@ static int nfs_validate_mount_data(void *options, ...@@ -1334,21 +1393,17 @@ static int nfs_validate_mount_data(void *options,
&args->nfs_server.address)) &args->nfs_server.address))
goto out_no_address; goto out_no_address;
c = strchr(dev_name, ':'); status = nfs_parse_devname(dev_name,
if (c == NULL) &args->nfs_server.hostname,
return -EINVAL; PAGE_SIZE,
len = c - dev_name; &args->nfs_server.export_path,
/* N.B. caller will free nfs_server.hostname in all cases */ NFS_MAXPATHLEN);
args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); if (!status)
if (!args->nfs_server.hostname) status = nfs_try_mount(args, mntfh);
goto out_nomem;
c++; kfree(args->nfs_server.export_path);
if (strlen(c) > NFS_MAXPATHLEN) args->nfs_server.export_path = NULL;
return -ENAMETOOLONG;
args->nfs_server.export_path = c;
status = nfs_try_mount(args, mntfh);
if (status) if (status)
return status; return status;
...@@ -1958,7 +2013,7 @@ static int nfs4_validate_mount_data(void *options, ...@@ -1958,7 +2013,7 @@ static int nfs4_validate_mount_data(void *options,
break; break;
default: { default: {
unsigned int len; int status;
if (nfs_parse_mount_options((char *)options, args) == 0) if (nfs_parse_mount_options((char *)options, args) == 0)
return -EINVAL; return -EINVAL;
...@@ -1977,34 +2032,17 @@ static int nfs4_validate_mount_data(void *options, ...@@ -1977,34 +2032,17 @@ static int nfs4_validate_mount_data(void *options,
goto out_inval_auth; goto out_inval_auth;
} }
/*
* Split "dev_name" into "hostname:mntpath".
*/
c = strchr(dev_name, ':');
if (c == NULL)
return -EINVAL;
/* while calculating len, pretend ':' is '\0' */
len = c - dev_name;
if (len > NFS4_MAXNAMLEN)
return -ENAMETOOLONG;
/* N.B. caller will free nfs_server.hostname in all cases */
args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL);
if (!args->nfs_server.hostname)
goto out_nomem;
c++; /* step over the ':' */
len = strlen(c);
if (len > NFS4_MAXPATHLEN)
return -ENAMETOOLONG;
args->nfs_server.export_path = kstrndup(c, len, GFP_KERNEL);
if (!args->nfs_server.export_path)
goto out_nomem;
dprintk("NFS: MNTPATH: '%s'\n", args->nfs_server.export_path);
if (args->client_address == NULL) if (args->client_address == NULL)
goto out_no_client_address; goto out_no_client_address;
status = nfs_parse_devname(dev_name,
&args->nfs_server.hostname,
NFS4_MAXNAMLEN,
&args->nfs_server.export_path,
NFS4_MAXPATHLEN);
if (status < 0)
return status;
break; break;
} }
} }
...@@ -2020,10 +2058,6 @@ static int nfs4_validate_mount_data(void *options, ...@@ -2020,10 +2058,6 @@ static int nfs4_validate_mount_data(void *options,
data->auth_flavourlen); data->auth_flavourlen);
return -EINVAL; return -EINVAL;
out_nomem:
dfprintk(MOUNT, "NFS4: not enough memory to handle mount options\n");
return -ENOMEM;
out_no_address: out_no_address:
dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n"); dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment