diff options
Diffstat (limited to 'fs/nfs/nfs4filelayoutdev.c')
-rw-r--r-- | fs/nfs/nfs4filelayoutdev.c | 452 |
1 files changed, 338 insertions, 114 deletions
diff --git a/fs/nfs/nfs4filelayoutdev.c b/fs/nfs/nfs4filelayoutdev.c index 3b7bf137726..ed388aae968 100644 --- a/fs/nfs/nfs4filelayoutdev.c +++ b/fs/nfs/nfs4filelayoutdev.c | |||
@@ -56,54 +56,139 @@ print_ds(struct nfs4_pnfs_ds *ds) | |||
56 | printk("%s NULL device\n", __func__); | 56 | printk("%s NULL device\n", __func__); |
57 | return; | 57 | return; |
58 | } | 58 | } |
59 | printk(" ip_addr %x port %hu\n" | 59 | printk(" ds %s\n" |
60 | " ref count %d\n" | 60 | " ref count %d\n" |
61 | " client %p\n" | 61 | " client %p\n" |
62 | " cl_exchange_flags %x\n", | 62 | " cl_exchange_flags %x\n", |
63 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port), | 63 | ds->ds_remotestr, |
64 | atomic_read(&ds->ds_count), ds->ds_clp, | 64 | atomic_read(&ds->ds_count), ds->ds_clp, |
65 | ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0); | 65 | ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0); |
66 | } | 66 | } |
67 | 67 | ||
68 | /* nfs4_ds_cache_lock is held */ | 68 | static bool |
69 | static struct nfs4_pnfs_ds * | 69 | same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2) |
70 | _data_server_lookup_locked(u32 ip_addr, u32 port) | ||
71 | { | 70 | { |
72 | struct nfs4_pnfs_ds *ds; | 71 | struct sockaddr_in *a, *b; |
72 | struct sockaddr_in6 *a6, *b6; | ||
73 | |||
74 | if (addr1->sa_family != addr2->sa_family) | ||
75 | return false; | ||
76 | |||
77 | switch (addr1->sa_family) { | ||
78 | case AF_INET: | ||
79 | a = (struct sockaddr_in *)addr1; | ||
80 | b = (struct sockaddr_in *)addr2; | ||
81 | |||
82 | if (a->sin_addr.s_addr == b->sin_addr.s_addr && | ||
83 | a->sin_port == b->sin_port) | ||
84 | return true; | ||
85 | break; | ||
86 | |||
87 | case AF_INET6: | ||
88 | a6 = (struct sockaddr_in6 *)addr1; | ||
89 | b6 = (struct sockaddr_in6 *)addr2; | ||
90 | |||
91 | /* LINKLOCAL addresses must have matching scope_id */ | ||
92 | if (ipv6_addr_scope(&a6->sin6_addr) == | ||
93 | IPV6_ADDR_SCOPE_LINKLOCAL && | ||
94 | a6->sin6_scope_id != b6->sin6_scope_id) | ||
95 | return false; | ||
96 | |||
97 | if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) && | ||
98 | a6->sin6_port == b6->sin6_port) | ||
99 | return true; | ||
100 | break; | ||
101 | |||
102 | default: | ||
103 | dprintk("%s: unhandled address family: %u\n", | ||
104 | __func__, addr1->sa_family); | ||
105 | return false; | ||
106 | } | ||
73 | 107 | ||
74 | dprintk("_data_server_lookup: ip_addr=%x port=%hu\n", | 108 | return false; |
75 | ntohl(ip_addr), ntohs(port)); | 109 | } |
76 | 110 | ||
77 | list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) { | 111 | /* |
78 | if (ds->ds_ip_addr == ip_addr && | 112 | * Lookup DS by addresses. The first matching address returns true. |
79 | ds->ds_port == port) { | 113 | * nfs4_ds_cache_lock is held |
80 | return ds; | 114 | */ |
115 | static struct nfs4_pnfs_ds * | ||
116 | _data_server_lookup_locked(struct list_head *dsaddrs) | ||
117 | { | ||
118 | struct nfs4_pnfs_ds *ds; | ||
119 | struct nfs4_pnfs_ds_addr *da1, *da2; | ||
120 | |||
121 | list_for_each_entry(da1, dsaddrs, da_node) { | ||
122 | list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) { | ||
123 | list_for_each_entry(da2, &ds->ds_addrs, da_node) { | ||
124 | if (same_sockaddr( | ||
125 | (struct sockaddr *)&da1->da_addr, | ||
126 | (struct sockaddr *)&da2->da_addr)) | ||
127 | return ds; | ||
128 | } | ||
81 | } | 129 | } |
82 | } | 130 | } |
83 | return NULL; | 131 | return NULL; |
84 | } | 132 | } |
85 | 133 | ||
86 | /* | 134 | /* |
135 | * Compare two lists of addresses. | ||
136 | */ | ||
137 | static bool | ||
138 | _data_server_match_all_addrs_locked(struct list_head *dsaddrs1, | ||
139 | struct list_head *dsaddrs2) | ||
140 | { | ||
141 | struct nfs4_pnfs_ds_addr *da1, *da2; | ||
142 | size_t count1 = 0, | ||
143 | count2 = 0; | ||
144 | |||
145 | list_for_each_entry(da1, dsaddrs1, da_node) | ||
146 | count1++; | ||
147 | |||
148 | list_for_each_entry(da2, dsaddrs2, da_node) { | ||
149 | bool found = false; | ||
150 | count2++; | ||
151 | list_for_each_entry(da1, dsaddrs1, da_node) { | ||
152 | if (same_sockaddr((struct sockaddr *)&da1->da_addr, | ||
153 | (struct sockaddr *)&da2->da_addr)) { | ||
154 | found = true; | ||
155 | break; | ||
156 | } | ||
157 | } | ||
158 | if (!found) | ||
159 | return false; | ||
160 | } | ||
161 | |||
162 | return (count1 == count2); | ||
163 | } | ||
164 | |||
165 | /* | ||
87 | * Create an rpc connection to the nfs4_pnfs_ds data server | 166 | * Create an rpc connection to the nfs4_pnfs_ds data server |
88 | * Currently only support IPv4 | 167 | * Currently only supports IPv4 and IPv6 addresses |
89 | */ | 168 | */ |
90 | static int | 169 | static int |
91 | nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) | 170 | nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) |
92 | { | 171 | { |
93 | struct nfs_client *clp; | 172 | struct nfs_client *clp = ERR_PTR(-EIO); |
94 | struct sockaddr_in sin; | 173 | struct nfs4_pnfs_ds_addr *da; |
95 | int status = 0; | 174 | int status = 0; |
96 | 175 | ||
97 | dprintk("--> %s ip:port %x:%hu au_flavor %d\n", __func__, | 176 | dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr, |
98 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port), | ||
99 | mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor); | 177 | mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor); |
100 | 178 | ||
101 | sin.sin_family = AF_INET; | 179 | BUG_ON(list_empty(&ds->ds_addrs)); |
102 | sin.sin_addr.s_addr = ds->ds_ip_addr; | 180 | |
103 | sin.sin_port = ds->ds_port; | 181 | list_for_each_entry(da, &ds->ds_addrs, da_node) { |
182 | dprintk("%s: DS %s: trying address %s\n", | ||
183 | __func__, ds->ds_remotestr, da->da_remotestr); | ||
184 | |||
185 | clp = nfs4_set_ds_client(mds_srv->nfs_client, | ||
186 | (struct sockaddr *)&da->da_addr, | ||
187 | da->da_addrlen, IPPROTO_TCP); | ||
188 | if (!IS_ERR(clp)) | ||
189 | break; | ||
190 | } | ||
104 | 191 | ||
105 | clp = nfs4_set_ds_client(mds_srv->nfs_client, (struct sockaddr *)&sin, | ||
106 | sizeof(sin), IPPROTO_TCP); | ||
107 | if (IS_ERR(clp)) { | 192 | if (IS_ERR(clp)) { |
108 | status = PTR_ERR(clp); | 193 | status = PTR_ERR(clp); |
109 | goto out; | 194 | goto out; |
@@ -115,8 +200,8 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) | |||
115 | goto out_put; | 200 | goto out_put; |
116 | } | 201 | } |
117 | ds->ds_clp = clp; | 202 | ds->ds_clp = clp; |
118 | dprintk("%s [existing] ip=%x, port=%hu\n", __func__, | 203 | dprintk("%s [existing] server=%s\n", __func__, |
119 | ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); | 204 | ds->ds_remotestr); |
120 | goto out; | 205 | goto out; |
121 | } | 206 | } |
122 | 207 | ||
@@ -135,8 +220,7 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) | |||
135 | goto out_put; | 220 | goto out_put; |
136 | 221 | ||
137 | ds->ds_clp = clp; | 222 | ds->ds_clp = clp; |
138 | dprintk("%s [new] ip=%x, port=%hu\n", __func__, ntohl(ds->ds_ip_addr), | 223 | dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr); |
139 | ntohs(ds->ds_port)); | ||
140 | out: | 224 | out: |
141 | return status; | 225 | return status; |
142 | out_put: | 226 | out_put: |
@@ -147,12 +231,25 @@ out_put: | |||
147 | static void | 231 | static void |
148 | destroy_ds(struct nfs4_pnfs_ds *ds) | 232 | destroy_ds(struct nfs4_pnfs_ds *ds) |
149 | { | 233 | { |
234 | struct nfs4_pnfs_ds_addr *da; | ||
235 | |||
150 | dprintk("--> %s\n", __func__); | 236 | dprintk("--> %s\n", __func__); |
151 | ifdebug(FACILITY) | 237 | ifdebug(FACILITY) |
152 | print_ds(ds); | 238 | print_ds(ds); |
153 | 239 | ||
154 | if (ds->ds_clp) | 240 | if (ds->ds_clp) |
155 | nfs_put_client(ds->ds_clp); | 241 | nfs_put_client(ds->ds_clp); |
242 | |||
243 | while (!list_empty(&ds->ds_addrs)) { | ||
244 | da = list_first_entry(&ds->ds_addrs, | ||
245 | struct nfs4_pnfs_ds_addr, | ||
246 | da_node); | ||
247 | list_del_init(&da->da_node); | ||
248 | kfree(da->da_remotestr); | ||
249 | kfree(da); | ||
250 | } | ||
251 | |||
252 | kfree(ds->ds_remotestr); | ||
156 | kfree(ds); | 253 | kfree(ds); |
157 | } | 254 | } |
158 | 255 | ||
@@ -179,31 +276,96 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) | |||
179 | kfree(dsaddr); | 276 | kfree(dsaddr); |
180 | } | 277 | } |
181 | 278 | ||
279 | /* | ||
280 | * Create a string with a human readable address and port to avoid | ||
281 | * complicated setup around many dprinks. | ||
282 | */ | ||
283 | static char * | ||
284 | nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags) | ||
285 | { | ||
286 | struct nfs4_pnfs_ds_addr *da; | ||
287 | char *remotestr; | ||
288 | size_t len; | ||
289 | char *p; | ||
290 | |||
291 | len = 3; /* '{', '}' and eol */ | ||
292 | list_for_each_entry(da, dsaddrs, da_node) { | ||
293 | len += strlen(da->da_remotestr) + 1; /* string plus comma */ | ||
294 | } | ||
295 | |||
296 | remotestr = kzalloc(len, gfp_flags); | ||
297 | if (!remotestr) | ||
298 | return NULL; | ||
299 | |||
300 | p = remotestr; | ||
301 | *(p++) = '{'; | ||
302 | len--; | ||
303 | list_for_each_entry(da, dsaddrs, da_node) { | ||
304 | size_t ll = strlen(da->da_remotestr); | ||
305 | |||
306 | if (ll > len) | ||
307 | goto out_err; | ||
308 | |||
309 | memcpy(p, da->da_remotestr, ll); | ||
310 | p += ll; | ||
311 | len -= ll; | ||
312 | |||
313 | if (len < 1) | ||
314 | goto out_err; | ||
315 | (*p++) = ','; | ||
316 | len--; | ||
317 | } | ||
318 | if (len < 2) | ||
319 | goto out_err; | ||
320 | *(p++) = '}'; | ||
321 | *p = '\0'; | ||
322 | return remotestr; | ||
323 | out_err: | ||
324 | kfree(remotestr); | ||
325 | return NULL; | ||
326 | } | ||
327 | |||
182 | static struct nfs4_pnfs_ds * | 328 | static struct nfs4_pnfs_ds * |
183 | nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port, gfp_t gfp_flags) | 329 | nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) |
184 | { | 330 | { |
185 | struct nfs4_pnfs_ds *tmp_ds, *ds; | 331 | struct nfs4_pnfs_ds *tmp_ds, *ds = NULL; |
332 | char *remotestr; | ||
186 | 333 | ||
187 | ds = kzalloc(sizeof(*tmp_ds), gfp_flags); | 334 | if (list_empty(dsaddrs)) { |
335 | dprintk("%s: no addresses defined\n", __func__); | ||
336 | goto out; | ||
337 | } | ||
338 | |||
339 | ds = kzalloc(sizeof(*ds), gfp_flags); | ||
188 | if (!ds) | 340 | if (!ds) |
189 | goto out; | 341 | goto out; |
190 | 342 | ||
343 | /* this is only used for debugging, so it's ok if its NULL */ | ||
344 | remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags); | ||
345 | |||
191 | spin_lock(&nfs4_ds_cache_lock); | 346 | spin_lock(&nfs4_ds_cache_lock); |
192 | tmp_ds = _data_server_lookup_locked(ip_addr, port); | 347 | tmp_ds = _data_server_lookup_locked(dsaddrs); |
193 | if (tmp_ds == NULL) { | 348 | if (tmp_ds == NULL) { |
194 | ds->ds_ip_addr = ip_addr; | 349 | INIT_LIST_HEAD(&ds->ds_addrs); |
195 | ds->ds_port = port; | 350 | list_splice_init(dsaddrs, &ds->ds_addrs); |
351 | ds->ds_remotestr = remotestr; | ||
196 | atomic_set(&ds->ds_count, 1); | 352 | atomic_set(&ds->ds_count, 1); |
197 | INIT_LIST_HEAD(&ds->ds_node); | 353 | INIT_LIST_HEAD(&ds->ds_node); |
198 | ds->ds_clp = NULL; | 354 | ds->ds_clp = NULL; |
199 | list_add(&ds->ds_node, &nfs4_data_server_cache); | 355 | list_add(&ds->ds_node, &nfs4_data_server_cache); |
200 | dprintk("%s add new data server ip 0x%x\n", __func__, | 356 | dprintk("%s add new data server %s\n", __func__, |
201 | ds->ds_ip_addr); | 357 | ds->ds_remotestr); |
202 | } else { | 358 | } else { |
359 | if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs, | ||
360 | dsaddrs)) { | ||
361 | dprintk("%s: multipath address mismatch: %s != %s", | ||
362 | __func__, tmp_ds->ds_remotestr, remotestr); | ||
363 | } | ||
364 | kfree(remotestr); | ||
203 | kfree(ds); | 365 | kfree(ds); |
204 | atomic_inc(&tmp_ds->ds_count); | 366 | atomic_inc(&tmp_ds->ds_count); |
205 | dprintk("%s data server found ip 0x%x, inc'ed ds_count to %d\n", | 367 | dprintk("%s data server %s found, inc'ed ds_count to %d\n", |
206 | __func__, tmp_ds->ds_ip_addr, | 368 | __func__, tmp_ds->ds_remotestr, |
207 | atomic_read(&tmp_ds->ds_count)); | 369 | atomic_read(&tmp_ds->ds_count)); |
208 | ds = tmp_ds; | 370 | ds = tmp_ds; |
209 | } | 371 | } |
@@ -213,18 +375,22 @@ out: | |||
213 | } | 375 | } |
214 | 376 | ||
215 | /* | 377 | /* |
216 | * Currently only support ipv4, and one multi-path address. | 378 | * Currently only supports ipv4, ipv6 and one multi-path address. |
217 | */ | 379 | */ |
218 | static struct nfs4_pnfs_ds * | 380 | static struct nfs4_pnfs_ds_addr * |
219 | decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_flags) | 381 | decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) |
220 | { | 382 | { |
221 | struct nfs4_pnfs_ds *ds = NULL; | 383 | struct nfs4_pnfs_ds_addr *da = NULL; |
222 | char *buf; | 384 | char *buf, *portstr; |
223 | const char *ipend, *pstr; | 385 | u32 port; |
224 | u32 ip_addr, port; | 386 | int nlen, rlen; |
225 | int nlen, rlen, i; | ||
226 | int tmp[2]; | 387 | int tmp[2]; |
227 | __be32 *p; | 388 | __be32 *p; |
389 | char *netid, *match_netid; | ||
390 | size_t len, match_netid_len; | ||
391 | char *startsep = ""; | ||
392 | char *endsep = ""; | ||
393 | |||
228 | 394 | ||
229 | /* r_netid */ | 395 | /* r_netid */ |
230 | p = xdr_inline_decode(streamp, 4); | 396 | p = xdr_inline_decode(streamp, 4); |
@@ -236,64 +402,123 @@ decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_fla | |||
236 | if (unlikely(!p)) | 402 | if (unlikely(!p)) |
237 | goto out_err; | 403 | goto out_err; |
238 | 404 | ||
239 | /* Check that netid is "tcp" */ | 405 | netid = kmalloc(nlen+1, gfp_flags); |
240 | if (nlen != 3 || memcmp((char *)p, "tcp", 3)) { | 406 | if (unlikely(!netid)) |
241 | dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); | ||
242 | goto out_err; | 407 | goto out_err; |
243 | } | ||
244 | 408 | ||
245 | /* r_addr */ | 409 | netid[nlen] = '\0'; |
410 | memcpy(netid, p, nlen); | ||
411 | |||
412 | /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */ | ||
246 | p = xdr_inline_decode(streamp, 4); | 413 | p = xdr_inline_decode(streamp, 4); |
247 | if (unlikely(!p)) | 414 | if (unlikely(!p)) |
248 | goto out_err; | 415 | goto out_free_netid; |
249 | rlen = be32_to_cpup(p); | 416 | rlen = be32_to_cpup(p); |
250 | 417 | ||
251 | p = xdr_inline_decode(streamp, rlen); | 418 | p = xdr_inline_decode(streamp, rlen); |
252 | if (unlikely(!p)) | 419 | if (unlikely(!p)) |
253 | goto out_err; | 420 | goto out_free_netid; |
254 | 421 | ||
255 | /* ipv6 length plus port is legal */ | 422 | /* port is ".ABC.DEF", 8 chars max */ |
256 | if (rlen > INET6_ADDRSTRLEN + 8) { | 423 | if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) { |
257 | dprintk("%s: Invalid address, length %d\n", __func__, | 424 | dprintk("%s: Invalid address, length %d\n", __func__, |
258 | rlen); | 425 | rlen); |
259 | goto out_err; | 426 | goto out_free_netid; |
260 | } | 427 | } |
261 | buf = kmalloc(rlen + 1, gfp_flags); | 428 | buf = kmalloc(rlen + 1, gfp_flags); |
262 | if (!buf) { | 429 | if (!buf) { |
263 | dprintk("%s: Not enough memory\n", __func__); | 430 | dprintk("%s: Not enough memory\n", __func__); |
264 | goto out_err; | 431 | goto out_free_netid; |
265 | } | 432 | } |
266 | buf[rlen] = '\0'; | 433 | buf[rlen] = '\0'; |
267 | memcpy(buf, p, rlen); | 434 | memcpy(buf, p, rlen); |
268 | 435 | ||
269 | /* replace the port dots with dashes for the in4_pton() delimiter*/ | 436 | /* replace port '.' with '-' */ |
270 | for (i = 0; i < 2; i++) { | 437 | portstr = strrchr(buf, '.'); |
271 | char *res = strrchr(buf, '.'); | 438 | if (!portstr) { |
272 | if (!res) { | 439 | dprintk("%s: Failed finding expected dot in port\n", |
273 | dprintk("%s: Failed finding expected dots in port\n", | 440 | __func__); |
274 | __func__); | 441 | goto out_free_buf; |
275 | goto out_free; | 442 | } |
276 | } | 443 | *portstr = '-'; |
277 | *res = '-'; | 444 | |
445 | /* find '.' between address and port */ | ||
446 | portstr = strrchr(buf, '.'); | ||
447 | if (!portstr) { | ||
448 | dprintk("%s: Failed finding expected dot between address and " | ||
449 | "port\n", __func__); | ||
450 | goto out_free_buf; | ||
278 | } | 451 | } |
452 | *portstr = '\0'; | ||
279 | 453 | ||
280 | /* Currently only support ipv4 address */ | 454 | da = kzalloc(sizeof(*da), gfp_flags); |
281 | if (in4_pton(buf, rlen, (u8 *)&ip_addr, '-', &ipend) == 0) { | 455 | if (unlikely(!da)) |
282 | dprintk("%s: Only ipv4 addresses supported\n", __func__); | 456 | goto out_free_buf; |
283 | goto out_free; | 457 | |
458 | INIT_LIST_HEAD(&da->da_node); | ||
459 | |||
460 | if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr, | ||
461 | sizeof(da->da_addr))) { | ||
462 | dprintk("%s: error parsing address %s\n", __func__, buf); | ||
463 | goto out_free_da; | ||
284 | } | 464 | } |
285 | 465 | ||
286 | /* port */ | 466 | portstr++; |
287 | pstr = ipend; | 467 | sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]); |
288 | sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]); | ||
289 | port = htons((tmp[0] << 8) | (tmp[1])); | 468 | port = htons((tmp[0] << 8) | (tmp[1])); |
290 | 469 | ||
291 | ds = nfs4_pnfs_ds_add(inode, ip_addr, port, gfp_flags); | 470 | switch (da->da_addr.ss_family) { |
292 | dprintk("%s: Decoded address and port %s\n", __func__, buf); | 471 | case AF_INET: |
293 | out_free: | 472 | ((struct sockaddr_in *)&da->da_addr)->sin_port = port; |
473 | da->da_addrlen = sizeof(struct sockaddr_in); | ||
474 | match_netid = "tcp"; | ||
475 | match_netid_len = 3; | ||
476 | break; | ||
477 | |||
478 | case AF_INET6: | ||
479 | ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port; | ||
480 | da->da_addrlen = sizeof(struct sockaddr_in6); | ||
481 | match_netid = "tcp6"; | ||
482 | match_netid_len = 4; | ||
483 | startsep = "["; | ||
484 | endsep = "]"; | ||
485 | break; | ||
486 | |||
487 | default: | ||
488 | dprintk("%s: unsupported address family: %u\n", | ||
489 | __func__, da->da_addr.ss_family); | ||
490 | goto out_free_da; | ||
491 | } | ||
492 | |||
493 | if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) { | ||
494 | dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n", | ||
495 | __func__, netid, match_netid); | ||
496 | goto out_free_da; | ||
497 | } | ||
498 | |||
499 | /* save human readable address */ | ||
500 | len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7; | ||
501 | da->da_remotestr = kzalloc(len, gfp_flags); | ||
502 | |||
503 | /* NULL is ok, only used for dprintk */ | ||
504 | if (da->da_remotestr) | ||
505 | snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep, | ||
506 | buf, endsep, ntohs(port)); | ||
507 | |||
508 | dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr); | ||
294 | kfree(buf); | 509 | kfree(buf); |
510 | kfree(netid); | ||
511 | return da; | ||
512 | |||
513 | out_free_da: | ||
514 | kfree(da); | ||
515 | out_free_buf: | ||
516 | dprintk("%s: Error parsing DS addr: %s\n", __func__, buf); | ||
517 | kfree(buf); | ||
518 | out_free_netid: | ||
519 | kfree(netid); | ||
295 | out_err: | 520 | out_err: |
296 | return ds; | 521 | return NULL; |
297 | } | 522 | } |
298 | 523 | ||
299 | /* Decode opaque device data and return the result */ | 524 | /* Decode opaque device data and return the result */ |
@@ -310,6 +535,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
310 | struct xdr_stream stream; | 535 | struct xdr_stream stream; |
311 | struct xdr_buf buf; | 536 | struct xdr_buf buf; |
312 | struct page *scratch; | 537 | struct page *scratch; |
538 | struct list_head dsaddrs; | ||
539 | struct nfs4_pnfs_ds_addr *da; | ||
313 | 540 | ||
314 | /* set up xdr stream */ | 541 | /* set up xdr stream */ |
315 | scratch = alloc_page(gfp_flags); | 542 | scratch = alloc_page(gfp_flags); |
@@ -386,6 +613,8 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
386 | NFS_SERVER(ino)->nfs_client, | 613 | NFS_SERVER(ino)->nfs_client, |
387 | &pdev->dev_id); | 614 | &pdev->dev_id); |
388 | 615 | ||
616 | INIT_LIST_HEAD(&dsaddrs); | ||
617 | |||
389 | for (i = 0; i < dsaddr->ds_num; i++) { | 618 | for (i = 0; i < dsaddr->ds_num; i++) { |
390 | int j; | 619 | int j; |
391 | u32 mp_count; | 620 | u32 mp_count; |
@@ -395,48 +624,43 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) | |||
395 | goto out_err_free_deviceid; | 624 | goto out_err_free_deviceid; |
396 | 625 | ||
397 | mp_count = be32_to_cpup(p); /* multipath count */ | 626 | mp_count = be32_to_cpup(p); /* multipath count */ |
398 | if (mp_count > 1) { | ||
399 | printk(KERN_WARNING | ||
400 | "%s: Multipath count %d not supported, " | ||
401 | "skipping all greater than 1\n", __func__, | ||
402 | mp_count); | ||
403 | } | ||
404 | for (j = 0; j < mp_count; j++) { | 627 | for (j = 0; j < mp_count; j++) { |
405 | if (j == 0) { | 628 | da = decode_ds_addr(&stream, gfp_flags); |
406 | dsaddr->ds_list[i] = decode_and_add_ds(&stream, | 629 | if (da) |
407 | ino, gfp_flags); | 630 | list_add_tail(&da->da_node, &dsaddrs); |
408 | if (dsaddr->ds_list[i] == NULL) | 631 | } |
409 | goto out_err_free_deviceid; | 632 | if (list_empty(&dsaddrs)) { |
410 | } else { | 633 | dprintk("%s: no suitable DS addresses found\n", |
411 | u32 len; | 634 | __func__); |
412 | /* skip extra multipath */ | 635 | goto out_err_free_deviceid; |
413 | 636 | } | |
414 | /* read len, skip */ | 637 | |
415 | p = xdr_inline_decode(&stream, 4); | 638 | dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); |
416 | if (unlikely(!p)) | 639 | if (!dsaddr->ds_list[i]) |
417 | goto out_err_free_deviceid; | 640 | goto out_err_drain_dsaddrs; |
418 | len = be32_to_cpup(p); | 641 | |
419 | 642 | /* If DS was already in cache, free ds addrs */ | |
420 | p = xdr_inline_decode(&stream, len); | 643 | while (!list_empty(&dsaddrs)) { |
421 | if (unlikely(!p)) | 644 | da = list_first_entry(&dsaddrs, |
422 | goto out_err_free_deviceid; | 645 | struct nfs4_pnfs_ds_addr, |
423 | 646 | da_node); | |
424 | /* read len, skip */ | 647 | list_del_init(&da->da_node); |
425 | p = xdr_inline_decode(&stream, 4); | 648 | kfree(da->da_remotestr); |
426 | if (unlikely(!p)) | 649 | kfree(da); |
427 | goto out_err_free_deviceid; | ||
428 | len = be32_to_cpup(p); | ||
429 | |||
430 | p = xdr_inline_decode(&stream, len); | ||
431 | if (unlikely(!p)) | ||
432 | goto out_err_free_deviceid; | ||
433 | } | ||
434 | } | 650 | } |
435 | } | 651 | } |
436 | 652 | ||
437 | __free_page(scratch); | 653 | __free_page(scratch); |
438 | return dsaddr; | 654 | return dsaddr; |
439 | 655 | ||
656 | out_err_drain_dsaddrs: | ||
657 | while (!list_empty(&dsaddrs)) { | ||
658 | da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, | ||
659 | da_node); | ||
660 | list_del_init(&da->da_node); | ||
661 | kfree(da->da_remotestr); | ||
662 | kfree(da); | ||
663 | } | ||
440 | out_err_free_deviceid: | 664 | out_err_free_deviceid: |
441 | nfs4_fl_free_deviceid(dsaddr); | 665 | nfs4_fl_free_deviceid(dsaddr); |
442 | /* stripe_indicies was part of dsaddr */ | 666 | /* stripe_indicies was part of dsaddr */ |
@@ -591,13 +815,13 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) | |||
591 | 815 | ||
592 | static void | 816 | static void |
593 | filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr, | 817 | filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr, |
594 | int err, u32 ds_addr) | 818 | int err, const char *ds_remotestr) |
595 | { | 819 | { |
596 | u32 *p = (u32 *)&dsaddr->id_node.deviceid; | 820 | u32 *p = (u32 *)&dsaddr->id_node.deviceid; |
597 | 821 | ||
598 | printk(KERN_ERR "NFS: data server %x connection error %d." | 822 | printk(KERN_ERR "NFS: data server %s connection error %d." |
599 | " Deviceid [%x%x%x%x] marked out of use.\n", | 823 | " Deviceid [%x%x%x%x] marked out of use.\n", |
600 | ds_addr, err, p[0], p[1], p[2], p[3]); | 824 | ds_remotestr, err, p[0], p[1], p[2], p[3]); |
601 | 825 | ||
602 | spin_lock(&nfs4_ds_cache_lock); | 826 | spin_lock(&nfs4_ds_cache_lock); |
603 | dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY; | 827 | dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY; |
@@ -628,7 +852,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) | |||
628 | err = nfs4_ds_connect(s, ds); | 852 | err = nfs4_ds_connect(s, ds); |
629 | if (err) { | 853 | if (err) { |
630 | filelayout_mark_devid_negative(dsaddr, err, | 854 | filelayout_mark_devid_negative(dsaddr, err, |
631 | ntohl(ds->ds_ip_addr)); | 855 | ds->ds_remotestr); |
632 | return NULL; | 856 | return NULL; |
633 | } | 857 | } |
634 | } | 858 | } |