aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorPeng Tao <tao.peng@primarydata.com>2014-05-29 09:06:59 -0400
committerTom Haynes <loghyr@primarydata.com>2015-02-03 14:06:32 -0500
commit6b7f3cf96364eaf597940cb5c68a682894829915 (patch)
tree532e1216ff4e72da9600f5504d862ced8e0fd8db /fs/nfs
parent875ae0694be48f3e3bdddd435b79abf52b680299 (diff)
nfs41: pull decode_ds_addr from file layout to generic pnfs
It can be reused by flexfile layout. Reviewed-by: Jeff Layton <jlayton@primarydata.com> Signed-off-by: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Tom Haynes <Thomas.Haynes@primarydata.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/filelayout/filelayoutdev.c152
-rw-r--r--fs/nfs/pnfs.h3
-rw-r--r--fs/nfs/pnfs_nfs.c149
3 files changed, 154 insertions, 150 deletions
diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c
index fbfbb701159d..c7f6041a287f 100644
--- a/fs/nfs/filelayout/filelayoutdev.c
+++ b/fs/nfs/filelayout/filelayoutdev.c
@@ -31,7 +31,6 @@
31#include <linux/nfs_fs.h> 31#include <linux/nfs_fs.h>
32#include <linux/vmalloc.h> 32#include <linux/vmalloc.h>
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/sunrpc/addr.h>
35 34
36#include "../internal.h" 35#include "../internal.h"
37#include "../nfs4session.h" 36#include "../nfs4session.h"
@@ -104,153 +103,6 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
104 kfree(dsaddr); 103 kfree(dsaddr);
105} 104}
106 105
107/*
108 * Currently only supports ipv4, ipv6 and one multi-path address.
109 */
110static struct nfs4_pnfs_ds_addr *
111decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
112{
113 struct nfs4_pnfs_ds_addr *da = NULL;
114 char *buf, *portstr;
115 __be16 port;
116 int nlen, rlen;
117 int tmp[2];
118 __be32 *p;
119 char *netid, *match_netid;
120 size_t len, match_netid_len;
121 char *startsep = "";
122 char *endsep = "";
123
124
125 /* r_netid */
126 p = xdr_inline_decode(streamp, 4);
127 if (unlikely(!p))
128 goto out_err;
129 nlen = be32_to_cpup(p++);
130
131 p = xdr_inline_decode(streamp, nlen);
132 if (unlikely(!p))
133 goto out_err;
134
135 netid = kmalloc(nlen+1, gfp_flags);
136 if (unlikely(!netid))
137 goto out_err;
138
139 netid[nlen] = '\0';
140 memcpy(netid, p, nlen);
141
142 /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
143 p = xdr_inline_decode(streamp, 4);
144 if (unlikely(!p))
145 goto out_free_netid;
146 rlen = be32_to_cpup(p);
147
148 p = xdr_inline_decode(streamp, rlen);
149 if (unlikely(!p))
150 goto out_free_netid;
151
152 /* port is ".ABC.DEF", 8 chars max */
153 if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
154 dprintk("%s: Invalid address, length %d\n", __func__,
155 rlen);
156 goto out_free_netid;
157 }
158 buf = kmalloc(rlen + 1, gfp_flags);
159 if (!buf) {
160 dprintk("%s: Not enough memory\n", __func__);
161 goto out_free_netid;
162 }
163 buf[rlen] = '\0';
164 memcpy(buf, p, rlen);
165
166 /* replace port '.' with '-' */
167 portstr = strrchr(buf, '.');
168 if (!portstr) {
169 dprintk("%s: Failed finding expected dot in port\n",
170 __func__);
171 goto out_free_buf;
172 }
173 *portstr = '-';
174
175 /* find '.' between address and port */
176 portstr = strrchr(buf, '.');
177 if (!portstr) {
178 dprintk("%s: Failed finding expected dot between address and "
179 "port\n", __func__);
180 goto out_free_buf;
181 }
182 *portstr = '\0';
183
184 da = kzalloc(sizeof(*da), gfp_flags);
185 if (unlikely(!da))
186 goto out_free_buf;
187
188 INIT_LIST_HEAD(&da->da_node);
189
190 if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
191 sizeof(da->da_addr))) {
192 dprintk("%s: error parsing address %s\n", __func__, buf);
193 goto out_free_da;
194 }
195
196 portstr++;
197 sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
198 port = htons((tmp[0] << 8) | (tmp[1]));
199
200 switch (da->da_addr.ss_family) {
201 case AF_INET:
202 ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
203 da->da_addrlen = sizeof(struct sockaddr_in);
204 match_netid = "tcp";
205 match_netid_len = 3;
206 break;
207
208 case AF_INET6:
209 ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
210 da->da_addrlen = sizeof(struct sockaddr_in6);
211 match_netid = "tcp6";
212 match_netid_len = 4;
213 startsep = "[";
214 endsep = "]";
215 break;
216
217 default:
218 dprintk("%s: unsupported address family: %u\n",
219 __func__, da->da_addr.ss_family);
220 goto out_free_da;
221 }
222
223 if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
224 dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
225 __func__, netid, match_netid);
226 goto out_free_da;
227 }
228
229 /* save human readable address */
230 len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
231 da->da_remotestr = kzalloc(len, gfp_flags);
232
233 /* NULL is ok, only used for dprintk */
234 if (da->da_remotestr)
235 snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
236 buf, endsep, ntohs(port));
237
238 dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
239 kfree(buf);
240 kfree(netid);
241 return da;
242
243out_free_da:
244 kfree(da);
245out_free_buf:
246 dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
247 kfree(buf);
248out_free_netid:
249 kfree(netid);
250out_err:
251 return NULL;
252}
253
254/* Decode opaque device data and return the result */ 106/* Decode opaque device data and return the result */
255struct nfs4_file_layout_dsaddr * 107struct nfs4_file_layout_dsaddr *
256nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, 108nfs4_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,
353 205
354 mp_count = be32_to_cpup(p); /* multipath count */ 206 mp_count = be32_to_cpup(p); /* multipath count */
355 for (j = 0; j < mp_count; j++) { 207 for (j = 0; j < mp_count; j++) {
356 da = decode_ds_addr(server->nfs_client->cl_net, 208 da = nfs4_decode_mp_ds_addr(server->nfs_client->cl_net,
357 &stream, gfp_flags); 209 &stream, gfp_flags);
358 if (da) 210 if (da)
359 list_add_tail(&da->da_node, &dsaddrs); 211 list_add_tail(&da->da_node, &dsaddrs);
360 } 212 }
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index b0168f1dd072..403d7bb67c41 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -312,6 +312,9 @@ void pnfs_generic_write_commit_done(struct rpc_task *task, void *data);
312void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); 312void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds);
313struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, 313struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs,
314 gfp_t gfp_flags); 314 gfp_t gfp_flags);
315struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net,
316 struct xdr_stream *xdr,
317 gfp_t gfp_flags);
315 318
316static inline struct nfs4_deviceid_node * 319static inline struct nfs4_deviceid_node *
317nfs4_get_deviceid(struct nfs4_deviceid_node *d) 320nfs4_get_deviceid(struct nfs4_deviceid_node *d)
diff --git a/fs/nfs/pnfs_nfs.c b/fs/nfs/pnfs_nfs.c
index 3bb2b74cf600..81ec449138a8 100644
--- a/fs/nfs/pnfs_nfs.c
+++ b/fs/nfs/pnfs_nfs.c
@@ -9,6 +9,7 @@
9 9
10#include <linux/nfs_fs.h> 10#include <linux/nfs_fs.h>
11#include <linux/nfs_page.h> 11#include <linux/nfs_page.h>
12#include <linux/sunrpc/addr.h>
12 13
13#include "internal.h" 14#include "internal.h"
14#include "pnfs.h" 15#include "pnfs.h"
@@ -532,3 +533,151 @@ out:
532 return ds; 533 return ds;
533} 534}
534EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add); 535EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add);
536
537/*
538 * Currently only supports ipv4, ipv6 and one multi-path address.
539 */
540struct nfs4_pnfs_ds_addr *
541nfs4_decode_mp_ds_addr(struct net *net, struct xdr_stream *xdr, gfp_t gfp_flags)
542{
543 struct nfs4_pnfs_ds_addr *da = NULL;
544 char *buf, *portstr;
545 __be16 port;
546 int nlen, rlen;
547 int tmp[2];
548 __be32 *p;
549 char *netid, *match_netid;
550 size_t len, match_netid_len;
551 char *startsep = "";
552 char *endsep = "";
553
554
555 /* r_netid */
556 p = xdr_inline_decode(xdr, 4);
557 if (unlikely(!p))
558 goto out_err;
559 nlen = be32_to_cpup(p++);
560
561 p = xdr_inline_decode(xdr, nlen);
562 if (unlikely(!p))
563 goto out_err;
564
565 netid = kmalloc(nlen+1, gfp_flags);
566 if (unlikely(!netid))
567 goto out_err;
568
569 netid[nlen] = '\0';
570 memcpy(netid, p, nlen);
571
572 /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
573 p = xdr_inline_decode(xdr, 4);
574 if (unlikely(!p))
575 goto out_free_netid;
576 rlen = be32_to_cpup(p);
577
578 p = xdr_inline_decode(xdr, rlen);
579 if (unlikely(!p))
580 goto out_free_netid;
581
582 /* port is ".ABC.DEF", 8 chars max */
583 if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
584 dprintk("%s: Invalid address, length %d\n", __func__,
585 rlen);
586 goto out_free_netid;
587 }
588 buf = kmalloc(rlen + 1, gfp_flags);
589 if (!buf) {
590 dprintk("%s: Not enough memory\n", __func__);
591 goto out_free_netid;
592 }
593 buf[rlen] = '\0';
594 memcpy(buf, p, rlen);
595
596 /* replace port '.' with '-' */
597 portstr = strrchr(buf, '.');
598 if (!portstr) {
599 dprintk("%s: Failed finding expected dot in port\n",
600 __func__);
601 goto out_free_buf;
602 }
603 *portstr = '-';
604
605 /* find '.' between address and port */
606 portstr = strrchr(buf, '.');
607 if (!portstr) {
608 dprintk("%s: Failed finding expected dot between address and "
609 "port\n", __func__);
610 goto out_free_buf;
611 }
612 *portstr = '\0';
613
614 da = kzalloc(sizeof(*da), gfp_flags);
615 if (unlikely(!da))
616 goto out_free_buf;
617
618 INIT_LIST_HEAD(&da->da_node);
619
620 if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
621 sizeof(da->da_addr))) {
622 dprintk("%s: error parsing address %s\n", __func__, buf);
623 goto out_free_da;
624 }
625
626 portstr++;
627 sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
628 port = htons((tmp[0] << 8) | (tmp[1]));
629
630 switch (da->da_addr.ss_family) {
631 case AF_INET:
632 ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
633 da->da_addrlen = sizeof(struct sockaddr_in);
634 match_netid = "tcp";
635 match_netid_len = 3;
636 break;
637
638 case AF_INET6:
639 ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
640 da->da_addrlen = sizeof(struct sockaddr_in6);
641 match_netid = "tcp6";
642 match_netid_len = 4;
643 startsep = "[";
644 endsep = "]";
645 break;
646
647 default:
648 dprintk("%s: unsupported address family: %u\n",
649 __func__, da->da_addr.ss_family);
650 goto out_free_da;
651 }
652
653 if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
654 dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
655 __func__, netid, match_netid);
656 goto out_free_da;
657 }
658
659 /* save human readable address */
660 len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
661 da->da_remotestr = kzalloc(len, gfp_flags);
662
663 /* NULL is ok, only used for dprintk */
664 if (da->da_remotestr)
665 snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
666 buf, endsep, ntohs(port));
667
668 dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
669 kfree(buf);
670 kfree(netid);
671 return da;
672
673out_free_da:
674 kfree(da);
675out_free_buf:
676 dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
677 kfree(buf);
678out_free_netid:
679 kfree(netid);
680out_err:
681 return NULL;
682}
683EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr);