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