History

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 ...

Linus Torvalds committed 3 years ago

Commit 4e1c80a2 parents 0127f25 9280c5731 files · +802 −442Browse files

Unified · Split

31 files
  1. fs/lockd/Makefile +4 −2
  2. fs/lockd/clntlock.c +25 −33
  3. fs/lockd/clntproc.c +32 −10
  4. fs/lockd/host.c +1 −0
  5. fs/lockd/svclock.c +17 −4
  6. fs/lockd/trace.c +3 −0
  7. fs/lockd/trace.h +106 −0
  8. fs/nfs/export.c +6 −3
  9. fs/nfs/internal.h +0 −15
  10. fs/nfsd/export.c +54 −10
  11. fs/nfsd/export.h +1 −0
  12. fs/nfsd/filecache.c +185 −245
  13. fs/nfsd/filecache.h +5 −4
  14. fs/nfsd/nfs4idmap.c +4 −4
  15. fs/nfsd/vfs.c +7 −6
  16. include/linux/exportfs.h +1 −0
  17. include/linux/lockd/lockd.h +15 −14
  18. include/linux/nfs.h +20 −0
  19. include/linux/sunrpc/cache.h +8 −7
  20. include/linux/sunrpc/svc.h +3 −13
  21. include/linux/sunrpc/svc_xprt.h +4 −1
  22. include/linux/sunrpc/svcsock.h +3 −1
  23. include/net/tls.h +2 −0
  24. include/trace/events/sunrpc.h +40 −1
  25. include/uapi/linux/nfsd/export.h +13 −0
  26. net/sunrpc/auth_gss/svcauth_gss.c +6 −6
  27. net/sunrpc/svc.c +42 −7
  28. net/sunrpc/svc_xprt.c +16 −17
  29. net/sunrpc/svcauth_unix.c +15 −8
  30. net/sunrpc/svcsock.c +162 −12
  31. net/sunrpc/xprtrdma/svc_rdma.c +2 −19
