Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 32e62b7c authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

NFS: Add nfs4_update_server



New function nfs4_update_server() moves an nfs_server to a different
nfs_client.  This is done as part of migration recovery.

Though it may be appealing to think of them as the same thing,
migration recovery is not the same as following a referral.

For a referral, the client has not descended into the file system
yet: it has no nfs_server, no super block, no inodes or open state.
It is enough to simply instantiate the nfs_server and super block,
and perform a referral mount.

For a migration, however, we have all of those things already, and
they have to be moved to a different nfs_client.  No local namespace
changes are needed here.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 40b00b6b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -945,7 +945,7 @@ void nfs_server_insert_lists(struct nfs_server *server)
}
EXPORT_SYMBOL_GPL(nfs_server_insert_lists);

static void nfs_server_remove_lists(struct nfs_server *server)
void nfs_server_remove_lists(struct nfs_server *server)
{
	struct nfs_client *clp = server->nfs_client;
	struct nfs_net *nn;
@@ -962,6 +962,7 @@ static void nfs_server_remove_lists(struct nfs_server *server)

	synchronize_rcu();
}
EXPORT_SYMBOL_GPL(nfs_server_remove_lists);

/*
 * Allocate and initialise a server record
+3 −0
Original line number Diff line number Diff line
@@ -154,6 +154,7 @@ struct nfs_client *nfs_get_client(const struct nfs_client_initdata *,
				  rpc_authflavor_t);
int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *, struct nfs_fattr *);
void nfs_server_insert_lists(struct nfs_server *);
void nfs_server_remove_lists(struct nfs_server *);
void nfs_init_timeout_values(struct rpc_timeout *, int, unsigned int, unsigned int);
int nfs_init_server_rpcclient(struct nfs_server *, const struct rpc_timeout *t,
		rpc_authflavor_t);
@@ -174,6 +175,8 @@ extern struct nfs_server *nfs4_create_server(
					struct nfs_subversion *);
extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
						      struct nfs_fh *);
extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
					struct sockaddr *sap, size_t salen);
extern void nfs_free_server(struct nfs_server *server);
extern struct nfs_server *nfs_clone_server(struct nfs_server *,
					   struct nfs_fh *,
+108 −0
Original line number Diff line number Diff line
@@ -1092,3 +1092,111 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
	dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
	return ERR_PTR(error);
}

/*
 * Grab the destination's particulars, including lease expiry time.
 *
 * Returns zero if probe succeeded and retrieved FSID matches the FSID
 * we have cached.
 */
static int nfs_probe_destination(struct nfs_server *server)
{
	struct inode *inode = server->super->s_root->d_inode;
	struct nfs_fattr *fattr;
	int error;

	fattr = nfs_alloc_fattr();
	if (fattr == NULL)
		return -ENOMEM;

	/* Sanity: the probe won't work if the destination server
	 * does not recognize the migrated FH. */
	error = nfs_probe_fsinfo(server, NFS_FH(inode), fattr);

	nfs_free_fattr(fattr);
	return error;
}

/**
 * nfs4_update_server - Move an nfs_server to a different nfs_client
 *
 * @server: represents FSID to be moved
 * @hostname: new end-point's hostname
 * @sap: new end-point's socket address
 * @salen: size of "sap"
 *
 * The nfs_server must be quiescent before this function is invoked.
 * Either its session is drained (NFSv4.1+), or its transport is
 * plugged and drained (NFSv4.0).
 *
 * Returns zero on success, or a negative errno value.
 */
int nfs4_update_server(struct nfs_server *server, const char *hostname,
		       struct sockaddr *sap, size_t salen)
{
	struct nfs_client *clp = server->nfs_client;
	struct rpc_clnt *clnt = server->client;
	struct xprt_create xargs = {
		.ident		= clp->cl_proto,
		.net		= &init_net,
		.dstaddr	= sap,
		.addrlen	= salen,
		.servername	= hostname,
	};
	char buf[INET6_ADDRSTRLEN + 1];
	struct sockaddr_storage address;
	struct sockaddr *localaddr = (struct sockaddr *)&address;
	int error;

	dprintk("--> %s: move FSID %llx:%llx to \"%s\")\n", __func__,
			(unsigned long long)server->fsid.major,
			(unsigned long long)server->fsid.minor,
			hostname);

	error = rpc_switch_client_transport(clnt, &xargs, clnt->cl_timeout);
	if (error != 0) {
		dprintk("<-- %s(): rpc_switch_client_transport returned %d\n",
			__func__, error);
		goto out;
	}

	error = rpc_localaddr(clnt, localaddr, sizeof(address));
	if (error != 0) {
		dprintk("<-- %s(): rpc_localaddr returned %d\n",
			__func__, error);
		goto out;
	}

	error = -EAFNOSUPPORT;
	if (rpc_ntop(localaddr, buf, sizeof(buf)) == 0) {
		dprintk("<-- %s(): rpc_ntop returned %d\n",
			__func__, error);
		goto out;
	}

	nfs_server_remove_lists(server);
	error = nfs4_set_client(server, hostname, sap, salen, buf,
				clp->cl_rpcclient->cl_auth->au_flavor,
				clp->cl_proto, clnt->cl_timeout,
				clp->cl_minorversion, clp->cl_net);
	nfs_put_client(clp);
	if (error != 0) {
		nfs_server_insert_lists(server);
		dprintk("<-- %s(): nfs4_set_client returned %d\n",
			__func__, error);
		goto out;
	}

	if (server->nfs_client->cl_hostname == NULL)
		server->nfs_client->cl_hostname = kstrdup(hostname, GFP_KERNEL);
	nfs_server_insert_lists(server);

	error = nfs_probe_destination(server);
	if (error < 0)
		goto out;

	dprintk("<-- %s() succeeded\n", __func__);

out:
	return error;
}