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