cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nfs4client.c (35224B)


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