1 /* 2 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. 3 * Written by David Howells (dhowells@redhat.com) 4 */ 5 #include <linux/module.h> 6 #include <linux/nfs_fs.h> 7 #include <linux/nfs_idmap.h> 8 #include <linux/nfs_mount.h> 9 #include <linux/sunrpc/addr.h> 10 #include <linux/sunrpc/auth.h> 11 #include <linux/sunrpc/xprt.h> 12 #include <linux/sunrpc/bc_xprt.h> 13 #include "internal.h" 14 #include "callback.h" 15 #include "delegation.h" 16 #include "nfs4session.h" 17 #include "pnfs.h" 18 #include "netns.h" 19 20 #define NFSDBG_FACILITY NFSDBG_CLIENT 21 22 /* 23 * Get a unique NFSv4.0 callback identifier which will be used 24 * by the V4.0 callback service to lookup the nfs_client struct 25 */ 26 static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion) 27 { 28 int ret = 0; 29 struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id); 30 31 if (clp->rpc_ops->version != 4 || minorversion != 0) 32 return ret; 33 idr_preload(GFP_KERNEL); 34 spin_lock(&nn->nfs_client_lock); 35 ret = idr_alloc(&nn->cb_ident_idr, clp, 0, 0, GFP_NOWAIT); 36 if (ret >= 0) 37 clp->cl_cb_ident = ret; 38 spin_unlock(&nn->nfs_client_lock); 39 idr_preload_end(); 40 return ret < 0 ? ret : 0; 41 } 42 43 #ifdef CONFIG_NFS_V4_1 44 static void nfs4_shutdown_session(struct nfs_client *clp) 45 { 46 if (nfs4_has_session(clp)) { 47 nfs4_destroy_session(clp->cl_session); 48 nfs4_destroy_clientid(clp); 49 } 50 51 } 52 #else /* CONFIG_NFS_V4_1 */ 53 static void nfs4_shutdown_session(struct nfs_client *clp) 54 { 55 } 56 #endif /* CONFIG_NFS_V4_1 */ 57 58 struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init) 59 { 60 int err; 61 struct nfs_client *clp = nfs_alloc_client(cl_init); 62 if (IS_ERR(clp)) 63 return clp; 64 65 err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); 66 if (err) 67 goto error; 68 69 spin_lock_init(&clp->cl_lock); 70 INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state); 71 rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client"); 72 clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED; 73 clp->cl_minorversion = cl_init->minorversion; 74 clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion]; 75 return clp; 76 77 error: 78 nfs_free_client(clp); 79 return ERR_PTR(err); 80 } 81 82 /* 83 * Destroy the NFS4 callback service 84 */ 85 static void nfs4_destroy_callback(struct nfs_client *clp) 86 { 87 if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state)) 88 nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net); 89 } 90 91 static void nfs4_shutdown_client(struct nfs_client *clp) 92 { 93 if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state)) 94 nfs4_kill_renewd(clp); 95 nfs4_shutdown_session(clp); 96 nfs4_destroy_callback(clp); 97 if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state)) 98 nfs_idmap_delete(clp); 99 100 rpc_destroy_wait_queue(&clp->cl_rpcwaitq); 101 kfree(clp->cl_serverowner); 102 kfree(clp->cl_serverscope); 103 kfree(clp->cl_implid); 104 } 105 106 void nfs4_free_client(struct nfs_client *clp) 107 { 108 nfs4_shutdown_client(clp); 109 nfs_free_client(clp); 110 } 111 112 /* 113 * Initialize the NFS4 callback service 114 */ 115 static int nfs4_init_callback(struct nfs_client *clp) 116 { 117 int error; 118 119 if (clp->rpc_ops->version == 4) { 120 struct rpc_xprt *xprt; 121 122 xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); 123 124 if (nfs4_has_session(clp)) { 125 error = xprt_setup_backchannel(xprt, 126 NFS41_BC_MIN_CALLBACKS); 127 if (error < 0) 128 return error; 129 } 130 131 error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); 132 if (error < 0) { 133 dprintk("%s: failed to start callback. Error = %d\n", 134 __func__, error); 135 return error; 136 } 137 __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state); 138 } 139 return 0; 140 } 141 142 /* 143 * Initialize the minor version specific parts of an NFS4 client record 144 */ 145 static int nfs4_init_client_minor_version(struct nfs_client *clp) 146 { 147 #if defined(CONFIG_NFS_V4_1) 148 if (clp->cl_mvops->minor_version) { 149 struct nfs4_session *session = NULL; 150 /* 151 * Create the session and mark it expired. 152 * When a SEQUENCE operation encounters the expired session 153 * it will do session recovery to initialize it. 154 */ 155 session = nfs4_alloc_session(clp); 156 if (!session) 157 return -ENOMEM; 158 159 clp->cl_session = session; 160 /* 161 * The create session reply races with the server back 162 * channel probe. Mark the client NFS_CS_SESSION_INITING 163 * so that the client back channel can find the 164 * nfs_client struct 165 */ 166 nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING); 167 } 168 #endif /* CONFIG_NFS_V4_1 */ 169 170 return nfs4_init_callback(clp); 171 } 172 173 /** 174 * nfs4_init_client - Initialise an NFS4 client record 175 * 176 * @clp: nfs_client to initialise 177 * @timeparms: timeout parameters for underlying RPC transport 178 * @ip_addr: callback IP address in presentation format 179 * @authflavor: authentication flavor for underlying RPC transport 180 * 181 * Returns pointer to an NFS client, or an ERR_PTR value. 182 */ 183 struct nfs_client *nfs4_init_client(struct nfs_client *clp, 184 const struct rpc_timeout *timeparms, 185 const char *ip_addr, 186 rpc_authflavor_t authflavour) 187 { 188 char buf[INET6_ADDRSTRLEN + 1]; 189 struct nfs_client *old; 190 int error; 191 192 if (clp->cl_cons_state == NFS_CS_READY) { 193 /* the client is initialised already */ 194 dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp); 195 return clp; 196 } 197 198 /* Check NFS protocol revision and initialize RPC op vector */ 199 clp->rpc_ops = &nfs_v4_clientops; 200 201 if (clp->cl_minorversion != 0) 202 __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags); 203 __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags); 204 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I); 205 if (error == -EINVAL) 206 error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX); 207 if (error < 0) 208 goto error; 209 210 /* If no clientaddr= option was specified, find a usable cb address */ 211 if (ip_addr == NULL) { 212 struct sockaddr_storage cb_addr; 213 struct sockaddr *sap = (struct sockaddr *)&cb_addr; 214 215 error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); 216 if (error < 0) 217 goto error; 218 error = rpc_ntop(sap, buf, sizeof(buf)); 219 if (error < 0) 220 goto error; 221 ip_addr = (const char *)buf; 222 } 223 strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr)); 224 225 error = nfs_idmap_new(clp); 226 if (error < 0) { 227 dprintk("%s: failed to create idmapper. Error = %d\n", 228 __func__, error); 229 goto error; 230 } 231 __set_bit(NFS_CS_IDMAP, &clp->cl_res_state); 232 233 error = nfs4_init_client_minor_version(clp); 234 if (error < 0) 235 goto error; 236 237 if (!nfs4_has_session(clp)) 238 nfs_mark_client_ready(clp, NFS_CS_READY); 239 240 error = nfs4_discover_server_trunking(clp, &old); 241 if (error < 0) 242 goto error; 243 nfs_put_client(clp); 244 if (clp != old) { 245 clp->cl_preserve_clid = true; 246 clp = old; 247 } 248 249 return clp; 250 251 error: 252 nfs_mark_client_ready(clp, error); 253 nfs_put_client(clp); 254 dprintk("<-- nfs4_init_client() = xerror %d\n", error); 255 return ERR_PTR(error); 256 } 257 258 /* 259 * SETCLIENTID just did a callback update with the callback ident in 260 * "drop," but server trunking discovery claims "drop" and "keep" are 261 * actually the same server. Swap the callback IDs so that "keep" 262 * will continue to use the callback ident the server now knows about, 263 * and so that "keep"'s original callback ident is destroyed when 264 * "drop" is freed. 265 */ 266 static void nfs4_swap_callback_idents(struct nfs_client *keep, 267 struct nfs_client *drop) 268 { 269 struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id); 270 unsigned int save = keep->cl_cb_ident; 271 272 if (keep->cl_cb_ident == drop->cl_cb_ident) 273 return; 274 275 dprintk("%s: keeping callback ident %u and dropping ident %u\n", 276 __func__, keep->cl_cb_ident, drop->cl_cb_ident); 277 278 spin_lock(&nn->nfs_client_lock); 279 280 idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident); 281 keep->cl_cb_ident = drop->cl_cb_ident; 282 283 idr_replace(&nn->cb_ident_idr, drop, save); 284 drop->cl_cb_ident = save; 285 286 spin_unlock(&nn->nfs_client_lock); 287 } 288 289 /** 290 * nfs40_walk_client_list - Find server that recognizes a client ID 291 * 292 * @new: nfs_client with client ID to test 293 * @result: OUT: found nfs_client, or new 294 * @cred: credential to use for trunking test 295 * 296 * Returns zero, a negative errno, or a negative NFS4ERR status. 297 * If zero is returned, an nfs_client pointer is planted in "result." 298 * 299 * NB: nfs40_walk_client_list() relies on the new nfs_client being 300 * the last nfs_client on the list. 301 */ 302 int nfs40_walk_client_list(struct nfs_client *new, 303 struct nfs_client **result, 304 struct rpc_cred *cred) 305 { 306 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 307 struct nfs_client *pos, *prev = NULL; 308 struct nfs4_setclientid_res clid = { 309 .clientid = new->cl_clientid, 310 .confirm = new->cl_confirm, 311 }; 312 int status = -NFS4ERR_STALE_CLIENTID; 313 314 spin_lock(&nn->nfs_client_lock); 315 list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { 316 /* If "pos" isn't marked ready, we can't trust the 317 * remaining fields in "pos" */ 318 if (pos->cl_cons_state > NFS_CS_READY) { 319 atomic_inc(&pos->cl_count); 320 spin_unlock(&nn->nfs_client_lock); 321 322 if (prev) 323 nfs_put_client(prev); 324 prev = pos; 325 326 status = nfs_wait_client_init_complete(pos); 327 spin_lock(&nn->nfs_client_lock); 328 if (status < 0) 329 continue; 330 } 331 if (pos->cl_cons_state != NFS_CS_READY) 332 continue; 333 334 if (pos->rpc_ops != new->rpc_ops) 335 continue; 336 337 if (pos->cl_proto != new->cl_proto) 338 continue; 339 340 if (pos->cl_minorversion != new->cl_minorversion) 341 continue; 342 343 if (pos->cl_clientid != new->cl_clientid) 344 continue; 345 346 atomic_inc(&pos->cl_count); 347 spin_unlock(&nn->nfs_client_lock); 348 349 if (prev) 350 nfs_put_client(prev); 351 prev = pos; 352 353 status = nfs4_proc_setclientid_confirm(pos, &clid, cred); 354 switch (status) { 355 case -NFS4ERR_STALE_CLIENTID: 356 break; 357 case 0: 358 nfs4_swap_callback_idents(pos, new); 359 360 prev = NULL; 361 *result = pos; 362 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", 363 __func__, pos, atomic_read(&pos->cl_count)); 364 default: 365 goto out; 366 } 367 368 spin_lock(&nn->nfs_client_lock); 369 } 370 spin_unlock(&nn->nfs_client_lock); 371 372 /* No match found. The server lost our clientid */ 373 out: 374 if (prev) 375 nfs_put_client(prev); 376 dprintk("NFS: <-- %s status = %d\n", __func__, status); 377 return status; 378 } 379 380 #ifdef CONFIG_NFS_V4_1 381 /* 382 * Returns true if the client IDs match 383 */ 384 static bool nfs4_match_clientids(struct nfs_client *a, struct nfs_client *b) 385 { 386 if (a->cl_clientid != b->cl_clientid) { 387 dprintk("NFS: --> %s client ID %llx does not match %llx\n", 388 __func__, a->cl_clientid, b->cl_clientid); 389 return false; 390 } 391 dprintk("NFS: --> %s client ID %llx matches %llx\n", 392 __func__, a->cl_clientid, b->cl_clientid); 393 return true; 394 } 395 396 /* 397 * Returns true if the server owners match 398 */ 399 static bool 400 nfs4_match_serverowners(struct nfs_client *a, struct nfs_client *b) 401 { 402 struct nfs41_server_owner *o1 = a->cl_serverowner; 403 struct nfs41_server_owner *o2 = b->cl_serverowner; 404 405 if (o1->minor_id != o2->minor_id) { 406 dprintk("NFS: --> %s server owner minor IDs do not match\n", 407 __func__); 408 return false; 409 } 410 411 if (o1->major_id_sz != o2->major_id_sz) 412 goto out_major_mismatch; 413 if (memcmp(o1->major_id, o2->major_id, o1->major_id_sz) != 0) 414 goto out_major_mismatch; 415 416 dprintk("NFS: --> %s server owners match\n", __func__); 417 return true; 418 419 out_major_mismatch: 420 dprintk("NFS: --> %s server owner major IDs do not match\n", 421 __func__); 422 return false; 423 } 424 425 /** 426 * nfs41_walk_client_list - Find nfs_client that matches a client/server owner 427 * 428 * @new: nfs_client with client ID to test 429 * @result: OUT: found nfs_client, or new 430 * @cred: credential to use for trunking test 431 * 432 * Returns zero, a negative errno, or a negative NFS4ERR status. 433 * If zero is returned, an nfs_client pointer is planted in "result." 434 * 435 * NB: nfs41_walk_client_list() relies on the new nfs_client being 436 * the last nfs_client on the list. 437 */ 438 int nfs41_walk_client_list(struct nfs_client *new, 439 struct nfs_client **result, 440 struct rpc_cred *cred) 441 { 442 struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id); 443 struct nfs_client *pos, *prev = NULL; 444 int status = -NFS4ERR_STALE_CLIENTID; 445 446 spin_lock(&nn->nfs_client_lock); 447 list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) { 448 /* If "pos" isn't marked ready, we can't trust the 449 * remaining fields in "pos", especially the client 450 * ID and serverowner fields. Wait for CREATE_SESSION 451 * to finish. */ 452 if (pos->cl_cons_state > NFS_CS_READY) { 453 atomic_inc(&pos->cl_count); 454 spin_unlock(&nn->nfs_client_lock); 455 456 if (prev) 457 nfs_put_client(prev); 458 prev = pos; 459 460 status = nfs_wait_client_init_complete(pos); 461 if (status == 0) { 462 nfs4_schedule_lease_recovery(pos); 463 status = nfs4_wait_clnt_recover(pos); 464 } 465 spin_lock(&nn->nfs_client_lock); 466 if (status < 0) 467 continue; 468 } 469 if (pos->cl_cons_state != NFS_CS_READY) 470 continue; 471 472 if (pos->rpc_ops != new->rpc_ops) 473 continue; 474 475 if (pos->cl_proto != new->cl_proto) 476 continue; 477 478 if (pos->cl_minorversion != new->cl_minorversion) 479 continue; 480 481 if (!nfs4_match_clientids(pos, new)) 482 continue; 483 484 if (!nfs4_match_serverowners(pos, new)) 485 continue; 486 487 atomic_inc(&pos->cl_count); 488 *result = pos; 489 status = 0; 490 dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n", 491 __func__, pos, atomic_read(&pos->cl_count)); 492 break; 493 } 494 495 /* No matching nfs_client found. */ 496 spin_unlock(&nn->nfs_client_lock); 497 dprintk("NFS: <-- %s status = %d\n", __func__, status); 498 if (prev) 499 nfs_put_client(prev); 500 return status; 501 } 502 #endif /* CONFIG_NFS_V4_1 */ 503 504 static void nfs4_destroy_server(struct nfs_server *server) 505 { 506 nfs_server_return_all_delegations(server); 507 unset_pnfs_layoutdriver(server); 508 nfs4_purge_state_owners(server); 509 } 510 511 /* 512 * NFSv4.0 callback thread helper 513 * 514 * Find a client by callback identifier 515 */ 516 struct nfs_client * 517 nfs4_find_client_ident(struct net *net, int cb_ident) 518 { 519 struct nfs_client *clp; 520 struct nfs_net *nn = net_generic(net, nfs_net_id); 521 522 spin_lock(&nn->nfs_client_lock); 523 clp = idr_find(&nn->cb_ident_idr, cb_ident); 524 if (clp) 525 atomic_inc(&clp->cl_count); 526 spin_unlock(&nn->nfs_client_lock); 527 return clp; 528 } 529 530 #if defined(CONFIG_NFS_V4_1) 531 /* Common match routine for v4.0 and v4.1 callback services */ 532 static bool nfs4_cb_match_client(const struct sockaddr *addr, 533 struct nfs_client *clp, u32 minorversion) 534 { 535 struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; 536 537 /* Don't match clients that failed to initialise */ 538 if (!(clp->cl_cons_state == NFS_CS_READY || 539 clp->cl_cons_state == NFS_CS_SESSION_INITING)) 540 return false; 541 542 smp_rmb(); 543 544 /* Match the version and minorversion */ 545 if (clp->rpc_ops->version != 4 || 546 clp->cl_minorversion != minorversion) 547 return false; 548 549 /* Match only the IP address, not the port number */ 550 if (!nfs_sockaddr_match_ipaddr(addr, clap)) 551 return false; 552 553 return true; 554 } 555 556 /* 557 * NFSv4.1 callback thread helper 558 * For CB_COMPOUND calls, find a client by IP address, protocol version, 559 * minorversion, and sessionID 560 * 561 * Returns NULL if no such client 562 */ 563 struct nfs_client * 564 nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, 565 struct nfs4_sessionid *sid) 566 { 567 struct nfs_client *clp; 568 struct nfs_net *nn = net_generic(net, nfs_net_id); 569 570 spin_lock(&nn->nfs_client_lock); 571 list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) { 572 if (nfs4_cb_match_client(addr, clp, 1) == false) 573 continue; 574 575 if (!nfs4_has_session(clp)) 576 continue; 577 578 /* Match sessionid*/ 579 if (memcmp(clp->cl_session->sess_id.data, 580 sid->data, NFS4_MAX_SESSIONID_LEN) != 0) 581 continue; 582 583 atomic_inc(&clp->cl_count); 584 spin_unlock(&nn->nfs_client_lock); 585 return clp; 586 } 587 spin_unlock(&nn->nfs_client_lock); 588 return NULL; 589 } 590 591 #else /* CONFIG_NFS_V4_1 */ 592 593 struct nfs_client * 594 nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr, 595 struct nfs4_sessionid *sid) 596 { 597 return NULL; 598 } 599 #endif /* CONFIG_NFS_V4_1 */ 600 601 /* 602 * Set up an NFS4 client 603 */ 604 static int nfs4_set_client(struct nfs_server *server, 605 const char *hostname, 606 const struct sockaddr *addr, 607 const size_t addrlen, 608 const char *ip_addr, 609 rpc_authflavor_t authflavour, 610 int proto, const struct rpc_timeout *timeparms, 611 u32 minorversion, struct net *net) 612 { 613 struct nfs_client_initdata cl_init = { 614 .hostname = hostname, 615 .addr = addr, 616 .addrlen = addrlen, 617 .nfs_mod = &nfs_v4, 618 .proto = proto, 619 .minorversion = minorversion, 620 .net = net, 621 }; 622 struct nfs_client *clp; 623 int error; 624 625 dprintk("--> nfs4_set_client()\n"); 626 627 if (server->flags & NFS_MOUNT_NORESVPORT) 628 set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); 629 630 /* Allocate or find a client reference we can use */ 631 clp = nfs_get_client(&cl_init, timeparms, ip_addr, authflavour); 632 if (IS_ERR(clp)) { 633 error = PTR_ERR(clp); 634 goto error; 635 } 636 637 /* 638 * Query for the lease time on clientid setup or renewal 639 * 640 * Note that this will be set on nfs_clients that were created 641 * only for the DS role and did not set this bit, but now will 642 * serve a dual role. 643 */ 644 set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state); 645 646 server->nfs_client = clp; 647 dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp); 648 return 0; 649 error: 650 dprintk("<-- nfs4_set_client() = xerror %d\n", error); 651 return error; 652 } 653 654 /* 655 * Set up a pNFS Data Server client. 656 * 657 * Return any existing nfs_client that matches server address,port,version 658 * and minorversion. 659 * 660 * For a new nfs_client, use a soft mount (default), a low retrans and a 661 * low timeout interval so that if a connection is lost, we retry through 662 * the MDS. 663 */ 664 struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, 665 const struct sockaddr *ds_addr, int ds_addrlen, 666 int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans) 667 { 668 struct nfs_client_initdata cl_init = { 669 .addr = ds_addr, 670 .addrlen = ds_addrlen, 671 .nfs_mod = &nfs_v4, 672 .proto = ds_proto, 673 .minorversion = mds_clp->cl_minorversion, 674 .net = mds_clp->cl_net, 675 }; 676 struct rpc_timeout ds_timeout; 677 struct nfs_client *clp; 678 679 /* 680 * Set an authflavor equual to the MDS value. Use the MDS nfs_client 681 * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS 682 * (section 13.1 RFC 5661). 683 */ 684 nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans); 685 clp = nfs_get_client(&cl_init, &ds_timeout, mds_clp->cl_ipaddr, 686 mds_clp->cl_rpcclient->cl_auth->au_flavor); 687 688 dprintk("<-- %s %p\n", __func__, clp); 689 return clp; 690 } 691 EXPORT_SYMBOL_GPL(nfs4_set_ds_client); 692 693 /* 694 * Session has been established, and the client marked ready. 695 * Set the mount rsize and wsize with negotiated fore channel 696 * attributes which will be bound checked in nfs_server_set_fsinfo. 697 */ 698 static void nfs4_session_set_rwsize(struct nfs_server *server) 699 { 700 #ifdef CONFIG_NFS_V4_1 701 struct nfs4_session *sess; 702 u32 server_resp_sz; 703 u32 server_rqst_sz; 704 705 if (!nfs4_has_session(server->nfs_client)) 706 return; 707 sess = server->nfs_client->cl_session; 708 server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead; 709 server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead; 710 711 if (server->rsize > server_resp_sz) 712 server->rsize = server_resp_sz; 713 if (server->wsize > server_rqst_sz) 714 server->wsize = server_rqst_sz; 715 #endif /* CONFIG_NFS_V4_1 */ 716 } 717 718 static int nfs4_server_common_setup(struct nfs_server *server, 719 struct nfs_fh *mntfh) 720 { 721 struct nfs_fattr *fattr; 722 int error; 723 724 /* data servers support only a subset of NFSv4.1 */ 725 if (is_ds_only_client(server->nfs_client)) 726 return -EPROTONOSUPPORT; 727 728 fattr = nfs_alloc_fattr(); 729 if (fattr == NULL) 730 return -ENOMEM; 731 732 /* We must ensure the session is initialised first */ 733 error = nfs4_init_session(server); 734 if (error < 0) 735 goto out; 736 737 /* Set the basic capabilities */ 738 server->caps |= server->nfs_client->cl_mvops->init_caps; 739 if (server->flags & NFS_MOUNT_NORDIRPLUS) 740 server->caps &= ~NFS_CAP_READDIRPLUS; 741 /* 742 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower 743 * authentication. 744 */ 745 if (nfs4_disable_idmapping && 746 server->client->cl_auth->au_flavor == RPC_AUTH_UNIX) 747 server->caps |= NFS_CAP_UIDGID_NOMAP; 748 749 750 /* Probe the root fh to retrieve its FSID and filehandle */ 751 error = nfs4_get_rootfh(server, mntfh); 752 if (error < 0) 753 goto out; 754 755 dprintk("Server FSID: %llx:%llx\n", 756 (unsigned long long) server->fsid.major, 757 (unsigned long long) server->fsid.minor); 758 dprintk("Mount FH: %d\n", mntfh->size); 759 760 nfs4_session_set_rwsize(server); 761 762 error = nfs_probe_fsinfo(server, mntfh, fattr); 763 if (error < 0) 764 goto out; 765 766 if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN) 767 server->namelen = NFS4_MAXNAMLEN; 768 769 nfs_server_insert_lists(server); 770 server->mount_time = jiffies; 771 server->destroy = nfs4_destroy_server; 772 out: 773 nfs_free_fattr(fattr); 774 return error; 775 } 776 777 /* 778 * Create a version 4 volume record 779 */ 780 static int nfs4_init_server(struct nfs_server *server, 781 const struct nfs_parsed_mount_data *data) 782 { 783 struct rpc_timeout timeparms; 784 int error; 785 786 dprintk("--> nfs4_init_server()\n"); 787 788 nfs_init_timeout_values(&timeparms, data->nfs_server.protocol, 789 data->timeo, data->retrans); 790 791 /* Initialise the client representation from the mount data */ 792 server->flags = data->flags; 793 server->options = data->options; 794 795 /* Get a client record */ 796 error = nfs4_set_client(server, 797 data->nfs_server.hostname, 798 (const struct sockaddr *)&data->nfs_server.address, 799 data->nfs_server.addrlen, 800 data->client_address, 801 data->auth_flavors[0], 802 data->nfs_server.protocol, 803 &timeparms, 804 data->minorversion, 805 data->net); 806 if (error < 0) 807 goto error; 808 809 if (data->rsize) 810 server->rsize = nfs_block_size(data->rsize, NULL); 811 if (data->wsize) 812 server->wsize = nfs_block_size(data->wsize, NULL); 813 814 server->acregmin = data->acregmin * HZ; 815 server->acregmax = data->acregmax * HZ; 816 server->acdirmin = data->acdirmin * HZ; 817 server->acdirmax = data->acdirmax * HZ; 818 819 server->port = data->nfs_server.port; 820 821 error = nfs_init_server_rpcclient(server, &timeparms, data->auth_flavors[0]); 822 823 error: 824 /* Done */ 825 dprintk("<-- nfs4_init_server() = %d\n", error); 826 return error; 827 } 828 829 /* 830 * Create a version 4 volume record 831 * - keyed on server and FSID 832 */ 833 /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data, 834 struct nfs_fh *mntfh)*/ 835 struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info, 836 struct nfs_subversion *nfs_mod) 837 { 838 struct nfs_server *server; 839 int error; 840 841 dprintk("--> nfs4_create_server()\n"); 842 843 server = nfs_alloc_server(); 844 if (!server) 845 return ERR_PTR(-ENOMEM); 846 847 /* set up the general RPC client */ 848 error = nfs4_init_server(server, mount_info->parsed); 849 if (error < 0) 850 goto error; 851 852 error = nfs4_server_common_setup(server, mount_info->mntfh); 853 if (error < 0) 854 goto error; 855 856 dprintk("<-- nfs4_create_server() = %p\n", server); 857 return server; 858 859 error: 860 nfs_free_server(server); 861 dprintk("<-- nfs4_create_server() = error %d\n", error); 862 return ERR_PTR(error); 863 } 864 865 /* 866 * Create an NFS4 referral server record 867 */ 868 struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, 869 struct nfs_fh *mntfh) 870 { 871 struct nfs_client *parent_client; 872 struct nfs_server *server, *parent_server; 873 int error; 874 875 dprintk("--> nfs4_create_referral_server()\n"); 876 877 server = nfs_alloc_server(); 878 if (!server) 879 return ERR_PTR(-ENOMEM); 880 881 parent_server = NFS_SB(data->sb); 882 parent_client = parent_server->nfs_client; 883 884 /* Initialise the client representation from the parent server */ 885 nfs_server_copy_userdata(server, parent_server); 886 887 /* Get a client representation. 888 * Note: NFSv4 always uses TCP, */ 889 error = nfs4_set_client(server, data->hostname, 890 data->addr, 891 data->addrlen, 892 parent_client->cl_ipaddr, 893 data->authflavor, 894 rpc_protocol(parent_server->client), 895 parent_server->client->cl_timeout, 896 parent_client->cl_mvops->minor_version, 897 parent_client->cl_net); 898 if (error < 0) 899 goto error; 900 901 error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor); 902 if (error < 0) 903 goto error; 904 905 error = nfs4_server_common_setup(server, mntfh); 906 if (error < 0) 907 goto error; 908 909 dprintk("<-- nfs_create_referral_server() = %p\n", server); 910 return server; 911 912 error: 913 nfs_free_server(server); 914 dprintk("<-- nfs4_create_referral_server() = error %d\n", error); 915 return ERR_PTR(error); 916 } 917