aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r--fs/nfs/client.c132
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
159error_3: 162error_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)
227static 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
242static 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 */
270static int nfs_sockaddr_cmp_ip6(const struct sockaddr *sa1, 243static 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
285static 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
291static 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) */
300static int nfs_sockaddr_cmp_ip6(const struct sockaddr * sa1, 256static 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 */
270static 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
279static 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
314static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1, 289static 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 */
303static 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 */
329static int nfs_sockaddr_cmp(const struct sockaddr *sa1, 322static 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);