Commit 4e1c80ae authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull nfsd updates from Chuck Lever:
 "The big ticket item for this release is that support for RPC-with-TLS
  [RFC 9289] has been added to the Linux NFS server.

  The goal is to provide a simple-to-deploy, low-overhead in-transit
  confidentiality and peer authentication mechanism. It can supplement
  NFS Kerberos and it can protect the use of legacy non-cryptographic
  user authentication flavors such as AUTH_SYS. The TLS Record protocol
  is handled entirely by kTLS, meaning it can use either software
  encryption or offload encryption to smart NICs.

  Aside from that, work continues on improving NFSD's open file cache.
  Among the many clean-ups in that area is a patch to convert the
  rhashtable to use the list-hashing version of that data structure"

* tag 'nfsd-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (31 commits)
  NFSD: Handle new xprtsec= export option
  SUNRPC: Support TLS handshake in the server-side TCP socket code
  NFSD: Clean up xattr memory allocation flags
  NFSD: Fix problem of COMMIT and NFS4ERR_DELAY in infinite loop
  SUNRPC: Clear rq_xid when receiving a new RPC Call
  SUNRPC: Recognize control messages in server-side TCP socket code
  SUNRPC: Be even lazier about releasing pages
  SUNRPC: Convert svc_xprt_release() to the release_pages() API
  SUNRPC: Relocate svc_free_res_pages()
  nfsd: simplify the delayed disposal list code
  SUNRPC: Ignore return value of ->xpo_sendto
  SUNRPC: Ensure server-side sockets have a sock->file
  NFSD: Watch for rq_pages bounds checking errors in nfsd_splice_actor()
  sunrpc: simplify two-level sysctl registration for svcrdma_parm_table
  SUNRPC: return proper error from get_expiry()
  lockd: add some client-side tracepoints
  nfs: move nfs_fhandle_hash to common include file
  lockd: server should unlock lock if client rejects the grant
  lockd: fix races in client GRANTED_MSG wait logic
  lockd: move struct nlm_wait to lockd.h
  ...
parents 0127f25b 9280c577
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -3,10 +3,12 @@
# Makefile for the linux lock manager stuff
#

ccflags-y += -I$(src)			# needed for trace events

obj-$(CONFIG_LOCKD) += lockd.o

lockd-objs-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
	        svcshare.o svcproc.o svcsubs.o mon.o xdr.o
lockd-objs-y += clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
	        svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o
lockd-objs-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
lockd-objs-$(CONFIG_PROC_FS) += procfs.o
lockd-objs		      := $(lockd-objs-y)
+25 −33
Original line number Diff line number Diff line
@@ -14,9 +14,12 @@
#include <linux/nfs_fs.h>
#include <linux/sunrpc/addr.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svc_xprt.h>
#include <linux/lockd/lockd.h>
#include <linux/kthread.h>

#include "trace.h"

#define NLMDBG_FACILITY		NLMDBG_CLIENT

/*
@@ -29,18 +32,6 @@ static int reclaimer(void *ptr);
 * client perspective.
 */

/*
 * This is the representation of a blocked client lock.
 */
struct nlm_wait {
	struct list_head	b_list;		/* linked list */
	wait_queue_head_t	b_wait;		/* where to wait on */
	struct nlm_host *	b_host;
	struct file_lock *	b_lock;		/* local file lock */
	unsigned short		b_reclaim;	/* got to reclaim lock */
	__be32			b_status;	/* grant callback status */
};

static LIST_HEAD(nlm_blocked);
static DEFINE_SPINLOCK(nlm_blocked_lock);

@@ -94,41 +85,42 @@ void nlmclnt_done(struct nlm_host *host)
}
EXPORT_SYMBOL_GPL(nlmclnt_done);

/*
 * Queue up a lock for blocking so that the GRANTED request can see it
 */
struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl)
void nlmclnt_prepare_block(struct nlm_wait *block, struct nlm_host *host, struct file_lock *fl)
{
	struct nlm_wait *block;

	block = kmalloc(sizeof(*block), GFP_KERNEL);
	if (block != NULL) {
	block->b_host = host;
	block->b_lock = fl;
	init_waitqueue_head(&block->b_wait);
	block->b_status = nlm_lck_blocked;
}

/*
 * Queue up a lock for blocking so that the GRANTED request can see it
 */
void nlmclnt_queue_block(struct nlm_wait *block)
{
	spin_lock(&nlm_blocked_lock);
	list_add(&block->b_list, &nlm_blocked);
	spin_unlock(&nlm_blocked_lock);
}
	return block;
}

void nlmclnt_finish_block(struct nlm_wait *block)
/*
 * Dequeue the block and return its final status
 */
__be32 nlmclnt_dequeue_block(struct nlm_wait *block)
{
	if (block == NULL)
		return;
	__be32 status;

	spin_lock(&nlm_blocked_lock);
	list_del(&block->b_list);
	status = block->b_status;
	spin_unlock(&nlm_blocked_lock);
	kfree(block);
	return status;
}

/*
 * Block on a lock
 */
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
{
	long ret;

@@ -154,7 +146,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
	/* Reset the lock status after a server reboot so we resend */
	if (block->b_status == nlm_lck_denied_grace_period)
		block->b_status = nlm_lck_blocked;
	req->a_res.status = block->b_status;
	return 0;
}

@@ -198,6 +189,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
		res = nlm_granted;
	}
	spin_unlock(&nlm_blocked_lock);
	trace_nlmclnt_grant(lock, addr, svc_addr_len(addr), res);
	return res;
}

+32 −10
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>

