diff options
Diffstat (limited to 'fs/nfs/client.c')
-rw-r--r-- | fs/nfs/client.c | 95 |
1 files changed, 61 insertions, 34 deletions
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 7547600b6174..9b728f3565a1 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -143,7 +143,6 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ | |||
143 | clp->cl_proto = cl_init->proto; | 143 | clp->cl_proto = cl_init->proto; |
144 | 144 | ||
145 | #ifdef CONFIG_NFS_V4 | 145 | #ifdef CONFIG_NFS_V4 |
146 | init_rwsem(&clp->cl_sem); | ||
147 | INIT_LIST_HEAD(&clp->cl_delegations); | 146 | INIT_LIST_HEAD(&clp->cl_delegations); |
148 | spin_lock_init(&clp->cl_lock); | 147 | spin_lock_init(&clp->cl_lock); |
149 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); | 148 | INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); |
@@ -224,31 +223,54 @@ void nfs_put_client(struct nfs_client *clp) | |||
224 | } | 223 | } |
225 | } | 224 | } |
226 | 225 | ||
227 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | 226 | #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) |
228 | const struct sockaddr_in *sa2) | 227 | static const struct in6_addr *nfs_map_ipv4_addr(const struct sockaddr *sa, struct in6_addr *addr_mapped) |
229 | { | 228 | { |
230 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; | 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 | } | ||
231 | } | 240 | } |
232 | 241 | ||
233 | static int nfs_sockaddr_match_ipaddr6(const struct sockaddr_in6 *sa1, | 242 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, |
234 | const struct sockaddr_in6 *sa2) | 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 | #else | ||
259 | static int nfs_sockaddr_match_ipaddr4(const struct sockaddr_in *sa1, | ||
260 | const struct sockaddr_in *sa2) | ||
235 | { | 261 | { |
236 | return ipv6_addr_equal(&sa1->sin6_addr, &sa2->sin6_addr); | 262 | return sa1->sin_addr.s_addr == sa2->sin_addr.s_addr; |
237 | } | 263 | } |
238 | 264 | ||
239 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, | 265 | static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1, |
240 | const struct sockaddr *sa2) | 266 | const struct sockaddr *sa2) |
241 | { | 267 | { |
242 | switch (sa1->sa_family) { | 268 | if (unlikely(sa1->sa_family != AF_INET || sa2->sa_family != AF_INET)) |
243 | case AF_INET: | 269 | return 0; |
244 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, | 270 | return nfs_sockaddr_match_ipaddr4((const struct sockaddr_in *)sa1, |
245 | (const struct sockaddr_in *)sa2); | 271 | (const struct sockaddr_in *)sa2); |
246 | case AF_INET6: | ||
247 | return nfs_sockaddr_match_ipaddr6((const struct sockaddr_in6 *)sa1, | ||
248 | (const struct sockaddr_in6 *)sa2); | ||
249 | } | ||
250 | BUG(); | ||
251 | } | 272 | } |
273 | #endif | ||
252 | 274 | ||
253 | /* | 275 | /* |
254 | * Find a client by IP address and protocol version | 276 | * Find a client by IP address and protocol version |
@@ -270,8 +292,6 @@ struct nfs_client *nfs_find_client(const struct sockaddr *addr, u32 nfsversion) | |||
270 | if (clp->rpc_ops->version != nfsversion) | 292 | if (clp->rpc_ops->version != nfsversion) |
271 | continue; | 293 | continue; |
272 | 294 | ||
273 | if (addr->sa_family != clap->sa_family) | ||
274 | continue; | ||
275 | /* Match only the IP address, not the port number */ | 295 | /* Match only the IP address, not the port number */ |
276 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) | 296 | if (!nfs_sockaddr_match_ipaddr(addr, clap)) |
277 | continue; | 297 | continue; |
@@ -305,8 +325,6 @@ struct nfs_client *nfs_find_client_next(struct nfs_client *clp) | |||
305 | if (clp->rpc_ops->version != nfsvers) | 325 | if (clp->rpc_ops->version != nfsvers) |
306 | continue; | 326 | continue; |
307 | 327 | ||
308 | if (sap->sa_family != clap->sa_family) | ||
309 | continue; | ||
310 | /* Match only the IP address, not the port number */ | 328 | /* Match only the IP address, not the port number */ |
311 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) | 329 | if (!nfs_sockaddr_match_ipaddr(sap, clap)) |
312 | continue; | 330 | continue; |
@@ -470,7 +488,7 @@ static void nfs_init_timeout_values(struct rpc_timeout *to, int proto, | |||
470 | static int nfs_create_rpc_client(struct nfs_client *clp, | 488 | static int nfs_create_rpc_client(struct nfs_client *clp, |
471 | const struct rpc_timeout *timeparms, | 489 | const struct rpc_timeout *timeparms, |
472 | rpc_authflavor_t flavor, | 490 | rpc_authflavor_t flavor, |
473 | int flags) | 491 | int discrtry, int noresvport) |
474 | { | 492 | { |
475 | struct rpc_clnt *clnt = NULL; | 493 | struct rpc_clnt *clnt = NULL; |
476 | struct rpc_create_args args = { | 494 | struct rpc_create_args args = { |
@@ -482,9 +500,13 @@ static int nfs_create_rpc_client(struct nfs_client *clp, | |||
482 | .program = &nfs_program, | 500 | .program = &nfs_program, |
483 | .version = clp->rpc_ops->version, | 501 | .version = clp->rpc_ops->version, |
484 | .authflavor = flavor, | 502 | .authflavor = flavor, |
485 | .flags = flags, | ||
486 | }; | 503 | }; |
487 | 504 | ||
505 | if (discrtry) | ||
506 | args.flags |= RPC_CLNT_CREATE_DISCRTRY; | ||
507 | if (noresvport) | ||
508 | args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; | ||
509 | |||
488 | if (!IS_ERR(clp->cl_rpcclient)) | 510 | if (!IS_ERR(clp->cl_rpcclient)) |
489 | return 0; | 511 | return 0; |
490 | 512 | ||
@@ -522,6 +544,8 @@ static int nfs_start_lockd(struct nfs_server *server) | |||
522 | .protocol = server->flags & NFS_MOUNT_TCP ? | 544 | .protocol = server->flags & NFS_MOUNT_TCP ? |
523 | IPPROTO_TCP : IPPROTO_UDP, | 545 | IPPROTO_TCP : IPPROTO_UDP, |
524 | .nfs_version = clp->rpc_ops->version, | 546 | .nfs_version = clp->rpc_ops->version, |
547 | .noresvport = server->flags & NFS_MOUNT_NORESVPORT ? | ||
548 | 1 : 0, | ||
525 | }; | 549 | }; |
526 | 550 | ||
527 | if (nlm_init.nfs_version > 3) | 551 | if (nlm_init.nfs_version > 3) |
@@ -623,7 +647,8 @@ static int nfs_init_client(struct nfs_client *clp, | |||
623 | * Create a client RPC handle for doing FSSTAT with UNIX auth only | 647 | * Create a client RPC handle for doing FSSTAT with UNIX auth only |
624 | * - RFC 2623, sec 2.3.2 | 648 | * - RFC 2623, sec 2.3.2 |
625 | */ | 649 | */ |
626 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, 0); | 650 | error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX, |
651 | 0, data->flags & NFS_MOUNT_NORESVPORT); | ||
627 | if (error < 0) | 652 | if (error < 0) |
628 | goto error; | 653 | goto error; |
629 | nfs_mark_client_ready(clp, NFS_CS_READY); | 654 | nfs_mark_client_ready(clp, NFS_CS_READY); |
@@ -965,7 +990,8 @@ error: | |||
965 | static int nfs4_init_client(struct nfs_client *clp, | 990 | static int nfs4_init_client(struct nfs_client *clp, |
966 | const struct rpc_timeout *timeparms, | 991 | const struct rpc_timeout *timeparms, |
967 | const char *ip_addr, | 992 | const char *ip_addr, |
968 | rpc_authflavor_t authflavour) | 993 | rpc_authflavor_t authflavour, |
994 | int flags) | ||
969 | { | 995 | { |
970 | int error; | 996 | int error; |
971 | 997 | ||
@@ -979,7 +1005,7 @@ static int nfs4_init_client(struct nfs_client *clp, | |||
979 | clp->rpc_ops = &nfs_v4_clientops; | 1005 | clp->rpc_ops = &nfs_v4_clientops; |
980 | 1006 | ||
981 | error = nfs_create_rpc_client(clp, timeparms, authflavour, | 1007 | error = nfs_create_rpc_client(clp, timeparms, authflavour, |
982 | RPC_CLNT_CREATE_DISCRTRY); | 1008 | 1, flags & NFS_MOUNT_NORESVPORT); |
983 | if (error < 0) | 1009 | if (error < 0) |
984 | goto error; | 1010 | goto error; |
985 | memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); | 1011 | memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); |
@@ -1030,7 +1056,8 @@ static int nfs4_set_client(struct nfs_server *server, | |||
1030 | error = PTR_ERR(clp); | 1056 | error = PTR_ERR(clp); |
1031 | goto error; | 1057 | goto error; |
1032 | } | 1058 | } |
1033 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour); | 1059 | error = nfs4_init_client(clp, timeparms, ip_addr, authflavour, |
1060 | server->flags); | ||
1034 | if (error < 0) | 1061 | if (error < 0) |
1035 | goto error_put; | 1062 | goto error_put; |
1036 | 1063 | ||
@@ -1059,6 +1086,10 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1059 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, | 1086 | nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, |
1060 | data->timeo, data->retrans); | 1087 | data->timeo, data->retrans); |
1061 | 1088 | ||
1089 | /* Initialise the client representation from the mount data */ | ||
1090 | server->flags = data->flags; | ||
1091 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
1092 | |||
1062 | /* Get a client record */ | 1093 | /* Get a client record */ |
1063 | error = nfs4_set_client(server, | 1094 | error = nfs4_set_client(server, |
1064 | data->nfs_server.hostname, | 1095 | data->nfs_server.hostname, |
@@ -1071,10 +1102,6 @@ static int nfs4_init_server(struct nfs_server *server, | |||
1071 | if (error < 0) | 1102 | if (error < 0) |
1072 | goto error; | 1103 | goto error; |
1073 | 1104 | ||
1074 | /* Initialise the client representation from the mount data */ | ||
1075 | server->flags = data->flags; | ||
1076 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
1077 | |||
1078 | if (data->rsize) | 1105 | if (data->rsize) |
1079 | server->rsize = nfs_block_size(data->rsize, NULL); | 1106 | server->rsize = nfs_block_size(data->rsize, NULL); |
1080 | if (data->wsize) | 1107 | if (data->wsize) |
@@ -1177,6 +1204,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1177 | parent_server = NFS_SB(data->sb); | 1204 | parent_server = NFS_SB(data->sb); |
1178 | parent_client = parent_server->nfs_client; | 1205 | parent_client = parent_server->nfs_client; |
1179 | 1206 | ||
1207 | /* Initialise the client representation from the parent server */ | ||
1208 | nfs_server_copy_userdata(server, parent_server); | ||
1209 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
1210 | |||
1180 | /* Get a client representation. | 1211 | /* Get a client representation. |
1181 | * Note: NFSv4 always uses TCP, */ | 1212 | * Note: NFSv4 always uses TCP, */ |
1182 | error = nfs4_set_client(server, data->hostname, | 1213 | error = nfs4_set_client(server, data->hostname, |
@@ -1189,10 +1220,6 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1189 | if (error < 0) | 1220 | if (error < 0) |
1190 | goto error; | 1221 | goto error; |
1191 | 1222 | ||
1192 | /* Initialise the client representation from the parent server */ | ||
1193 | nfs_server_copy_userdata(server, parent_server); | ||
1194 | server->caps |= NFS_CAP_ATOMIC_OPEN; | ||
1195 | |||
1196 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); | 1223 | error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); |
1197 | if (error < 0) | 1224 | if (error < 0) |
1198 | goto error; | 1225 | goto error; |