|
@@ -31,7 +31,6 @@
|
|
|
#include <linux/nfs_fs.h>
|
|
|
#include <linux/vmalloc.h>
|
|
|
#include <linux/module.h>
|
|
|
-#include <linux/sunrpc/addr.h>
|
|
|
|
|
|
#include "../internal.h"
|
|
|
#include "../nfs4session.h"
|
|
@@ -104,153 +103,6 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
|
|
|
kfree(dsaddr);
|
|
|
}
|
|
|
|
|
|
-/*
|
|
|
- * Currently only supports ipv4, ipv6 and one multi-path address.
|
|
|
- */
|
|
|
-static struct nfs4_pnfs_ds_addr *
|
|
|
-decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
|
|
|
-{
|
|
|
- struct nfs4_pnfs_ds_addr *da = NULL;
|
|
|
- char *buf, *portstr;
|
|
|
- __be16 port;
|
|
|
- int nlen, rlen;
|
|
|
- int tmp[2];
|
|
|
- __be32 *p;
|
|
|
- char *netid, *match_netid;
|
|
|
- size_t len, match_netid_len;
|
|
|
- char *startsep = "";
|
|
|
- char *endsep = "";
|
|
|
-
|
|
|
-
|
|
|
- /* r_netid */
|
|
|
- p = xdr_inline_decode(streamp, 4);
|
|
|
- if (unlikely(!p))
|
|
|
- goto out_err;
|
|
|
- nlen = be32_to_cpup(p++);
|
|
|
-
|
|
|
- p = xdr_inline_decode(streamp, nlen);
|
|
|
- if (unlikely(!p))
|
|
|
- goto out_err;
|
|
|
-
|
|
|
- netid = kmalloc(nlen+1, gfp_flags);
|
|
|
- if (unlikely(!netid))
|
|
|
- goto out_err;
|
|
|
-
|
|
|
- netid[nlen] = '\0';
|
|
|
- memcpy(netid, p, nlen);
|
|
|
-
|
|
|
- /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
|
|
|
- p = xdr_inline_decode(streamp, 4);
|
|
|
- if (unlikely(!p))
|
|
|
- goto out_free_netid;
|
|
|
- rlen = be32_to_cpup(p);
|
|
|
-
|
|
|
- p = xdr_inline_decode(streamp, rlen);
|
|
|
- if (unlikely(!p))
|
|
|
- goto out_free_netid;
|
|
|
-
|
|
|
- /* port is ".ABC.DEF", 8 chars max */
|
|
|
- if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
|
|
|
- dprintk("%s: Invalid address, length %d\n", __func__,
|
|
|
- rlen);
|
|
|
- goto out_free_netid;
|
|
|
- }
|
|
|
- buf = kmalloc(rlen + 1, gfp_flags);
|
|
|
- if (!buf) {
|
|
|
- dprintk("%s: Not enough memory\n", __func__);
|
|
|
- goto out_free_netid;
|
|
|
- }
|
|
|
- buf[rlen] = '\0';
|
|
|
- memcpy(buf, p, rlen);
|
|
|
-
|
|
|
- /* replace port '.' with '-' */
|
|
|
- portstr = strrchr(buf, '.');
|
|
|
- if (!portstr) {
|
|
|
- dprintk("%s: Failed finding expected dot in port\n",
|
|
|
- __func__);
|
|
|
- goto out_free_buf;
|
|
|
- }
|
|
|
- *portstr = '-';
|
|
|
-
|
|
|
- /* find '.' between address and port */
|
|
|
- portstr = strrchr(buf, '.');
|
|
|
- if (!portstr) {
|
|
|
- dprintk("%s: Failed finding expected dot between address and "
|
|
|
- "port\n", __func__);
|
|
|
- goto out_free_buf;
|
|
|
- }
|
|
|
- *portstr = '\0';
|
|
|
-
|
|
|
- da = kzalloc(sizeof(*da), gfp_flags);
|
|
|
- if (unlikely(!da))
|
|
|
- goto out_free_buf;
|
|
|
-
|
|
|
- INIT_LIST_HEAD(&da->da_node);
|
|
|
-
|
|
|
- if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
|
|
|
- sizeof(da->da_addr))) {
|
|
|
- dprintk("%s: error parsing address %s\n", __func__, buf);
|
|
|
- goto out_free_da;
|
|
|
- }
|
|
|
-
|
|
|
- portstr++;
|
|
|
- sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
|
|
|
- port = htons((tmp[0] << 8) | (tmp[1]));
|
|
|
-
|
|
|
- switch (da->da_addr.ss_family) {
|
|
|
- case AF_INET:
|
|
|
- ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
|
|
|
- da->da_addrlen = sizeof(struct sockaddr_in);
|
|
|
- match_netid = "tcp";
|
|
|
- match_netid_len = 3;
|
|
|
- break;
|
|
|
-
|
|
|
- case AF_INET6:
|
|
|
- ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
|
|
|
- da->da_addrlen = sizeof(struct sockaddr_in6);
|
|
|
- match_netid = "tcp6";
|
|
|
- match_netid_len = 4;
|
|
|
- startsep = "[";
|
|
|
- endsep = "]";
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- dprintk("%s: unsupported address family: %u\n",
|
|
|
- __func__, da->da_addr.ss_family);
|
|
|
- goto out_free_da;
|
|
|
- }
|
|
|
-
|
|
|
- if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
|
|
|
- dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
|
|
|
- __func__, netid, match_netid);
|
|
|
- goto out_free_da;
|
|
|
- }
|
|
|
-
|
|
|
- /* save human readable address */
|
|
|
- len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
|
|
|
- da->da_remotestr = kzalloc(len, gfp_flags);
|
|
|
-
|
|
|
- /* NULL is ok, only used for dprintk */
|
|
|
- if (da->da_remotestr)
|
|
|
- snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
|
|
|
- buf, endsep, ntohs(port));
|
|
|
-
|
|
|
- dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
|
|
|
- kfree(buf);
|
|
|
- kfree(netid);
|
|
|
- return da;
|
|
|
-
|
|
|
-out_free_da:
|
|
|
- kfree(da);
|
|
|
-out_free_buf:
|
|
|
- dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
|
|
|
- kfree(buf);
|
|
|
-out_free_netid:
|
|
|
- kfree(netid);
|
|
|
-out_err:
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
/* Decode opaque device data and return the result */
|
|
|
struct nfs4_file_layout_dsaddr *
|
|
|
nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
|
@@ -353,8 +205,8 @@ nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev,
|
|
|
|
|
|
mp_count = be32_to_cpup(p); /* multipath count */
|
|
|
for (j = 0; j < mp_count; j++) {
|
|
|
- da = decode_ds_addr(server->nfs_client->cl_net,
|
|
|
- &stream, gfp_flags);
|
|
|
+ da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net,
|
|
|
+ &stream, gfp_flags);
|
|
|
if (da)
|
|
|
list_add_tail(&da->da_node, &dsaddrs);
|
|
|
}
|