diff options
author | Peng Tao <tao.peng@primarydata.com> | 2014-05-29 09:06:59 -0400 |
---|---|---|
committer | Tom Haynes <loghyr@primarydata.com> | 2015-02-03 14:06:32 -0500 |
commit | 6b7f3cf96364eaf597940cb5c68a682894829915 (patch) | |
tree | 532e1216ff4e72da9600f5504d862ced8e0fd8db /fs/nfs | |
parent | 875ae0694be48f3e3bdddd435b79abf52b680299 (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.c | 152 | ||||
-rw-r--r-- | fs/nfs/pnfs.h | 3 | ||||
-rw-r--r-- | fs/nfs/pnfs_nfs.c | 149 |
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 | */ | ||
110 | static struct nfs4_pnfs_ds_addr * | ||
111 | decode_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 | |||
243 | out_free_da: | ||
244 | kfree(da); | ||
245 | out_free_buf: | ||
246 | dprintk("%s: Error parsing DS addr: %s\n", __func__, buf); | ||
247 | kfree(buf); | ||
248 | out_free_netid: | ||
249 | kfree(netid); | ||
250 | out_err: | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
254 | /* Decode opaque device data and return the result */ | 106 | /* Decode opaque device data and return the result */ |
255 | struct nfs4_file_layout_dsaddr * | 107 | struct nfs4_file_layout_dsaddr * |
256 | nfs4_fl_alloc_deviceid_node(struct nfs_server *server, struct pnfs_device *pdev, | 108 | 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, | |||
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); | |||
312 | void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); | 312 | void nfs4_pnfs_ds_put(struct nfs4_pnfs_ds *ds); |
313 | struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, | 313 | struct nfs4_pnfs_ds *nfs4_pnfs_ds_add(struct list_head *dsaddrs, |
314 | gfp_t gfp_flags); | 314 | gfp_t gfp_flags); |
315 | struct nfs4_pnfs_ds_addr *nfs4_decode_mp_ds_addr(struct net *net, | ||
316 | struct xdr_stream *xdr, | ||
317 | gfp_t gfp_flags); | ||
315 | 318 | ||
316 | static inline struct nfs4_deviceid_node * | 319 | static inline struct nfs4_deviceid_node * |
317 | nfs4_get_deviceid(struct nfs4_deviceid_node *d) | 320 | nfs4_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 | } |
534 | EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add); | 535 | EXPORT_SYMBOL_GPL(nfs4_pnfs_ds_add); |
536 | |||
537 | /* | ||
538 | * Currently only supports ipv4, ipv6 and one multi-path address. | ||
539 | */ | ||
540 | struct nfs4_pnfs_ds_addr * | ||
541 | nfs4_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 | |||
673 | out_free_da: | ||
674 | kfree(da); | ||
675 | out_free_buf: | ||
676 | dprintk("%s: Error parsing DS addr: %s\n", __func__, buf); | ||
677 | kfree(buf); | ||
678 | out_free_netid: | ||
679 | kfree(netid); | ||
680 | out_err: | ||
681 | return NULL; | ||
682 | } | ||
683 | EXPORT_SYMBOL_GPL(nfs4_decode_mp_ds_addr); | ||