Commit b01f21ca authored by Trond Myklebust's avatar Trond Myklebust
Browse files

NFS: Fix the setting of capabilities when automounting a new filesystem



Capabilities cannot be inherited when we cross into a new filesystem.
They need to be reset to the minimal defaults, and then probed for
again.

Fixes: 54ceac45 ("NFS: Share NFS superblocks per-protocol per-server per-FSID")
Cc: stable@vger.kernel.org
Reviewed-by: default avatarBenjamin Coddington <bcodding@redhat.com>
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
parent cc5d5908
Loading
Loading
Loading
Loading
+42 −2
Original line number Diff line number Diff line
@@ -682,6 +682,44 @@ struct nfs_client *nfs_init_client(struct nfs_client *clp,
}
EXPORT_SYMBOL_GPL(nfs_init_client);

static void nfs4_server_set_init_caps(struct nfs_server *server)
{
#if IS_ENABLED(CONFIG_NFS_V4)
	/* Set the basic capabilities */
	server->caps = server->nfs_client->cl_mvops->init_caps;
	if (server->flags & NFS_MOUNT_NORDIRPLUS)
		server->caps &= ~NFS_CAP_READDIRPLUS;
	if (server->nfs_client->cl_proto == XPRT_TRANSPORT_RDMA)
		server->caps &= ~NFS_CAP_READ_PLUS;

	/*
	 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
	 * authentication.
	 */
	if (nfs4_disable_idmapping &&
	    server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
		server->caps |= NFS_CAP_UIDGID_NOMAP;
#endif
}

void nfs_server_set_init_caps(struct nfs_server *server)
{
	switch (server->nfs_client->rpc_ops->version) {
	case 2:
		server->caps = NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
		break;
	case 3:
		server->caps = NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;
		if (!(server->flags & NFS_MOUNT_NORDIRPLUS))
			server->caps |= NFS_CAP_READDIRPLUS;
		break;
	default:
		nfs4_server_set_init_caps(server);
		break;
	}
}
EXPORT_SYMBOL_GPL(nfs_server_set_init_caps);

/*
 * Create a version 2 or 3 client
 */
@@ -726,7 +764,6 @@ static int nfs_init_server(struct nfs_server *server,
	/* Initialise the client representation from the mount data */
	server->flags = ctx->flags;
	server->options = ctx->options;
	server->caps |= NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS;

	switch (clp->rpc_ops->version) {
	case 2:
@@ -762,6 +799,8 @@ static int nfs_init_server(struct nfs_server *server,
	if (error < 0)
		goto error;

	nfs_server_set_init_caps(server);

	/* Preserve the values of mount_server-related mount options */
	if (ctx->mount_server.addrlen) {
		memcpy(&server->mountd_address, &ctx->mount_server.address,
@@ -934,7 +973,6 @@ void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *sour
	target->acregmax = source->acregmax;
	target->acdirmin = source->acdirmin;
	target->acdirmax = source->acdirmax;
	target->caps = source->caps;
	target->options = source->options;
	target->auth_info = source->auth_info;
	target->port = source->port;
@@ -1169,6 +1207,8 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
	if (error < 0)
		goto out_free_server;

	nfs_server_set_init_caps(server);

	/* probe the filesystem info for this server filesystem */
	error = nfs_probe_server(server, fh);
	if (error < 0)
+1 −1
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ extern struct nfs_client *
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
				struct nfs4_sessionid *, u32);
extern struct nfs_server *nfs_create_server(struct fs_context *);
extern void nfs4_server_set_init_caps(struct nfs_server *);
extern void nfs_server_set_init_caps(struct nfs_server *);
extern struct nfs_server *nfs4_create_server(struct fs_context *);
extern struct nfs_server *nfs4_create_referral_server(struct fs_context *);
extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
+1 −19
Original line number Diff line number Diff line
@@ -1074,24 +1074,6 @@ static void nfs4_session_limit_xasize(struct nfs_server *server)
#endif
}

void nfs4_server_set_init_caps(struct nfs_server *server)
{
	/* Set the basic capabilities */
	server->caps |= server->nfs_client->cl_mvops->init_caps;
	if (server->flags & NFS_MOUNT_NORDIRPLUS)
			server->caps &= ~NFS_CAP_READDIRPLUS;
	if (server->nfs_client->cl_proto == XPRT_TRANSPORT_RDMA)
		server->caps &= ~NFS_CAP_READ_PLUS;

	/*
	 * Don't use NFS uid/gid mapping if we're using AUTH_SYS or lower
	 * authentication.
	 */
	if (nfs4_disable_idmapping &&
			server->client->cl_auth->au_flavor == RPC_AUTH_UNIX)
		server->caps |= NFS_CAP_UIDGID_NOMAP;
}

static int nfs4_server_common_setup(struct nfs_server *server,
		struct nfs_fh *mntfh, bool auth_probe)
{
@@ -1110,7 +1092,7 @@ static int nfs4_server_common_setup(struct nfs_server *server,
	if (error < 0)
		return error;

	nfs4_server_set_init_caps(server);
	nfs_server_set_init_caps(server);

	/* Probe the root fh to retrieve its FSID and filehandle */
	error = nfs4_get_rootfh(server, mntfh, auth_probe);
+1 −1
Original line number Diff line number Diff line
@@ -4092,7 +4092,7 @@ int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
	};
	int err;

	nfs4_server_set_init_caps(server);
	nfs_server_set_init_caps(server);
	do {
		err = nfs4_handle_exception(server,
				_nfs4_server_capabilities(server, fhandle),