root/fs/nfs/nfs4client.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_get_cb_ident_idr
  2. nfs4_find_ds_client
  3. nfs4_add_ds_client
  4. nfs4_alloc_ds_server
  5. nfs4_free_ds_server
  6. nfs4_find_or_create_ds_client
  7. nfs4_shutdown_ds_clients
  8. nfs4_cleanup_callback
  9. nfs41_shutdown_client
  10. nfs40_shutdown_client
  11. nfs4_alloc_client
  12. nfs4_destroy_callback
  13. nfs4_shutdown_client
  14. nfs4_free_client
  15. nfs4_init_callback
  16. nfs40_init_client
  17. nfs41_init_client
  18. nfs4_init_client_minor_version
  19. nfs4_init_client
  20. nfs4_swap_callback_idents
  21. nfs4_match_client_owner_id
  22. nfs4_same_verifier
  23. nfs4_match_client
  24. nfs40_walk_client_list
  25. nfs4_check_serverowner_major_id
  26. nfs4_check_server_scope
  27. nfs4_detect_session_trunking
  28. nfs41_walk_client_list
  29. nfs4_destroy_server
  30. nfs4_find_client_ident
  31. nfs4_cb_match_client
  32. nfs4_find_client_sessionid
  33. nfs4_find_client_sessionid
  34. nfs4_set_client
  35. nfs4_set_ds_client
  36. nfs4_session_limit_rwsize
  37. nfs4_server_common_setup
  38. nfs4_init_server
  39. nfs4_create_server
  40. nfs4_create_referral_server
  41. nfs_probe_destination
  42. nfs4_update_server

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   4  * Written by David Howells (dhowells@redhat.com)
   5  */
   6 #include <linux/module.h>
   7 #include <linux/nfs_fs.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 <linux/sunrpc/rpc_pipe_fs.h>
  14 #include "internal.h"
  15 #include "callback.h"
  16 #include "delegation.h"
  17 #include "nfs4session.h"
  18 #include "nfs4idmap.h"
  19 #include "pnfs.h"
  20 #include "netns.h"
  21 
  22 #define NFSDBG_FACILITY         NFSDBG_CLIENT
  23 
  24 /*
  25  * Get a unique NFSv4.0 callback identifier which will be used
  26  * by the V4.0 callback service to lookup the nfs_client struct
  27  */
  28 static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)
  29 {
  30         int ret = 0;
  31         struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
  32 
  33         if (clp->rpc_ops->version != 4 || minorversion != 0)
  34                 return ret;
  35         idr_preload(GFP_KERNEL);
  36         spin_lock(&nn->nfs_client_lock);
  37         ret = idr_alloc(&nn->cb_ident_idr, clp, 1, 0, GFP_NOWAIT);
  38         if (ret >= 0)
  39                 clp->cl_cb_ident = ret;
  40         spin_unlock(&nn->nfs_client_lock);
  41         idr_preload_end();
  42         return ret < 0 ? ret : 0;
  43 }
  44 
  45 #ifdef CONFIG_NFS_V4_1
  46 /*
  47  * Per auth flavor data server rpc clients
  48  */
  49 struct nfs4_ds_server {
  50         struct list_head        list;   /* ds_clp->cl_ds_clients */
  51         struct rpc_clnt         *rpc_clnt;
  52 };
  53 
  54 /**
  55  * nfs4_find_ds_client - Common lookup case for DS I/O
  56  * @ds_clp: pointer to the DS's nfs_client
  57  * @flavor: rpc auth flavour to match
  58  */
  59 static struct nfs4_ds_server *
  60 nfs4_find_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
  61 {
  62         struct nfs4_ds_server *dss;
  63 
  64         rcu_read_lock();
  65         list_for_each_entry_rcu(dss, &ds_clp->cl_ds_clients, list) {
  66                 if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
  67                         continue;
  68                 goto out;
  69         }
  70         dss = NULL;
  71 out:
  72         rcu_read_unlock();
  73         return dss;
  74 }
  75 
  76 static struct nfs4_ds_server *
  77 nfs4_add_ds_client(struct nfs_client *ds_clp, rpc_authflavor_t flavor,
  78                            struct nfs4_ds_server *new)
  79 {
  80         struct nfs4_ds_server *dss;
  81 
  82         spin_lock(&ds_clp->cl_lock);
  83         list_for_each_entry(dss, &ds_clp->cl_ds_clients, list) {
  84                 if (dss->rpc_clnt->cl_auth->au_flavor != flavor)
  85                         continue;
  86                 goto out;
  87         }
  88         if (new)
  89                 list_add_rcu(&new->list, &ds_clp->cl_ds_clients);
  90         dss = new;
  91 out:
  92         spin_unlock(&ds_clp->cl_lock); /* need some lock to protect list */
  93         return dss;
  94 }
  95 
  96 static struct nfs4_ds_server *
  97 nfs4_alloc_ds_server(struct nfs_client *ds_clp, rpc_authflavor_t flavor)
  98 {
  99         struct nfs4_ds_server *dss;
 100 
 101         dss = kmalloc(sizeof(*dss), GFP_NOFS);
 102         if (dss == NULL)
 103                 return ERR_PTR(-ENOMEM);
 104 
 105         dss->rpc_clnt = rpc_clone_client_set_auth(ds_clp->cl_rpcclient, flavor);
 106         if (IS_ERR(dss->rpc_clnt)) {
 107                 int err = PTR_ERR(dss->rpc_clnt);
 108                 kfree (dss);
 109                 return ERR_PTR(err);
 110         }
 111         INIT_LIST_HEAD(&dss->list);
 112 
 113         return dss;
 114 }
 115 
 116 static void
 117 nfs4_free_ds_server(struct nfs4_ds_server *dss)
 118 {
 119         rpc_release_client(dss->rpc_clnt);
 120         kfree(dss);
 121 }
 122 
 123 /**
 124  * nfs4_find_or_create_ds_client - Find or create a DS rpc client
 125  * @ds_clp: pointer to the DS's nfs_client
 126  * @inode: pointer to the inode
 127  *
 128  * Find or create a DS rpc client with th MDS server rpc client auth flavor
 129  * in the nfs_client cl_ds_clients list.
 130  */
 131 struct rpc_clnt *
 132 nfs4_find_or_create_ds_client(struct nfs_client *ds_clp, struct inode *inode)
 133 {
 134         struct nfs4_ds_server *dss, *new;
 135         rpc_authflavor_t flavor = NFS_SERVER(inode)->client->cl_auth->au_flavor;
 136 
 137         dss = nfs4_find_ds_client(ds_clp, flavor);
 138         if (dss != NULL)
 139                 goto out;
 140         new = nfs4_alloc_ds_server(ds_clp, flavor);
 141         if (IS_ERR(new))
 142                 return ERR_CAST(new);
 143         dss = nfs4_add_ds_client(ds_clp, flavor, new);
 144         if (dss != new)
 145                 nfs4_free_ds_server(new);
 146 out:
 147         return dss->rpc_clnt;
 148 }
 149 EXPORT_SYMBOL_GPL(nfs4_find_or_create_ds_client);
 150 
 151 static void
 152 nfs4_shutdown_ds_clients(struct nfs_client *clp)
 153 {
 154         struct nfs4_ds_server *dss;
 155 
 156         while (!list_empty(&clp->cl_ds_clients)) {
 157                 dss = list_entry(clp->cl_ds_clients.next,
 158                                         struct nfs4_ds_server, list);
 159                 list_del(&dss->list);
 160                 rpc_shutdown_client(dss->rpc_clnt);
 161                 kfree (dss);
 162         }
 163 }
 164 
 165 static void
 166 nfs4_cleanup_callback(struct nfs_client *clp)
 167 {
 168         struct nfs4_copy_state *cp_state;
 169 
 170         while (!list_empty(&clp->pending_cb_stateids)) {
 171                 cp_state = list_entry(clp->pending_cb_stateids.next,
 172                                         struct nfs4_copy_state, copies);
 173                 list_del(&cp_state->copies);
 174                 kfree(cp_state);
 175         }
 176 }
 177 
 178 void nfs41_shutdown_client(struct nfs_client *clp)
 179 {
 180         if (nfs4_has_session(clp)) {
 181                 nfs4_cleanup_callback(clp);
 182                 nfs4_shutdown_ds_clients(clp);
 183                 nfs4_destroy_session(clp->cl_session);
 184                 nfs4_destroy_clientid(clp);
 185         }
 186 
 187 }
 188 #endif  /* CONFIG_NFS_V4_1 */
 189 
 190 void nfs40_shutdown_client(struct nfs_client *clp)
 191 {
 192         if (clp->cl_slot_tbl) {
 193                 nfs4_shutdown_slot_table(clp->cl_slot_tbl);
 194                 kfree(clp->cl_slot_tbl);
 195         }
 196 }
 197 
 198 struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *cl_init)
 199 {
 200         int err;
 201         struct nfs_client *clp = nfs_alloc_client(cl_init);
 202         if (IS_ERR(clp))
 203                 return clp;
 204 
 205         err = nfs_get_cb_ident_idr(clp, cl_init->minorversion);
 206         if (err)
 207                 goto error;
 208 
 209         if (cl_init->minorversion > NFS4_MAX_MINOR_VERSION) {
 210                 err = -EINVAL;
 211                 goto error;
 212         }
 213 
 214         spin_lock_init(&clp->cl_lock);
 215         INIT_DELAYED_WORK(&clp->cl_renewd, nfs4_renew_state);
 216         INIT_LIST_HEAD(&clp->cl_ds_clients);
 217         rpc_init_wait_queue(&clp->cl_rpcwaitq, "NFS client");
 218         clp->cl_state = 1 << NFS4CLNT_LEASE_EXPIRED;
 219         clp->cl_mvops = nfs_v4_minor_ops[cl_init->minorversion];
 220         clp->cl_mig_gen = 1;
 221 #if IS_ENABLED(CONFIG_NFS_V4_1)
 222         init_waitqueue_head(&clp->cl_lock_waitq);
 223 #endif
 224         INIT_LIST_HEAD(&clp->pending_cb_stateids);
 225         return clp;
 226 
 227 error:
 228         nfs_free_client(clp);
 229         return ERR_PTR(err);
 230 }
 231 
 232 /*
 233  * Destroy the NFS4 callback service
 234  */
 235 static void nfs4_destroy_callback(struct nfs_client *clp)
 236 {
 237         if (__test_and_clear_bit(NFS_CS_CALLBACK, &clp->cl_res_state))
 238                 nfs_callback_down(clp->cl_mvops->minor_version, clp->cl_net);
 239 }
 240 
 241 static void nfs4_shutdown_client(struct nfs_client *clp)
 242 {
 243         if (__test_and_clear_bit(NFS_CS_RENEWD, &clp->cl_res_state))
 244                 nfs4_kill_renewd(clp);
 245         clp->cl_mvops->shutdown_client(clp);
 246         nfs4_destroy_callback(clp);
 247         if (__test_and_clear_bit(NFS_CS_IDMAP, &clp->cl_res_state))
 248                 nfs_idmap_delete(clp);
 249 
 250         rpc_destroy_wait_queue(&clp->cl_rpcwaitq);
 251         kfree(clp->cl_serverowner);
 252         kfree(clp->cl_serverscope);
 253         kfree(clp->cl_implid);
 254         kfree(clp->cl_owner_id);
 255 }
 256 
 257 void nfs4_free_client(struct nfs_client *clp)
 258 {
 259         nfs4_shutdown_client(clp);
 260         nfs_free_client(clp);
 261 }
 262 
 263 /*
 264  * Initialize the NFS4 callback service
 265  */
 266 static int nfs4_init_callback(struct nfs_client *clp)
 267 {
 268         struct rpc_xprt *xprt;
 269         int error;
 270 
 271         xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
 272 
 273         if (nfs4_has_session(clp)) {
 274                 error = xprt_setup_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
 275                 if (error < 0)
 276                         return error;
 277         }
 278 
 279         error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
 280         if (error < 0) {
 281                 dprintk("%s: failed to start callback. Error = %d\n",
 282                         __func__, error);
 283                 return error;
 284         }
 285         __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
 286 
 287         return 0;
 288 }
 289 
 290 /**
 291  * nfs40_init_client - nfs_client initialization tasks for NFSv4.0
 292  * @clp: nfs_client to initialize
 293  *
 294  * Returns zero on success, or a negative errno if some error occurred.
 295  */
 296 int nfs40_init_client(struct nfs_client *clp)
 297 {
 298         struct nfs4_slot_table *tbl;
 299         int ret;
 300 
 301         tbl = kzalloc(sizeof(*tbl), GFP_NOFS);
 302         if (tbl == NULL)
 303                 return -ENOMEM;
 304 
 305         ret = nfs4_setup_slot_table(tbl, NFS4_MAX_SLOT_TABLE,
 306                                         "NFSv4.0 transport Slot table");
 307         if (ret) {
 308                 kfree(tbl);
 309                 return ret;
 310         }
 311 
 312         clp->cl_slot_tbl = tbl;
 313         return 0;
 314 }
 315 
 316 #if defined(CONFIG_NFS_V4_1)
 317 
 318 /**
 319  * nfs41_init_client - nfs_client initialization tasks for NFSv4.1+
 320  * @clp: nfs_client to initialize
 321  *
 322  * Returns zero on success, or a negative errno if some error occurred.
 323  */
 324 int nfs41_init_client(struct nfs_client *clp)
 325 {
 326         struct nfs4_session *session = NULL;
 327 
 328         /*
 329          * Create the session and mark it expired.
 330          * When a SEQUENCE operation encounters the expired session
 331          * it will do session recovery to initialize it.
 332          */
 333         session = nfs4_alloc_session(clp);
 334         if (!session)
 335                 return -ENOMEM;
 336 
 337         clp->cl_session = session;
 338 
 339         /*
 340          * The create session reply races with the server back
 341          * channel probe. Mark the client NFS_CS_SESSION_INITING
 342          * so that the client back channel can find the
 343          * nfs_client struct
 344          */
 345         nfs_mark_client_ready(clp, NFS_CS_SESSION_INITING);
 346         return 0;
 347 }
 348 
 349 #endif  /* CONFIG_NFS_V4_1 */
 350 
 351 /*
 352  * Initialize the minor version specific parts of an NFS4 client record
 353  */
 354 static int nfs4_init_client_minor_version(struct nfs_client *clp)
 355 {
 356         int ret;
 357 
 358         ret = clp->cl_mvops->init_client(clp);
 359         if (ret)
 360                 return ret;
 361         return nfs4_init_callback(clp);
 362 }
 363 
 364 /**
 365  * nfs4_init_client - Initialise an NFS4 client record
 366  *
 367  * @clp: nfs_client to initialise
 368  * @cl_init: pointer to nfs_client_initdata
 369  *
 370  * Returns pointer to an NFS client, or an ERR_PTR value.
 371  */
 372 struct nfs_client *nfs4_init_client(struct nfs_client *clp,
 373                                     const struct nfs_client_initdata *cl_init)
 374 {
 375         char buf[INET6_ADDRSTRLEN + 1];
 376         const char *ip_addr = cl_init->ip_addr;
 377         struct nfs_client *old;
 378         int error;
 379 
 380         if (clp->cl_cons_state == NFS_CS_READY)
 381                 /* the client is initialised already */
 382                 return clp;
 383 
 384         /* Check NFS protocol revision and initialize RPC op vector */
 385         clp->rpc_ops = &nfs_v4_clientops;
 386 
 387         if (clp->cl_minorversion != 0)
 388                 __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
 389         __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
 390         __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
 391 
 392         error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_GSS_KRB5I);
 393         if (error == -EINVAL)
 394                 error = nfs_create_rpc_client(clp, cl_init, RPC_AUTH_UNIX);
 395         if (error < 0)
 396                 goto error;
 397 
 398         /* If no clientaddr= option was specified, find a usable cb address */
 399         if (ip_addr == NULL) {
 400                 struct sockaddr_storage cb_addr;
 401                 struct sockaddr *sap = (struct sockaddr *)&cb_addr;
 402 
 403                 error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr));
 404                 if (error < 0)
 405                         goto error;
 406                 error = rpc_ntop(sap, buf, sizeof(buf));
 407                 if (error < 0)
 408                         goto error;
 409                 ip_addr = (const char *)buf;
 410         }
 411         strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
 412 
 413         error = nfs_idmap_new(clp);
 414         if (error < 0) {
 415                 dprintk("%s: failed to create idmapper. Error = %d\n",
 416                         __func__, error);
 417                 goto error;
 418         }
 419         __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
 420 
 421         error = nfs4_init_client_minor_version(clp);
 422         if (error < 0)
 423                 goto error;
 424 
 425         error = nfs4_discover_server_trunking(clp, &old);
 426         if (error < 0)
 427                 goto error;
 428 
 429         if (clp != old) {
 430                 clp->cl_preserve_clid = true;
 431                 /*
 432                  * Mark the client as having failed initialization so other
 433                  * processes walking the nfs_client_list in nfs_match_client()
 434                  * won't try to use it.
 435                  */
 436                 nfs_mark_client_ready(clp, -EPERM);
 437         }
 438         nfs_put_client(clp);
 439         clear_bit(NFS_CS_TSM_POSSIBLE, &clp->cl_flags);
 440         return old;
 441 
 442 error:
 443         nfs_mark_client_ready(clp, error);
 444         nfs_put_client(clp);
 445         return ERR_PTR(error);
 446 }
 447 
 448 /*
 449  * SETCLIENTID just did a callback update with the callback ident in
 450  * "drop," but server trunking discovery claims "drop" and "keep" are
 451  * actually the same server.  Swap the callback IDs so that "keep"
 452  * will continue to use the callback ident the server now knows about,
 453  * and so that "keep"'s original callback ident is destroyed when
 454  * "drop" is freed.
 455  */
 456 static void nfs4_swap_callback_idents(struct nfs_client *keep,
 457                                       struct nfs_client *drop)
 458 {
 459         struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
 460         unsigned int save = keep->cl_cb_ident;
 461 
 462         if (keep->cl_cb_ident == drop->cl_cb_ident)
 463                 return;
 464 
 465         dprintk("%s: keeping callback ident %u and dropping ident %u\n",
 466                 __func__, keep->cl_cb_ident, drop->cl_cb_ident);
 467 
 468         spin_lock(&nn->nfs_client_lock);
 469 
 470         idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
 471         keep->cl_cb_ident = drop->cl_cb_ident;
 472 
 473         idr_replace(&nn->cb_ident_idr, drop, save);
 474         drop->cl_cb_ident = save;
 475 
 476         spin_unlock(&nn->nfs_client_lock);
 477 }
 478 
 479 static bool nfs4_match_client_owner_id(const struct nfs_client *clp1,
 480                 const struct nfs_client *clp2)
 481 {
 482         if (clp1->cl_owner_id == NULL || clp2->cl_owner_id == NULL)
 483                 return true;
 484         return strcmp(clp1->cl_owner_id, clp2->cl_owner_id) == 0;
 485 }
 486 
 487 static bool nfs4_same_verifier(nfs4_verifier *v1, nfs4_verifier *v2)
 488 {
 489         return memcmp(v1->data, v2->data, sizeof(v1->data)) == 0;
 490 }
 491 
 492 static int nfs4_match_client(struct nfs_client  *pos,  struct nfs_client *new,
 493                              struct nfs_client **prev, struct nfs_net *nn)
 494 {
 495         int status;
 496 
 497         if (pos->rpc_ops != new->rpc_ops)
 498                 return 1;
 499 
 500         if (pos->cl_minorversion != new->cl_minorversion)
 501                 return 1;
 502 
 503         /* If "pos" isn't marked ready, we can't trust the
 504          * remaining fields in "pos", especially the client
 505          * ID and serverowner fields.  Wait for CREATE_SESSION
 506          * to finish. */
 507         if (pos->cl_cons_state > NFS_CS_READY) {
 508                 refcount_inc(&pos->cl_count);
 509                 spin_unlock(&nn->nfs_client_lock);
 510 
 511                 nfs_put_client(*prev);
 512                 *prev = pos;
 513 
 514                 status = nfs_wait_client_init_complete(pos);
 515                 spin_lock(&nn->nfs_client_lock);
 516 
 517                 if (status < 0)
 518                         return status;
 519         }
 520 
 521         if (pos->cl_cons_state != NFS_CS_READY)
 522                 return 1;
 523 
 524         if (pos->cl_clientid != new->cl_clientid)
 525                 return 1;
 526 
 527         /* NFSv4.1 always uses the uniform string, however someone
 528          * might switch the uniquifier string on us.
 529          */
 530         if (!nfs4_match_client_owner_id(pos, new))
 531                 return 1;
 532 
 533         return 0;
 534 }
 535 
 536 /**
 537  * nfs40_walk_client_list - Find server that recognizes a client ID
 538  *
 539  * @new: nfs_client with client ID to test
 540  * @result: OUT: found nfs_client, or new
 541  * @cred: credential to use for trunking test
 542  *
 543  * Returns zero, a negative errno, or a negative NFS4ERR status.
 544  * If zero is returned, an nfs_client pointer is planted in "result."
 545  *
 546  * NB: nfs40_walk_client_list() relies on the new nfs_client being
 547  *     the last nfs_client on the list.
 548  */
 549 int nfs40_walk_client_list(struct nfs_client *new,
 550                            struct nfs_client **result,
 551                            const struct cred *cred)
 552 {
 553         struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
 554         struct nfs_client *pos, *prev = NULL;
 555         struct nfs4_setclientid_res clid = {
 556                 .clientid       = new->cl_clientid,
 557                 .confirm        = new->cl_confirm,
 558         };
 559         int status = -NFS4ERR_STALE_CLIENTID;
 560 
 561         spin_lock(&nn->nfs_client_lock);
 562         list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
 563 
 564                 if (pos == new)
 565                         goto found;
 566 
 567                 status = nfs4_match_client(pos, new, &prev, nn);
 568                 if (status < 0)
 569                         goto out_unlock;
 570                 if (status != 0)
 571                         continue;
 572                 /*
 573                  * We just sent a new SETCLIENTID, which should have
 574                  * caused the server to return a new cl_confirm.  So if
 575                  * cl_confirm is the same, then this is a different
 576                  * server that just returned the same cl_confirm by
 577                  * coincidence:
 578                  */
 579                 if ((new != pos) && nfs4_same_verifier(&pos->cl_confirm,
 580                                                        &new->cl_confirm))
 581                         continue;
 582                 /*
 583                  * But if the cl_confirm's are different, then the only
 584                  * way that a SETCLIENTID_CONFIRM to pos can succeed is
 585                  * if new and pos point to the same server:
 586                  */
 587 found:
 588                 refcount_inc(&pos->cl_count);
 589                 spin_unlock(&nn->nfs_client_lock);
 590 
 591                 nfs_put_client(prev);
 592                 prev = pos;
 593 
 594                 status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
 595                 switch (status) {
 596                 case -NFS4ERR_STALE_CLIENTID:
 597                         break;
 598                 case 0:
 599                         nfs4_swap_callback_idents(pos, new);
 600                         pos->cl_confirm = new->cl_confirm;
 601                         nfs_mark_client_ready(pos, NFS_CS_READY);
 602 
 603                         prev = NULL;
 604                         *result = pos;
 605                         goto out;
 606                 case -ERESTARTSYS:
 607                 case -ETIMEDOUT:
 608                         /* The callback path may have been inadvertently
 609                          * changed. Schedule recovery!
 610                          */
 611                         nfs4_schedule_path_down_recovery(pos);
 612                 default:
 613                         goto out;
 614                 }
 615 
 616                 spin_lock(&nn->nfs_client_lock);
 617         }
 618 out_unlock:
 619         spin_unlock(&nn->nfs_client_lock);
 620 
 621         /* No match found. The server lost our clientid */
 622 out:
 623         nfs_put_client(prev);
 624         return status;
 625 }
 626 
 627 #ifdef CONFIG_NFS_V4_1
 628 /*
 629  * Returns true if the server major ids match
 630  */
 631 static bool
 632 nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
 633                                 struct nfs41_server_owner *o2)
 634 {
 635         if (o1->major_id_sz != o2->major_id_sz)
 636                 return false;
 637         return memcmp(o1->major_id, o2->major_id, o1->major_id_sz) == 0;
 638 }
 639 
 640 /*
 641  * Returns true if the server scopes match
 642  */
 643 static bool
 644 nfs4_check_server_scope(struct nfs41_server_scope *s1,
 645                         struct nfs41_server_scope *s2)
 646 {
 647         if (s1->server_scope_sz != s2->server_scope_sz)
 648                 return false;
 649         return memcmp(s1->server_scope, s2->server_scope,
 650                                         s1->server_scope_sz) == 0;
 651 }
 652 
 653 /**
 654  * nfs4_detect_session_trunking - Checks for session trunking.
 655  * @clp:    original mount nfs_client
 656  * @res:    result structure from an exchange_id using the original mount
 657  *          nfs_client with a new multi_addr transport
 658  * @xprt:   pointer to the transport to add.
 659  *
 660  * Called after a successful EXCHANGE_ID on a multi-addr connection.
 661  * Upon success, add the transport.
 662  *
 663  * Returns zero on success, otherwise -EINVAL
 664  *
 665  * Note: since the exchange_id for the new multi_addr transport uses the
 666  * same nfs_client from the original mount, the cl_owner_id is reused,
 667  * so eir_clientowner is the same.
 668  */
 669 int nfs4_detect_session_trunking(struct nfs_client *clp,
 670                                  struct nfs41_exchange_id_res *res,
 671                                  struct rpc_xprt *xprt)
 672 {
 673         /* Check eir_clientid */
 674         if (clp->cl_clientid != res->clientid)
 675                 goto out_err;
 676 
 677         /* Check eir_server_owner so_major_id */
 678         if (!nfs4_check_serverowner_major_id(clp->cl_serverowner,
 679                                              res->server_owner))
 680                 goto out_err;
 681 
 682         /* Check eir_server_owner so_minor_id */
 683         if (clp->cl_serverowner->minor_id != res->server_owner->minor_id)
 684                 goto out_err;
 685 
 686         /* Check eir_server_scope */
 687         if (!nfs4_check_server_scope(clp->cl_serverscope, res->server_scope))
 688                 goto out_err;
 689 
 690         pr_info("NFS:  %s: Session trunking succeeded for %s\n",
 691                 clp->cl_hostname,
 692                 xprt->address_strings[RPC_DISPLAY_ADDR]);
 693 
 694         return 0;
 695 out_err:
 696         pr_info("NFS:  %s: Session trunking failed for %s\n", clp->cl_hostname,
 697                 xprt->address_strings[RPC_DISPLAY_ADDR]);
 698 
 699         return -EINVAL;
 700 }
 701 
 702 /**
 703  * nfs41_walk_client_list - Find nfs_client that matches a client/server owner
 704  *
 705  * @new: nfs_client with client ID to test
 706  * @result: OUT: found nfs_client, or new
 707  * @cred: credential to use for trunking test
 708  *
 709  * Returns zero, a negative errno, or a negative NFS4ERR status.
 710  * If zero is returned, an nfs_client pointer is planted in "result."
 711  *
 712  * NB: nfs41_walk_client_list() relies on the new nfs_client being
 713  *     the last nfs_client on the list.
 714  */
 715 int nfs41_walk_client_list(struct nfs_client *new,
 716                            struct nfs_client **result,
 717                            const struct cred *cred)
 718 {
 719         struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
 720         struct nfs_client *pos, *prev = NULL;
 721         int status = -NFS4ERR_STALE_CLIENTID;
 722 
 723         spin_lock(&nn->nfs_client_lock);
 724         list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
 725 
 726                 if (pos == new)
 727                         goto found;
 728 
 729                 status = nfs4_match_client(pos, new, &prev, nn);
 730                 if (status < 0)
 731                         goto out;
 732                 if (status != 0)
 733                         continue;
 734 
 735                 /*
 736                  * Note that session trunking is just a special subcase of
 737                  * client id trunking. In either case, we want to fall back
 738                  * to using the existing nfs_client.
 739                  */
 740                 if (!nfs4_check_serverowner_major_id(pos->cl_serverowner,
 741                                                      new->cl_serverowner))
 742                         continue;
 743 
 744 found:
 745                 refcount_inc(&pos->cl_count);
 746                 *result = pos;
 747                 status = 0;
 748                 break;
 749         }
 750 
 751 out:
 752         spin_unlock(&nn->nfs_client_lock);
 753         nfs_put_client(prev);
 754         return status;
 755 }
 756 #endif  /* CONFIG_NFS_V4_1 */
 757 
 758 static void nfs4_destroy_server(struct nfs_server *server)
 759 {
 760         LIST_HEAD(freeme);
 761 
 762         nfs_server_return_all_delegations(server);
 763         unset_pnfs_layoutdriver(server);
 764         nfs4_purge_state_owners(server, &freeme);
 765         nfs4_free_state_owners(&freeme);
 766 }
 767 
 768 /*
 769  * NFSv4.0 callback thread helper
 770  *
 771  * Find a client by callback identifier
 772  */
 773 struct nfs_client *
 774 nfs4_find_client_ident(struct net *net, int cb_ident)
 775 {
 776         struct nfs_client *clp;
 777         struct nfs_net *nn = net_generic(net, nfs_net_id);
 778 
 779         spin_lock(&nn->nfs_client_lock);
 780         clp = idr_find(&nn->cb_ident_idr, cb_ident);
 781         if (clp)
 782                 refcount_inc(&clp->cl_count);
 783         spin_unlock(&nn->nfs_client_lock);
 784         return clp;
 785 }
 786 
 787 #if defined(CONFIG_NFS_V4_1)
 788 /* Common match routine for v4.0 and v4.1 callback services */
 789 static bool nfs4_cb_match_client(const struct sockaddr *addr,
 790                 struct nfs_client *clp, u32 minorversion)
 791 {
 792         struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
 793 
 794         /* Don't match clients that failed to initialise */
 795         if (!(clp->cl_cons_state == NFS_CS_READY ||
 796             clp->cl_cons_state == NFS_CS_SESSION_INITING))
 797                 return false;
 798 
 799         smp_rmb();
 800 
 801         /* Match the version and minorversion */
 802         if (clp->rpc_ops->version != 4 ||
 803             clp->cl_minorversion != minorversion)
 804                 return false;
 805 
 806         /* Match only the IP address, not the port number */
 807         return rpc_cmp_addr(addr, clap);
 808 }
 809 
 810 /*
 811  * NFSv4.1 callback thread helper
 812  * For CB_COMPOUND calls, find a client by IP address, protocol version,
 813  * minorversion, and sessionID
 814  *
 815  * Returns NULL if no such client
 816  */
 817 struct nfs_client *
 818 nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
 819                            struct nfs4_sessionid *sid, u32 minorversion)
 820 {
 821         struct nfs_client *clp;
 822         struct nfs_net *nn = net_generic(net, nfs_net_id);
 823 
 824         spin_lock(&nn->nfs_client_lock);
 825         list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
 826                 if (!nfs4_cb_match_client(addr, clp, minorversion))
 827                         continue;
 828 
 829                 if (!nfs4_has_session(clp))
 830                         continue;
 831 
 832                 /* Match sessionid*/
 833                 if (memcmp(clp->cl_session->sess_id.data,
 834                     sid->data, NFS4_MAX_SESSIONID_LEN) != 0)
 835                         continue;
 836 
 837                 refcount_inc(&clp->cl_count);
 838                 spin_unlock(&nn->nfs_client_lock);
 839                 return clp;
 840         }
 841         spin_unlock(&nn->nfs_client_lock);
 842         return NULL;
 843 }
 844 
 845 #else /* CONFIG_NFS_V4_1 */
 846 
 847 struct nfs_client *
 848 nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,
 849                            struct nfs4_sessionid *sid, u32 minorversion)
 850 {
 851         return NULL;
 852 }
 853 #endif /* CONFIG_NFS_V4_1 */
 854 
 855 /*
 856  * Set up an NFS4 client
 857  */
 858 static int nfs4_set_client(struct nfs_server *server,
 859                 const char *hostname,
 860                 const struct sockaddr *addr,
 861                 const size_t addrlen,
 862                 const char *ip_addr,
 863                 int proto, const struct rpc_timeout *timeparms,
 864                 u32 minorversion, unsigned int nconnect,
 865                 struct net *net)
 866 {
 867         struct nfs_client_initdata cl_init = {
 868                 .hostname = hostname,
 869                 .addr = addr,
 870                 .addrlen = addrlen,
 871                 .ip_addr = ip_addr,
 872                 .nfs_mod = &nfs_v4,
 873                 .proto = proto,
 874                 .minorversion = minorversion,
 875                 .net = net,
 876                 .timeparms = timeparms,
 877                 .cred = server->cred,
 878         };
 879         struct nfs_client *clp;
 880 
 881         if (minorversion > 0 && proto == XPRT_TRANSPORT_TCP)
 882                 cl_init.nconnect = nconnect;
 883         if (server->flags & NFS_MOUNT_NORESVPORT)
 884                 set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 885         if (server->options & NFS_OPTION_MIGRATION)
 886                 set_bit(NFS_CS_MIGRATION, &cl_init.init_flags);
 887         if (test_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status))
 888                 set_bit(NFS_CS_TSM_POSSIBLE, &cl_init.init_flags);
 889         server->port = rpc_get_port(addr);
 890 
 891         /* Allocate or find a client reference we can use */
 892         clp = nfs_get_client(&cl_init);
 893         if (IS_ERR(clp))
 894                 return PTR_ERR(clp);
 895 
 896         if (server->nfs_client == clp) {
 897                 nfs_put_client(clp);
 898                 return -ELOOP;
 899         }
 900 
 901         /*
 902          * Query for the lease time on clientid setup or renewal
 903          *
 904          * Note that this will be set on nfs_clients that were created
 905          * only for the DS role and did not set this bit, but now will
 906          * serve a dual role.
 907          */
 908         set_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state);
 909 
 910         server->nfs_client = clp;
 911         return 0;
 912 }
 913 
 914 /*
 915  * Set up a pNFS Data Server client.
 916  *
 917  * Return any existing nfs_client that matches server address,port,version
 918  * and minorversion.
 919  *
 920  * For a new nfs_client, use a soft mount (default), a low retrans and a
 921  * low timeout interval so that if a connection is lost, we retry through
 922  * the MDS.
 923  */
 924 struct nfs_client *nfs4_set_ds_client(struct nfs_server *mds_srv,
 925                 const struct sockaddr *ds_addr, int ds_addrlen,
 926                 int ds_proto, unsigned int ds_timeo, unsigned int ds_retrans,
 927                 u32 minor_version)
 928 {
 929         struct rpc_timeout ds_timeout;
 930         struct nfs_client *mds_clp = mds_srv->nfs_client;
 931         struct nfs_client_initdata cl_init = {
 932                 .addr = ds_addr,
 933                 .addrlen = ds_addrlen,
 934                 .nodename = mds_clp->cl_rpcclient->cl_nodename,
 935                 .ip_addr = mds_clp->cl_ipaddr,
 936                 .nfs_mod = &nfs_v4,
 937                 .proto = ds_proto,
 938                 .minorversion = minor_version,
 939                 .net = mds_clp->cl_net,
 940                 .timeparms = &ds_timeout,
 941                 .cred = mds_srv->cred,
 942         };
 943         char buf[INET6_ADDRSTRLEN + 1];
 944 
 945         if (rpc_ntop(ds_addr, buf, sizeof(buf)) <= 0)
 946                 return ERR_PTR(-EINVAL);
 947         cl_init.hostname = buf;
 948 
 949         if (mds_clp->cl_nconnect > 1 && ds_proto == XPRT_TRANSPORT_TCP)
 950                 cl_init.nconnect = mds_clp->cl_nconnect;
 951 
 952         if (mds_srv->flags & NFS_MOUNT_NORESVPORT)
 953                 __set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
 954 
 955         /*
 956          * Set an authflavor equual to the MDS value. Use the MDS nfs_client
 957          * cl_ipaddr so as to use the same EXCHANGE_ID co_ownerid as the MDS
 958          * (section 13.1 RFC 5661).
 959          */
 960         nfs_init_timeout_values(&ds_timeout, ds_proto, ds_timeo, ds_retrans);
 961         return nfs_get_client(&cl_init);
 962 }
 963 EXPORT_SYMBOL_GPL(nfs4_set_ds_client);
 964 
 965 /*
 966  * Session has been established, and the client marked ready.
 967  * Limit the mount rsize, wsize and dtsize using negotiated fore
 968  * channel attributes.
 969  */
 970 static void nfs4_session_limit_rwsize(struct nfs_server *server)
 971 {
 972 #ifdef CONFIG_NFS_V4_1
 973         struct nfs4_session *sess;
 974         u32 server_resp_sz;
 975         u32 server_rqst_sz;
 976 
 977         if (!nfs4_has_session(server->nfs_client))
 978                 return;
 979         sess = server->nfs_client->cl_session;
 980         server_resp_sz = sess->fc_attrs.max_resp_sz - nfs41_maxread_overhead;
 981         server_rqst_sz = sess->fc_attrs.max_rqst_sz - nfs41_maxwrite_overhead;
 982 
 983         if (server->dtsize > server_resp_sz)
 984                 server->dtsize = server_resp_sz;
 985         if (server->rsize > server_resp_sz)
 986                 server->rsize = server_resp_sz;
 987         if (server->wsize > server_rqst_sz)
 988                 server->wsize = server_rqst_sz;
 989 #endif /* CONFIG_NFS_V4_1 */
 990 }
 991 
 992 static int nfs4_server_common_setup(struct nfs_server *server,
 993                 struct nfs_fh *mntfh, bool auth_probe)
 994 {
 995         struct nfs_fattr *fattr;
 996         int error;
 997 
 998         /* data servers support only a subset of NFSv4.1 */
 999         if (is_ds_only_client(server->nfs_client))
1000                 return -EPROTONOSUPPORT;
1001 
1002         fattr = nfs_alloc_fattr();
1003         if (fattr == NULL)
1004                 return -ENOMEM;
1005 
1006         /* We must ensure the session is initialised first */
1007         error = nfs4_init_session(server->nfs_client);
1008         if (error < 0)
1009                 goto out;
1010 
1011         /* Set the basic capabilities */
1012         server->caps |= server->nfs_client->cl_mvops->init_caps;
1013         if (server->flags & NFS_MOUNT_NORDIRPLUS)
1014                         server->caps &= ~NFS_CAP_READDIRPLUS;
1015         /*
1016          * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
1017          * authentication.
1018          */
1019         if (nfs4_disable_idmapping &&
1020                         server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
1021                 server->caps |= NFS_CAP_UIDGID_NOMAP;
1022 
1023 
1024         /* Probe the root fh to retrieve its FSID and filehandle */
1025         error = nfs4_get_rootfh(server, mntfh, auth_probe);
1026         if (error < 0)
1027                 goto out;
1028 
1029         dprintk("Server FSID: %llx:%llx\n",
1030                         (unsigned long long) server->fsid.major,
1031                         (unsigned long long) server->fsid.minor);
1032         nfs_display_fhandle(mntfh, "Pseudo-fs root FH");
1033 
1034         error = nfs_probe_fsinfo(server, mntfh, fattr);
1035         if (error < 0)
1036                 goto out;
1037 
1038         nfs4_session_limit_rwsize(server);
1039 
1040         if (server->namelen == 0 || server->namelen > NFS4_MAXNAMLEN)
1041                 server->namelen = NFS4_MAXNAMLEN;
1042 
1043         nfs_server_insert_lists(server);
1044         server->mount_time = jiffies;
1045         server->destroy = nfs4_destroy_server;
1046 out:
1047         nfs_free_fattr(fattr);
1048         return error;
1049 }
1050 
1051 /*
1052  * Create a version 4 volume record
1053  */
1054 static int nfs4_init_server(struct nfs_server *server,
1055                 struct nfs_parsed_mount_data *data)
1056 {
1057         struct rpc_timeout timeparms;
1058         int error;
1059 
1060         nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
1061                         data->timeo, data->retrans);
1062 
1063         /* Initialise the client representation from the mount data */
1064         server->flags = data->flags;
1065         server->options = data->options;
1066         server->auth_info = data->auth_info;
1067 
1068         /* Use the first specified auth flavor. If this flavor isn't
1069          * allowed by the server, use the SECINFO path to try the
1070          * other specified flavors */
1071         if (data->auth_info.flavor_len >= 1)
1072                 data->selected_flavor = data->auth_info.flavors[0];
1073         else
1074                 data->selected_flavor = RPC_AUTH_UNIX;
1075 
1076         /* Get a client record */
1077         error = nfs4_set_client(server,
1078                         data->nfs_server.hostname,
1079                         (const struct sockaddr *)&data->nfs_server.address,
1080                         data->nfs_server.addrlen,
1081                         data->client_address,
1082                         data->nfs_server.protocol,
1083                         &timeparms,
1084                         data->minorversion,
1085                         data->nfs_server.nconnect,
1086                         data->net);
1087         if (error < 0)
1088                 return error;
1089 
1090         if (data->rsize)
1091                 server->rsize = nfs_block_size(data->rsize, NULL);
1092         if (data->wsize)
1093                 server->wsize = nfs_block_size(data->wsize, NULL);
1094 
1095         server->acregmin = data->acregmin * HZ;
1096         server->acregmax = data->acregmax * HZ;
1097         server->acdirmin = data->acdirmin * HZ;
1098         server->acdirmax = data->acdirmax * HZ;
1099         server->port     = data->nfs_server.port;
1100 
1101         return nfs_init_server_rpcclient(server, &timeparms,
1102                                          data->selected_flavor);
1103 }
1104 
1105 /*
1106  * Create a version 4 volume record
1107  * - keyed on server and FSID
1108  */
1109 /*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
1110                                       struct nfs_fh *mntfh)*/
1111 struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info,
1112                                       struct nfs_subversion *nfs_mod)
1113 {
1114         struct nfs_server *server;
1115         bool auth_probe;
1116         int error;
1117 
1118         server = nfs_alloc_server();
1119         if (!server)
1120                 return ERR_PTR(-ENOMEM);
1121 
1122         server->cred = get_cred(current_cred());
1123 
1124         auth_probe = mount_info->parsed->auth_info.flavor_len < 1;
1125 
1126         /* set up the general RPC client */
1127         error = nfs4_init_server(server, mount_info->parsed);
1128         if (error < 0)
1129                 goto error;
1130 
1131         error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
1132         if (error < 0)
1133                 goto error;
1134 
1135         return server;
1136 
1137 error:
1138         nfs_free_server(server);
1139         return ERR_PTR(error);
1140 }
1141 
1142 /*
1143  * Create an NFS4 referral server record
1144  */
1145 struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
1146                                                struct nfs_fh *mntfh)
1147 {
1148         struct nfs_client *parent_client;
1149         struct nfs_server *server, *parent_server;
1150         bool auth_probe;
1151         int error;
1152 
1153         server = nfs_alloc_server();
1154         if (!server)
1155                 return ERR_PTR(-ENOMEM);
1156 
1157         parent_server = NFS_SB(data->sb);
1158         parent_client = parent_server->nfs_client;
1159 
1160         server->cred = get_cred(parent_server->cred);
1161 
1162         /* Initialise the client representation from the parent server */
1163         nfs_server_copy_userdata(server, parent_server);
1164 
1165         /* Get a client representation */
1166 #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
1167         rpc_set_port(data->addr, NFS_RDMA_PORT);
1168         error = nfs4_set_client(server, data->hostname,
1169                                 data->addr,
1170                                 data->addrlen,
1171                                 parent_client->cl_ipaddr,
1172                                 XPRT_TRANSPORT_RDMA,
1173                                 parent_server->client->cl_timeout,
1174                                 parent_client->cl_mvops->minor_version,
1175                                 parent_client->cl_nconnect,
1176                                 parent_client->cl_net);
1177         if (!error)
1178                 goto init_server;
1179 #endif  /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
1180 
1181         rpc_set_port(data->addr, NFS_PORT);
1182         error = nfs4_set_client(server, data->hostname,
1183                                 data->addr,
1184                                 data->addrlen,
1185                                 parent_client->cl_ipaddr,
1186                                 XPRT_TRANSPORT_TCP,
1187                                 parent_server->client->cl_timeout,
1188                                 parent_client->cl_mvops->minor_version,
1189                                 parent_client->cl_nconnect,
1190                                 parent_client->cl_net);
1191         if (error < 0)
1192                 goto error;
1193 
1194 #if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
1195 init_server:
1196 #endif
1197         error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
1198         if (error < 0)
1199                 goto error;
1200 
1201         auth_probe = parent_server->auth_info.flavor_len < 1;
1202 
1203         error = nfs4_server_common_setup(server, mntfh, auth_probe);
1204         if (error < 0)
1205                 goto error;
1206 
1207         return server;
1208 
1209 error:
1210         nfs_free_server(server);
1211         return ERR_PTR(error);
1212 }
1213 
1214 /*
1215  * Grab the destination's particulars, including lease expiry time.
1216  *
1217  * Returns zero if probe succeeded and retrieved FSID matches the FSID
1218  * we have cached.
1219  */
1220 static int nfs_probe_destination(struct nfs_server *server)
1221 {
1222         struct inode *inode = d_inode(server->super->s_root);
1223         struct nfs_fattr *fattr;
1224         int error;
1225 
1226         fattr = nfs_alloc_fattr();
1227         if (fattr == NULL)
1228                 return -ENOMEM;
1229 
1230         /* Sanity: the probe won't work if the destination server
1231          * does not recognize the migrated FH. */
1232         error = nfs_probe_fsinfo(server, NFS_FH(inode), fattr);
1233 
1234         nfs_free_fattr(fattr);
1235         return error;
1236 }
1237 
1238 /**
1239  * nfs4_update_server - Move an nfs_server to a different nfs_client
1240  *
1241  * @server: represents FSID to be moved
1242  * @hostname: new end-point's hostname
1243  * @sap: new end-point's socket address
1244  * @salen: size of "sap"
1245  * @net: net namespace
1246  *
1247  * The nfs_server must be quiescent before this function is invoked.
1248  * Either its session is drained (NFSv4.1+), or its transport is
1249  * plugged and drained (NFSv4.0).
1250  *
1251  * Returns zero on success, or a negative errno value.
1252  */
1253 int nfs4_update_server(struct nfs_server *server, const char *hostname,
1254                        struct sockaddr *sap, size_t salen, struct net *net)
1255 {
1256         struct nfs_client *clp = server->nfs_client;
1257         struct rpc_clnt *clnt = server->client;
1258         struct xprt_create xargs = {
1259                 .ident          = clp->cl_proto,
1260                 .net            = net,
1261                 .dstaddr        = sap,
1262                 .addrlen        = salen,
1263                 .servername     = hostname,
1264         };
1265         char buf[INET6_ADDRSTRLEN + 1];
1266         struct sockaddr_storage address;
1267         struct sockaddr *localaddr = (struct sockaddr *)&address;
1268         int error;
1269 
1270         error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
1271         if (error != 0)
1272                 return error;
1273 
1274         error = rpc_localaddr(clnt, localaddr, sizeof(address));
1275         if (error != 0)
1276                 return error;
1277 
1278         if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0)
1279                 return -EAFNOSUPPORT;
1280 
1281         nfs_server_remove_lists(server);
1282         set_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
1283         error = nfs4_set_client(server, hostname, sap, salen, buf,
1284                                 clp->cl_proto, clnt->cl_timeout,
1285                                 clp->cl_minorversion,
1286                                 clp->cl_nconnect, net);
1287         clear_bit(NFS_MIG_TSM_POSSIBLE, &server->mig_status);
1288         if (error != 0) {
1289                 nfs_server_insert_lists(server);
1290                 return error;
1291         }
1292         nfs_put_client(clp);
1293 
1294         if (server->nfs_client->cl_hostname == NULL)
1295                 server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
1296         nfs_server_insert_lists(server);
1297 
1298         return nfs_probe_destination(server);
1299 }

/* [<][>][^][v][top][bottom][index][help] */