#include "trace.h"

#define NLMDBG_FACILITY		NLMDBG_CLIENT
#define NLMCLNT_GRACE_WAIT	(5*HZ)
#define NLMCLNT_POLL_TIMEOUT	(30*HZ)
@@ -451,6 +453,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
			status = nlm_stat_to_errno(req->a_res.status);
	}
out:
	trace_nlmclnt_test(&req->a_args.lock,
			   (const struct sockaddr *)&req->a_host->h_addr,
			   req->a_host->h_addrlen, req->a_res.status);
	nlmclnt_release_call(req);
	return status;
}
@@ -516,9 +521,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
	const struct cred *cred = nfs_file_cred(fl->fl_file);
	struct nlm_host	*host = req->a_host;
	struct nlm_res	*resp = &req->a_res;
	struct nlm_wait *block = NULL;
	struct nlm_wait block;
	unsigned char fl_flags = fl->fl_flags;
	unsigned char fl_type;
	__be32 b_status;
	int status = -ENOLCK;

	if (nsm_monitor(host) < 0)
@@ -531,13 +537,20 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
	if (status < 0)
		goto out;

	block = nlmclnt_prepare_block(host, fl);
	nlmclnt_prepare_block(&block, host, fl);
again:
	/*
	 * Initialise resp->status to a valid non-zero value,
	 * since 0 == nlm_lck_granted
	 */
	resp->status = nlm_lck_blocked;

	/*
	 * A GRANTED callback can come at any time -- even before the reply
	 * to the LOCK request arrives, so we queue the wait before
	 * requesting the lock.
	 */
	nlmclnt_queue_block(&block);
	for (;;) {
		/* Reboot protection */
		fl->fl_u.nfs_fl.state = host->h_state;
@@ -550,12 +563,15 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
		if (resp->status != nlm_lck_blocked)
			break;
		/* Wait on an NLM blocking lock */
		status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
		status = nlmclnt_wait(&block, req, NLMCLNT_POLL_TIMEOUT);
		if (status < 0)
			break;
		if (resp->status != nlm_lck_blocked)
		if (block.b_status != nlm_lck_blocked)
			break;
	}
	b_status = nlmclnt_dequeue_block(&block);
	if (resp->status == nlm_lck_blocked)
		resp->status = b_status;

	/* if we were interrupted while blocking, then cancel the lock request
	 * and exit
@@ -564,7 +580,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
		if (!req->a_args.block)
			goto out_unlock;
		if (nlmclnt_cancel(host, req->a_args.block, fl) == 0)
			goto out_unblock;
			goto out;
	}

	if (resp->status == nlm_granted) {
@@ -593,16 +609,19 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
		status = -ENOLCK;
	else
		status = nlm_stat_to_errno(resp->status);
out_unblock:
	nlmclnt_finish_block(block);
out:
	trace_nlmclnt_lock(&req->a_args.lock,
			   (const struct sockaddr *)&req->a_host->h_addr,
			   req->a_host->h_addrlen, req->a_res.status);
	nlmclnt_release_call(req);
	return status;
out_unlock:
	/* Fatal error: ensure that we remove the lock altogether */
	trace_nlmclnt_lock(&req->a_args.lock,
			   (const struct sockaddr *)&req->a_host->h_addr,
			   req->a_host->h_addrlen, req->a_res.status);
	dprintk("lockd: lock attempt ended in fatal error.\n"
		"       Attempting to unlock.\n");
	nlmclnt_finish_block(block);
	fl_type = fl->fl_type;
	fl->fl_type = F_UNLCK;
	down_read(&host->h_rwsem);
@@ -696,6 +715,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
	/* What to do now? I'm out of my depth... */
	status = -ENOLCK;
out:
	trace_nlmclnt_unlock(&req->a_args.lock,
			     (const struct sockaddr *)&req->a_host->h_addr,
			     req->a_host->h_addrlen, req->a_res.status);
	nlmclnt_release_call(req);
	return status;
}
+1 −0
Original line number Diff line number Diff line
@@ -629,6 +629,7 @@ nlm_shutdown_hosts_net(struct net *net)
			rpc_shutdown_client(host->h_rpcclnt);
			host->h_rpcclnt = NULL;
		}
		nlmsvc_free_host_resources(host);
	}

	/* Then, perform a garbage collection pass */
+17 −4
Original line number Diff line number Diff line
@@ -954,19 +954,32 @@ void
nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
{
	struct nlm_block	*block;
	struct file_lock	*fl;
	int			error;

	dprintk("grant_reply: looking for cookie %x, s=%d \n",
		*(unsigned int *)(cookie->data), status);
	if (!(block = nlmsvc_find_block(cookie)))
		return;

	if (status == nlm_lck_denied_grace_period) {
	switch (status) {
	case nlm_lck_denied_grace_period:
		/* Try again in a couple of seconds */
		nlmsvc_insert_block(block, 10 * HZ);
	} else {
		break;
	case nlm_lck_denied:
		/* Client doesn't want it, just unlock it */
		nlmsvc_unlink_block(block);
		fl = &block->b_call->a_args.lock.fl;
		fl->fl_type = F_UNLCK;
		error = vfs_lock_file(fl->fl_file, F_SETLK, fl, NULL);
		if (error)
			pr_warn("lockd: unable to unlock lock rejected by client!\n");
		break;
	default:
		/*
		 * Lock is now held by client, or has been rejected.
		 * In both cases, the block should be removed.
		 * Either it was accepted or the status makes no sense
		 * just unlink it either way.
		 */
		nlmsvc_unlink_block(block);
	}
Loading