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