fs/lockd/Makefile+4−2
@@ -3,10 +3,12 @@ · 2 unmodified lines
3# Makefile for the linux lock manager stuff3# Makefile for the linux lock manager stuff
4#4#
5 5
6ccflags-y += -I$(src) # needed for trace events
7
6obj-$(CONFIG_LOCKD) += lockd.o8obj-$(CONFIG_LOCKD) += lockd.o
7 9
8lockd-objs-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \10lockd-objs-y += clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
9 svcshare.o svcproc.o svcsubs.o mon.o xdr.o11 svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o
10lockd-objs-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o12lockd-objs-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
11lockd-objs-$(CONFIG_PROC_FS) += procfs.o13lockd-objs-$(CONFIG_PROC_FS) += procfs.o
12lockd-objs := $(lockd-objs-y)14lockd-objs := $(lockd-objs-y)
fs/lockd/clntlock.c+25−33
@@ -14,9 +14,12 @@ · 13 unmodified lines
14#include <linux/nfs_fs.h>14#include <linux/nfs_fs.h>
15#include <linux/sunrpc/addr.h>15#include <linux/sunrpc/addr.h>
16#include <linux/sunrpc/svc.h>16#include <linux/sunrpc/svc.h>
17#include <linux/sunrpc/svc_xprt.h>
17#include <linux/lockd/lockd.h>18#include <linux/lockd/lockd.h>
18#include <linux/kthread.h>19#include <linux/kthread.h>
19 20
21#include "trace.h"
22
20#define NLMDBG_FACILITY NLMDBG_CLIENT23#define NLMDBG_FACILITY NLMDBG_CLIENT
21 24
22/*25/*
@@ -29,18 +32,6 @@ static int reclaimer(void *ptr); · 6 unmodified lines
29 * client perspective.32 * client perspective.
30 */33 */
31 34
32/*
33 * This is the representation of a blocked client lock.
34 */
35struct 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
44static LIST_HEAD(nlm_blocked);35static LIST_HEAD(nlm_blocked);
45static DEFINE_SPINLOCK(nlm_blocked_lock);36static DEFINE_SPINLOCK(nlm_blocked_lock);
46 37
@@ -94,41 +85,42 @@ void nlmclnt_done(struct nlm_host *host) · 47 unmodified lines
94}85}
95EXPORT_SYMBOL_GPL(nlmclnt_done);86EXPORT_SYMBOL_GPL(nlmclnt_done);
96 87
88void 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
97/*96/*
98 * Queue up a lock for blocking so that the GRANTED request can see it97 * Queue up a lock for blocking so that the GRANTED request can see it
99 */98 */
100struct nlm_wait *nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl)99void nlmclnt_queue_block(struct nlm_wait *block)
101{100{
102 struct nlm_wait *block;101 spin_lock(&nlm_blocked_lock);
103 102 list_add(&block->b_list, &nlm_blocked);
104 block = kmalloc(sizeof(*block), GFP_KERNEL);103 spin_unlock(&nlm_blocked_lock);
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;
116}104}
117 105
118void 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)
119{110{
120 if (block == NULL)111 __be32 status;
121 return;112
122 spin_lock(&nlm_blocked_lock);113 spin_lock(&nlm_blocked_lock);
123 list_del(&block->b_list);114 list_del(&block->b_list);
115 status = block->b_status;
124 spin_unlock(&nlm_blocked_lock);116 spin_unlock(&nlm_blocked_lock);
125 kfree(block);117 return status;
126}118}
127 119
128/*120/*
129 * Block on a lock121 * Block on a lock
130 */122 */
131int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)123int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
132{124{
133 long ret;125 long ret;
134 126
@@ -154,7 +146,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout) · 19 unmodified lines
154 /* Reset the lock status after a server reboot so we resend */146 /* Reset the lock status after a server reboot so we resend */
155 if (block->b_status == nlm_lck_denied_grace_period)147 if (block->b_status == nlm_lck_denied_grace_period)
156 block->b_status = nlm_lck_blocked;148 block->b_status = nlm_lck_blocked;
157 req->a_res.status = block->b_status;
158 return 0;149 return 0;
159}150}
160 151
@@ -198,6 +189,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock) · 37 unmodified lines
198 res = nlm_granted;189 res = nlm_granted;
199 }190 }
200 spin_unlock(&nlm_blocked_lock);191 spin_unlock(&nlm_blocked_lock);
192 trace_nlmclnt_grant(lock, addr, svc_addr_len(addr), res);
201 return res;193 return res;
202}194}
203 195
fs/lockd/clntproc.c+32−10
@@ -20,6 +20,8 @@ · 19 unmodified lines
20#include <linux/sunrpc/svc.h>20#include <linux/sunrpc/svc.h>
21#include <linux/lockd/lockd.h>21#include <linux/lockd/lockd.h>
22 22
23#include "trace.h"
24
23#define NLMDBG_FACILITY NLMDBG_CLIENT25#define NLMDBG_FACILITY NLMDBG_CLIENT
24#define NLMCLNT_GRACE_WAIT (5*HZ)26#define NLMCLNT_GRACE_WAIT (5*HZ)
25#define NLMCLNT_POLL_TIMEOUT (30*HZ)27#define NLMCLNT_POLL_TIMEOUT (30*HZ)
@@ -451,6 +453,9 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) · 425 unmodified lines
451 status = nlm_stat_to_errno(req->a_res.status);453 status = nlm_stat_to_errno(req->a_res.status);
452 }454 }
453out:455out:
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);
454 nlmclnt_release_call(req);459 nlmclnt_release_call(req);
455 return status;460 return status;
456}461}
@@ -516,9 +521,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) · 59 unmodified lines
516 const struct cred *cred = nfs_file_cred(fl->fl_file);521 const struct cred *cred = nfs_file_cred(fl->fl_file);
517 struct nlm_host *host = req->a_host;522 struct nlm_host *host = req->a_host;
518 struct nlm_res *resp = &req->a_res;523 struct nlm_res *resp = &req->a_res;
519 struct nlm_wait *block = NULL;524 struct nlm_wait block;
520 unsigned char fl_flags = fl->fl_flags;525 unsigned char fl_flags = fl->fl_flags;
521 unsigned char fl_type;526 unsigned char fl_type;
527 __be32 b_status;
522 int status = -ENOLCK;528 int status = -ENOLCK;
523 529
524 if (nsm_monitor(host) < 0)530 if (nsm_monitor(host) < 0)
@@ -531,31 +537,41 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) · 6 unmodified lines
531 if (status < 0)537 if (status < 0)
532 goto out;538 goto out;
533 539
534 block = nlmclnt_prepare_block(host, fl);540 nlmclnt_prepare_block(&block, host, fl);
535again:541again:
536 /*542 /*
537 * Initialise resp->status to a valid non-zero value,543 * Initialise resp->status to a valid non-zero value,
538 * since 0 == nlm_lck_granted544 * since 0 == nlm_lck_granted
539 */545 */
540 resp->status = nlm_lck_blocked;546 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 (;;) {
542 /* Reboot protection */555 /* Reboot protection */
543 fl->fl_u.nfs_fl.state = host->h_state;556 fl->fl_u.nfs_fl.state = host->h_state;
544 status = nlmclnt_call(cred, req, NLMPROC_LOCK);557 status = nlmclnt_call(cred, req, NLMPROC_LOCK);
545 if (status < 0)558 if (status < 0)
546 break;559 break;
547 /* Did a reclaimer thread notify us of a server reboot? */560 /* 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)
549 continue;562 continue;
550 if (resp->status != nlm_lck_blocked)563 if (resp->status != nlm_lck_blocked)
551 break;564 break;
552 /* Wait on an NLM blocking lock */565 /* Wait on an NLM blocking lock */
553 status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT);566 status = nlmclnt_wait(&block, req, NLMCLNT_POLL_TIMEOUT);
554 if (status < 0)567 if (status < 0)
555 break;568 break;
556 if (resp->status != nlm_lck_blocked)569 if (block.b_status != nlm_lck_blocked)
557 break;570 break;
558 }571 }
572 b_status = nlmclnt_dequeue_block(&block);
573 if (resp->status == nlm_lck_blocked)
574 resp->status = b_status;
559 575
560 /* if we were interrupted while blocking, then cancel the lock request576 /* if we were interrupted while blocking, then cancel the lock request
561 * and exit577 * and exit
@@ -564,7 +580,7 @@ again: · 2 unmodified lines
564 if (!req->a_args.block)580 if (!req->a_args.block)
565 goto out_unlock;581 goto out_unlock;
566 if (nlmclnt_cancel(host, req->a_args.block, fl) == 0)582 if (nlmclnt_cancel(host, req->a_args.block, fl) == 0)
567 goto out_unblock;583 goto out;
568 }584 }
569 585
570 if (resp->status == nlm_granted) {586 if (resp->status == nlm_granted) {
@@ -593,16 +609,19 @@ again: · 22 unmodified lines
593 status = -ENOLCK;609 status = -ENOLCK;
594 else610 else
595 status = nlm_stat_to_errno(resp->status);611 status = nlm_stat_to_errno(resp->status);
596out_unblock:
597 nlmclnt_finish_block(block);
598out:612out:
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);
599 nlmclnt_release_call(req);616 nlmclnt_release_call(req);
600 return status;617 return status;
601out_unlock:618out_unlock:
602 /* Fatal error: ensure that we remove the lock altogether */619 /* 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);
603 dprintk("lockd: lock attempt ended in fatal error.\n"623 dprintk("lockd: lock attempt ended in fatal error.\n"
604 " Attempting to unlock.\n");624 " Attempting to unlock.\n");
605 nlmclnt_finish_block(block);
606 fl_type = fl->fl_type;625 fl_type = fl->fl_type;
607 fl->fl_type = F_UNLCK;626 fl->fl_type = F_UNLCK;
608 down_read(&host->h_rwsem);627 down_read(&host->h_rwsem);
@@ -696,6 +715,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) · 87 unmodified lines
696 /* What to do now? I'm out of my depth... */715 /* What to do now? I'm out of my depth... */
697 status = -ENOLCK;716 status = -ENOLCK;
698out:717out:
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);
699 nlmclnt_release_call(req);721 nlmclnt_release_call(req);
700 return status;722 return status;
701}723}
fs/lockd/host.c+1−0
@@ -629,6 +629,7 @@ nlm_shutdown_hosts_net(struct net *net) · 628 unmodified lines
629 rpc_shutdown_client(host->h_rpcclnt);629 rpc_shutdown_client(host->h_rpcclnt);
630 host->h_rpcclnt = NULL;630 host->h_rpcclnt = NULL;
631 }631 }
632 nlmsvc_free_host_resources(host);
632 }633 }
633 634
634 /* Then, perform a garbage collection pass */635 /* Then, perform a garbage collection pass */
fs/lockd/svclock.c+17−4
@@ -954,19 +954,32 @@ void · 953 unmodified lines
954nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)954nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
955{955{
956 struct nlm_block *block;956 struct nlm_block *block;
957 struct file_lock *fl;
958 int error;
957 959
958 dprintk("grant_reply: looking for cookie %x, s=%d \n",960 dprintk("grant_reply: looking for cookie %x, s=%d \n",
959 *(unsigned int *)(cookie->data), status);961 *(unsigned int *)(cookie->data), status);
960 if (!(block = nlmsvc_find_block(cookie)))962 if (!(block = nlmsvc_find_block(cookie)))
961 return;963 return;
962 964
963 if (status == nlm_lck_denied_grace_period) {965 switch (status) {
966 case nlm_lck_denied_grace_period:
964 /* Try again in a couple of seconds */967 /* Try again in a couple of seconds */
965 nlmsvc_insert_block(block, 10 * HZ);968 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:
967 /*980 /*
968 * Lock is now held by client, or has been rejected.981 * Either it was accepted or the status makes no sense
969 * In both cases, the block should be removed.982 * just unlink it either way.
970 */983 */
971 nlmsvc_unlink_block(block);984 nlmsvc_unlink_block(block);
972 }985 }
fs/lockd/trace.c+3−0
@@ -0,0 +1,3 @@
1// SPDX-License-Identifier: GPL-2.0
2#define CREATE_TRACE_POINTS
3#include "trace.h"
fs/lockd/trace.h+106−0
@@ -0,0 +1,106 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#undef TRACE_SYSTEM
3#define TRACE_SYSTEM lockd
4
5#if !defined(_TRACE_LOCKD_H) || defined(TRACE_HEADER_MULTI_READ)
6#define _TRACE_LOCKD_H
7
8#include <linux/tracepoint.h>
9#include <linux/crc32.h>
10#include <linux/nfs.h>
11#include <linux/lockd/lockd.h>
12
13#ifdef CONFIG_LOCKD_V4
14#define NLM_STATUS_LIST \
15 nlm_status_code(LCK_GRANTED) \
16 nlm_status_code(LCK_DENIED) \
17 nlm_status_code(LCK_DENIED_NOLOCKS) \
18 nlm_status_code(LCK_BLOCKED) \
19 nlm_status_code(LCK_DENIED_GRACE_PERIOD) \
20 nlm_status_code(DEADLCK) \
21 nlm_status_code(ROFS) \
22 nlm_status_code(STALE_FH) \
23 nlm_status_code(FBIG) \
24 nlm_status_code_end(FAILED)
25#else
26#define NLM_STATUS_LIST \
27 nlm_status_code(LCK_GRANTED) \
28 nlm_status_code(LCK_DENIED) \
29 nlm_status_code(LCK_DENIED_NOLOCKS) \
30 nlm_status_code(LCK_BLOCKED) \
31 nlm_status_code_end(LCK_DENIED_GRACE_PERIOD)
32#endif
33
34#undef nlm_status_code
35#undef nlm_status_code_end
36#define nlm_status_code(x) TRACE_DEFINE_ENUM(NLM_##x);
37#define nlm_status_code_end(x) TRACE_DEFINE_ENUM(NLM_##x);
38
39NLM_STATUS_LIST
40
41#undef nlm_status_code
42#undef nlm_status_code_end
43#define nlm_status_code(x) { NLM_##x, #x },
44#define nlm_status_code_end(x) { NLM_##x, #x }
45
46#define show_nlm_status(x) __print_symbolic(x, NLM_STATUS_LIST)
47
48DECLARE_EVENT_CLASS(nlmclnt_lock_event,
49 TP_PROTO(
50 const struct nlm_lock *lock,
51 const struct sockaddr *addr,
52 unsigned int addrlen,
53 __be32 status
54 ),
55
56 TP_ARGS(lock, addr, addrlen, status),
57
58 TP_STRUCT__entry(
59 __field(u32, oh)
60 __field(u32, svid)
61 __field(u32, fh)
62 __field(unsigned long, status)
63 __field(u64, start)
64 __field(u64, len)
65 __sockaddr(addr, addrlen)
66 ),
67
68 TP_fast_assign(
69 __entry->oh = ~crc32_le(0xffffffff, lock->oh.data, lock->oh.len);
70 __entry->svid = lock->svid;
71 __entry->fh = nfs_fhandle_hash(&lock->fh);
72 __entry->start = lock->lock_start;
73 __entry->len = lock->lock_len;
74 __entry->status = be32_to_cpu(status);
75 __assign_sockaddr(addr, addr, addrlen);
76 ),
77
78 TP_printk(
79 "addr=%pISpc oh=0x%08x svid=0x%08x fh=0x%08x start=%llu len=%llu status=%s",
80 __get_sockaddr(addr), __entry->oh, __entry->svid,
81 __entry->fh, __entry->start, __entry->len,
82 show_nlm_status(__entry->status)
83 )
84);
85
86#define DEFINE_NLMCLNT_EVENT(name) \
87 DEFINE_EVENT(nlmclnt_lock_event, name, \
88 TP_PROTO( \
89 const struct nlm_lock *lock, \
90 const struct sockaddr *addr, \
91 unsigned int addrlen, \
92 __be32 status \
93 ), \
94 TP_ARGS(lock, addr, addrlen, status))
95
96DEFINE_NLMCLNT_EVENT(nlmclnt_test);
97DEFINE_NLMCLNT_EVENT(nlmclnt_lock);
98DEFINE_NLMCLNT_EVENT(nlmclnt_unlock);
99DEFINE_NLMCLNT_EVENT(nlmclnt_grant);
100
101#endif /* _TRACE_LOCKD_H */
102
103#undef TRACE_INCLUDE_PATH
104#define TRACE_INCLUDE_PATH .
105#define TRACE_INCLUDE_FILE trace
106#include <trace/define_trace.h>
fs/nfs/export.c+6−3
@@ -149,7 +149,10 @@ const struct export_operations nfs_export_ops = { · 148 unmodified lines
149 .encode_fh = nfs_encode_fh,149 .encode_fh = nfs_encode_fh,
150 .fh_to_dentry = nfs_fh_to_dentry,150 .fh_to_dentry = nfs_fh_to_dentry,
151 .get_parent = nfs_get_parent,151 .get_parent = nfs_get_parent,
152 .flags = EXPORT_OP_NOWCC|EXPORT_OP_NOSUBTREECHK|152 .flags = EXPORT_OP_NOWCC |
153 EXPORT_OP_CLOSE_BEFORE_UNLINK|EXPORT_OP_REMOTE_FS|153 EXPORT_OP_NOSUBTREECHK |
154 EXPORT_OP_NOATOMIC_ATTR,154 EXPORT_OP_CLOSE_BEFORE_UNLINK |
155 EXPORT_OP_REMOTE_FS |
156 EXPORT_OP_NOATOMIC_ATTR |
157 EXPORT_OP_FLUSH_ON_CLOSE,
155};158};
fs/nfs/internal.h+0−15
@@ -855,27 +855,12 @@ u64 nfs_timespec_to_change_attr(const struct timespec64 *ts) · 854 unmodified lines
855}855}
856 856
857#ifdef CONFIG_CRC32857#ifdef CONFIG_CRC32
858/**
859 * nfs_fhandle_hash - calculate the crc32 hash for the filehandle
860 * @fh - pointer to filehandle
861 *
862 * returns a crc32 hash for the filehandle that is compatible with
863 * the one displayed by "wireshark".
864 */
865static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
866{
867 return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size);
868}
869static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid)858static inline u32 nfs_stateid_hash(const nfs4_stateid *stateid)
870{859{
871 return ~crc32_le(0xFFFFFFFF, &stateid->other[0],860 return ~crc32_le(0xFFFFFFFF, &stateid->other[0],
872 NFS4_STATEID_OTHER_SIZE);861 NFS4_STATEID_OTHER_SIZE);
873}862}
874#else863#else
875static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
876{
877 return 0;
878}
879static inline u32 nfs_stateid_hash(nfs4_stateid *stateid)864static inline u32 nfs_stateid_hash(nfs4_stateid *stateid)
880{865{
881 return 0;866 return 0;
fs/nfsd/export.c+54−10
@@ -123,11 +123,11 @@ static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen) · 122 unmodified lines
123 123
124 /* OK, we seem to have a valid key */124 /* OK, we seem to have a valid key */
125 key.h.flags = 0;125 key.h.flags = 0;
126 key.h.expiry_time = get_expiry(&mesg);126 err = get_expiry(&mesg, &key.h.expiry_time);
127 if (key.h.expiry_time == 0)127 if (err)
128 goto out;128 goto out;
129 129
130 key.ek_client = dom; 130 key.ek_client = dom;
131 key.ek_fsidtype = fsidtype;131 key.ek_fsidtype = fsidtype;
132 memcpy(key.ek_fsid, buf, len);132 memcpy(key.ek_fsid, buf, len);
133 133
@@ -439,7 +439,6 @@ static int check_export(struct path *path, int *flags, unsigned char *uuid) · 305 unmodified lines
439 return -EINVAL;439 return -EINVAL;
440 }440 }
441 return 0;441 return 0;
442
443}442}
444 443
445#ifdef CONFIG_NFSD_V4444#ifdef CONFIG_NFSD_V4
@@ -546,6 +545,29 @@ static inline int · 100 unmodified lines
546secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }545secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
547#endif546#endif
548 547
548static int xprtsec_parse(char **mesg, char *buf, struct svc_export *exp)
549{
550 unsigned int i, mode, listsize;
551 int err;
552
553 err = get_uint(mesg, &listsize);
554 if (err)
555 return err;
556 if (listsize > NFSEXP_XPRTSEC_NUM)
557 return -EINVAL;
558
559 exp->ex_xprtsec_modes = 0;
560 for (i = 0; i < listsize; i++) {
561 err = get_uint(mesg, &mode);
562 if (err)
563 return err;
564 if (mode > NFSEXP_XPRTSEC_MTLS)
565 return -EINVAL;
566 exp->ex_xprtsec_modes |= mode;
567 }
568 return 0;
569}
570
549static inline int571static inline int
550nfsd_uuid_parse(char **mesg, char *buf, unsigned char **puuid)572nfsd_uuid_parse(char **mesg, char *buf, unsigned char **puuid)
551{573{
@@ -608,11 +630,11 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) · 56 unmodified lines
608 exp.ex_client = dom;630 exp.ex_client = dom;
609 exp.cd = cd;631 exp.cd = cd;
610 exp.ex_devid_map = NULL;632 exp.ex_devid_map = NULL;
633 exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL;
611 634
612 /* expiry */635 /* expiry */
613 err = -EINVAL;636 err = get_expiry(&mesg, &exp.h.expiry_time);
614 exp.h.expiry_time = get_expiry(&mesg);637 if (err)
615 if (exp.h.expiry_time == 0)
616 goto out3;638 goto out3;
617 639
618 /* flags */640 /* flags */
@@ -624,7 +646,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) · 5 unmodified lines
624 if (err || an_int < 0)646 if (err || an_int < 0)
625 goto out3;647 goto out3;
626 exp.ex_flags= an_int;648 exp.ex_flags= an_int;
627 649
628 /* anon uid */650 /* anon uid */
629 err = get_int(&mesg, &an_int);651 err = get_int(&mesg, &an_int);
630 if (err)652 if (err)
@@ -650,6 +672,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) · 19 unmodified lines
650 err = nfsd_uuid_parse(&mesg, buf, &exp.ex_uuid);672 err = nfsd_uuid_parse(&mesg, buf, &exp.ex_uuid);
651 else if (strcmp(buf, "secinfo") == 0)673 else if (strcmp(buf, "secinfo") == 0)
652 err = secinfo_parse(&mesg, buf, &exp);674 err = secinfo_parse(&mesg, buf, &exp);
675 else if (strcmp(buf, "xprtsec") == 0)
676 err = xprtsec_parse(&mesg, buf, &exp);
653 else677 else
654 /* quietly ignore unknown words and anything678 /* quietly ignore unknown words and anything
655 * following. Newer user-space can try to set679 * following. Newer user-space can try to set
@@ -663,6 +687,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) · 7 unmodified lines
663 err = check_export(&exp.ex_path, &exp.ex_flags, exp.ex_uuid);687 err = check_export(&exp.ex_path, &exp.ex_flags, exp.ex_uuid);
664 if (err)688 if (err)
665 goto out4;689 goto out4;
690
666 /*691 /*
667 * No point caching this if it would immediately expire.692 * No point caching this if it would immediately expire.
668 * Also, this protects exportfs's dummy export from the693 * Also, this protects exportfs's dummy export from the
@@ -824,6 +849,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem) · 155 unmodified lines
824 for (i = 0; i < MAX_SECINFO_LIST; i++) {849 for (i = 0; i < MAX_SECINFO_LIST; i++) {
825 new->ex_flavors[i] = item->ex_flavors[i];850 new->ex_flavors[i] = item->ex_flavors[i];
826 }851 }
852 new->ex_xprtsec_modes = item->ex_xprtsec_modes;
827}853}
828 854
829static struct cache_head *svc_export_alloc(void)855static struct cache_head *svc_export_alloc(void)
@@ -1035,9 +1061,26 @@ static struct svc_export *exp_find(struct cache_detail *cd, · 205 unmodified lines
1035 1061
1036__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)1062__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
1037{1063{
1038 struct exp_flavor_info *f;1064 struct exp_flavor_info *f, *end = exp->ex_flavors + exp->ex_nflavors;
1039 struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;1065 struct svc_xprt *xprt = rqstp->rq_xprt;
1066
1067 if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_NONE) {
1068 if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags))
1069 goto ok;
1070 }
1071 if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_TLS) {
1072 if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
1073 !test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
1074 goto ok;
1075 }
1076 if (exp->ex_xprtsec_modes & NFSEXP_XPRTSEC_MTLS) {
1077 if (test_bit(XPT_TLS_SESSION, &xprt->xpt_flags) &&
1078 test_bit(XPT_PEER_AUTH, &xprt->xpt_flags))
1079 goto ok;
1080 }
1081 goto denied;
1040 1082
1083ok:
1041 /* legacy gss-only clients are always OK: */1084 /* legacy gss-only clients are always OK: */
1042 if (exp->ex_client == rqstp->rq_gssclient)1085 if (exp->ex_client == rqstp->rq_gssclient)
1043 return 0;1086 return 0;
@@ -1062,6 +1105,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) · 18 unmodified lines
1062 if (nfsd4_spo_must_allow(rqstp))1105 if (nfsd4_spo_must_allow(rqstp))
1063 return 0;1106 return 0;
1064 1107
1108denied:
1065 return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;1109 return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
1066}1110}
1067 1111
fs/nfsd/export.h+1−0
@@ -77,6 +77,7 @@ struct svc_export { · 76 unmodified lines
77 struct cache_detail *cd;77 struct cache_detail *cd;
78 struct rcu_head ex_rcu;78 struct rcu_head ex_rcu;
79 struct export_stats ex_stats;79 struct export_stats ex_stats;
80 unsigned long ex_xprtsec_modes;
80};81};
81 82
82/* an "export key" (expkey) maps a filehandlefragement to an83/* an "export key" (expkey) maps a filehandlefragement to an
fs/nfsd/filecache.c+185−245
@@ -74,70 +74,9 @@ static struct list_lru nfsd_file_lru; · 73 unmodified lines
74static unsigned long nfsd_file_flags;74static unsigned long nfsd_file_flags;
75static struct fsnotify_group *nfsd_file_fsnotify_group;75static struct fsnotify_group *nfsd_file_fsnotify_group;
76static struct delayed_work nfsd_filecache_laundrette;76static struct delayed_work nfsd_filecache_laundrette;
77static struct rhashtable nfsd_file_rhash_tbl77static struct rhltable nfsd_file_rhltable
78 ____cacheline_aligned_in_smp;78 ____cacheline_aligned_in_smp;
79 79
80enum nfsd_file_lookup_type {
81 NFSD_FILE_KEY_INODE,
82 NFSD_FILE_KEY_FULL,
83};
84
85struct nfsd_file_lookup_key {
86 struct inode *inode;
87 struct net *net;
88 const struct cred *cred;
89 unsigned char need;
90 bool gc;
91 enum nfsd_file_lookup_type type;
92};
93
94/*
95 * The returned hash value is based solely on the address of an in-code
96 * inode, a pointer to a slab-allocated object. The entropy in such a
97 * pointer is concentrated in its middle bits.
98 */
99static u32 nfsd_file_inode_hash(const struct inode *inode, u32 seed)
100{
101 unsigned long ptr = (unsigned long)inode;
102 u32 k;
103
104 k = ptr >> L1_CACHE_SHIFT;
105 k &= 0x00ffffff;
106 return jhash2(&k, 1, seed);
107}
108
109/**
110 * nfsd_file_key_hashfn - Compute the hash value of a lookup key
111 * @data: key on which to compute the hash value
112 * @len: rhash table's key_len parameter (unused)
113 * @seed: rhash table's random seed of the day
114 *
115 * Return value:
116 * Computed 32-bit hash value
117 */
118static u32 nfsd_file_key_hashfn(const void *data, u32 len, u32 seed)
119{
120 const struct nfsd_file_lookup_key *key = data;
121
122 return nfsd_file_inode_hash(key->inode, seed);
123}
124
125/**
126 * nfsd_file_obj_hashfn - Compute the hash value of an nfsd_file
127 * @data: object on which to compute the hash value
128 * @len: rhash table's key_len parameter (unused)
129 * @seed: rhash table's random seed of the day
130 *
131 * Return value:
132 * Computed 32-bit hash value
133 */
134static u32 nfsd_file_obj_hashfn(const void *data, u32 len, u32 seed)
135{
136 const struct nfsd_file *nf = data;
137
138 return nfsd_file_inode_hash(nf->nf_inode, seed);
139}
140
141static bool80static bool
142nfsd_match_cred(const struct cred *c1, const struct cred *c2)81nfsd_match_cred(const struct cred *c1, const struct cred *c2)
143{82{
@@ -158,53 +97,16 @@ nfsd_match_cred(const struct cred *c1, const struct cred *c2) · 14 unmodified lines
158 return true;97 return true;
159}98}
160 99
161/**
162 * nfsd_file_obj_cmpfn - Match a cache item against search criteria
163 * @arg: search criteria
164 * @ptr: cache item to check
165 *
166 * Return values:
167 * %0 - Item matches search criteria
168 * %1 - Item does not match search criteria
169 */
170static int nfsd_file_obj_cmpfn(struct rhashtable_compare_arg *arg,
171 const void *ptr)
172{
173 const struct nfsd_file_lookup_key *key = arg->key;
174 const struct nfsd_file *nf = ptr;
175
176 switch (key->type) {
177 case NFSD_FILE_KEY_INODE:
178 if (nf->nf_inode != key->inode)
179 return 1;
180 break;
181 case NFSD_FILE_KEY_FULL:
182 if (nf->nf_inode != key->inode)
183 return 1;
184 if (nf->nf_may != key->need)
185 return 1;
186 if (nf->nf_net != key->net)
187 return 1;
188 if (!nfsd_match_cred(nf->nf_cred, key->cred))
189 return 1;
190 if (!!test_bit(NFSD_FILE_GC, &nf->nf_flags) != key->gc)
191 return 1;
192 if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
193 return 1;
194 break;
195 }
196 return 0;
197}
198
199static const struct rhashtable_params nfsd_file_rhash_params = {100static const struct rhashtable_params nfsd_file_rhash_params = {
200 .key_len = sizeof_field(struct nfsd_file, nf_inode),101 .key_len = sizeof_field(struct nfsd_file, nf_inode),
201 .key_offset = offsetof(struct nfsd_file, nf_inode),102 .key_offset = offsetof(struct nfsd_file, nf_inode),
202 .head_offset = offsetof(struct nfsd_file, nf_rhash),103 .head_offset = offsetof(struct nfsd_file, nf_rlist),
203 .hashfn = nfsd_file_key_hashfn,104
204 .obj_hashfn = nfsd_file_obj_hashfn,105 /*
205 .obj_cmpfn = nfsd_file_obj_cmpfn,106 * Start with a single page hash table to reduce resizing churn
206 /* Reduce resizing churn on light workloads */107 * on light workloads.
207 .min_size = 512, /* buckets */108 */
109 .min_size = 256,
208 .automatic_shrinking = true,110 .automatic_shrinking = true,
209};111};
210 112
@@ -307,27 +209,27 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode) · 96 unmodified lines
307}209}
308 210
309static struct nfsd_file *211static struct nfsd_file *
310nfsd_file_alloc(struct nfsd_file_lookup_key *key, unsigned int may)212nfsd_file_alloc(struct net *net, struct inode *inode, unsigned char need,
213 bool want_gc)
311{214{
312 struct nfsd_file *nf;215 struct nfsd_file *nf;
313 216
314 nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);217 nf = kmem_cache_alloc(nfsd_file_slab, GFP_KERNEL);
315 if (nf) {218 if (unlikely(!nf))
316 INIT_LIST_HEAD(&nf->nf_lru);219 return NULL;
317 nf->nf_birthtime = ktime_get();220
318 nf->nf_file = NULL;221 INIT_LIST_HEAD(&nf->nf_lru);
319 nf->nf_cred = get_current_cred();222 nf->nf_birthtime = ktime_get();
320 nf->nf_net = key->net;223 nf->nf_file = NULL;
321 nf->nf_flags = 0;224 nf->nf_cred = get_current_cred();
322 __set_bit(NFSD_FILE_HASHED, &nf->nf_flags);225 nf->nf_net = net;
323 __set_bit(NFSD_FILE_PENDING, &nf->nf_flags);226 nf->nf_flags = want_gc ?
324 if (key->gc)227 BIT(NFSD_FILE_HASHED) | BIT(NFSD_FILE_PENDING) | BIT(NFSD_FILE_GC) :
325 __set_bit(NFSD_FILE_GC, &nf->nf_flags);228 BIT(NFSD_FILE_HASHED) | BIT(NFSD_FILE_PENDING);
326 nf->nf_inode = key->inode;229 nf->nf_inode = inode;
327 refcount_set(&nf->nf_ref, 1);230 refcount_set(&nf->nf_ref, 1);
328 nf->nf_may = key->need;231 nf->nf_may = need;
329 nf->nf_mark = NULL;232 nf->nf_mark = NULL;
330 }
331 return nf;233 return nf;
332}234}
333 235
@@ -352,8 +254,8 @@ static void · 18 unmodified lines
352nfsd_file_hash_remove(struct nfsd_file *nf)254nfsd_file_hash_remove(struct nfsd_file *nf)
353{255{
354 trace_nfsd_file_unhash(nf);256 trace_nfsd_file_unhash(nf);
355 rhashtable_remove_fast(&nfsd_file_rhash_tbl, &nf->nf_rhash,257 rhltable_remove(&nfsd_file_rhltable, &nf->nf_rlist,
356 nfsd_file_rhash_params);258 nfsd_file_rhash_params);
357}259}
358 260
359static bool261static bool
@@ -380,10 +282,8 @@ nfsd_file_free(struct nfsd_file *nf) · 20 unmodified lines
380 if (nf->nf_mark)282 if (nf->nf_mark)
381 nfsd_file_mark_put(nf->nf_mark);283 nfsd_file_mark_put(nf->nf_mark);
382 if (nf->nf_file) {284 if (nf->nf_file) {
383 get_file(nf->nf_file);
384 filp_close(nf->nf_file, NULL);
385 nfsd_file_check_write_error(nf);285 nfsd_file_check_write_error(nf);
386 fput(nf->nf_file);286 filp_close(nf->nf_file, NULL);
387 }287 }
388 288
389 /*289 /*
@@ -402,13 +302,23 @@ nfsd_file_check_writeback(struct nfsd_file *nf) · 12 unmodified lines
402 struct file *file = nf->nf_file;302 struct file *file = nf->nf_file;
403 struct address_space *mapping;303 struct address_space *mapping;
404 304
405 if (!file || !(file->f_mode & FMODE_WRITE))305 /* File not open for write? */
306 if (!(file->f_mode & FMODE_WRITE))
307 return false;
308
309 /*
310 * Some filesystems (e.g. NFS) flush all dirty data on close.
311 * On others, there is no need to wait for writeback.
312 */
313 if (!(file_inode(file)->i_sb->s_export_op->flags & EXPORT_OP_FLUSH_ON_CLOSE))
406 return false;314 return false;
315
407 mapping = file->f_mapping;316 mapping = file->f_mapping;
408 return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) ||317 return mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) ||
409 mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);318 mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
410}319}
411 320
321
412static bool nfsd_file_lru_add(struct nfsd_file *nf)322static bool nfsd_file_lru_add(struct nfsd_file *nf)
413{323{
414 set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);324 set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
@@ -492,49 +402,26 @@ nfsd_file_dispose_list(struct list_head *dispose) · 77 unmodified lines
492 }402 }
493}403}
494 404
495static void405/**
496nfsd_file_list_remove_disposal(struct list_head *dst,406 * nfsd_file_dispose_list_delayed - move list of dead files to net's freeme list
497 struct nfsd_fcache_disposal *l)407 * @dispose: list of nfsd_files to be disposed
498{408 *
499 spin_lock(&l->lock);409 * Transfers each file to the "freeme" list for its nfsd_net, to eventually
500 list_splice_init(&l->freeme, dst);410 * be disposed of by the per-net garbage collector.
501 spin_unlock(&l->lock);411 */
502}
503
504static void
505nfsd_file_list_add_disposal(struct list_head *files, struct net *net)
506{
507 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
508 struct nfsd_fcache_disposal *l = nn->fcache_disposal;
509
510 spin_lock(&l->lock);
511 list_splice_tail_init(files, &l->freeme);
512 spin_unlock(&l->lock);
513 queue_work(nfsd_filecache_wq, &l->work);
514}
515
516static void
517nfsd_file_list_add_pernet(struct list_head *dst, struct list_head *src,
518 struct net *net)
519{
520 struct nfsd_file *nf, *tmp;
521
522 list_for_each_entry_safe(nf, tmp, src, nf_lru) {
523 if (nf->nf_net == net)
524 list_move_tail(&nf->nf_lru, dst);
525 }
526}
527
528static void412static void
529nfsd_file_dispose_list_delayed(struct list_head *dispose)413nfsd_file_dispose_list_delayed(struct list_head *dispose)
530{414{
531 LIST_HEAD(list);
532 struct nfsd_file *nf;
533
534 while(!list_empty(dispose)) {415 while(!list_empty(dispose)) {
535 nf = list_first_entry(dispose, struct nfsd_file, nf_lru);416 struct nfsd_file *nf = list_first_entry(dispose,
536 nfsd_file_list_add_pernet(&list, dispose, nf->nf_net);417 struct nfsd_file, nf_lru);
537 nfsd_file_list_add_disposal(&list, nf->nf_net);418 struct nfsd_net *nn = net_generic(nf->nf_net, nfsd_net_id);
419 struct nfsd_fcache_disposal *l = nn->fcache_disposal;
420
421 spin_lock(&l->lock);
422 list_move_tail(&nf->nf_lru, &l->freeme);
423 spin_unlock(&l->lock);
424 queue_work(nfsd_filecache_wq, &l->work);
538 }425 }
539}426}
540 427
@@ -678,8 +565,8 @@ nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose) · 137 unmodified lines
678 * @inode: inode on which to close out nfsd_files565 * @inode: inode on which to close out nfsd_files
679 * @dispose: list on which to gather nfsd_files to close out566 * @dispose: list on which to gather nfsd_files to close out
680 *567 *
681 * An nfsd_file represents a struct file being held open on behalf of nfsd. An568 * An nfsd_file represents a struct file being held open on behalf of nfsd.
682 * open file however can block other activity (such as leases), or cause569 * An open file however can block other activity (such as leases), or cause
683 * undesirable behavior (e.g. spurious silly-renames when reexporting NFS).570 * undesirable behavior (e.g. spurious silly-renames when reexporting NFS).
684 *571 *
685 * This function is intended to find open nfsd_files when this sort of572 * This function is intended to find open nfsd_files when this sort of
@@ -692,20 +579,17 @@ nfsd_file_cond_queue(struct nfsd_file *nf, struct list_head *dispose) · 6 unmodified lines
692static void579static void
693nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)580nfsd_file_queue_for_close(struct inode *inode, struct list_head *dispose)
694{581{
695 struct nfsd_file_lookup_key key = {582 struct rhlist_head *tmp, *list;
696 .type = NFSD_FILE_KEY_INODE,
697 .inode = inode,
698 };
699 struct nfsd_file *nf;583 struct nfsd_file *nf;
700 584
701 rcu_read_lock();585 rcu_read_lock();
702 do {586 list = rhltable_lookup(&nfsd_file_rhltable, &inode,
703 nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,587 nfsd_file_rhash_params);
704 nfsd_file_rhash_params);588 rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) {
705 if (!nf)589 if (!test_bit(NFSD_FILE_GC, &nf->nf_flags))
706 break;590 continue;
707 nfsd_file_cond_queue(nf, dispose);591 nfsd_file_cond_queue(nf, dispose);
708 } while (1);592 }
709 rcu_read_unlock();593 rcu_read_unlock();
710}594}
711 595
@@ -758,8 +642,8 @@ nfsd_file_close_inode_sync(struct inode *inode) · 46 unmodified lines
758 * nfsd_file_delayed_close - close unused nfsd_files642 * nfsd_file_delayed_close - close unused nfsd_files
759 * @work: dummy643 * @work: dummy
760 *644 *
761 * Walk the LRU list and destroy any entries that have not been used since645 * Scrape the freeme list for this nfsd_net, and then dispose of them
762 * the last scan.646 * all.
763 */647 */
764static void648static void
765nfsd_file_delayed_close(struct work_struct *work)649nfsd_file_delayed_close(struct work_struct *work)
@@ -768,7 +652,10 @@ nfsd_file_delayed_close(struct work_struct *work) · 2 unmodified lines
768 struct nfsd_fcache_disposal *l = container_of(work,652 struct nfsd_fcache_disposal *l = container_of(work,
769 struct nfsd_fcache_disposal, work);653 struct nfsd_fcache_disposal, work);
770 654
771 nfsd_file_list_remove_disposal(&head, l);655 spin_lock(&l->lock);
656 list_splice_init(&l->freeme, &head);
657 spin_unlock(&l->lock);
658
772 nfsd_file_dispose_list(&head);659 nfsd_file_dispose_list(&head);
773}660}
774 661
@@ -829,7 +716,7 @@ nfsd_file_cache_init(void) · 54 unmodified lines
829 if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)716 if (test_and_set_bit(NFSD_FILE_CACHE_UP, &nfsd_file_flags) == 1)
830 return 0;717 return 0;
831 718
832 ret = rhashtable_init(&nfsd_file_rhash_tbl, &nfsd_file_rhash_params);719 ret = rhltable_init(&nfsd_file_rhltable, &nfsd_file_rhash_params);
833 if (ret)720 if (ret)
834 return ret;721 return ret;
835 722
@@ -897,7 +784,7 @@ out_err: · 61 unmodified lines
897 nfsd_file_mark_slab = NULL;784 nfsd_file_mark_slab = NULL;
898 destroy_workqueue(nfsd_filecache_wq);785 destroy_workqueue(nfsd_filecache_wq);
899 nfsd_filecache_wq = NULL;786 nfsd_filecache_wq = NULL;
900 rhashtable_destroy(&nfsd_file_rhash_tbl);787 rhltable_destroy(&nfsd_file_rhltable);
901 goto out;788 goto out;
902}789}
903 790
@@ -906,7 +793,8 @@ out_err: · 2 unmodified lines
906 * @net: net-namespace to shut down the cache (may be NULL)793 * @net: net-namespace to shut down the cache (may be NULL)
907 *794 *
908 * Walk the nfsd_file cache and close out any that match @net. If @net is NULL,795 * Walk the nfsd_file cache and close out any that match @net. If @net is NULL,
909 * then close out everything. Called when an nfsd instance is being shut down.796 * then close out everything. Called when an nfsd instance is being shut down,
797 * and when the exports table is flushed.
910 */798 */
911static void799static void
912__nfsd_file_cache_purge(struct net *net)800__nfsd_file_cache_purge(struct net *net)
@@ -915,7 +803,7 @@ __nfsd_file_cache_purge(struct net *net) · 2 unmodified lines
915 struct nfsd_file *nf;803 struct nfsd_file *nf;
916 LIST_HEAD(dispose);804 LIST_HEAD(dispose);
917 805
918 rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter);806 rhltable_walk_enter(&nfsd_file_rhltable, &iter);
919 do {807 do {
920 rhashtable_walk_start(&iter);808 rhashtable_walk_start(&iter);
921 809
@@ -1021,7 +909,7 @@ nfsd_file_cache_shutdown(void) · 99 unmodified lines
1021 nfsd_file_mark_slab = NULL;909 nfsd_file_mark_slab = NULL;
1022 destroy_workqueue(nfsd_filecache_wq);910 destroy_workqueue(nfsd_filecache_wq);
1023 nfsd_filecache_wq = NULL;911 nfsd_filecache_wq = NULL;
1024 rhashtable_destroy(&nfsd_file_rhash_tbl);912 rhltable_destroy(&nfsd_file_rhltable);
1025 913
1026 for_each_possible_cpu(i) {914 for_each_possible_cpu(i) {
1027 per_cpu(nfsd_file_cache_hits, i) = 0;915 per_cpu(nfsd_file_cache_hits, i) = 0;
@@ -1032,6 +920,35 @@ nfsd_file_cache_shutdown(void) · 4 unmodified lines
1032 }920 }
1033}921}
1034 922
923static struct nfsd_file *
924nfsd_file_lookup_locked(const struct net *net, const struct cred *cred,
925 struct inode *inode, unsigned char need,
926 bool want_gc)
927{
928 struct rhlist_head *tmp, *list;
929 struct nfsd_file *nf;
930
931 list = rhltable_lookup(&nfsd_file_rhltable, &inode,
932 nfsd_file_rhash_params);
933 rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist) {
934 if (nf->nf_may != need)
935 continue;
936 if (nf->nf_net != net)
937 continue;
938 if (!nfsd_match_cred(nf->nf_cred, cred))
939 continue;
940 if (test_bit(NFSD_FILE_GC, &nf->nf_flags) != want_gc)
941 continue;
942 if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) == 0)
943 continue;
944
945 if (!nfsd_file_get(nf))
946 continue;
947 return nf;
948 }
949 return NULL;
950}
951
1035/**952/**
1036 * nfsd_file_is_cached - are there any cached open files for this inode?953 * nfsd_file_is_cached - are there any cached open files for this inode?
1037 * @inode: inode to check954 * @inode: inode to check
@@ -1046,15 +963,20 @@ nfsd_file_cache_shutdown(void) · 8 unmodified lines
1046bool963bool
1047nfsd_file_is_cached(struct inode *inode)964nfsd_file_is_cached(struct inode *inode)
1048{965{
1049 struct nfsd_file_lookup_key key = {966 struct rhlist_head *tmp, *list;
1050 .type = NFSD_FILE_KEY_INODE,967 struct nfsd_file *nf;
1051 .inode = inode,
1052 };
1053 bool ret = false;968 bool ret = false;
1054 969
1055 if (rhashtable_lookup_fast(&nfsd_file_rhash_tbl, &key,970 rcu_read_lock();
1056 nfsd_file_rhash_params) != NULL)971 list = rhltable_lookup(&nfsd_file_rhltable, &inode,
1057 ret = true;972 nfsd_file_rhash_params);
973 rhl_for_each_entry_rcu(nf, tmp, list, nf_rlist)
974 if (test_bit(NFSD_FILE_GC, &nf->nf_flags)) {
975 ret = true;
976 break;
977 }
978 rcu_read_unlock();
979
1058 trace_nfsd_file_is_cached(inode, (int)ret);980 trace_nfsd_file_is_cached(inode, (int)ret);
1059 return ret;981 return ret;
1060}982}
@@ -1064,14 +986,12 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, · 3 unmodified lines
1064 unsigned int may_flags, struct file *file,986 unsigned int may_flags, struct file *file,
1065 struct nfsd_file **pnf, bool want_gc)987 struct nfsd_file **pnf, bool want_gc)
1066{988{
1067 struct nfsd_file_lookup_key key = {989 unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
1068 .type = NFSD_FILE_KEY_FULL,990 struct net *net = SVC_NET(rqstp);
1069 .need = may_flags & NFSD_FILE_MAY_MASK,991 struct nfsd_file *new, *nf;
1070 .net = SVC_NET(rqstp),992 const struct cred *cred;
1071 .gc = want_gc,
1072 };
1073 bool open_retry = true;993 bool open_retry = true;
1074 struct nfsd_file *nf;994 struct inode *inode;
1075 __be32 status;995 __be32 status;
1076 int ret;996 int ret;
1077 997
@@ -1079,80 +999,88 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, · 1 unmodified line
1079 may_flags|NFSD_MAY_OWNER_OVERRIDE);999 may_flags|NFSD_MAY_OWNER_OVERRIDE);
1080 if (status != nfs_ok)1000 if (status != nfs_ok)
1081 return status;1001 return status;
1082 key.inode = d_inode(fhp->fh_dentry);1002 inode = d_inode(fhp->fh_dentry);
1083 key.cred = get_current_cred();1003 cred = get_current_cred();
1084 1004
1085retry:1005retry:
1086 rcu_read_lock();1006 rcu_read_lock();
1087 nf = rhashtable_lookup(&nfsd_file_rhash_tbl, &key,1007 nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc);
1088 nfsd_file_rhash_params);
1089 nf = nfsd_file_get(nf);
1090 rcu_read_unlock();1008 rcu_read_unlock();
1091 1009
1092 if (nf) {1010 if (nf) {
1011 /*
1012 * If the nf is on the LRU then it holds an extra reference
1013 * that must be put if it's removed. It had better not be
1014 * the last one however, since we should hold another.
1015 */
1093 if (nfsd_file_lru_remove(nf))1016 if (nfsd_file_lru_remove(nf))
1094 WARN_ON_ONCE(refcount_dec_and_test(&nf->nf_ref));1017 WARN_ON_ONCE(refcount_dec_and_test(&nf->nf_ref));
1095 goto wait_for_construction;1018 goto wait_for_construction;
1096 }1019 }
1097 1020
1098 nf = nfsd_file_alloc(&key, may_flags);1021 new = nfsd_file_alloc(net, inode, need, want_gc);
1099 if (!nf) {1022 if (!new) {
1100 status = nfserr_jukebox;1023 status = nfserr_jukebox;
1101 goto out_status;1024 goto out;
1102 }1025 }
1103 1026
1104 ret = rhashtable_lookup_insert_key(&nfsd_file_rhash_tbl,1027 rcu_read_lock();
1105 &key, &nf->nf_rhash,1028 spin_lock(&inode->i_lock);
1106 nfsd_file_rhash_params);1029 nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc);
1030 if (unlikely(nf)) {
1031 spin_unlock(&inode->i_lock);
1032 rcu_read_unlock();
1033 nfsd_file_slab_free(&new->nf_rcu);
1034 goto wait_for_construction;
1035 }
1036 nf = new;
1037 ret = rhltable_insert(&nfsd_file_rhltable, &nf->nf_rlist,
1038 nfsd_file_rhash_params);
1039 spin_unlock(&inode->i_lock);
1040 rcu_read_unlock();
1107 if (likely(ret == 0))1041 if (likely(ret == 0))
1108 goto open_file;1042 goto open_file;
1109 1043
1110 nfsd_file_slab_free(&nf->nf_rcu);
1111 nf = NULL;
1112 if (ret == -EEXIST)1044 if (ret == -EEXIST)
1113 goto retry;1045 goto retry;
1114 trace_nfsd_file_insert_err(rqstp, key.inode, may_flags, ret);1046 trace_nfsd_file_insert_err(rqstp, inode, may_flags, ret);
1115 status = nfserr_jukebox;1047 status = nfserr_jukebox;
1116 goto out_status;1048 goto construction_err;
1117 1049
1118wait_for_construction:1050wait_for_construction:
1119 wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE);1051 wait_on_bit(&nf->nf_flags, NFSD_FILE_PENDING, TASK_UNINTERRUPTIBLE);
1120 1052
1121 /* Did construction of this file fail? */1053 /* Did construction of this file fail? */
1122 if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {1054 if (!test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
1123 trace_nfsd_file_cons_err(rqstp, key.inode, may_flags, nf);1055 trace_nfsd_file_cons_err(rqstp, inode, may_flags, nf);
1124 if (!open_retry) {1056 if (!open_retry) {
1125 status = nfserr_jukebox;1057 status = nfserr_jukebox;
1126 goto out;1058 goto construction_err;
1127 }1059 }
1128 open_retry = false;1060 open_retry = false;
1129 if (refcount_dec_and_test(&nf->nf_ref))
1130 nfsd_file_free(nf);
1131 goto retry;1061 goto retry;
1132 }1062 }
1133
1134 this_cpu_inc(nfsd_file_cache_hits);1063 this_cpu_inc(nfsd_file_cache_hits);
1135 1064
1136 status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));1065 status = nfserrno(nfsd_open_break_lease(file_inode(nf->nf_file), may_flags));
1066 if (status != nfs_ok) {
1067 nfsd_file_put(nf);
1068 nf = NULL;
1069 }
1070
1137out:1071out:
1138 if (status == nfs_ok) {1072 if (status == nfs_ok) {
1139 this_cpu_inc(nfsd_file_acquisitions);1073 this_cpu_inc(nfsd_file_acquisitions);
1140 nfsd_file_check_write_error(nf);1074 nfsd_file_check_write_error(nf);
1141 *pnf = nf;1075 *pnf = nf;
1142 } else {
1143 if (refcount_dec_and_test(&nf->nf_ref))
1144 nfsd_file_free(nf);
1145 nf = NULL;
1146 }1076 }
1147 1077 put_cred(cred);
1148out_status:1078 trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status);
1149 put_cred(key.cred);
1150 trace_nfsd_file_acquire(rqstp, key.inode, may_flags, nf, status);
1151 return status;1079 return status;
1152 1080
1153open_file:1081open_file:
1154 trace_nfsd_file_alloc(nf);1082 trace_nfsd_file_alloc(nf);
1155 nf->nf_mark = nfsd_file_mark_find_or_create(nf, key.inode);1083 nf->nf_mark = nfsd_file_mark_find_or_create(nf, inode);
1156 if (nf->nf_mark) {1084 if (nf->nf_mark) {
1157 if (file) {1085 if (file) {
1158 get_file(file);1086 get_file(file);
@@ -1170,13 +1098,16 @@ open_file: · 11 unmodified lines
1170 * If construction failed, or we raced with a call to unlink()1098 * If construction failed, or we raced with a call to unlink()
1171 * then unhash.1099 * then unhash.
1172 */1100 */
1173 if (status == nfs_ok && key.inode->i_nlink == 0)1101 if (status != nfs_ok || inode->i_nlink == 0)
1174 status = nfserr_jukebox;
1175 if (status != nfs_ok)
1176 nfsd_file_unhash(nf);1102 nfsd_file_unhash(nf);
1177 clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags);1103 clear_and_wake_up_bit(NFSD_FILE_PENDING, &nf->nf_flags);
1178 smp_mb__after_atomic();1104 if (status == nfs_ok)
1179 wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING);1105 goto out;
1106
1107construction_err:
1108 if (refcount_dec_and_test(&nf->nf_ref))
1109 nfsd_file_free(nf);
1110 nf = NULL;
1180 goto out;1111 goto out;
1181}1112}
1182 1113
@@ -1192,8 +1123,11 @@ open_file: · 9 unmodified lines
1192 * seconds after the final nfsd_file_put() in case the caller1123 * seconds after the final nfsd_file_put() in case the caller
1193 * wants to re-use it.1124 * wants to re-use it.
1194 *1125 *
1195 * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in1126 * Return values:
1196 * network byte order is returned.1127 * %nfs_ok - @pnf points to an nfsd_file with its reference
1128 * count boosted.
1129 *
1130 * On error, an nfsstat value in network byte order is returned.
1197 */1131 */
1198__be321132__be32
1199nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,1133nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -1213,8 +1147,11 @@ nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, · 13 unmodified lines
1213 * but not garbage-collected. The object is unhashed after the1147 * but not garbage-collected. The object is unhashed after the
1214 * final nfsd_file_put().1148 * final nfsd_file_put().
1215 *1149 *
1216 * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in1150 * Return values:
1217 * network byte order is returned.1151 * %nfs_ok - @pnf points to an nfsd_file with its reference
1152 * count boosted.
1153 *
1154 * On error, an nfsstat value in network byte order is returned.
1218 */1155 */
1219__be321156__be32
1220nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,1157nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -1235,8 +1172,11 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, · 14 unmodified lines
1235 * and @file is non-NULL, use it to instantiate a new nfsd_file instead of1172 * and @file is non-NULL, use it to instantiate a new nfsd_file instead of
1236 * opening a new one.1173 * opening a new one.
1237 *1174 *
1238 * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in1175 * Return values:
1239 * network byte order is returned.1176 * %nfs_ok - @pnf points to an nfsd_file with its reference
1177 * count boosted.
1178 *
1179 * On error, an nfsstat value in network byte order is returned.
1240 */1180 */
1241__be321181__be32
1242nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,1182nfsd_file_acquire_opened(struct svc_rqst *rqstp, struct svc_fh *fhp,
@@ -1267,7 +1207,7 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v) · 24 unmodified lines
1267 lru = list_lru_count(&nfsd_file_lru);1207 lru = list_lru_count(&nfsd_file_lru);
1268 1208
1269 rcu_read_lock();1209 rcu_read_lock();
1270 ht = &nfsd_file_rhash_tbl;1210 ht = &nfsd_file_rhltable.ht;
1271 count = atomic_read(&ht->nelems);1211 count = atomic_read(&ht->nelems);
1272 tbl = rht_dereference_rcu(ht->tbl, ht);1212 tbl = rht_dereference_rcu(ht->tbl, ht);
1273 buckets = tbl->size;1213 buckets = tbl->size;
@@ -1283,7 +1223,7 @@ int nfsd_file_cache_stats_show(struct seq_file *m, void *v) · 9 unmodified lines
1283 evictions += per_cpu(nfsd_file_evictions, i);1223 evictions += per_cpu(nfsd_file_evictions, i);
1284 }1224 }
1285 1225
1286 seq_printf(m, "total entries: %u\n", count);1226 seq_printf(m, "total inodes: %u\n", count);
1287 seq_printf(m, "hash buckets: %u\n", buckets);1227 seq_printf(m, "hash buckets: %u\n", buckets);
1288 seq_printf(m, "lru entries: %lu\n", lru);1228 seq_printf(m, "lru entries: %lu\n", lru);
1289 seq_printf(m, "cache hits: %lu\n", hits);1229 seq_printf(m, "cache hits: %lu\n", hits);
fs/nfsd/filecache.h+5−4
@@ -29,9 +29,8 @@ struct nfsd_file_mark { · 28 unmodified lines
29 * never be dereferenced, only used for comparison.29 * never be dereferenced, only used for comparison.
30 */30 */
31struct nfsd_file {31struct nfsd_file {
32 struct rhash_head nf_rhash;32 struct rhlist_head nf_rlist;
33 struct list_head nf_lru;33 void *nf_inode;
34 struct rcu_head nf_rcu;
35 struct file *nf_file;34 struct file *nf_file;
36 const struct cred *nf_cred;35 const struct cred *nf_cred;
37 struct net *nf_net;36 struct net *nf_net;
@@ -40,10 +39,12 @@ struct nfsd_file { · 2 unmodified lines
40#define NFSD_FILE_REFERENCED (2)39#define NFSD_FILE_REFERENCED (2)
41#define NFSD_FILE_GC (3)40#define NFSD_FILE_GC (3)
42 unsigned long nf_flags;41 unsigned long nf_flags;
43 struct inode *nf_inode; /* don't deref */
44 refcount_t nf_ref;42 refcount_t nf_ref;
45 unsigned char nf_may;43 unsigned char nf_may;
44
46 struct nfsd_file_mark *nf_mark;45 struct nfsd_file_mark *nf_mark;
46 struct list_head nf_lru;
47 struct rcu_head nf_rcu;
47 ktime_t nf_birthtime;48 ktime_t nf_birthtime;
48};49};
49 50
fs/nfsd/nfs4idmap.c+4−4
@@ -240,8 +240,8 @@ idtoname_parse(struct cache_detail *cd, char *buf, int buflen) · 239 unmodified lines
240 goto out;240 goto out;
241 241
242 /* expiry */242 /* expiry */
243 ent.h.expiry_time = get_expiry(&buf);243 error = get_expiry(&buf, &ent.h.expiry_time);
244 if (ent.h.expiry_time == 0)244 if (error)
245 goto out;245 goto out;
246 246
247 error = -ENOMEM;247 error = -ENOMEM;
@@ -408,8 +408,8 @@ nametoid_parse(struct cache_detail *cd, char *buf, int buflen) · 160 unmodified lines
408 memcpy(ent.name, buf1, sizeof(ent.name));408 memcpy(ent.name, buf1, sizeof(ent.name));
409 409
410 /* expiry */410 /* expiry */
411 ent.h.expiry_time = get_expiry(&buf);411 error = get_expiry(&buf, &ent.h.expiry_time);
412 if (ent.h.expiry_time == 0)412 if (error)
413 goto out;413 goto out;
414 414
415 /* ID */415 /* ID */
fs/nfsd/vfs.c+7−6
@@ -930,6 +930,9 @@ nfsd_open_verified(struct svc_rqst *rqstp, struct svc_fh *fhp, int may_flags, · 929 unmodified lines
930 * Grab and keep cached pages associated with a file in the svc_rqst930 * Grab and keep cached pages associated with a file in the svc_rqst
931 * so that they can be passed to the network sendmsg/sendpage routines931 * so that they can be passed to the network sendmsg/sendpage routines
932 * directly. They will be released after the sending has completed.932 * directly. They will be released after the sending has completed.
933 *
934 * Return values: Number of bytes consumed, or -EIO if there are no
935 * remaining pages in rqstp->rq_pages.
933 */936 */
934static int937static int
935nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,938nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
@@ -948,7 +951,8 @@ nfsd_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf, · 12 unmodified lines
948 */951 */
949 if (page == *(rqstp->rq_next_page - 1))952 if (page == *(rqstp->rq_next_page - 1))
950 continue;953 continue;
951 svc_rqst_replace_page(rqstp, page);954 if (unlikely(!svc_rqst_replace_page(rqstp, page)))
955 return -EIO;
952 }956 }
953 if (rqstp->rq_res.page_len == 0) // first call957 if (rqstp->rq_res.page_len == 0) // first call
954 rqstp->rq_res.page_base = offset % PAGE_SIZE;958 rqstp->rq_res.page_base = offset % PAGE_SIZE;
@@ -2164,7 +2168,7 @@ nfsd_getxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, · 1209 unmodified lines
2164 goto out;2168 goto out;
2165 }2169 }
2166 2170
2167 buf = kvmalloc(len, GFP_KERNEL | GFP_NOFS);2171 buf = kvmalloc(len, GFP_KERNEL);
2168 if (buf == NULL) {2172 if (buf == NULL) {
2169 err = nfserr_jukebox;2173 err = nfserr_jukebox;
2170 goto out;2174 goto out;
@@ -2227,10 +2231,7 @@ nfsd_listxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char **bufp, · 56 unmodified lines
2227 goto out;2231 goto out;
2228 }2232 }
2229 2233
2230 /*2234 buf = kvmalloc(len, GFP_KERNEL);
2231 * We're holding i_rwsem - use GFP_NOFS.
2232 */
2233 buf = kvmalloc(len, GFP_KERNEL | GFP_NOFS);
2234 if (buf == NULL) {2235 if (buf == NULL) {
2235 err = nfserr_jukebox;2236 err = nfserr_jukebox;
2236 goto out;2237 goto out;
include/linux/exportfs.h+1−0
@@ -220,6 +220,7 @@ struct export_operations { · 219 unmodified lines
220#define EXPORT_OP_NOATOMIC_ATTR (0x10) /* Filesystem cannot supply220#define EXPORT_OP_NOATOMIC_ATTR (0x10) /* Filesystem cannot supply
221 atomic attribute updates221 atomic attribute updates
222 */222 */
223#define EXPORT_OP_FLUSH_ON_CLOSE (0x20) /* fs flushes file data on close */
223 unsigned long flags;224 unsigned long flags;
224};225};
225 226
include/linux/lockd/lockd.h+15−14
@@ -99,21 +99,11 @@ struct nsm_handle { · 98 unmodified lines
99/*99/*
100 * Rigorous type checking on sockaddr type conversions100 * Rigorous type checking on sockaddr type conversions
101 */101 */
102static inline struct sockaddr_in *nlm_addr_in(const struct nlm_host *host)
103{
104 return (struct sockaddr_in *)&host->h_addr;
105}
106
107static inline struct sockaddr *nlm_addr(const struct nlm_host *host)102static inline struct sockaddr *nlm_addr(const struct nlm_host *host)
108{103{
109 return (struct sockaddr *)&host->h_addr;104 return (struct sockaddr *)&host->h_addr;
110}105}
111 106
112static inline struct sockaddr_in *nlm_srcaddr_in(const struct nlm_host *host)
113{
114 return (struct sockaddr_in *)&host->h_srcaddr;
115}
116
117static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)107static inline struct sockaddr *nlm_srcaddr(const struct nlm_host *host)
118{108{
119 return (struct sockaddr *)&host->h_srcaddr;109 return (struct sockaddr *)&host->h_srcaddr;
@@ -131,7 +121,16 @@ struct nlm_lockowner { · 11 unmodified lines
131 uint32_t pid;121 uint32_t pid;
132};122};
133 123
134struct nlm_wait;124/*
125 * This is the representation of a blocked client lock.
126 */
127struct nlm_wait {
128 struct list_head b_list; /* linked list */
129 wait_queue_head_t b_wait; /* where to wait on */
130 struct nlm_host *b_host;
131 struct file_lock *b_lock; /* local file lock */
132 __be32 b_status; /* grant callback status */
133};
135 134
136/*135/*
137 * Memory chunk for NLM client RPC request.136 * Memory chunk for NLM client RPC request.
@@ -212,9 +211,11 @@ struct nlm_rqst * nlm_alloc_call(struct nlm_host *host); · 74 unmodified lines
212int nlm_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);211int nlm_async_call(struct nlm_rqst *, u32, const struct rpc_call_ops *);
213int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);212int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);
214void nlmclnt_release_call(struct nlm_rqst *);213void nlmclnt_release_call(struct nlm_rqst *);
215struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);214void nlmclnt_prepare_block(struct nlm_wait *block, struct nlm_host *host,
216void nlmclnt_finish_block(struct nlm_wait *block);215 struct file_lock *fl);
217int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);216void nlmclnt_queue_block(struct nlm_wait *block);
217__be32 nlmclnt_dequeue_block(struct nlm_wait *block);
218int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
218__be32 nlmclnt_grant(const struct sockaddr *addr,219__be32 nlmclnt_grant(const struct sockaddr *addr,
219 const struct nlm_lock *lock);220 const struct nlm_lock *lock);
220void nlmclnt_recovery(struct nlm_host *);221void nlmclnt_recovery(struct nlm_host *);
include/linux/nfs.h+20−0
@@ -10,6 +10,7 @@ · 9 unmodified lines
10 10
11#include <linux/sunrpc/msg_prot.h>11#include <linux/sunrpc/msg_prot.h>
12#include <linux/string.h>12#include <linux/string.h>
13#include <linux/crc32.h>
13#include <uapi/linux/nfs.h>14#include <uapi/linux/nfs.h>
14 15
15/*16/*
@@ -44,4 +45,23 @@ enum nfs3_stable_how { · 28 unmodified lines
44 /* used by direct.c to mark verf as invalid */45 /* used by direct.c to mark verf as invalid */
45 NFS_INVALID_STABLE_HOW = -146 NFS_INVALID_STABLE_HOW = -1
46};47};
48
49#ifdef CONFIG_CRC32
50/**
51 * nfs_fhandle_hash - calculate the crc32 hash for the filehandle
52 * @fh - pointer to filehandle
53 *
54 * returns a crc32 hash for the filehandle that is compatible with
55 * the one displayed by "wireshark".
56 */
57static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
58{
59 return ~crc32_le(0xFFFFFFFF, &fh->data[0], fh->size);
60}
61#else /* CONFIG_CRC32 */
62static inline u32 nfs_fhandle_hash(const struct nfs_fh *fh)
63{
64 return 0;
65}
66#endif /* CONFIG_CRC32 */
47#endif /* _LINUX_NFS_H */67#endif /* _LINUX_NFS_H */
include/linux/sunrpc/cache.h+8−7
@@ -300,17 +300,18 @@ static inline int get_time(char **bpp, time64_t *time) · 299 unmodified lines
300 return 0;300 return 0;
301}301}
302 302
303static inline time64_t get_expiry(char **bpp)303static inline int get_expiry(char **bpp, time64_t *rvp)
304{304{
305 time64_t rv;305 int error;
306 struct timespec64 boot;306 struct timespec64 boot;
307 307
308 if (get_time(bpp, &rv))308 error = get_time(bpp, rvp);
309 return 0;309 if (error)
310 if (rv < 0)310 return error;
311 return 0;311
312 getboottime64(&boot);312 getboottime64(&boot);
313 return rv - boot.tv_sec;313 (*rvp) -= boot.tv_sec;
314 return 0;
314}315}
315 316
316#endif /* _LINUX_SUNRPC_CACHE_H_ */317#endif /* _LINUX_SUNRPC_CACHE_H_ */
include/linux/sunrpc/svc.h+3−13
@@ -309,17 +309,6 @@ static inline struct sockaddr *svc_daddr(const struct svc_rqst *rqst) · 308 unmodified lines
309 return (struct sockaddr *) &rqst->rq_daddr;309 return (struct sockaddr *) &rqst->rq_daddr;
310}310}
311 311
312static inline void svc_free_res_pages(struct svc_rqst *rqstp)
313{
314 while (rqstp->rq_next_page != rqstp->rq_respages) {
315 struct page **pp = --rqstp->rq_next_page;
316 if (*pp) {
317 put_page(*pp);
318 *pp = NULL;
319 }
320 }
321}
322
323struct svc_deferred_req {312struct svc_deferred_req {
324 u32 prot; /* protocol (UDP or TCP) */313 u32 prot; /* protocol (UDP or TCP) */
325 struct svc_xprt *xprt;314 struct svc_xprt *xprt;
@@ -422,15 +411,16 @@ struct svc_serv *svc_create(struct svc_program *, unsigned int, · 96 unmodified lines
422 int (*threadfn)(void *data));411 int (*threadfn)(void *data));
423struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv,412struct svc_rqst *svc_rqst_alloc(struct svc_serv *serv,
424 struct svc_pool *pool, int node);413 struct svc_pool *pool, int node);
425void svc_rqst_replace_page(struct svc_rqst *rqstp,414bool svc_rqst_replace_page(struct svc_rqst *rqstp,
426 struct page *page);415 struct page *page);
416void svc_rqst_release_pages(struct svc_rqst *rqstp);
427void svc_rqst_free(struct svc_rqst *);417void svc_rqst_free(struct svc_rqst *);
428void svc_exit_thread(struct svc_rqst *);418void svc_exit_thread(struct svc_rqst *);
429struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,419struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
430 int (*threadfn)(void *data));420 int (*threadfn)(void *data));
431int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);421int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
432int svc_pool_stats_open(struct svc_serv *serv, struct file *file);422int svc_pool_stats_open(struct svc_serv *serv, struct file *file);
433int svc_process(struct svc_rqst *);423void svc_process(struct svc_rqst *rqstp);
434int bc_svc_process(struct svc_serv *, struct rpc_rqst *,424int bc_svc_process(struct svc_serv *, struct rpc_rqst *,
435 struct svc_rqst *);425 struct svc_rqst *);
436int svc_register(const struct svc_serv *, struct net *, const int,426int svc_register(const struct svc_serv *, struct net *, const int,
include/linux/sunrpc/svc_xprt.h+4−1
@@ -27,7 +27,7 @@ struct svc_xprt_ops { · 26 unmodified lines
27 void (*xpo_detach)(struct svc_xprt *);27 void (*xpo_detach)(struct svc_xprt *);
28 void (*xpo_free)(struct svc_xprt *);28 void (*xpo_free)(struct svc_xprt *);
29 void (*xpo_kill_temp_xprt)(struct svc_xprt *);29 void (*xpo_kill_temp_xprt)(struct svc_xprt *);
30 void (*xpo_start_tls)(struct svc_xprt *);30 void (*xpo_handshake)(struct svc_xprt *xprt);
31};31};
32 32
33struct svc_xprt_class {33struct svc_xprt_class {
@@ -70,6 +70,9 @@ struct svc_xprt { · 36 unmodified lines
70#define XPT_LOCAL 12 /* connection from loopback interface */70#define XPT_LOCAL 12 /* connection from loopback interface */
71#define XPT_KILL_TEMP 13 /* call xpo_kill_temp_xprt before closing */71#define XPT_KILL_TEMP 13 /* call xpo_kill_temp_xprt before closing */
72#define XPT_CONG_CTRL 14 /* has congestion control */72#define XPT_CONG_CTRL 14 /* has congestion control */
73#define XPT_HANDSHAKE 15 /* xprt requests a handshake */
74#define XPT_TLS_SESSION 16 /* transport-layer security established */
75#define XPT_PEER_AUTH 17 /* peer has been authenticated */
73 76
74 struct svc_serv *xpt_server; /* service for transport */77 struct svc_serv *xpt_server; /* service for transport */
75 atomic_t xpt_reserved; /* space on outq that is rsvd */78 atomic_t xpt_reserved; /* space on outq that is rsvd */
include/linux/sunrpc/svcsock.h+3−1
@@ -38,6 +38,8 @@ struct svc_sock { · 37 unmodified lines
38 /* Number of queued send requests */38 /* Number of queued send requests */
39 atomic_t sk_sendqlen;39 atomic_t sk_sendqlen;
40 40
41 struct completion sk_handshake_done;
42
41 struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */43 struct page * sk_pages[RPCSVC_MAXPAGES]; /* received data */
42};44};
43 45
@@ -56,7 +58,7 @@ static inline u32 svc_sock_final_rec(struct svc_sock *svsk) · 12 unmodified lines
56 */58 */
57void svc_close_net(struct svc_serv *, struct net *);59void svc_close_net(struct svc_serv *, struct net *);
58int svc_recv(struct svc_rqst *, long);60int svc_recv(struct svc_rqst *, long);
59int svc_send(struct svc_rqst *);61void svc_send(struct svc_rqst *rqstp);
60void svc_drop(struct svc_rqst *);62void svc_drop(struct svc_rqst *);
61void svc_sock_update_bufs(struct svc_serv *serv);63void svc_sock_update_bufs(struct svc_serv *serv);
62bool svc_alien_sock(struct net *net, int fd);64bool svc_alien_sock(struct net *net, int fd);
include/net/tls.h+2−0
@@ -69,6 +69,8 @@ extern const struct tls_cipher_size_desc tls_cipher_size_desc[]; · 68 unmodified lines
69 69
70#define TLS_CRYPTO_INFO_READY(info) ((info)->cipher_type)70#define TLS_CRYPTO_INFO_READY(info) ((info)->cipher_type)
71 71
72#define TLS_RECORD_TYPE_ALERT 0x15
73#define TLS_RECORD_TYPE_HANDSHAKE 0x16
72#define TLS_RECORD_TYPE_DATA 0x1774#define TLS_RECORD_TYPE_DATA 0x17
73 75
74#define TLS_AAD_SPACE_SIZE 1376#define TLS_AAD_SPACE_SIZE 13
include/trace/events/sunrpc.h+40−1
@@ -1790,6 +1790,31 @@ DEFINE_EVENT(svc_rqst_status, svc_send, · 1789 unmodified lines
1790 TP_PROTO(const struct svc_rqst *rqst, int status),1790 TP_PROTO(const struct svc_rqst *rqst, int status),
1791 TP_ARGS(rqst, status));1791 TP_ARGS(rqst, status));
1792 1792
1793TRACE_EVENT(svc_replace_page_err,
1794 TP_PROTO(const struct svc_rqst *rqst),
1795
1796 TP_ARGS(rqst),
1797 TP_STRUCT__entry(
1798 SVC_RQST_ENDPOINT_FIELDS(rqst)
1799
1800 __field(const void *, begin)
1801 __field(const void *, respages)
1802 __field(const void *, nextpage)
1803 ),
1804
1805 TP_fast_assign(
1806 SVC_RQST_ENDPOINT_ASSIGNMENTS(rqst);
1807
1808 __entry->begin = rqst->rq_pages;
1809 __entry->respages = rqst->rq_respages;
1810 __entry->nextpage = rqst->rq_next_page;
1811 ),
1812
1813 TP_printk(SVC_RQST_ENDPOINT_FORMAT " begin=%p respages=%p nextpage=%p",
1814 SVC_RQST_ENDPOINT_VARARGS,
1815 __entry->begin, __entry->respages, __entry->nextpage)
1816);
1817
1793TRACE_EVENT(svc_stats_latency,1818TRACE_EVENT(svc_stats_latency,
1794 TP_PROTO(1819 TP_PROTO(
1795 const struct svc_rqst *rqst1820 const struct svc_rqst *rqst
@@ -1832,7 +1857,10 @@ TRACE_EVENT(svc_stats_latency, · 36 unmodified lines
1832 { BIT(XPT_CACHE_AUTH), "CACHE_AUTH" }, \1857 { BIT(XPT_CACHE_AUTH), "CACHE_AUTH" }, \
1833 { BIT(XPT_LOCAL), "LOCAL" }, \1858 { BIT(XPT_LOCAL), "LOCAL" }, \
1834 { BIT(XPT_KILL_TEMP), "KILL_TEMP" }, \1859 { BIT(XPT_KILL_TEMP), "KILL_TEMP" }, \
1835 { BIT(XPT_CONG_CTRL), "CONG_CTRL" })1860 { BIT(XPT_CONG_CTRL), "CONG_CTRL" }, \
1861 { BIT(XPT_HANDSHAKE), "HANDSHAKE" }, \
1862 { BIT(XPT_TLS_SESSION), "TLS_SESSION" }, \
1863 { BIT(XPT_PEER_AUTH), "PEER_AUTH" })
1836 1864
1837TRACE_EVENT(svc_xprt_create_err,1865TRACE_EVENT(svc_xprt_create_err,
1838 TP_PROTO(1866 TP_PROTO(
@@ -1965,6 +1993,17 @@ DEFINE_SVC_XPRT_EVENT(close); · 126 unmodified lines
1965DEFINE_SVC_XPRT_EVENT(detach);1993DEFINE_SVC_XPRT_EVENT(detach);
1966DEFINE_SVC_XPRT_EVENT(free);1994DEFINE_SVC_XPRT_EVENT(free);
1967 1995
1996#define DEFINE_SVC_TLS_EVENT(name) \
1997 DEFINE_EVENT(svc_xprt_event, svc_tls_##name, \
1998 TP_PROTO(const struct svc_xprt *xprt), \
1999 TP_ARGS(xprt))
2000
2001DEFINE_SVC_TLS_EVENT(start);
2002DEFINE_SVC_TLS_EVENT(upcall);
2003DEFINE_SVC_TLS_EVENT(unavailable);
2004DEFINE_SVC_TLS_EVENT(not_started);
2005DEFINE_SVC_TLS_EVENT(timed_out);
2006
1968TRACE_EVENT(svc_xprt_accept,2007TRACE_EVENT(svc_xprt_accept,
1969 TP_PROTO(2008 TP_PROTO(
1970 const struct svc_xprt *xprt,2009 const struct svc_xprt *xprt,
include/uapi/linux/nfsd/export.h+13−0
@@ -62,5 +62,18 @@ · 61 unmodified lines
62 | NFSEXP_ALLSQUASH \62 | NFSEXP_ALLSQUASH \
63 | NFSEXP_INSECURE_PORT)63 | NFSEXP_INSECURE_PORT)
64 64
65/*
66 * Transport layer security policies that are permitted to access
67 * an export
68 */
69#define NFSEXP_XPRTSEC_NONE 0x0001
70#define NFSEXP_XPRTSEC_TLS 0x0002
71#define NFSEXP_XPRTSEC_MTLS 0x0004
72
73#define NFSEXP_XPRTSEC_NUM (3)
74
75#define NFSEXP_XPRTSEC_ALL (NFSEXP_XPRTSEC_NONE | \
76 NFSEXP_XPRTSEC_TLS | \
77 NFSEXP_XPRTSEC_MTLS)
65 78
66#endif /* _UAPINFSD_EXPORT_H */79#endif /* _UAPINFSD_EXPORT_H */
net/sunrpc/auth_gss/svcauth_gss.c+6−6
@@ -257,11 +257,11 @@ static int rsi_parse(struct cache_detail *cd, · 256 unmodified lines
257 257
258 rsii.h.flags = 0;258 rsii.h.flags = 0;
259 /* expiry */259 /* expiry */
260 expiry = get_expiry(&mesg);260 status = get_expiry(&mesg, &expiry);
261 status = -EINVAL;261 if (status)
262 if (expiry == 0)
263 goto out;262 goto out;
264 263
264 status = -EINVAL;
265 /* major/minor */265 /* major/minor */
266 len = qword_get(&mesg, buf, mlen);266 len = qword_get(&mesg, buf, mlen);
267 if (len <= 0)267 if (len <= 0)
@@ -483,11 +483,11 @@ static int rsc_parse(struct cache_detail *cd, · 215 unmodified lines
483 483
484 rsci.h.flags = 0;484 rsci.h.flags = 0;
485 /* expiry */485 /* expiry */
486 expiry = get_expiry(&mesg);486 status = get_expiry(&mesg, &expiry);
487 status = -EINVAL;487 if (status)
488 if (expiry == 0)
489 goto out;488 goto out;
490 489
490 status = -EINVAL;
491 rscp = rsc_lookup(cd, &rsci);491 rscp = rsc_lookup(cd, &rsci);
492 if (!rscp)492 if (!rscp)
493 goto out;493 goto out;
net/sunrpc/svc.c+42−7
@@ -649,6 +649,8 @@ svc_rqst_alloc(struct svc_serv *serv, struct svc_pool *pool, int node) · 648 unmodified lines
649 if (!rqstp)649 if (!rqstp)
650 return rqstp;650 return rqstp;
651 651
652 pagevec_init(&rqstp->rq_pvec);
653
652 __set_bit(RQ_BUSY, &rqstp->rq_flags);654 __set_bit(RQ_BUSY, &rqstp->rq_flags);
653 rqstp->rq_server = serv;655 rqstp->rq_server = serv;
654 rqstp->rq_pool = pool;656 rqstp->rq_pool = pool;
@@ -842,9 +844,21 @@ EXPORT_SYMBOL_GPL(svc_set_num_threads); · 187 unmodified lines
842 *844 *
843 * When replacing a page in rq_pages, batch the release of the845 * When replacing a page in rq_pages, batch the release of the
844 * replaced pages to avoid hammering the page allocator.846 * replaced pages to avoid hammering the page allocator.
847 *
848 * Return values:
849 * %true: page replaced
850 * %false: array bounds checking failed
845 */851 */
846void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)852bool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page)
847{853{
854 struct page **begin = rqstp->rq_pages;
855 struct page **end = &rqstp->rq_pages[RPCSVC_MAXPAGES];
856
857 if (unlikely(rqstp->rq_next_page < begin || rqstp->rq_next_page > end)) {
858 trace_svc_replace_page_err(rqstp);
859 return false;
860 }
861
848 if (*rqstp->rq_next_page) {862 if (*rqstp->rq_next_page) {
849 if (!pagevec_space(&rqstp->rq_pvec))863 if (!pagevec_space(&rqstp->rq_pvec))
850 __pagevec_release(&rqstp->rq_pvec);864 __pagevec_release(&rqstp->rq_pvec);
@@ -853,9 +867,28 @@ void svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page) · 2 unmodified lines
853 867
854 get_page(page);868 get_page(page);
855 *(rqstp->rq_next_page++) = page;869 *(rqstp->rq_next_page++) = page;
870 return true;
856}871}
857EXPORT_SYMBOL_GPL(svc_rqst_replace_page);872EXPORT_SYMBOL_GPL(svc_rqst_replace_page);
858 873
874/**
875 * svc_rqst_release_pages - Release Reply buffer pages
876 * @rqstp: RPC transaction context
877 *
878 * Release response pages that might still be in flight after
879 * svc_send, and any spliced filesystem-owned pages.
880 */
881void svc_rqst_release_pages(struct svc_rqst *rqstp)
882{
883 int i, count = rqstp->rq_next_page - rqstp->rq_respages;
884
885 if (count) {
886 release_pages(rqstp->rq_respages, count);
887 for (i = 0; i < count; i++)
888 rqstp->rq_respages[i] = NULL;
889 }
890}
891
859/*892/*
860 * Called from a server thread as it's exiting. Caller must hold the "service893 * Called from a server thread as it's exiting. Caller must hold the "service
861 * mutex" for the service.894 * mutex" for the service.
@@ -863,6 +896,7 @@ EXPORT_SYMBOL_GPL(svc_rqst_replace_page); · 1 unmodified line
863void896void
864svc_rqst_free(struct svc_rqst *rqstp)897svc_rqst_free(struct svc_rqst *rqstp)
865{898{
899 pagevec_release(&rqstp->rq_pvec);
866 svc_release_buffer(rqstp);900 svc_release_buffer(rqstp);
867 if (rqstp->rq_scratch_page)901 if (rqstp->rq_scratch_page)
868 put_page(rqstp->rq_scratch_page);902 put_page(rqstp->rq_scratch_page);
@@ -1431,11 +1465,12 @@ err_system_err: · 562 unmodified lines
1431 goto sendit;1465 goto sendit;
1432}1466}
1433 1467
1434/*1468/**
1435 * Process the RPC request.1469 * svc_process - Execute one RPC transaction
1470 * @rqstp: RPC transaction context
1471 *
1436 */1472 */
1437int1473void svc_process(struct svc_rqst *rqstp)
1438svc_process(struct svc_rqst *rqstp)
1439{1474{
1440 struct kvec *resv = &rqstp->rq_res.head[0];1475 struct kvec *resv = &rqstp->rq_res.head[0];
1441 __be32 *p;1476 __be32 *p;
@@ -1471,7 +1506,8 @@ svc_process(struct svc_rqst *rqstp) · 29 unmodified lines
1471 1506
1472 if (!svc_process_common(rqstp))1507 if (!svc_process_common(rqstp))
1473 goto out_drop;1508 goto out_drop;
1474 return svc_send(rqstp);1509 svc_send(rqstp);
1510 return;
1475 1511
1476out_baddir:1512out_baddir:
1477 svc_printk(rqstp, "bad direction 0x%08x, dropping request\n",1513 svc_printk(rqstp, "bad direction 0x%08x, dropping request\n",
@@ -1479,7 +1515,6 @@ out_baddir: · 1 unmodified line
1479 rqstp->rq_server->sv_stats->rpcbadfmt++;1515 rqstp->rq_server->sv_stats->rpcbadfmt++;
1480out_drop:1516out_drop:
1481 svc_drop(rqstp);1517 svc_drop(rqstp);
1482 return 0;
1483}1518}
1484EXPORT_SYMBOL_GPL(svc_process);1519EXPORT_SYMBOL_GPL(svc_process);
1485 1520
net/sunrpc/svc_xprt.c+16−17
@@ -427,7 +427,7 @@ static bool svc_xprt_ready(struct svc_xprt *xprt) · 426 unmodified lines
427 427
428 if (xpt_flags & BIT(XPT_BUSY))428 if (xpt_flags & BIT(XPT_BUSY))
429 return false;429 return false;
430 if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE)))430 if (xpt_flags & (BIT(XPT_CONN) | BIT(XPT_CLOSE) | BIT(XPT_HANDSHAKE)))
431 return true;431 return true;
432 if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED))) {432 if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED))) {
433 if (xprt->xpt_ops->xpo_has_wspace(xprt) &&433 if (xprt->xpt_ops->xpo_has_wspace(xprt) &&
@@ -541,8 +541,7 @@ static void svc_xprt_release(struct svc_rqst *rqstp) · 107 unmodified lines
541 kfree(rqstp->rq_deferred);541 kfree(rqstp->rq_deferred);
542 rqstp->rq_deferred = NULL;542 rqstp->rq_deferred = NULL;
543 543
544 pagevec_release(&rqstp->rq_pvec);544 svc_rqst_release_pages(rqstp);
545 svc_free_res_pages(rqstp);
546 rqstp->rq_res.page_len = 0;545 rqstp->rq_res.page_len = 0;
547 rqstp->rq_res.page_base = 0;546 rqstp->rq_res.page_base = 0;
548 547
@@ -667,8 +666,6 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) · 118 unmodified lines
667 struct xdr_buf *arg = &rqstp->rq_arg;666 struct xdr_buf *arg = &rqstp->rq_arg;
668 unsigned long pages, filled, ret;667 unsigned long pages, filled, ret;
669 668
670 pagevec_init(&rqstp->rq_pvec);
671
672 pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;669 pages = (serv->sv_max_mesg + 2 * PAGE_SIZE) >> PAGE_SHIFT;
673 if (pages > RPCSVC_MAXPAGES) {670 if (pages > RPCSVC_MAXPAGES) {
674 pr_warn_once("svc: warning: pages=%lu > RPCSVC_MAXPAGES=%lu\n",671 pr_warn_once("svc: warning: pages=%lu > RPCSVC_MAXPAGES=%lu\n",
@@ -704,6 +701,8 @@ static int svc_alloc_arg(struct svc_rqst *rqstp) · 29 unmodified lines
704 arg->page_len = (pages-2)*PAGE_SIZE;701 arg->page_len = (pages-2)*PAGE_SIZE;
705 arg->len = (pages-1)*PAGE_SIZE;702 arg->len = (pages-1)*PAGE_SIZE;
706 arg->tail[0].iov_len = 0;703 arg->tail[0].iov_len = 0;
704
705 rqstp->rq_xid = xdr_zero;
707 return 0;706 return 0;
708}707}
709 708
@@ -829,6 +828,9 @@ static int svc_handle_xprt(struct svc_rqst *rqstp, struct svc_xprt *xprt) · 119 unmodified lines
829 module_put(xprt->xpt_class->xcl_owner);828 module_put(xprt->xpt_class->xcl_owner);
830 }829 }
831 svc_xprt_received(xprt);830 svc_xprt_received(xprt);
831 } else if (test_bit(XPT_HANDSHAKE, &xprt->xpt_flags)) {
832 xprt->xpt_ops->xpo_handshake(xprt);
833 svc_xprt_received(xprt);
832 } else if (svc_xprt_reserve_slot(rqstp, xprt)) {834 } else if (svc_xprt_reserve_slot(rqstp, xprt)) {
833 /* XPT_DATA|XPT_DEFERRED case: */835 /* XPT_DATA|XPT_DEFERRED case: */
834 dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",836 dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n",
@@ -909,18 +911,20 @@ void svc_drop(struct svc_rqst *rqstp) · 74 unmodified lines
909}911}
910EXPORT_SYMBOL_GPL(svc_drop);912EXPORT_SYMBOL_GPL(svc_drop);
911 913
912/*914/**
913 * Return reply to client.915 * svc_send - Return reply to client
916 * @rqstp: RPC transaction context
917 *
914 */918 */
915int svc_send(struct svc_rqst *rqstp)919void svc_send(struct svc_rqst *rqstp)
916{920{
917 struct svc_xprt *xprt;921 struct svc_xprt *xprt;
918 int len = -EFAULT;
919 struct xdr_buf *xb;922 struct xdr_buf *xb;
923 int status;
920 924
921 xprt = rqstp->rq_xprt;925 xprt = rqstp->rq_xprt;
922 if (!xprt)926 if (!xprt)
923 goto out;927 return;
924 928
925 /* calculate over-all length */929 /* calculate over-all length */
926 xb = &rqstp->rq_res;930 xb = &rqstp->rq_res;
@@ -930,15 +934,10 @@ int svc_send(struct svc_rqst *rqstp) · 3 unmodified lines
930 trace_svc_xdr_sendto(rqstp->rq_xid, xb);934 trace_svc_xdr_sendto(rqstp->rq_xid, xb);
931 trace_svc_stats_latency(rqstp);935 trace_svc_stats_latency(rqstp);
932 936
933 len = xprt->xpt_ops->xpo_sendto(rqstp);937 status = xprt->xpt_ops->xpo_sendto(rqstp);
934 938
935 trace_svc_send(rqstp, len);939 trace_svc_send(rqstp, status);
936 svc_xprt_release(rqstp);940 svc_xprt_release(rqstp);
937
938 if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
939 len = 0;
940out:
941 return len;
942}941}
943 942
944/*943/*
net/sunrpc/svcauth_unix.c+15−8
@@ -17,8 +17,9 @@ · 16 unmodified lines
17#include <net/ipv6.h>17#include <net/ipv6.h>
18#include <linux/kernel.h>18#include <linux/kernel.h>
19#include <linux/user_namespace.h>19#include <linux/user_namespace.h>
20#define RPCDBG_FACILITY RPCDBG_AUTH20#include <trace/events/sunrpc.h>
21 21
22#define RPCDBG_FACILITY RPCDBG_AUTH
22 23
23#include "netns.h"24#include "netns.h"
24 25
@@ -225,9 +226,9 @@ static int ip_map_parse(struct cache_detail *cd, · 200 unmodified lines
225 return -EINVAL;226 return -EINVAL;
226 }227 }
227 228
228 expiry = get_expiry(&mesg);229 err = get_expiry(&mesg, &expiry);
229 if (expiry ==0)230 if (err)
230 return -EINVAL;231 return err;
231 232
232 /* domainname, or empty for NEGATIVE */233 /* domainname, or empty for NEGATIVE */
233 len = qword_get(&mesg, buf, mlen);234 len = qword_get(&mesg, buf, mlen);
@@ -506,9 +507,9 @@ static int unix_gid_parse(struct cache_detail *cd, · 272 unmodified lines
506 uid = make_kuid(current_user_ns(), id);507 uid = make_kuid(current_user_ns(), id);
507 ug.uid = uid;508 ug.uid = uid;
508 509
509 expiry = get_expiry(&mesg);510 err = get_expiry(&mesg, &expiry);
510 if (expiry == 0)511 if (err)
511 return -EINVAL;512 return err;
512 513
513 rv = get_int(&mesg, &gids);514 rv = get_int(&mesg, &gids);
514 if (rv || gids < 0 || gids > 8192)515 if (rv || gids < 0 || gids > 8192)
@@ -832,6 +833,7 @@ svcauth_tls_accept(struct svc_rqst *rqstp) · 317 unmodified lines
832{833{
833 struct xdr_stream *xdr = &rqstp->rq_arg_stream;834 struct xdr_stream *xdr = &rqstp->rq_arg_stream;
834 struct svc_cred *cred = &rqstp->rq_cred;835 struct svc_cred *cred = &rqstp->rq_cred;
836 struct svc_xprt *xprt = rqstp->rq_xprt;
835 u32 flavor, len;837 u32 flavor, len;
836 void *body;838 void *body;
837 __be32 *p;839 __be32 *p;
@@ -865,14 +867,19 @@ svcauth_tls_accept(struct svc_rqst *rqstp) · 27 unmodified lines
865 if (cred->cr_group_info == NULL)867 if (cred->cr_group_info == NULL)
866 return SVC_CLOSE;868 return SVC_CLOSE;
867 869
868 if (rqstp->rq_xprt->xpt_ops->xpo_start_tls) {870 if (xprt->xpt_ops->xpo_handshake) {
869 p = xdr_reserve_space(&rqstp->rq_res_stream, XDR_UNIT * 2 + 8);871 p = xdr_reserve_space(&rqstp->rq_res_stream, XDR_UNIT * 2 + 8);
870 if (!p)872 if (!p)
871 return SVC_CLOSE;873 return SVC_CLOSE;
874 trace_svc_tls_start(xprt);
872 *p++ = rpc_auth_null;875 *p++ = rpc_auth_null;
873 *p++ = cpu_to_be32(8);876 *p++ = cpu_to_be32(8);
874 memcpy(p, "STARTTLS", 8);877 memcpy(p, "STARTTLS", 8);
878
879 set_bit(XPT_HANDSHAKE, &xprt->xpt_flags);
880 svc_xprt_enqueue(xprt);
875 } else {881 } else {
882 trace_svc_tls_unavailable(xprt);
876 if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream,883 if (xdr_stream_encode_opaque_auth(&rqstp->rq_res_stream,
877 RPC_AUTH_NULL, NULL, 0) < 0)884 RPC_AUTH_NULL, NULL, 0) < 0)
878 return SVC_CLOSE;885 return SVC_CLOSE;
net/sunrpc/svcsock.c+162−12
@@ -43,9 +43,12 @@ · 42 unmodified lines
43#include <net/udp.h>43#include <net/udp.h>
44#include <net/tcp.h>44#include <net/tcp.h>
45#include <net/tcp_states.h>45#include <net/tcp_states.h>
46#include <net/tls.h>
47#include <net/handshake.h>
46#include <linux/uaccess.h>48#include <linux/uaccess.h>
47#include <linux/highmem.h>49#include <linux/highmem.h>
48#include <asm/ioctls.h>50#include <asm/ioctls.h>
51#include <linux/key.h>
49 52
50#include <linux/sunrpc/types.h>53#include <linux/sunrpc/types.h>
51#include <linux/sunrpc/clnt.h>54#include <linux/sunrpc/clnt.h>
@@ -63,6 +66,12 @@ · 11 unmodified lines
63 66
64#define RPCDBG_FACILITY RPCDBG_SVCXPRT67#define RPCDBG_FACILITY RPCDBG_SVCXPRT
65 68
69/* To-do: to avoid tying up an nfsd thread while waiting for a
70 * handshake request, the request could instead be deferred.
71 */
72enum {
73 SVC_HANDSHAKE_TO = 5U * HZ
74};
66 75
67static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,76static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *,
68 int flags);77 int flags);
@@ -216,6 +225,49 @@ static int svc_one_sock_name(struct svc_sock *svsk, char *buf, int remaining) · 147 unmodified lines
216 return len;225 return len;
217}226}
218 227
228static int
229svc_tcp_sock_process_cmsg(struct svc_sock *svsk, struct msghdr *msg,
230 struct cmsghdr *cmsg, int ret)
231{
232 if (cmsg->cmsg_level == SOL_TLS &&
233 cmsg->cmsg_type == TLS_GET_RECORD_TYPE) {
234 u8 content_type = *((u8 *)CMSG_DATA(cmsg));
235
236 switch (content_type) {
237 case TLS_RECORD_TYPE_DATA:
238 /* TLS sets EOR at the end of each application data
239 * record, even though there might be more frames
240 * waiting to be decrypted.
241 */
242 msg->msg_flags &= ~MSG_EOR;
243 break;
244 case TLS_RECORD_TYPE_ALERT:
245 ret = -ENOTCONN;
246 break;
247 default:
248 ret = -EAGAIN;
249 }
250 }
251 return ret;
252}
253
254static int
255svc_tcp_sock_recv_cmsg(struct svc_sock *svsk, struct msghdr *msg)
256{
257 union {
258 struct cmsghdr cmsg;
259 u8 buf[CMSG_SPACE(sizeof(u8))];
260 } u;
261 int ret;
262
263 msg->msg_control = &u;
264 msg->msg_controllen = sizeof(u);
265 ret = sock_recvmsg(svsk->sk_sock, msg, MSG_DONTWAIT);
266 if (unlikely(msg->msg_controllen != sizeof(u)))
267 ret = svc_tcp_sock_process_cmsg(svsk, msg, &u.cmsg, ret);
268 return ret;
269}
270
219#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE271#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
220static void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t seek)272static void svc_flush_bvec(const struct bio_vec *bvec, size_t size, size_t seek)
221{273{
@@ -263,7 +315,7 @@ static ssize_t svc_tcp_read_msg(struct svc_rqst *rqstp, size_t buflen, · 41 unmodified lines
263 iov_iter_advance(&msg.msg_iter, seek);315 iov_iter_advance(&msg.msg_iter, seek);
264 buflen -= seek;316 buflen -= seek;
265 }317 }
266 len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);318 len = svc_tcp_sock_recv_cmsg(svsk, &msg);
267 if (len > 0)319 if (len > 0)
268 svc_flush_bvec(bvec, len, seek);320 svc_flush_bvec(bvec, len, seek);
269 321
@@ -315,6 +367,8 @@ static void svc_data_ready(struct sock *sk) · 45 unmodified lines
315 rmb();367 rmb();
316 svsk->sk_odata(sk);368 svsk->sk_odata(sk);
317 trace_svcsock_data_ready(&svsk->sk_xprt, 0);369 trace_svcsock_data_ready(&svsk->sk_xprt, 0);
370 if (test_bit(XPT_HANDSHAKE, &svsk->sk_xprt.xpt_flags))
371 return;
318 if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))372 if (!test_and_set_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags))
319 svc_xprt_enqueue(&svsk->sk_xprt);373 svc_xprt_enqueue(&svsk->sk_xprt);
320 }374 }
@@ -352,6 +406,88 @@ static void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt) · 31 unmodified lines
352 sock_no_linger(svsk->sk_sock->sk);406 sock_no_linger(svsk->sk_sock->sk);
353}407}
354 408
409/**
410 * svc_tcp_handshake_done - Handshake completion handler
411 * @data: address of xprt to wake
412 * @status: status of handshake
413 * @peerid: serial number of key containing the remote peer's identity
414 *
415 * If a security policy is specified as an export option, we don't
416 * have a specific export here to check. So we set a "TLS session
417 * is present" flag on the xprt and let an upper layer enforce local
418 * security policy.
419 */
420static void svc_tcp_handshake_done(void *data, int status, key_serial_t peerid)
421{
422 struct svc_xprt *xprt = data;
423 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
424
425 if (!status) {
426 if (peerid != TLS_NO_PEERID)
427 set_bit(XPT_PEER_AUTH, &xprt->xpt_flags);
428 set_bit(XPT_TLS_SESSION, &xprt->xpt_flags);
429 }
430 clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags);
431 complete_all(&svsk->sk_handshake_done);
432}
433
434/**
435 * svc_tcp_handshake - Perform a transport-layer security handshake
436 * @xprt: connected transport endpoint
437 *
438 */
439static void svc_tcp_handshake(struct svc_xprt *xprt)
440{
441 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
442 struct sock *sk = svsk->sk_sock->sk;
443 struct tls_handshake_args args = {
444 .ta_sock = svsk->sk_sock,
445 .ta_done = svc_tcp_handshake_done,
446 .ta_data = xprt,
447 };
448 int ret;
449
450 trace_svc_tls_upcall(xprt);
451
452 clear_bit(XPT_TLS_SESSION, &xprt->xpt_flags);
453 init_completion(&svsk->sk_handshake_done);
454
455 ret = tls_server_hello_x509(&args, GFP_KERNEL);
456 if (ret) {
457 trace_svc_tls_not_started(xprt);
458 goto out_failed;
459 }
460
461 ret = wait_for_completion_interruptible_timeout(&svsk->sk_handshake_done,
462 SVC_HANDSHAKE_TO);
463 if (ret <= 0) {
464 if (tls_handshake_cancel(sk)) {
465 trace_svc_tls_timed_out(xprt);
466 goto out_close;
467 }
468 }
469
470 if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) {
471 trace_svc_tls_unavailable(xprt);
472 goto out_close;
473 }
474
475 /* Mark the transport ready in case the remote sent RPC
476 * traffic before the kernel received the handshake
477 * completion downcall.
478 */
479 set_bit(XPT_DATA, &xprt->xpt_flags);
480 svc_xprt_enqueue(xprt);
481 return;
482
483out_close:
484 set_bit(XPT_CLOSE, &xprt->xpt_flags);
485out_failed:
486 clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags);
487 set_bit(XPT_DATA, &xprt->xpt_flags);
488 svc_xprt_enqueue(xprt);
489}
490
355/*491/*
356 * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo492 * See net/ipv6/ip_sockglue.c : ip_cmsg_recv_pktinfo
357 */493 */
@@ -877,7 +1013,7 @@ static ssize_t svc_tcp_read_marker(struct svc_sock *svsk, · 519 unmodified lines
877 iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;1013 iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;
878 iov.iov_len = want;1014 iov.iov_len = want;
879 iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, want);1015 iov_iter_kvec(&msg.msg_iter, ITER_DEST, &iov, 1, want);
880 len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);1016 len = svc_tcp_sock_recv_cmsg(svsk, &msg);
881 if (len < 0)1017 if (len < 0)
882 return len;1018 return len;
883 svsk->sk_tcplen += len;1019 svsk->sk_tcplen += len;
@@ -1213,6 +1349,7 @@ static const struct svc_xprt_ops svc_tcp_ops = { · 329 unmodified lines
1213 .xpo_has_wspace = svc_tcp_has_wspace,1349 .xpo_has_wspace = svc_tcp_has_wspace,
1214 .xpo_accept = svc_tcp_accept,1350 .xpo_accept = svc_tcp_accept,
1215 .xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt,1351 .xpo_kill_temp_xprt = svc_tcp_kill_temp_xprt,
1352 .xpo_handshake = svc_tcp_handshake,
1216};1353};
1217 1354
1218static struct svc_xprt_class svc_tcp_class = {1355static struct svc_xprt_class svc_tcp_class = {
@@ -1293,26 +1430,37 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv, · 74 unmodified lines
1293 struct socket *sock,1430 struct socket *sock,
1294 int flags)1431 int flags)
1295{1432{
1433 struct file *filp = NULL;
1296 struct svc_sock *svsk;1434 struct svc_sock *svsk;
1297 struct sock *inet;1435 struct sock *inet;
1298 int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);1436 int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
1299 int err = 0;
1300 1437
1301 svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);1438 svsk = kzalloc(sizeof(*svsk), GFP_KERNEL);
1302 if (!svsk)1439 if (!svsk)
1303 return ERR_PTR(-ENOMEM);1440 return ERR_PTR(-ENOMEM);
1304 1441
1442 if (!sock->file) {
1443 filp = sock_alloc_file(sock, O_NONBLOCK, NULL);
1444 if (IS_ERR(filp)) {
1445 kfree(svsk);
1446 return ERR_CAST(filp);
1447 }
1448 }
1449
1305 inet = sock->sk;1450 inet = sock->sk;
1306 1451
1307 /* Register socket with portmapper */1452 if (pmap_register) {
1308 if (pmap_register)1453 int err;
1454
1309 err = svc_register(serv, sock_net(sock->sk), inet->sk_family,1455 err = svc_register(serv, sock_net(sock->sk), inet->sk_family,
1310 inet->sk_protocol,1456 inet->sk_protocol,
1311 ntohs(inet_sk(inet)->inet_sport));1457 ntohs(inet_sk(inet)->inet_sport));
1312 1458 if (err < 0) {
1313 if (err < 0) {1459 if (filp)
1314 kfree(svsk);1460 fput(filp);
1315 return ERR_PTR(err);1461 kfree(svsk);
1462 return ERR_PTR(err);
1463 }
1316 }1464 }
1317 1465
1318 svsk->sk_sock = sock;1466 svsk->sk_sock = sock;
@@ -1525,10 +1673,12 @@ static void svc_tcp_sock_detach(struct svc_xprt *xprt) · 206 unmodified lines
1525static void svc_sock_free(struct svc_xprt *xprt)1673static void svc_sock_free(struct svc_xprt *xprt)
1526{1674{
1527 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);1675 struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
1676 struct socket *sock = svsk->sk_sock;
1528 1677
1529 if (svsk->sk_sock->file)1678 tls_handshake_cancel(sock->sk);
1530 sockfd_put(svsk->sk_sock);1679 if (sock->file)
1680 sockfd_put(sock);
1531 else1681 else
1532 sock_release(svsk->sk_sock);1682 sock_release(sock);
1533 kfree(svsk);1683 kfree(svsk);
1534}1684}
net/sunrpc/xprtrdma/svc_rdma.c+2−19
@@ -212,24 +212,6 @@ static struct ctl_table svcrdma_parm_table[] = { · 211 unmodified lines
212 { },212 { },
213};213};
214 214
215static struct ctl_table svcrdma_table[] = {
216 {
217 .procname = "svc_rdma",
218 .mode = 0555,
219 .child = svcrdma_parm_table
220 },
221 { },
222};
223
224static struct ctl_table svcrdma_root_table[] = {
225 {
226 .procname = "sunrpc",
227 .mode = 0555,
228 .child = svcrdma_table
229 },
230 { },
231};
232
233static void svc_rdma_proc_cleanup(void)215static void svc_rdma_proc_cleanup(void)
234{216{
235 if (!svcrdma_table_header)217 if (!svcrdma_table_header)
@@ -263,7 +245,8 @@ static int svc_rdma_proc_init(void) · 27 unmodified lines
263 if (rc)245 if (rc)
264 goto out_err;246 goto out_err;
265 247
266 svcrdma_table_header = register_sysctl_table(svcrdma_root_table);248 svcrdma_table_header = register_sysctl("sunrpc/svc_rdma",
249 svcrdma_parm_table);
267 return 0;250 return 0;
268 251
269out_err:252out_err: