Skip to content

Commit 4e1c80a

Browse files
committed
Merge tag 'nfsd-6.4' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
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 ...
2 parents 0127f25 + 9280c57 commit 4e1c80a

31 files changed

Lines changed: 802 additions & 442 deletions

fs/lockd/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
# Makefile for the linux lock manager stuff
44
#
55

6+
ccflags-y += -I$(src) # needed for trace events
7+
68
obj-$(CONFIG_LOCKD) += lockd.o
79

8-
lockd-objs-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
9-
svcshare.o svcproc.o svcsubs.o mon.o xdr.o
10+
lockd-objs-y += clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
11+
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o
1012
lockd-objs-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
1113
lockd-objs-$(CONFIG_PROC_FS) += procfs.o
1214
lockd-objs := $(lockd-objs-y)

fs/lockd/clntlock.c

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
#include <linux/nfs_fs.h>
1515
#include <linux/sunrpc/addr.h>
1616
#include <linux/sunrpc/svc.h>
17+
#include <linux/sunrpc/svc_xprt.h>
1718
#include <linux/lockd/lockd.h>
1819
#include <linux/kthread.h>
1920

21+
#include "trace.h"
22+
2023
#define NLMDBG_FACILITY NLMDBG_CLIENT
2124

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

32-
/*
33-
* This is the representation of a blocked client lock.
34-
*/
35-
struct nlm_wait {
36-
struct list_head b_list; /* linked list */
37-
wait_queue_head_t b_wait; /* where to wait on */
38-
struct nlm_host * b_host;
39-
struct file_lock * b_lock; /* local file lock */
40-
unsigned short b_reclaim; /* got to reclaim lock */
41-
__be32 b_status; /* grant callback status */
42-
};
43-
4435
static LIST_HEAD(nlm_blocked);
4536
static DEFINE_SPINLOCK(nlm_blocked_lock);
4637

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

88+
void nlmclnt_prepare_block(struct nlm_wait *block, struct nlm_host *host, struct file_lock *fl)
89+
{
90+
block->b_host = host;
91+
block->b_lock = fl;
92+
init_waitqueue_head(&block->b_wait);
93+
block->b_status = nlm_lck_blocked;
94+
}
95+
9796
/*
9897
* Queue up a lock for blocking so that the GRANTED request can see it
9998
*/
100-
struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl)
99+
void nlmclnt_queue_block(struct nlm_wait *block)
101100
{
102-
struct nlm_wait *block;
103-
104-
block = kmalloc(sizeof(*block), GFP_KERNEL);
105-
if (block != NULL) {
106-
block->b_host = host;
107-
block->b_lock = fl;
108-
init_waitqueue_head(&block->b_wait);
109-
block->b_status = nlm_lck_blocked;
110-
111-
spin_lock(&nlm_blocked_lock);
112-
list_add(&block->b_list, &nlm_blocked);
113-
spin_unlock(&nlm_blocked_lock);
114-
}
115-
return block;
101+
spin_lock(&nlm_blocked_lock);
102+
list_add(&block->b_list, &nlm_blocked);
103+
spin_unlock(&nlm_blocked_lock);
116104
}
117105

118-
void nlmclnt_finish_block(struct nlm_wait *block)
106+
/*
107+
* Dequeue the block and return its final status
108+
*/
109+
__be32 nlmclnt_dequeue_block(struct nlm_wait *block)
119110
{
120-
if (block == NULL)
121-
return;
111+
__be32 status;
112+
122113
spin_lock(&nlm_blocked_lock);
123114
list_del(&block->b_list);
115+
status = block->b_status;
124116
spin_unlock(&nlm_blocked_lock);
125-
kfree(block);
117+
return status;
126118
}
127119

128120
/*
129121
* Block on a lock
130122
*/
131-
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
123+
int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
132124
{
133125
long ret;
134126

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

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

fs/lockd/clntproc.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include <linux/sunrpc/svc.h>
2121
#include <linux/lockd/lockd.h>
2222

23+
#include "trace.h"
24+
2325
#define NLMDBG_FACILITY NLMDBG_CLIENT
2426
#define NLMCLNT_GRACE_WAIT (5*HZ)
2527
#define NLMCLNT_POLL_TIMEOUT (30*HZ)
@@ -451,6 +453,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl)
451453
status = nlm_stat_to_errno(req->a_res.status);
452454
}
453455
out:
456+
trace_nlmclnt_test(&req->a_args.lock,
457+
(const struct sockaddr *)&req->a_host->h_addr,
458+
req->a_host->h_addrlen, req->a_res.status);
454459
nlmclnt_release_call(req);
455460
return status;
456461
}
@@ -516,9 +521,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
516521
const struct cred *cred = nfs_file_cred(fl->fl_file);
517522
struct nlm_host *host = req->a_host;
518523
struct nlm_res *resp = &req->a_res;
519-
struct nlm_wait *block = NULL;
524+
struct nlm_wait block;
520525
unsigned char fl_flags = fl->fl_flags;
521526
unsigned char fl_type;
527+
__be32 b_status;
522528
int status = -ENOLCK;
523529

524530
if (nsm_monitor(host) < 0)
@@ -531,31 +537,41 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
531537
if (status < 0)
532538
goto out;
533539

534-
block = nlmclnt_prepare_block(host, fl);
540+
nlmclnt_prepare_block(&block, host, fl);
535541
again:
536542
/*
537543
* Initialise resp->status to a valid non-zero value,
538544
* since 0 == nlm_lck_granted
539545
*/
540546
resp->status = nlm_lck_blocked;
541-
for(;;) {
547+
548+
/*
549+
* A GRANTED callback can come at any time -- even before the reply
550+
* to the LOCK request arrives, so we queue the wait before
551+
* requesting the lock.
552+
*/
553+
nlmclnt_queue_block(&block);
554+
for (;;) {
542555
/* Reboot protection */
543556
fl->fl_u.nfs_fl.state = host->h_state;
544557
status = nlmclnt_call(cred, req, NLMPROC_LOCK);
545558
if (status < 0)
546559
break;
547560
/* Did a reclaimer thread notify us of a server reboot? */
548-
if (resp->status == nlm_lck_denied_grace_period)
561+
if (resp->status == nlm_lck_denied_grace_period)
549562
continue;
550563
if (resp->status != nlm_lck_blocked)
551564
break;
552565
/* Wait on an NLM blocking lock */
553-
status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);
566+
status = nlmclnt_wait(&block, req, NLMCLNT_POLL_TIMEOUT);
554567
if (status < 0)
555568
break;
556-
if (resp->status != nlm_lck_blocked)
569+
if (block.b_status != nlm_lck_blocked)
557570
break;
558571
}
572+
b_status = nlmclnt_dequeue_block(&block);
573+
if (resp->status == nlm_lck_blocked)
574+
resp->status = b_status;
559575

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

570586
if (resp->status == nlm_granted) {
@@ -593,16 +609,19 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
593609
status = -ENOLCK;
594610
else
595611
status = nlm_stat_to_errno(resp->status);
596-
out_unblock:
597-
nlmclnt_finish_block(block);
598612
out:
613+
trace_nlmclnt_lock(&req->a_args.lock,
614+
(const struct sockaddr *)&req->a_host->h_addr,
615+
req->a_host->h_addrlen, req->a_res.status);
599616
nlmclnt_release_call(req);
600617
return status;
601618
out_unlock:
602619
/* Fatal error: ensure that we remove the lock altogether */
620+
trace_nlmclnt_lock(&req->a_args.lock,
621+
(const struct sockaddr *)&req->a_host->h_addr,
622+
req->a_host->h_addrlen, req->a_res.status);
603623
dprintk("lockd: lock attempt ended in fatal error.\n"
604624
" Attempting to unlock.\n");
605-
nlmclnt_finish_block(block);
606625
fl_type = fl->fl_type;
607626
fl->fl_type = F_UNLCK;
608627
down_read(&host->h_rwsem);
@@ -696,6 +715,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
696715
/* What to do now? I'm out of my depth... */
697716
status = -ENOLCK;
698717
out:
718+
trace_nlmclnt_unlock(&req->a_args.lock,
719+
(const struct sockaddr *)&req->a_host->h_addr,
720+
req->a_host->h_addrlen, req->a_res.status);
699721
nlmclnt_release_call(req);
700722
return status;
701723
}

fs/lockd/host.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,7 @@ nlm_shutdown_hosts_net(struct net *net)
629629
rpc_shutdown_client(host->h_rpcclnt);
630630
host->h_rpcclnt = NULL;
631631
}
632+
nlmsvc_free_host_resources(host);
632633
}
633634

634635
/* Then, perform a garbage collection pass */

fs/lockd/svclock.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -954,19 +954,32 @@ void
954954
nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
955955
{
956956
struct nlm_block *block;
957+
struct file_lock *fl;
958+
int error;
957959

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

963-
if (status == nlm_lck_denied_grace_period) {
965+
switch (status) {
966+
case nlm_lck_denied_grace_period:
964967
/* Try again in a couple of seconds */
965968
nlmsvc_insert_block(block, 10 * HZ);
966-
} else {
969+
break;
970+
case nlm_lck_denied:
971+
/* Client doesn't want it, just unlock it */
972+
nlmsvc_unlink_block(block);
973+
fl = &block->b_call->a_args.lock.fl;
974+
fl->fl_type = F_UNLCK;
975+
error = vfs_lock_file(fl->fl_file, F_SETLK, fl, NULL);
976+
if (error)
977+
pr_warn("lockd: unable to unlock lock rejected by client!\n");
978+
break;
979+
default:
967980
/*
968-
* Lock is now held by client, or has been rejected.
969-
* In both cases, the block should be removed.
981+
* Either it was accepted or the status makes no sense
982+
* just unlink it either way.
970983
*/
971984
nlmsvc_unlink_block(block);
972985
}

fs/lockd/trace.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#define CREATE_TRACE_POINTS
3+
#include "trace.h"

0 commit comments

Comments
 (0)