diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 132 |
1 files changed, 63 insertions, 69 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 574158ae2398..75c9cd2aa119 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include "delegation.h" | 45 | #include "delegation.h" |
46 | #include "iostat.h" | 46 | #include "iostat.h" |
47 | #include "internal.h" | 47 | #include "internal.h" |
48 | #include "fscache.h" | ||
48 | 49 | ||
49 | #define NFSDBG_FACILITY NFSDBG_CLIENT | 50 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
50 | 51 | ||
@@ -154,6 +155,8 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
154 | if (!IS_ERR(cred)) | 155 | if (!IS_ERR(cred)) |
155 | clp->cl_machine_cred = cred; | 156 | clp->cl_machine_cred = cred; |
156 | 157 | ||
158 | nfs_fscache_get_client_cookie(clp); | ||
159 | |||
157 | return clp; | 160 | return clp; |
158 | 161 | ||
159 | error_3: | 162 | error_3: |
@@ -187,6 +190,8 @@ static void nfs_free_client(struct nfs_client *clp) | |||
187 | 190 | ||
188 | nfs4_shutdown_client(clp); | 191 | nfs4_shutdown_client(clp); |
189 | 192 | ||
193 | nfs_fscache_release_client_cookie(clp); | ||
194 | |||
190 | /* -EIO all pending I/O */ | 195 | /* -EIO all pending I/O */ |
191 | if (!IS_ERR(clp->cl_rpcclient)) | 196 | if (!IS_ERR(clp->cl_rpcclient)) |
192 | rpc_shutdown_client(clp->cl_rpcclient); | 197 | rpc_shutdown_client(clp->cl_rpcclient); |
@@ -224,38 +229,6 @@ void nfs_put_client(struct nfs_client *clp) | |||
224 | } | 229 | } |
225 | 230 | ||
226 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) | 231 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
227 | static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped) | ||
228 | { | ||
229 | switch (sa->sa_family) { | ||
230 | default: | ||
231 | return NULL; | ||
232 | case AF_INET6: | ||
233 | return &((const struct sockaddr_in6 *)sa)->sin6_addr; | ||
234 | break; | ||
235 | case AF_INET: | ||
236 | ipv6_addr_set_v4mapped(((const struct sockaddr_in *)sa)->sin_addr.s_addr, | ||
237 | addr_mapped); | ||
238 | return addr_mapped; | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
243 | const struct sockaddr *sa2) | ||
244 | { | ||
245 | const struct in6_addr *addr1; | ||
246 | const struct in6_addr *addr2; | ||
247 | struct in6_addr addr1_mapped; | ||
248 | struct in6_addr addr2_mapped; | ||
249 | |||
250 | addr1 = nfs_map_ipv4_addr(sa1, &addr1_mapped); | ||
251 | if (likely(addr1 != NULL)) { | ||
252 | addr2 = nfs_map_ipv4_addr(sa2, &addr2_mapped); | ||
253 | if (likely(addr2 != NULL)) | ||
254 | return ipv6_addr_equal(addr1, addr2); | ||
255 | } | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /* | 232 | /* |
260 | * Test if two ip6 socket addresses refer to the same socket by | 233 | * Test if two ip6 socket addresses refer to the same socket by |
261 | * comparing relevant fields. The padding bytes specifically, are not | 234 | * comparing relevant fields. The padding bytes specifically, are not |
@@ -267,38 +240,21 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | |||
267 | * | 240 | * |
268 | * The caller should ensure both socket addresses are AF_INET6. | 241 | * The caller should ensure both socket addresses are AF_INET6. |
269 | */ | 242 | */ |
270 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, | 243 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, |
271 | const struct sockaddr *sa2) | 244 | const struct sockaddr *sa2) |
272 | { | 245 | { |
273 | const struct sockaddr_in6 *saddr1 = (const struct sockaddr_in6 *)sa1; | 246 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; |
274 | const struct sockaddr_in6 *saddr2 = (const struct sockaddr_in6 *)sa2; | 247 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; |
275 | 248 | ||
276 | if (!ipv6_addr_equal(&saddr1->sin6_addr, | 249 | if (ipv6_addr_scope(&sin1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL && |
277 | &saddr1->sin6_addr)) | 250 | sin1->sin6_scope_id != sin2->sin6_scope_id) |
278 | return 0; | ||
279 | if (ipv6_addr_scope(&saddr1->sin6_addr) == IPV6_ADDR_SCOPE_LINKLOCAL && | ||
280 | saddr1->sin6_scope_id != saddr2->sin6_scope_id) | ||
281 | return 0; | 251 | return 0; |
282 | return saddr1->sin6_port == saddr2->sin6_port; | ||
283 | } | ||
284 | #else | ||
285 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
286 | const struct sockaddr_in *sa2) | ||
287 | { | ||
288 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | ||
289 | } | ||
290 | 252 | ||
291 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | 253 | return ipv6_addr_equal(&sin1->sin6_addr, &sin1->sin6_addr); |
292 | const struct sockaddr *sa2) | ||
293 | { | ||
294 | if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET)) | ||
295 | return 0; | ||
296 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | ||
297 | (const struct sockaddr_in *)sa2); | ||
298 | } | 254 | } |
299 | 255 | #else /* !defined(CONFIG_IPV6) && !defined(CONFIG_IPV6_MODULE) */ | |
300 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, | 256 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr *sa1, |
301 | const struct sockaddr * sa2) | 257 | const struct sockaddr *sa2) |
302 | { | 258 | { |
303 | return 0; | 259 | return 0; |
304 | } | 260 | } |
@@ -311,20 +267,57 @@ static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, | |||
311 | * | 267 | * |
312 | * The caller should ensure both socket addresses are AF_INET. | 268 | * The caller should ensure both socket addresses are AF_INET. |
313 | */ | 269 | */ |
270 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr *sa1, | ||
271 | const struct sockaddr *sa2) | ||
272 | { | ||
273 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; | ||
274 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; | ||
275 | |||
276 | return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; | ||
277 | } | ||
278 | |||
279 | static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, | ||
280 | const struct sockaddr *sa2) | ||
281 | { | ||
282 | const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; | ||
283 | const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; | ||
284 | |||
285 | return nfs_sockaddr_match_ipaddr6(sa1, sa2) && | ||
286 | (sin1->sin6_port == sin2->sin6_port); | ||
287 | } | ||
288 | |||
314 | static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, | 289 | static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, |
315 | const struct sockaddr *sa2) | 290 | const struct sockaddr *sa2) |
316 | { | 291 | { |
317 | const struct sockaddr_in *saddr1 = (const struct sockaddr_in *)sa1; | 292 | const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; |
318 | const struct sockaddr_in *saddr2 = (const struct sockaddr_in *)sa2; | 293 | const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; |
319 | 294 | ||
320 | if (saddr1->sin_addr.s_addr != saddr2->sin_addr.s_addr) | 295 | return nfs_sockaddr_match_ipaddr4(sa1, sa2) && |
296 | (sin1->sin_port == sin2->sin_port); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Test if two socket addresses represent the same actual socket, | ||
301 | * by comparing (only) relevant fields, excluding the port number. | ||
302 | */ | ||
303 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | ||
304 | const struct sockaddr *sa2) | ||
305 | { | ||
306 | if (sa1->sa_family != sa2->sa_family) | ||
321 | return 0; | 307 | return 0; |
322 | return saddr1->sin_port == saddr2->sin_port; | 308 | |
309 | switch (sa1->sa_family) { | ||
310 | case AF_INET: | ||
311 | return nfs_sockaddr_match_ipaddr4(sa1, sa2); | ||
312 | case AF_INET6: | ||
313 | return nfs_sockaddr_match_ipaddr6(sa1, sa2); | ||
314 | } | ||
315 | return 0; | ||
323 | } | 316 | } |
324 | 317 | ||
325 | /* | 318 | /* |
326 | * Test if two socket addresses represent the same actual socket, | 319 | * Test if two socket addresses represent the same actual socket, |
327 | * by comparing (only) relevant fields. | 320 | * by comparing (only) relevant fields, including the port number. |
328 | */ | 321 | */ |
329 | static int nfs_sockaddr_cmp(const struct sockaddr *sa1, | 322 | static int nfs_sockaddr_cmp(const struct sockaddr *sa1, |
330 | const struct sockaddr *sa2) | 323 | const struct sockaddr *sa2) |
@@ -772,6 +765,7 @@ static int nfs_init_server(struct nfs_server *server, | |||
772 | 765 | ||
773 | /* Initialise the client representation from the mount data */ | 766 | /* Initialise the client representation from the mount data */ |
774 | server->flags = data->flags; | 767 | server->flags = data->flags; |
768 | server->options = data->options; | ||
775 | 769 | ||
776 | if (data->rsize) | 770 | if (data->rsize) |
777 | server->rsize = nfs_block_size(data->rsize, NULL); | 771 | server->rsize = nfs_block_size(data->rsize, NULL); |
@@ -1160,6 +1154,7 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1160 | /* Initialise the client representation from the mount data */ | 1154 | /* Initialise the client representation from the mount data */ |
1161 | server->flags = data->flags; | 1155 | server->flags = data->flags; |
1162 | server->caps |= NFS_CAP_ATOMIC_OPEN; | 1156 | server->caps |= NFS_CAP_ATOMIC_OPEN; |
1157 | server->options = data->options; | ||
1163 | 1158 | ||
1164 | /* Get a client record */ | 1159 | /* Get a client record */ |
1165 | error = nfs4_set_client(server, | 1160 | error = nfs4_set_client(server, |
@@ -1571,7 +1566,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1571 | 1566 | ||
1572 | /* display header on line 1 */ | 1567 | /* display header on line 1 */ |
1573 | if (v == &nfs_volume_list) { | 1568 | if (v == &nfs_volume_list) { |
1574 | seq_puts(m, "NV SERVER PORT DEV FSID\n"); | 1569 | seq_puts(m, "NV SERVER PORT DEV FSID FSC\n"); |
1575 | return 0; | 1570 | return 0; |
1576 | } | 1571 | } |
1577 | /* display one transport per line on subsequent lines */ | 1572 | /* display one transport per line on subsequent lines */ |
@@ -1585,12 +1580,13 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1585 | (unsigned long long) server->fsid.major, | 1580 | (unsigned long long) server->fsid.major, |
1586 | (unsigned long long) server->fsid.minor); | 1581 | (unsigned long long) server->fsid.minor); |
1587 | 1582 | ||
1588 | seq_printf(m, "v%u %s %s %-7s %-17s\n", | 1583 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", |
1589 | clp->rpc_ops->version, | 1584 | clp->rpc_ops->version, |
1590 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 1585 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1591 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), | 1586 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1592 | dev, | 1587 | dev, |
1593 | fsid); | 1588 | fsid, |
1589 | nfs_server_fscache_state(server)); | ||
1594 | 1590 | ||
1595 | return 0; | 1591 | return 0; |
1596 | } | 1592 | } |
@@ -1606,8 +1602,6 @@ int __init nfs_fs_proc_init(void) | |||
1606 | if (!proc_fs_nfs) | 1602 | if (!proc_fs_nfs) |
1607 | goto error_0; | 1603 | goto error_0; |
1608 | 1604 | ||
1609 | proc_fs_nfs->owner = THIS_MODULE; | ||
1610 | |||
1611 | /* a file of servers with which we're dealing */ | 1605 | /* a file of servers with which we're dealing */ |
1612 | p = proc_create("servers", S_IFREG|S_IRUGO, | 1606 | p = proc_create("servers", S_IFREG|S_IRUGO, |
1613 | proc_fs_nfs, &nfs_server_list_fops); | 1607 | proc_fs_nfs, &nfs_server_list_fops); |