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; |
