Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'nfsd-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux

Pull nfsd updates from Chuck Lever:

- filehandle signing to defend against filehandle-guessing attacks
(Benjamin Coddington)

The server now appends a SipHash-2-4 MAC to each filehandle when
the new "sign_fh" export option is enabled. NFSD then verifies
filehandles received from clients against the expected MAC;
mismatches return NFS error STALE

- convert the entire NLMv4 server-side XDR layer from hand-written C to
xdrgen-generated code, spanning roughly thirty patches (Chuck Lever)

XDR functions are generally boilerplate code and are easy to get
wrong. The goals of this conversion are improved memory safety, lower
maintenance burden, and groundwork for eventual Rust code generation
for these functions.

- improve pNFS block/SCSI layout robustness with two related changes
(Dai Ngo)

SCSI persistent reservation fencing is now tracked per client and
per device via an xarray, to avoid both redundant preempt operations
on devices already fenced and a potential NFSD deadlock when all nfsd
threads are waiting for a layout return.

- scalability and infrastructure improvements

Sincere thanks to all contributors, reviewers, testers, and bug
reporters who participated in the v7.1 NFSD development cycle.

* tag 'nfsd-7.1' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (83 commits)
NFSD: Docs: clean up pnfs server timeout docs
nfsd: fix comment typo in nfsxdr
nfsd: fix comment typo in nfs3xdr
NFSD: convert callback RPC program to per-net namespace
NFSD: use per-operation statidx for callback procedures
svcrdma: Use contiguous pages for RDMA Read sink buffers
SUNRPC: Add svc_rqst_page_release() helper
SUNRPC: xdr.h: fix all kernel-doc warnings
svcrdma: Factor out WR chain linking into helper
svcrdma: Add Write chunk WRs to the RPC's Send WR chain
svcrdma: Clean up use of rdma->sc_pd->device
svcrdma: Clean up use of rdma->sc_pd->device in Receive paths
svcrdma: Add fair queuing for Send Queue access
SUNRPC: Optimize rq_respages allocation in svc_alloc_arg
SUNRPC: Track consumed rq_pages entries
svcrdma: preserve rq_next_page in svc_rdma_save_io_pages
SUNRPC: Handle NULL entries in svc_rqst_release_pages
SUNRPC: Allocate a separate Reply page array
SUNRPC: Tighten bounds checking in svc_rqst_replace_page
NFSD: Sign filehandles
...

+4454 -1757
+30
Documentation/admin-guide/nfs/pnfs-block-server.rst
··· 40 40 41 41 echo "fencing client ${CLIENT} serial ${EVPD}" >> /var/log/pnfsd-fence.log 42 42 EOF 43 + 44 + If the nfsd server needs to fence a non-responding client and the 45 + fencing operation fails, the server logs a warning message in the 46 + system log with the following format: 47 + 48 + FENCE failed client[IP_address] clid[#n] device[dev_name] 49 + 50 + where: 51 + 52 + - IP_address: refers to the IP address of the affected client. 53 + - #n: indicates the unique client identifier. 54 + - dev_name: specifies the name of the block device related 55 + to the fencing attempt. 56 + 57 + The server will repeatedly retry the operation indefinitely. During 58 + this time, access to the affected file is restricted for all other 59 + clients. This is to prevent potential data corruption if multiple 60 + clients access the same file simultaneously. 61 + 62 + To restore access to the affected file for other clients, the admin 63 + needs to take the following actions: 64 + 65 + - shutdown or power off the client being fenced. 66 + - manually expire the client to release all its state on the server:: 67 + 68 + echo 'expire' > /proc/fs/nfsd/clients/clid/ctl 69 + 70 + where: 71 + 72 + - clid: is the unique client identifier displayed in the system log.
+31
Documentation/admin-guide/nfs/pnfs-scsi-server.rst
··· 22 22 On the client make sure the kernel has the CONFIG_PNFS_BLOCK option 23 23 enabled, and the file system is mounted using the NFSv4.1 protocol 24 24 version (mount -o vers=4.1). 25 + 26 + If the nfsd server needs to fence a non-responding client and the 27 + fencing operation fails, the server logs a warning message in the 28 + system log with the following format: 29 + 30 + FENCE failed client[IP_address] clid[#n] device[dev_name] 31 + 32 + where: 33 + 34 + - IP_address: refers to the IP address of the affected client. 35 + - #n: indicates the unique client identifier. 36 + - dev_name: specifies the name of the block device related 37 + to the fencing attempt. 38 + 39 + The server will repeatedly retry the operation indefinitely. During 40 + this time, access to the affected file is restricted for all other 41 + clients. This is to prevent potential data corruption if multiple 42 + clients access the same file simultaneously. 43 + 44 + To restore access to the affected file for other clients, the admin 45 + needs to take the following actions: 46 + 47 + - shutdown or power off the client being fenced. 48 + - manually expire the client to release all its state on the server:: 49 + 50 + echo 'expire' > /proc/fs/nfsd/clients/clid/ctl 51 + 52 + where: 53 + 54 + - clid: is the unique client identifier displayed in the system log. 55 +
+2
Documentation/filesystems/locking.rst
··· 398 398 bool (*lm_breaker_owns_lease)(struct file_lock *); 399 399 bool (*lm_lock_expirable)(struct file_lock *); 400 400 void (*lm_expire_lock)(void); 401 + bool (*lm_breaker_timedout)(struct file_lease *); 401 402 402 403 locking rules: 403 404 ··· 413 412 lm_lock_expirable yes no no 414 413 lm_expire_lock no no yes 415 414 lm_open_conflict yes no no 415 + lm_breaker_timedout yes no no 416 416 ====================== ============= ================= ========= 417 417 418 418 buffer_head
+85
Documentation/filesystems/nfs/exporting.rst
··· 206 206 all of an inode's dirty data on last close. Exports that behave this 207 207 way should set EXPORT_OP_FLUSH_ON_CLOSE so that NFSD knows to skip 208 208 waiting for writeback when closing such files. 209 + 210 + Signed Filehandles 211 + ------------------ 212 + 213 + To protect against filehandle guessing attacks, the Linux NFS server can be 214 + configured to sign filehandles with a Message Authentication Code (MAC). 215 + 216 + Standard NFS filehandles are often predictable. If an attacker can guess 217 + a valid filehandle for a file they do not have permission to access via 218 + directory traversal, they may be able to bypass path-based permissions 219 + (though they still remain subject to inode-level permissions). 220 + 221 + Signed filehandles prevent this by appending a MAC to the filehandle 222 + before it is sent to the client. Upon receiving a filehandle back from a 223 + client, the server re-calculates the MAC using its internal key and 224 + verifies it against the one provided. If the signatures do not match, 225 + the server treats the filehandle as invalid (returning NFS[34]ERR_STALE). 226 + 227 + Note that signing filehandles provides integrity and authenticity but 228 + not confidentiality. The contents of the filehandle remain visible to 229 + the client; they simply cannot be forged or modified. 230 + 231 + Configuration 232 + ~~~~~~~~~~~~~ 233 + 234 + To enable signed filehandles, the administrator must provide a signing 235 + key to the kernel and enable the "sign_fh" export option. 236 + 237 + 1. Providing a Key 238 + The signing key is managed via the nfsd netlink interface. This key 239 + is per-network-namespace and must be set before any exports using 240 + "sign_fh" become active. 241 + 242 + 2. Export Options 243 + The feature is controlled on a per-export basis in /etc/exports: 244 + 245 + sign_fh 246 + Enables signing for all filehandles generated under this export. 247 + 248 + no_sign_fh 249 + (Default) Disables signing. 250 + 251 + Key Management and Rotation 252 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 253 + 254 + The security of this mechanism relies entirely on the secrecy of the 255 + signing key. 256 + 257 + Initial Setup: 258 + The key should be generated using a high-quality random source and 259 + loaded early in the boot process or during the nfs-server startup 260 + sequence. 261 + 262 + Changing Keys: 263 + If a key is changed while clients have active mounts, existing 264 + filehandles held by those clients will become invalid, resulting in 265 + "Stale file handle" errors on the client side. 266 + 267 + Safe Rotation: 268 + Currently, there is no mechanism for "graceful" key rotation 269 + (maintaining multiple valid keys). Changing the key is an atomic 270 + operation that immediately invalidates all previous signatures. 271 + 272 + Transitioning Exports 273 + ~~~~~~~~~~~~~~~~~~~~~ 274 + 275 + When adding or removing the "sign_fh" flag from an active export, the 276 + following behaviors should be expected: 277 + 278 + +-------------------+---------------------------------------------------+ 279 + | Change | Result for Existing Clients | 280 + +===================+===================================================+ 281 + | Adding sign_fh | Clients holding unsigned filehandles will find | 282 + | | them rejected, as the server now expects a | 283 + | | signature. | 284 + +-------------------+---------------------------------------------------+ 285 + | Removing sign_fh | Clients holding signed filehandles will find them | 286 + | | rejected, as the server now expects the | 287 + | | filehandle to end at its traditional boundary | 288 + | | without a MAC. | 289 + +-------------------+---------------------------------------------------+ 290 + 291 + Because filehandles are often cached persistently by clients, adding or 292 + removing this option should generally be done during a scheduled maintenance 293 + window involving a NFS client unmount/remount.
+6
Documentation/netlink/specs/nfsd.yaml
··· 81 81 - 82 82 name: min-threads 83 83 type: u32 84 + - 85 + name: fh-key 86 + type: binary 87 + checks: 88 + exact-len: 16 84 89 - 85 90 name: version 86 91 attributes: ··· 168 163 - leasetime 169 164 - scope 170 165 - min-threads 166 + - fh-key 171 167 - 172 168 name: threads-get 173 169 doc: get the maximum number of running threads
+211
Documentation/sunrpc/xdr/nlm4.x
··· 1 + /* 2 + * This file was extracted by hand from 3 + * https://www.rfc-editor.org/rfc/rfc1813.html . 4 + * 5 + * Note that RFC 1813 is Informational. Its official date of 6 + * publication (June 1995) is before the IETF required its RFCs to 7 + * carry an explicit copyright or other IP ownership notices. 8 + * 9 + * Note also that RFC 1813 does not specify the whole NLM4 protocol. 10 + * In particular, the argument and result types are not present in 11 + * that document, and had to be reverse-engineered. 12 + */ 13 + 14 + /* 15 + * The NLMv4 protocol 16 + */ 17 + 18 + pragma header nlm4; 19 + 20 + /* 21 + * The following definitions are missing in RFC 1813, 22 + * but can be found in the OpenNetworking Network Lock 23 + * Manager protocol: 24 + * 25 + * https://pubs.opengroup.org/onlinepubs/9629799/chap10.htm 26 + */ 27 + 28 + const LM_MAXSTRLEN = 1024; 29 + 30 + const LM_MAXNAMELEN = 1025; 31 + 32 + const MAXNETOBJ_SZ = 1024; 33 + 34 + typedef opaque netobj<MAXNETOBJ_SZ>; 35 + 36 + enum fsh4_mode { 37 + fsm_DN = 0, /* deny none */ 38 + fsm_DR = 1, /* deny read */ 39 + fsm_DW = 2, /* deny write */ 40 + fsm_DRW = 3 /* deny read/write */ 41 + }; 42 + 43 + enum fsh4_access { 44 + fsa_NONE = 0, /* for completeness */ 45 + fsa_R = 1, /* read-only */ 46 + fsa_W = 2, /* write-only */ 47 + fsa_RW = 3 /* read/write */ 48 + }; 49 + 50 + /* 51 + * The following definitions come from the OpenNetworking 52 + * Network Status Monitor protocol: 53 + * 54 + * https://pubs.opengroup.org/onlinepubs/9629799/chap11.htm 55 + */ 56 + 57 + const SM_MAXSTRLEN = 1024; 58 + 59 + /* 60 + * The NLM protocol as extracted from: 61 + * https://tools.ietf.org/html/rfc1813 Appendix II 62 + */ 63 + 64 + typedef unsigned hyper uint64; 65 + 66 + typedef hyper int64; 67 + 68 + typedef unsigned long uint32; 69 + 70 + typedef long int32; 71 + 72 + enum nlm4_stats { 73 + NLM4_GRANTED = 0, 74 + NLM4_DENIED = 1, 75 + NLM4_DENIED_NOLOCKS = 2, 76 + NLM4_BLOCKED = 3, 77 + NLM4_DENIED_GRACE_PERIOD = 4, 78 + NLM4_DEADLCK = 5, 79 + NLM4_ROFS = 6, 80 + NLM4_STALE_FH = 7, 81 + NLM4_FBIG = 8, 82 + NLM4_FAILED = 9 83 + }; 84 + 85 + pragma big_endian nlm4_stats; 86 + 87 + struct nlm4_holder { 88 + bool exclusive; 89 + int32 svid; 90 + netobj oh; 91 + uint64 l_offset; 92 + uint64 l_len; 93 + }; 94 + 95 + union nlm4_testrply switch (nlm4_stats stat) { 96 + case NLM4_DENIED: 97 + nlm4_holder holder; 98 + default: 99 + void; 100 + }; 101 + 102 + struct nlm4_stat { 103 + nlm4_stats stat; 104 + }; 105 + 106 + struct nlm4_res { 107 + netobj cookie; 108 + nlm4_stat stat; 109 + }; 110 + 111 + struct nlm4_testres { 112 + netobj cookie; 113 + nlm4_testrply stat; 114 + }; 115 + 116 + struct nlm4_lock { 117 + string caller_name<LM_MAXSTRLEN>; 118 + netobj fh; 119 + netobj oh; 120 + int32 svid; 121 + uint64 l_offset; 122 + uint64 l_len; 123 + }; 124 + 125 + struct nlm4_lockargs { 126 + netobj cookie; 127 + bool block; 128 + bool exclusive; 129 + nlm4_lock alock; 130 + bool reclaim; 131 + int32 state; 132 + }; 133 + 134 + struct nlm4_cancargs { 135 + netobj cookie; 136 + bool block; 137 + bool exclusive; 138 + nlm4_lock alock; 139 + }; 140 + 141 + struct nlm4_testargs { 142 + netobj cookie; 143 + bool exclusive; 144 + nlm4_lock alock; 145 + }; 146 + 147 + struct nlm4_unlockargs { 148 + netobj cookie; 149 + nlm4_lock alock; 150 + }; 151 + 152 + struct nlm4_share { 153 + string caller_name<LM_MAXSTRLEN>; 154 + netobj fh; 155 + netobj oh; 156 + fsh4_mode mode; 157 + fsh4_access access; 158 + }; 159 + 160 + struct nlm4_shareargs { 161 + netobj cookie; 162 + nlm4_share share; 163 + bool reclaim; 164 + }; 165 + 166 + struct nlm4_shareres { 167 + netobj cookie; 168 + nlm4_stats stat; 169 + int32 sequence; 170 + }; 171 + 172 + struct nlm4_notify { 173 + string name<LM_MAXNAMELEN>; 174 + int32 state; 175 + }; 176 + 177 + /* 178 + * Argument for the Linux-private SM_NOTIFY procedure 179 + */ 180 + const SM_PRIV_SIZE = 16; 181 + 182 + struct nlm4_notifyargs { 183 + nlm4_notify notify; 184 + opaque private[SM_PRIV_SIZE]; 185 + }; 186 + 187 + program NLM4_PROG { 188 + version NLM4_VERS { 189 + void NLMPROC4_NULL(void) = 0; 190 + nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1; 191 + nlm4_res NLMPROC4_LOCK(nlm4_lockargs) = 2; 192 + nlm4_res NLMPROC4_CANCEL(nlm4_cancargs) = 3; 193 + nlm4_res NLMPROC4_UNLOCK(nlm4_unlockargs) = 4; 194 + nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5; 195 + void NLMPROC4_TEST_MSG(nlm4_testargs) = 6; 196 + void NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7; 197 + void NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8; 198 + void NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9; 199 + void NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10; 200 + void NLMPROC4_TEST_RES(nlm4_testres) = 11; 201 + void NLMPROC4_LOCK_RES(nlm4_res) = 12; 202 + void NLMPROC4_CANCEL_RES(nlm4_res) = 13; 203 + void NLMPROC4_UNLOCK_RES(nlm4_res) = 14; 204 + void NLMPROC4_GRANTED_RES(nlm4_res) = 15; 205 + void NLMPROC4_SM_NOTIFY(nlm4_notifyargs) = 16; 206 + nlm4_shareres NLMPROC4_SHARE(nlm4_shareargs) = 20; 207 + nlm4_shareres NLMPROC4_UNSHARE(nlm4_shareargs) = 21; 208 + nlm4_res NLMPROC4_NM_LOCK(nlm4_lockargs) = 22; 209 + void NLMPROC4_FREE_ALL(nlm4_notify) = 23; 210 + } = 4; 211 + } = 100021;
+29 -1
fs/lockd/Makefile
··· 9 9 10 10 lockd-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \ 11 11 svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o 12 - lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o 12 + lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o svc4proc.o nlm4xdr_gen.o 13 13 lockd-$(CONFIG_PROC_FS) += procfs.o 14 + 15 + # 16 + # XDR code generation (requires Python and additional packages) 17 + # 18 + # The generated *xdr_gen.{h,c} files are checked into git. Normal kernel 19 + # builds do not require the xdrgen tool or its Python dependencies. 20 + # 21 + # Developers modifying .x files in Documentation/sunrpc/xdr/ should run 22 + # "make xdrgen" to regenerate the affected files. 23 + # 24 + .PHONY: xdrgen 25 + 26 + XDRGEN = ../../tools/net/sunrpc/xdrgen/xdrgen 27 + 28 + XDRGEN_DEFINITIONS = ../../include/linux/sunrpc/xdrgen/nlm4.h 29 + XDRGEN_DECLARATIONS = nlm4xdr_gen.h 30 + XDRGEN_SOURCE = nlm4xdr_gen.c 31 + 32 + xdrgen: $(XDRGEN_DEFINITIONS) $(XDRGEN_DECLARATIONS) $(XDRGEN_SOURCE) 33 + 34 + ../../include/linux/sunrpc/xdrgen/nlm4.h: ../../Documentation/sunrpc/xdr/nlm4.x 35 + $(XDRGEN) definitions $< > $@ 36 + 37 + nlm4xdr_gen.h: ../../Documentation/sunrpc/xdr/nlm4.x 38 + $(XDRGEN) declarations $< > $@ 39 + 40 + nlm4xdr_gen.c: ../../Documentation/sunrpc/xdr/nlm4.x 41 + $(XDRGEN) source --peer server $< > $@
+3 -2
fs/lockd/clnt4xdr.c
··· 13 13 #include <linux/sunrpc/xdr.h> 14 14 #include <linux/sunrpc/clnt.h> 15 15 #include <linux/sunrpc/stats.h> 16 - #include <linux/lockd/lockd.h> 16 + 17 + #include "lockd.h" 17 18 18 19 #include <uapi/linux/nfs3.h> 19 20 ··· 285 284 fl->c.flc_type = exclusive != 0 ? F_WRLCK : F_RDLCK; 286 285 p = xdr_decode_hyper(p, &l_offset); 287 286 xdr_decode_hyper(p, &l_len); 288 - nlm4svc_set_file_lock_range(fl, l_offset, l_len); 287 + lockd_set_file_lock_range4(fl, l_offset, l_len); 289 288 error = 0; 290 289 out: 291 290 return error;
+1 -1
fs/lockd/clntlock.c
··· 15 15 #include <linux/sunrpc/addr.h> 16 16 #include <linux/sunrpc/svc.h> 17 17 #include <linux/sunrpc/svc_xprt.h> 18 - #include <linux/lockd/lockd.h> 19 18 #include <linux/kthread.h> 20 19 20 + #include "lockd.h" 21 21 #include "trace.h" 22 22 23 23 #define NLMDBG_FACILITY NLMDBG_CLIENT
+1 -1
fs/lockd/clntproc.c
··· 18 18 #include <linux/freezer.h> 19 19 #include <linux/sunrpc/clnt.h> 20 20 #include <linux/sunrpc/svc.h> 21 - #include <linux/lockd/lockd.h> 22 21 22 + #include "lockd.h" 23 23 #include "trace.h" 24 24 25 25 #define NLMDBG_FACILITY NLMDBG_CLIENT
+2 -1
fs/lockd/clntxdr.c
··· 15 15 #include <linux/sunrpc/xdr.h> 16 16 #include <linux/sunrpc/clnt.h> 17 17 #include <linux/sunrpc/stats.h> 18 - #include <linux/lockd/lockd.h> 18 + 19 + #include "lockd.h" 19 20 20 21 #include <uapi/linux/nfs2.h> 21 22
+30 -1
fs/lockd/host.c
··· 16 16 #include <linux/sunrpc/clnt.h> 17 17 #include <linux/sunrpc/addr.h> 18 18 #include <linux/sunrpc/svc.h> 19 - #include <linux/lockd/lockd.h> 20 19 #include <linux/mutex.h> 21 20 22 21 #include <linux/sunrpc/svc_xprt.h> 23 22 24 23 #include <net/ipv6.h> 25 24 25 + #include "lockd.h" 26 26 #include "netns.h" 27 27 28 28 #define NLMDBG_FACILITY NLMDBG_HOSTCACHE ··· 305 305 mutex_unlock(&nlm_host_mutex); 306 306 } 307 307 } 308 + 309 + /* Callback for rpc_cancel_tasks() - matches all tasks for cancellation */ 310 + static bool nlmclnt_match_all(const struct rpc_task *task, const void *data) 311 + { 312 + return true; 313 + } 314 + 315 + /** 316 + * nlmclnt_shutdown_rpc_clnt - safely shut down NLM client RPC operations 317 + * @host: nlm_host to shut down 318 + * 319 + * Cancels outstanding RPC tasks and marks the client as shut down. 320 + * Synchronizes with nlmclnt_release_host() via nlm_host_mutex to prevent 321 + * races between shutdown and host destruction. Safe to call if h_rpcclnt 322 + * is NULL or already shut down. 323 + */ 324 + void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host) 325 + { 326 + struct rpc_clnt *clnt; 327 + 328 + mutex_lock(&nlm_host_mutex); 329 + clnt = host->h_rpcclnt; 330 + if (clnt) { 331 + clnt->cl_shutdown = 1; 332 + rpc_cancel_tasks(clnt, -EIO, nlmclnt_match_all, NULL); 333 + } 334 + mutex_unlock(&nlm_host_mutex); 335 + } 336 + EXPORT_SYMBOL_GPL(nlmclnt_shutdown_rpc_clnt); 308 337 309 338 /** 310 339 * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
+1 -1
fs/lockd/mon.c
··· 16 16 #include <linux/sunrpc/addr.h> 17 17 #include <linux/sunrpc/xprtsock.h> 18 18 #include <linux/sunrpc/svc.h> 19 - #include <linux/lockd/lockd.h> 20 19 21 20 #include <linux/unaligned.h> 22 21 22 + #include "lockd.h" 23 23 #include "netns.h" 24 24 25 25 #define NLMDBG_FACILITY NLMDBG_MONITOR
+724
fs/lockd/nlm4xdr_gen.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Generated by xdrgen. Manual edits will be lost. 3 + // XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x 4 + // XDR specification modification time: Thu Dec 25 13:10:19 2025 5 + 6 + #include <linux/sunrpc/svc.h> 7 + 8 + #include "nlm4xdr_gen.h" 9 + 10 + static bool __maybe_unused 11 + xdrgen_decode_netobj(struct xdr_stream *xdr, netobj *ptr) 12 + { 13 + return xdrgen_decode_opaque(xdr, ptr, MAXNETOBJ_SZ); 14 + } 15 + 16 + static bool __maybe_unused 17 + xdrgen_decode_fsh4_mode(struct xdr_stream *xdr, fsh4_mode *ptr) 18 + { 19 + u32 val; 20 + 21 + if (xdr_stream_decode_u32(xdr, &val) < 0) 22 + return false; 23 + *ptr = val; 24 + return true; 25 + } 26 + 27 + static bool __maybe_unused 28 + xdrgen_decode_fsh4_access(struct xdr_stream *xdr, fsh4_access *ptr) 29 + { 30 + u32 val; 31 + 32 + if (xdr_stream_decode_u32(xdr, &val) < 0) 33 + return false; 34 + *ptr = val; 35 + return true; 36 + } 37 + 38 + static bool __maybe_unused 39 + xdrgen_decode_uint64(struct xdr_stream *xdr, uint64 *ptr) 40 + { 41 + return xdrgen_decode_unsigned_hyper(xdr, ptr); 42 + } 43 + 44 + static bool __maybe_unused 45 + xdrgen_decode_int64(struct xdr_stream *xdr, int64 *ptr) 46 + { 47 + return xdrgen_decode_hyper(xdr, ptr); 48 + } 49 + 50 + static bool __maybe_unused 51 + xdrgen_decode_uint32(struct xdr_stream *xdr, uint32 *ptr) 52 + { 53 + return xdrgen_decode_unsigned_long(xdr, ptr); 54 + } 55 + 56 + static bool __maybe_unused 57 + xdrgen_decode_int32(struct xdr_stream *xdr, int32 *ptr) 58 + { 59 + return xdrgen_decode_long(xdr, ptr); 60 + } 61 + 62 + static bool __maybe_unused 63 + xdrgen_decode_nlm4_stats(struct xdr_stream *xdr, nlm4_stats *ptr) 64 + { 65 + return xdr_stream_decode_be32(xdr, ptr) == 0; 66 + } 67 + 68 + static bool __maybe_unused 69 + xdrgen_decode_nlm4_holder(struct xdr_stream *xdr, struct nlm4_holder *ptr) 70 + { 71 + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) 72 + return false; 73 + if (!xdrgen_decode_int32(xdr, &ptr->svid)) 74 + return false; 75 + if (!xdrgen_decode_netobj(xdr, &ptr->oh)) 76 + return false; 77 + if (!xdrgen_decode_uint64(xdr, &ptr->l_offset)) 78 + return false; 79 + if (!xdrgen_decode_uint64(xdr, &ptr->l_len)) 80 + return false; 81 + return true; 82 + } 83 + 84 + static bool __maybe_unused 85 + xdrgen_decode_nlm4_testrply(struct xdr_stream *xdr, struct nlm4_testrply *ptr) 86 + { 87 + if (!xdrgen_decode_nlm4_stats(xdr, &ptr->stat)) 88 + return false; 89 + switch (ptr->stat) { 90 + case __constant_cpu_to_be32(NLM4_DENIED): 91 + if (!xdrgen_decode_nlm4_holder(xdr, &ptr->u.holder)) 92 + return false; 93 + break; 94 + default: 95 + break; 96 + } 97 + return true; 98 + } 99 + 100 + static bool __maybe_unused 101 + xdrgen_decode_nlm4_stat(struct xdr_stream *xdr, struct nlm4_stat *ptr) 102 + { 103 + if (!xdrgen_decode_nlm4_stats(xdr, &ptr->stat)) 104 + return false; 105 + return true; 106 + } 107 + 108 + static bool __maybe_unused 109 + xdrgen_decode_nlm4_res(struct xdr_stream *xdr, struct nlm4_res *ptr) 110 + { 111 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 112 + return false; 113 + if (!xdrgen_decode_nlm4_stat(xdr, &ptr->stat)) 114 + return false; 115 + return true; 116 + } 117 + 118 + static bool __maybe_unused 119 + xdrgen_decode_nlm4_testres(struct xdr_stream *xdr, struct nlm4_testres *ptr) 120 + { 121 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 122 + return false; 123 + if (!xdrgen_decode_nlm4_testrply(xdr, &ptr->stat)) 124 + return false; 125 + return true; 126 + } 127 + 128 + static bool __maybe_unused 129 + xdrgen_decode_nlm4_lock(struct xdr_stream *xdr, struct nlm4_lock *ptr) 130 + { 131 + if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN)) 132 + return false; 133 + if (!xdrgen_decode_netobj(xdr, &ptr->fh)) 134 + return false; 135 + if (!xdrgen_decode_netobj(xdr, &ptr->oh)) 136 + return false; 137 + if (!xdrgen_decode_int32(xdr, &ptr->svid)) 138 + return false; 139 + if (!xdrgen_decode_uint64(xdr, &ptr->l_offset)) 140 + return false; 141 + if (!xdrgen_decode_uint64(xdr, &ptr->l_len)) 142 + return false; 143 + return true; 144 + } 145 + 146 + static bool __maybe_unused 147 + xdrgen_decode_nlm4_lockargs(struct xdr_stream *xdr, struct nlm4_lockargs *ptr) 148 + { 149 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 150 + return false; 151 + if (!xdrgen_decode_bool(xdr, &ptr->block)) 152 + return false; 153 + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) 154 + return false; 155 + if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock)) 156 + return false; 157 + if (!xdrgen_decode_bool(xdr, &ptr->reclaim)) 158 + return false; 159 + if (!xdrgen_decode_int32(xdr, &ptr->state)) 160 + return false; 161 + return true; 162 + } 163 + 164 + static bool __maybe_unused 165 + xdrgen_decode_nlm4_cancargs(struct xdr_stream *xdr, struct nlm4_cancargs *ptr) 166 + { 167 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 168 + return false; 169 + if (!xdrgen_decode_bool(xdr, &ptr->block)) 170 + return false; 171 + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) 172 + return false; 173 + if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock)) 174 + return false; 175 + return true; 176 + } 177 + 178 + static bool __maybe_unused 179 + xdrgen_decode_nlm4_testargs(struct xdr_stream *xdr, struct nlm4_testargs *ptr) 180 + { 181 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 182 + return false; 183 + if (!xdrgen_decode_bool(xdr, &ptr->exclusive)) 184 + return false; 185 + if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock)) 186 + return false; 187 + return true; 188 + } 189 + 190 + static bool __maybe_unused 191 + xdrgen_decode_nlm4_unlockargs(struct xdr_stream *xdr, struct nlm4_unlockargs *ptr) 192 + { 193 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 194 + return false; 195 + if (!xdrgen_decode_nlm4_lock(xdr, &ptr->alock)) 196 + return false; 197 + return true; 198 + } 199 + 200 + static bool __maybe_unused 201 + xdrgen_decode_nlm4_share(struct xdr_stream *xdr, struct nlm4_share *ptr) 202 + { 203 + if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN)) 204 + return false; 205 + if (!xdrgen_decode_netobj(xdr, &ptr->fh)) 206 + return false; 207 + if (!xdrgen_decode_netobj(xdr, &ptr->oh)) 208 + return false; 209 + if (!xdrgen_decode_fsh4_mode(xdr, &ptr->mode)) 210 + return false; 211 + if (!xdrgen_decode_fsh4_access(xdr, &ptr->access)) 212 + return false; 213 + return true; 214 + } 215 + 216 + static bool __maybe_unused 217 + xdrgen_decode_nlm4_shareargs(struct xdr_stream *xdr, struct nlm4_shareargs *ptr) 218 + { 219 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 220 + return false; 221 + if (!xdrgen_decode_nlm4_share(xdr, &ptr->share)) 222 + return false; 223 + if (!xdrgen_decode_bool(xdr, &ptr->reclaim)) 224 + return false; 225 + return true; 226 + } 227 + 228 + static bool __maybe_unused 229 + xdrgen_decode_nlm4_shareres(struct xdr_stream *xdr, struct nlm4_shareres *ptr) 230 + { 231 + if (!xdrgen_decode_netobj(xdr, &ptr->cookie)) 232 + return false; 233 + if (!xdrgen_decode_nlm4_stats(xdr, &ptr->stat)) 234 + return false; 235 + if (!xdrgen_decode_int32(xdr, &ptr->sequence)) 236 + return false; 237 + return true; 238 + } 239 + 240 + static bool __maybe_unused 241 + xdrgen_decode_nlm4_notify(struct xdr_stream *xdr, struct nlm4_notify *ptr) 242 + { 243 + if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXNAMELEN)) 244 + return false; 245 + if (!xdrgen_decode_int32(xdr, &ptr->state)) 246 + return false; 247 + return true; 248 + } 249 + 250 + static bool __maybe_unused 251 + xdrgen_decode_nlm4_notifyargs(struct xdr_stream *xdr, struct nlm4_notifyargs *ptr) 252 + { 253 + if (!xdrgen_decode_nlm4_notify(xdr, &ptr->notify)) 254 + return false; 255 + if (xdr_stream_decode_opaque_fixed(xdr, ptr->private, SM_PRIV_SIZE) < 0) 256 + return false; 257 + return true; 258 + } 259 + 260 + /** 261 + * nlm4_svc_decode_void - Decode a void argument 262 + * @rqstp: RPC transaction context 263 + * @xdr: source XDR data stream 264 + * 265 + * Return values: 266 + * %true: procedure arguments decoded successfully 267 + * %false: decode failed 268 + */ 269 + bool nlm4_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 270 + { 271 + return xdrgen_decode_void(xdr); 272 + } 273 + 274 + /** 275 + * nlm4_svc_decode_nlm4_testargs - Decode a nlm4_testargs argument 276 + * @rqstp: RPC transaction context 277 + * @xdr: source XDR data stream 278 + * 279 + * Return values: 280 + * %true: procedure arguments decoded successfully 281 + * %false: decode failed 282 + */ 283 + bool nlm4_svc_decode_nlm4_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 284 + { 285 + struct nlm4_testargs *argp = rqstp->rq_argp; 286 + 287 + return xdrgen_decode_nlm4_testargs(xdr, argp); 288 + } 289 + 290 + /** 291 + * nlm4_svc_decode_nlm4_lockargs - Decode a nlm4_lockargs argument 292 + * @rqstp: RPC transaction context 293 + * @xdr: source XDR data stream 294 + * 295 + * Return values: 296 + * %true: procedure arguments decoded successfully 297 + * %false: decode failed 298 + */ 299 + bool nlm4_svc_decode_nlm4_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 300 + { 301 + struct nlm4_lockargs *argp = rqstp->rq_argp; 302 + 303 + return xdrgen_decode_nlm4_lockargs(xdr, argp); 304 + } 305 + 306 + /** 307 + * nlm4_svc_decode_nlm4_cancargs - Decode a nlm4_cancargs argument 308 + * @rqstp: RPC transaction context 309 + * @xdr: source XDR data stream 310 + * 311 + * Return values: 312 + * %true: procedure arguments decoded successfully 313 + * %false: decode failed 314 + */ 315 + bool nlm4_svc_decode_nlm4_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 316 + { 317 + struct nlm4_cancargs *argp = rqstp->rq_argp; 318 + 319 + return xdrgen_decode_nlm4_cancargs(xdr, argp); 320 + } 321 + 322 + /** 323 + * nlm4_svc_decode_nlm4_unlockargs - Decode a nlm4_unlockargs argument 324 + * @rqstp: RPC transaction context 325 + * @xdr: source XDR data stream 326 + * 327 + * Return values: 328 + * %true: procedure arguments decoded successfully 329 + * %false: decode failed 330 + */ 331 + bool nlm4_svc_decode_nlm4_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 332 + { 333 + struct nlm4_unlockargs *argp = rqstp->rq_argp; 334 + 335 + return xdrgen_decode_nlm4_unlockargs(xdr, argp); 336 + } 337 + 338 + /** 339 + * nlm4_svc_decode_nlm4_testres - Decode a nlm4_testres argument 340 + * @rqstp: RPC transaction context 341 + * @xdr: source XDR data stream 342 + * 343 + * Return values: 344 + * %true: procedure arguments decoded successfully 345 + * %false: decode failed 346 + */ 347 + bool nlm4_svc_decode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 348 + { 349 + struct nlm4_testres *argp = rqstp->rq_argp; 350 + 351 + return xdrgen_decode_nlm4_testres(xdr, argp); 352 + } 353 + 354 + /** 355 + * nlm4_svc_decode_nlm4_res - Decode a nlm4_res argument 356 + * @rqstp: RPC transaction context 357 + * @xdr: source XDR data stream 358 + * 359 + * Return values: 360 + * %true: procedure arguments decoded successfully 361 + * %false: decode failed 362 + */ 363 + bool nlm4_svc_decode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) 364 + { 365 + struct nlm4_res *argp = rqstp->rq_argp; 366 + 367 + return xdrgen_decode_nlm4_res(xdr, argp); 368 + } 369 + 370 + /** 371 + * nlm4_svc_decode_nlm4_notifyargs - Decode a nlm4_notifyargs argument 372 + * @rqstp: RPC transaction context 373 + * @xdr: source XDR data stream 374 + * 375 + * Return values: 376 + * %true: procedure arguments decoded successfully 377 + * %false: decode failed 378 + */ 379 + bool nlm4_svc_decode_nlm4_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 380 + { 381 + struct nlm4_notifyargs *argp = rqstp->rq_argp; 382 + 383 + return xdrgen_decode_nlm4_notifyargs(xdr, argp); 384 + } 385 + 386 + /** 387 + * nlm4_svc_decode_nlm4_shareargs - Decode a nlm4_shareargs argument 388 + * @rqstp: RPC transaction context 389 + * @xdr: source XDR data stream 390 + * 391 + * Return values: 392 + * %true: procedure arguments decoded successfully 393 + * %false: decode failed 394 + */ 395 + bool nlm4_svc_decode_nlm4_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 396 + { 397 + struct nlm4_shareargs *argp = rqstp->rq_argp; 398 + 399 + return xdrgen_decode_nlm4_shareargs(xdr, argp); 400 + } 401 + 402 + /** 403 + * nlm4_svc_decode_nlm4_notify - Decode a nlm4_notify argument 404 + * @rqstp: RPC transaction context 405 + * @xdr: source XDR data stream 406 + * 407 + * Return values: 408 + * %true: procedure arguments decoded successfully 409 + * %false: decode failed 410 + */ 411 + bool nlm4_svc_decode_nlm4_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) 412 + { 413 + struct nlm4_notify *argp = rqstp->rq_argp; 414 + 415 + return xdrgen_decode_nlm4_notify(xdr, argp); 416 + } 417 + 418 + static bool __maybe_unused 419 + xdrgen_encode_netobj(struct xdr_stream *xdr, const netobj value) 420 + { 421 + return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0; 422 + } 423 + 424 + static bool __maybe_unused 425 + xdrgen_encode_fsh4_mode(struct xdr_stream *xdr, fsh4_mode value) 426 + { 427 + return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; 428 + } 429 + 430 + static bool __maybe_unused 431 + xdrgen_encode_fsh4_access(struct xdr_stream *xdr, fsh4_access value) 432 + { 433 + return xdr_stream_encode_u32(xdr, value) == XDR_UNIT; 434 + } 435 + 436 + static bool __maybe_unused 437 + xdrgen_encode_uint64(struct xdr_stream *xdr, const uint64 value) 438 + { 439 + return xdrgen_encode_unsigned_hyper(xdr, value); 440 + } 441 + 442 + static bool __maybe_unused 443 + xdrgen_encode_int64(struct xdr_stream *xdr, const int64 value) 444 + { 445 + return xdrgen_encode_hyper(xdr, value); 446 + } 447 + 448 + static bool __maybe_unused 449 + xdrgen_encode_uint32(struct xdr_stream *xdr, const uint32 value) 450 + { 451 + return xdrgen_encode_unsigned_long(xdr, value); 452 + } 453 + 454 + static bool __maybe_unused 455 + xdrgen_encode_int32(struct xdr_stream *xdr, const int32 value) 456 + { 457 + return xdrgen_encode_long(xdr, value); 458 + } 459 + 460 + static bool __maybe_unused 461 + xdrgen_encode_nlm4_stats(struct xdr_stream *xdr, nlm4_stats value) 462 + { 463 + return xdr_stream_encode_be32(xdr, value) == XDR_UNIT; 464 + } 465 + 466 + static bool __maybe_unused 467 + xdrgen_encode_nlm4_holder(struct xdr_stream *xdr, const struct nlm4_holder *value) 468 + { 469 + if (!xdrgen_encode_bool(xdr, value->exclusive)) 470 + return false; 471 + if (!xdrgen_encode_int32(xdr, value->svid)) 472 + return false; 473 + if (!xdrgen_encode_netobj(xdr, value->oh)) 474 + return false; 475 + if (!xdrgen_encode_uint64(xdr, value->l_offset)) 476 + return false; 477 + if (!xdrgen_encode_uint64(xdr, value->l_len)) 478 + return false; 479 + return true; 480 + } 481 + 482 + static bool __maybe_unused 483 + xdrgen_encode_nlm4_testrply(struct xdr_stream *xdr, const struct nlm4_testrply *ptr) 484 + { 485 + if (!xdrgen_encode_nlm4_stats(xdr, ptr->stat)) 486 + return false; 487 + switch (ptr->stat) { 488 + case __constant_cpu_to_be32(NLM4_DENIED): 489 + if (!xdrgen_encode_nlm4_holder(xdr, &ptr->u.holder)) 490 + return false; 491 + break; 492 + default: 493 + break; 494 + } 495 + return true; 496 + } 497 + 498 + static bool __maybe_unused 499 + xdrgen_encode_nlm4_stat(struct xdr_stream *xdr, const struct nlm4_stat *value) 500 + { 501 + if (!xdrgen_encode_nlm4_stats(xdr, value->stat)) 502 + return false; 503 + return true; 504 + } 505 + 506 + static bool __maybe_unused 507 + xdrgen_encode_nlm4_res(struct xdr_stream *xdr, const struct nlm4_res *value) 508 + { 509 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 510 + return false; 511 + if (!xdrgen_encode_nlm4_stat(xdr, &value->stat)) 512 + return false; 513 + return true; 514 + } 515 + 516 + static bool __maybe_unused 517 + xdrgen_encode_nlm4_testres(struct xdr_stream *xdr, const struct nlm4_testres *value) 518 + { 519 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 520 + return false; 521 + if (!xdrgen_encode_nlm4_testrply(xdr, &value->stat)) 522 + return false; 523 + return true; 524 + } 525 + 526 + static bool __maybe_unused 527 + xdrgen_encode_nlm4_lock(struct xdr_stream *xdr, const struct nlm4_lock *value) 528 + { 529 + if (value->caller_name.len > LM_MAXSTRLEN) 530 + return false; 531 + if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0) 532 + return false; 533 + if (!xdrgen_encode_netobj(xdr, value->fh)) 534 + return false; 535 + if (!xdrgen_encode_netobj(xdr, value->oh)) 536 + return false; 537 + if (!xdrgen_encode_int32(xdr, value->svid)) 538 + return false; 539 + if (!xdrgen_encode_uint64(xdr, value->l_offset)) 540 + return false; 541 + if (!xdrgen_encode_uint64(xdr, value->l_len)) 542 + return false; 543 + return true; 544 + } 545 + 546 + static bool __maybe_unused 547 + xdrgen_encode_nlm4_lockargs(struct xdr_stream *xdr, const struct nlm4_lockargs *value) 548 + { 549 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 550 + return false; 551 + if (!xdrgen_encode_bool(xdr, value->block)) 552 + return false; 553 + if (!xdrgen_encode_bool(xdr, value->exclusive)) 554 + return false; 555 + if (!xdrgen_encode_nlm4_lock(xdr, &value->alock)) 556 + return false; 557 + if (!xdrgen_encode_bool(xdr, value->reclaim)) 558 + return false; 559 + if (!xdrgen_encode_int32(xdr, value->state)) 560 + return false; 561 + return true; 562 + } 563 + 564 + static bool __maybe_unused 565 + xdrgen_encode_nlm4_cancargs(struct xdr_stream *xdr, const struct nlm4_cancargs *value) 566 + { 567 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 568 + return false; 569 + if (!xdrgen_encode_bool(xdr, value->block)) 570 + return false; 571 + if (!xdrgen_encode_bool(xdr, value->exclusive)) 572 + return false; 573 + if (!xdrgen_encode_nlm4_lock(xdr, &value->alock)) 574 + return false; 575 + return true; 576 + } 577 + 578 + static bool __maybe_unused 579 + xdrgen_encode_nlm4_testargs(struct xdr_stream *xdr, const struct nlm4_testargs *value) 580 + { 581 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 582 + return false; 583 + if (!xdrgen_encode_bool(xdr, value->exclusive)) 584 + return false; 585 + if (!xdrgen_encode_nlm4_lock(xdr, &value->alock)) 586 + return false; 587 + return true; 588 + } 589 + 590 + static bool __maybe_unused 591 + xdrgen_encode_nlm4_unlockargs(struct xdr_stream *xdr, const struct nlm4_unlockargs *value) 592 + { 593 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 594 + return false; 595 + if (!xdrgen_encode_nlm4_lock(xdr, &value->alock)) 596 + return false; 597 + return true; 598 + } 599 + 600 + static bool __maybe_unused 601 + xdrgen_encode_nlm4_share(struct xdr_stream *xdr, const struct nlm4_share *value) 602 + { 603 + if (value->caller_name.len > LM_MAXSTRLEN) 604 + return false; 605 + if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0) 606 + return false; 607 + if (!xdrgen_encode_netobj(xdr, value->fh)) 608 + return false; 609 + if (!xdrgen_encode_netobj(xdr, value->oh)) 610 + return false; 611 + if (!xdrgen_encode_fsh4_mode(xdr, value->mode)) 612 + return false; 613 + if (!xdrgen_encode_fsh4_access(xdr, value->access)) 614 + return false; 615 + return true; 616 + } 617 + 618 + static bool __maybe_unused 619 + xdrgen_encode_nlm4_shareargs(struct xdr_stream *xdr, const struct nlm4_shareargs *value) 620 + { 621 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 622 + return false; 623 + if (!xdrgen_encode_nlm4_share(xdr, &value->share)) 624 + return false; 625 + if (!xdrgen_encode_bool(xdr, value->reclaim)) 626 + return false; 627 + return true; 628 + } 629 + 630 + static bool __maybe_unused 631 + xdrgen_encode_nlm4_shareres(struct xdr_stream *xdr, const struct nlm4_shareres *value) 632 + { 633 + if (!xdrgen_encode_netobj(xdr, value->cookie)) 634 + return false; 635 + if (!xdrgen_encode_nlm4_stats(xdr, value->stat)) 636 + return false; 637 + if (!xdrgen_encode_int32(xdr, value->sequence)) 638 + return false; 639 + return true; 640 + } 641 + 642 + static bool __maybe_unused 643 + xdrgen_encode_nlm4_notify(struct xdr_stream *xdr, const struct nlm4_notify *value) 644 + { 645 + if (value->name.len > LM_MAXNAMELEN) 646 + return false; 647 + if (xdr_stream_encode_opaque(xdr, value->name.data, value->name.len) < 0) 648 + return false; 649 + if (!xdrgen_encode_int32(xdr, value->state)) 650 + return false; 651 + return true; 652 + } 653 + 654 + static bool __maybe_unused 655 + xdrgen_encode_nlm4_notifyargs(struct xdr_stream *xdr, const struct nlm4_notifyargs *value) 656 + { 657 + if (!xdrgen_encode_nlm4_notify(xdr, &value->notify)) 658 + return false; 659 + if (xdr_stream_encode_opaque_fixed(xdr, value->private, SM_PRIV_SIZE) < 0) 660 + return false; 661 + return true; 662 + } 663 + 664 + /** 665 + * nlm4_svc_encode_void - Encode a void result 666 + * @rqstp: RPC transaction context 667 + * @xdr: target XDR data stream 668 + * 669 + * Return values: 670 + * %true: procedure results encoded successfully 671 + * %false: encode failed 672 + */ 673 + bool nlm4_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 674 + { 675 + return xdrgen_encode_void(xdr); 676 + } 677 + 678 + /** 679 + * nlm4_svc_encode_nlm4_testres - Encode a nlm4_testres result 680 + * @rqstp: RPC transaction context 681 + * @xdr: target XDR data stream 682 + * 683 + * Return values: 684 + * %true: procedure results encoded successfully 685 + * %false: encode failed 686 + */ 687 + bool nlm4_svc_encode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 688 + { 689 + struct nlm4_testres *resp = rqstp->rq_resp; 690 + 691 + return xdrgen_encode_nlm4_testres(xdr, resp); 692 + } 693 + 694 + /** 695 + * nlm4_svc_encode_nlm4_res - Encode a nlm4_res result 696 + * @rqstp: RPC transaction context 697 + * @xdr: target XDR data stream 698 + * 699 + * Return values: 700 + * %true: procedure results encoded successfully 701 + * %false: encode failed 702 + */ 703 + bool nlm4_svc_encode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) 704 + { 705 + struct nlm4_res *resp = rqstp->rq_resp; 706 + 707 + return xdrgen_encode_nlm4_res(xdr, resp); 708 + } 709 + 710 + /** 711 + * nlm4_svc_encode_nlm4_shareres - Encode a nlm4_shareres result 712 + * @rqstp: RPC transaction context 713 + * @xdr: target XDR data stream 714 + * 715 + * Return values: 716 + * %true: procedure results encoded successfully 717 + * %false: encode failed 718 + */ 719 + bool nlm4_svc_encode_nlm4_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 720 + { 721 + struct nlm4_shareres *resp = rqstp->rq_resp; 722 + 723 + return xdrgen_encode_nlm4_shareres(xdr, resp); 724 + }
+32
fs/lockd/nlm4xdr_gen.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Generated by xdrgen. Manual edits will be lost. */ 3 + /* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */ 4 + /* XDR specification modification time: Thu Dec 25 13:10:19 2025 */ 5 + 6 + #ifndef _LINUX_XDRGEN_NLM4_DECL_H 7 + #define _LINUX_XDRGEN_NLM4_DECL_H 8 + 9 + #include <linux/types.h> 10 + 11 + #include <linux/sunrpc/xdr.h> 12 + #include <linux/sunrpc/xdrgen/_defs.h> 13 + #include <linux/sunrpc/xdrgen/_builtins.h> 14 + #include <linux/sunrpc/xdrgen/nlm4.h> 15 + 16 + bool nlm4_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 17 + bool nlm4_svc_decode_nlm4_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 18 + bool nlm4_svc_decode_nlm4_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 19 + bool nlm4_svc_decode_nlm4_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 20 + bool nlm4_svc_decode_nlm4_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 21 + bool nlm4_svc_decode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); 22 + bool nlm4_svc_decode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); 23 + bool nlm4_svc_decode_nlm4_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 24 + bool nlm4_svc_decode_nlm4_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 25 + bool nlm4_svc_decode_nlm4_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); 26 + 27 + bool nlm4_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 28 + bool nlm4_svc_encode_nlm4_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); 29 + bool nlm4_svc_encode_nlm4_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); 30 + bool nlm4_svc_encode_nlm4_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); 31 + 32 + #endif /* _LINUX_XDRGEN_NLM4_DECL_H */
+12 -38
fs/lockd/svc.c
··· 36 36 #include <net/ip.h> 37 37 #include <net/addrconf.h> 38 38 #include <net/ipv6.h> 39 - #include <linux/lockd/lockd.h> 40 39 #include <linux/nfs.h> 41 40 41 + #include "lockd.h" 42 42 #include "netns.h" 43 43 #include "procfs.h" 44 44 #include "netlink.h" 45 45 46 46 #define NLMDBG_FACILITY NLMDBG_SVC 47 - #define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE) 48 47 49 48 static struct svc_program nlmsvc_program; 50 49 ··· 318 319 static int lockd_get(void) 319 320 { 320 321 struct svc_serv *serv; 322 + unsigned int bufsize; 321 323 int error; 322 324 323 325 if (nlmsvc_serv) { ··· 334 334 printk(KERN_WARNING 335 335 "lockd_up: no pid, %d users??\n", nlmsvc_users); 336 336 337 - serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, lockd); 337 + #ifdef CONFIG_LOCKD_V4 338 + bufsize = 1024 + max3(nlmsvc_version1.vs_xdrsize, 339 + nlmsvc_version3.vs_xdrsize, 340 + nlmsvc_version4.vs_xdrsize); 341 + #else 342 + bufsize = 1024 + max(nlmsvc_version1.vs_xdrsize, 343 + nlmsvc_version3.vs_xdrsize); 344 + #endif 345 + serv = svc_create(&nlmsvc_program, bufsize, lockd); 338 346 if (!serv) { 339 347 printk(KERN_WARNING "lockd_up: create service failed\n"); 340 348 return -ENOMEM; ··· 648 640 * %0: Processing complete; do not send a Reply 649 641 * %1: Processing complete; send Reply in rqstp->rq_res 650 642 */ 651 - static int nlmsvc_dispatch(struct svc_rqst *rqstp) 643 + int nlmsvc_dispatch(struct svc_rqst *rqstp) 652 644 { 653 645 const struct svc_procedure *procp = rqstp->rq_procinfo; 654 646 __be32 *statp = rqstp->rq_accept_statp; ··· 679 671 /* 680 672 * Define NLM program and procedures 681 673 */ 682 - static DEFINE_PER_CPU_ALIGNED(unsigned long, nlmsvc_version1_count[17]); 683 - static const struct svc_version nlmsvc_version1 = { 684 - .vs_vers = 1, 685 - .vs_nproc = 17, 686 - .vs_proc = nlmsvc_procedures, 687 - .vs_count = nlmsvc_version1_count, 688 - .vs_dispatch = nlmsvc_dispatch, 689 - .vs_xdrsize = NLMSVC_XDRSIZE, 690 - }; 691 - 692 - static DEFINE_PER_CPU_ALIGNED(unsigned long, 693 - nlmsvc_version3_count[ARRAY_SIZE(nlmsvc_procedures)]); 694 - static const struct svc_version nlmsvc_version3 = { 695 - .vs_vers = 3, 696 - .vs_nproc = ARRAY_SIZE(nlmsvc_procedures), 697 - .vs_proc = nlmsvc_procedures, 698 - .vs_count = nlmsvc_version3_count, 699 - .vs_dispatch = nlmsvc_dispatch, 700 - .vs_xdrsize = NLMSVC_XDRSIZE, 701 - }; 702 - 703 - #ifdef CONFIG_LOCKD_V4 704 - static DEFINE_PER_CPU_ALIGNED(unsigned long, 705 - nlmsvc_version4_count[ARRAY_SIZE(nlmsvc_procedures4)]); 706 - static const struct svc_version nlmsvc_version4 = { 707 - .vs_vers = 4, 708 - .vs_nproc = ARRAY_SIZE(nlmsvc_procedures4), 709 - .vs_proc = nlmsvc_procedures4, 710 - .vs_count = nlmsvc_version4_count, 711 - .vs_dispatch = nlmsvc_dispatch, 712 - .vs_xdrsize = NLMSVC_XDRSIZE, 713 - }; 714 - #endif 715 - 716 674 static const struct svc_version *nlmsvc_version[] = { 717 675 [1] = &nlmsvc_version1, 718 676 [3] = &nlmsvc_version3,
+1231 -555
fs/lockd/svc4proc.c
··· 10 10 11 11 #include <linux/types.h> 12 12 #include <linux/time.h> 13 - #include <linux/lockd/lockd.h> 14 - #include <linux/lockd/share.h> 15 13 #include <linux/sunrpc/svc_xprt.h> 16 14 17 - #define NLMDBG_FACILITY NLMDBG_CLIENT 15 + #include "lockd.h" 18 16 19 17 /* 20 - * Obtain client and file from arguments 18 + * xdr.h defines SM_MAXSTRLEN and SM_PRIV_SIZE as macros. 19 + * nlm4xdr_gen.h defines them as enum constants. Undefine the 20 + * macros to allow the xdrgen enum definitions to be used. 21 21 */ 22 - static __be32 23 - nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp, 24 - struct nlm_host **hostp, struct nlm_file **filp) 25 - { 26 - struct nlm_host *host = NULL; 27 - struct nlm_file *file = NULL; 28 - struct nlm_lock *lock = &argp->lock; 29 - __be32 error = 0; 22 + #undef SM_MAXSTRLEN 23 + #undef SM_PRIV_SIZE 30 24 31 - /* nfsd callbacks must have been installed for this procedure */ 32 - if (!nlmsvc_ops) 25 + #include "share.h" 26 + #include "nlm4xdr_gen.h" 27 + 28 + /* 29 + * Wrapper structures combine xdrgen types with legacy nlm_lock. 30 + * The xdrgen field must be first so the structure can be cast 31 + * to its XDR type for the RPC dispatch layer. 32 + */ 33 + struct nlm4_testargs_wrapper { 34 + struct nlm4_testargs xdrgen; 35 + struct nlm_lock lock; 36 + }; 37 + 38 + static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0); 39 + 40 + struct nlm4_lockargs_wrapper { 41 + struct nlm4_lockargs xdrgen; 42 + struct nlm_cookie cookie; 43 + struct nlm_lock lock; 44 + }; 45 + 46 + static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0); 47 + 48 + struct nlm4_cancargs_wrapper { 49 + struct nlm4_cancargs xdrgen; 50 + struct nlm_lock lock; 51 + }; 52 + 53 + static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0); 54 + 55 + struct nlm4_unlockargs_wrapper { 56 + struct nlm4_unlockargs xdrgen; 57 + struct nlm_lock lock; 58 + }; 59 + 60 + static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0); 61 + 62 + struct nlm4_notifyargs_wrapper { 63 + struct nlm4_notifyargs xdrgen; 64 + struct nlm_reboot reboot; 65 + }; 66 + 67 + static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0); 68 + 69 + struct nlm4_notify_wrapper { 70 + struct nlm4_notify xdrgen; 71 + }; 72 + 73 + static_assert(offsetof(struct nlm4_notify_wrapper, xdrgen) == 0); 74 + 75 + struct nlm4_testres_wrapper { 76 + struct nlm4_testres xdrgen; 77 + struct nlm_lock lock; 78 + }; 79 + 80 + struct nlm4_shareargs_wrapper { 81 + struct nlm4_shareargs xdrgen; 82 + struct nlm_lock lock; 83 + }; 84 + 85 + static_assert(offsetof(struct nlm4_shareargs_wrapper, xdrgen) == 0); 86 + 87 + static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0); 88 + 89 + struct nlm4_res_wrapper { 90 + struct nlm4_res xdrgen; 91 + struct nlm_cookie cookie; 92 + }; 93 + 94 + static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0); 95 + 96 + struct nlm4_shareres_wrapper { 97 + struct nlm4_shareres xdrgen; 98 + }; 99 + 100 + static_assert(offsetof(struct nlm4_shareres_wrapper, xdrgen) == 0); 101 + 102 + static __be32 103 + nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object) 104 + { 105 + if (object->len > NLM_MAXCOOKIELEN) 33 106 return nlm_lck_denied_nolocks; 107 + cookie->len = object->len; 108 + memcpy(cookie->data, object->data, object->len); 109 + return nlm_granted; 110 + } 111 + 112 + static __be32 113 + nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock) 114 + { 115 + if (alock->fh.len > NFS_MAXFHSIZE) 116 + return nlm_lck_denied; 117 + lock->fh.size = alock->fh.len; 118 + memcpy(lock->fh.data, alock->fh.data, alock->fh.len); 119 + lock->oh.len = alock->oh.len; 120 + lock->oh.data = alock->oh.data; 121 + lock->svid = alock->svid; 122 + locks_init_lock(&lock->fl); 123 + lockd_set_file_lock_range4(&lock->fl, alock->l_offset, alock->l_len); 124 + return nlm_granted; 125 + } 126 + 127 + static struct nlm_host * 128 + nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored) 129 + { 130 + struct nlm_host *host; 131 + 132 + if (!nlmsvc_ops) 133 + return NULL; 134 + host = nlmsvc_lookup_host(rqstp, caller.data, caller.len); 135 + if (!host) 136 + return NULL; 137 + if (monitored && nsm_monitor(host) < 0) { 138 + nlmsvc_release_host(host); 139 + return NULL; 140 + } 141 + return host; 142 + } 143 + 144 + static __be32 145 + nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host, 146 + struct nlm_lock *lock, struct nlm_file **filp, 147 + struct nlm4_lock *xdr_lock, unsigned char type) 148 + { 149 + struct file_lock *fl = &lock->fl; 150 + struct nlm_file *file = NULL; 151 + __be32 error; 152 + 153 + if (xdr_lock->fh.len > NFS_MAXFHSIZE) 154 + return nlm_lck_denied_nolocks; 155 + lock->fh.size = xdr_lock->fh.len; 156 + memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len); 157 + 158 + lock->oh.len = xdr_lock->oh.len; 159 + lock->oh.data = xdr_lock->oh.data; 160 + 161 + lock->svid = xdr_lock->svid; 162 + lock->lock_start = xdr_lock->l_offset; 163 + lock->lock_len = xdr_lock->l_len; 34 164 35 165 if (lock->lock_start > OFFSET_MAX || 36 166 (lock->lock_len && ((lock->lock_len - 1) > (OFFSET_MAX - lock->lock_start)))) 37 167 return nlm4_fbig; 38 168 39 - /* Obtain host handle */ 40 - if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len)) 41 - || (argp->monitor && nsm_monitor(host) < 0)) 42 - goto no_locks; 43 - *hostp = host; 169 + locks_init_lock(fl); 170 + fl->c.flc_type = type; 171 + lockd_set_file_lock_range4(fl, lock->lock_start, lock->lock_len); 44 172 45 - /* Obtain file pointer. Not used by FREE_ALL call. */ 46 - if (filp != NULL) { 47 - int mode = lock_to_openmode(&lock->fl); 48 - 49 - lock->fl.c.flc_flags = FL_POSIX; 50 - 51 - error = nlm_lookup_file(rqstp, &file, lock); 52 - if (error) 53 - goto no_locks; 54 - *filp = file; 55 - 56 - /* Set up the missing parts of the file_lock structure */ 57 - lock->fl.c.flc_file = file->f_file[mode]; 58 - lock->fl.c.flc_pid = current->tgid; 59 - lock->fl.fl_start = (loff_t)lock->lock_start; 60 - lock->fl.fl_end = lock->lock_len ? 61 - (loff_t)(lock->lock_start + lock->lock_len - 1) : 62 - OFFSET_MAX; 63 - lock->fl.fl_lmops = &nlmsvc_lock_operations; 64 - nlmsvc_locks_init_private(&lock->fl, host, (pid_t)lock->svid); 65 - if (!lock->fl.c.flc_owner) { 66 - /* lockowner allocation has failed */ 67 - nlmsvc_release_host(host); 68 - return nlm_lck_denied_nolocks; 69 - } 173 + error = nlm_lookup_file(rqstp, &file, lock); 174 + switch (error) { 175 + case nlm_granted: 176 + break; 177 + case nlm__int__stale_fh: 178 + return nlm4_stale_fh; 179 + case nlm__int__failed: 180 + return nlm4_failed; 181 + default: 182 + return error; 70 183 } 184 + *filp = file; 71 185 72 - return 0; 186 + fl->c.flc_flags = FL_POSIX; 187 + fl->c.flc_file = file->f_file[lock_to_openmode(fl)]; 188 + fl->c.flc_pid = current->tgid; 189 + fl->fl_lmops = &nlmsvc_lock_operations; 190 + nlmsvc_locks_init_private(fl, host, (pid_t)lock->svid); 191 + if (!fl->c.flc_owner) 192 + return nlm_lck_denied_nolocks; 73 193 74 - no_locks: 75 - nlmsvc_release_host(host); 76 - if (error) 77 - return error; 78 - return nlm_lck_denied_nolocks; 194 + return nlm_granted; 79 195 } 80 196 81 - /* 82 - * NULL: Test for presence of service 197 + /** 198 + * nlm4svc_proc_null - NULL: Test for presence of service 199 + * @rqstp: RPC transaction context 200 + * 201 + * Returns: 202 + * %rpc_success: RPC executed successfully 203 + * 204 + * RPC synopsis: 205 + * void NLMPROC4_NULL(void) = 0; 83 206 */ 84 207 static __be32 85 208 nlm4svc_proc_null(struct svc_rqst *rqstp) 86 209 { 87 - dprintk("lockd: NULL called\n"); 88 210 return rpc_success; 89 211 } 90 212 91 - /* 92 - * TEST: Check for conflicting lock 213 + /** 214 + * nlm4svc_proc_test - TEST: Check for conflicting lock 215 + * @rqstp: RPC transaction context 216 + * 217 + * Returns: 218 + * %rpc_success: RPC executed successfully. 219 + * %rpc_drop_reply: Do not send an RPC reply. 220 + * 221 + * RPC synopsis: 222 + * nlm4_testres NLMPROC4_TEST(nlm4_testargs) = 1; 223 + * 224 + * Permissible procedure status codes: 225 + * %NLM4_GRANTED: The server would be able to grant the 226 + * requested lock. 227 + * %NLM4_DENIED: The requested lock conflicted with existing 228 + * lock reservations for the file. 229 + * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources 230 + * needed to process the request. 231 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 232 + * re-establishing existing locks, and is not 233 + * yet ready to accept normal service requests. 234 + * 235 + * The Linux NLM server implementation also returns: 236 + * %NLM4_STALE_FH: The request specified an invalid file handle. 237 + * %NLM4_FBIG: The request specified a length or offset 238 + * that exceeds the range supported by the 239 + * server. 240 + * %NLM4_FAILED: The request failed for an unspecified reason. 93 241 */ 94 - static __be32 95 - __nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_res *resp) 242 + static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp) 96 243 { 97 - struct nlm_args *argp = rqstp->rq_argp; 244 + struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; 245 + unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; 246 + struct nlm4_testres_wrapper *resp = rqstp->rq_resp; 247 + struct nlm_file *file = NULL; 98 248 struct nlm_host *host; 99 - struct nlm_file *file; 100 - __be32 rc = rpc_success; 101 249 102 - dprintk("lockd: TEST4 called\n"); 103 - resp->cookie = argp->cookie; 250 + resp->xdrgen.cookie = argp->xdrgen.cookie; 104 251 105 - /* Obtain client and file */ 106 - if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 107 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 252 + resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; 253 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 254 + if (!host) 255 + goto out; 108 256 109 - /* Now check for conflicting locks */ 110 - resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, 111 - &resp->lock); 112 - if (resp->status == nlm_drop_reply) 113 - rc = rpc_drop_reply; 114 - else 115 - dprintk("lockd: TEST4 status %d\n", ntohl(resp->status)); 257 + resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock, 258 + &file, &argp->xdrgen.alock, 259 + type); 260 + if (resp->xdrgen.stat.stat) 261 + goto out; 262 + 263 + resp->xdrgen.stat.stat = nlmsvc_testlock(rqstp, file, host, 264 + &argp->lock, &resp->lock); 265 + nlmsvc_release_lockowner(&argp->lock); 266 + 267 + if (resp->xdrgen.stat.stat == nlm_lck_denied) { 268 + struct nlm_lock *conf = &resp->lock; 269 + struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder; 270 + 271 + holder->exclusive = (conf->fl.c.flc_type != F_RDLCK); 272 + holder->svid = conf->svid; 273 + holder->oh.len = conf->oh.len; 274 + holder->oh.data = conf->oh.data; 275 + holder->l_offset = conf->fl.fl_start; 276 + if (conf->fl.fl_end == OFFSET_MAX) 277 + holder->l_len = 0; 278 + else 279 + holder->l_len = conf->fl.fl_end - conf->fl.fl_start + 1; 280 + } 281 + 282 + out: 283 + if (file) 284 + nlm_release_file(file); 285 + nlmsvc_release_host(host); 286 + return resp->xdrgen.stat.stat == nlm__int__drop_reply ? 287 + rpc_drop_reply : rpc_success; 288 + } 289 + 290 + static __be32 291 + nlm4svc_do_lock(struct svc_rqst *rqstp, bool monitored) 292 + { 293 + struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp; 294 + unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; 295 + struct nlm4_res_wrapper *resp = rqstp->rq_resp; 296 + struct nlm_file *file = NULL; 297 + struct nlm_host *host = NULL; 298 + 299 + resp->xdrgen.cookie = argp->xdrgen.cookie; 300 + 301 + resp->xdrgen.stat.stat = nlm4_netobj_to_cookie(&argp->cookie, 302 + &argp->xdrgen.cookie); 303 + if (resp->xdrgen.stat.stat) 304 + goto out; 305 + 306 + resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; 307 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, 308 + monitored); 309 + if (!host) 310 + goto out; 311 + 312 + resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock, 313 + &file, &argp->xdrgen.alock, 314 + type); 315 + if (resp->xdrgen.stat.stat) 316 + goto out; 317 + 318 + resp->xdrgen.stat.stat = nlmsvc_lock(rqstp, file, host, &argp->lock, 319 + argp->xdrgen.block, &argp->cookie, 320 + argp->xdrgen.reclaim); 321 + if (resp->xdrgen.stat.stat == nlm__int__deadlock) 322 + resp->xdrgen.stat.stat = nlm4_deadlock; 116 323 117 324 nlmsvc_release_lockowner(&argp->lock); 325 + 326 + out: 327 + if (file) 328 + nlm_release_file(file); 118 329 nlmsvc_release_host(host); 119 - nlm_release_file(file); 120 - return rc; 330 + return resp->xdrgen.stat.stat == nlm__int__drop_reply ? 331 + rpc_drop_reply : rpc_success; 121 332 } 122 333 123 - static __be32 124 - nlm4svc_proc_test(struct svc_rqst *rqstp) 125 - { 126 - return __nlm4svc_proc_test(rqstp, rqstp->rq_resp); 127 - } 128 - 129 - static __be32 130 - __nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_res *resp) 131 - { 132 - struct nlm_args *argp = rqstp->rq_argp; 133 - struct nlm_host *host; 134 - struct nlm_file *file; 135 - __be32 rc = rpc_success; 136 - 137 - dprintk("lockd: LOCK called\n"); 138 - 139 - resp->cookie = argp->cookie; 140 - 141 - /* Obtain client and file */ 142 - if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 143 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 144 - 145 - /* Now try to lock the file */ 146 - resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock, 147 - argp->block, &argp->cookie, 148 - argp->reclaim); 149 - if (resp->status == nlm_drop_reply) 150 - rc = rpc_drop_reply; 151 - else 152 - dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); 153 - 154 - nlmsvc_release_lockowner(&argp->lock); 155 - nlmsvc_release_host(host); 156 - nlm_release_file(file); 157 - return rc; 158 - } 159 - 334 + /** 335 + * nlm4svc_proc_lock - LOCK: Establish a monitored lock 336 + * @rqstp: RPC transaction context 337 + * 338 + * Returns: 339 + * %rpc_success: RPC executed successfully. 340 + * %rpc_drop_reply: Do not send an RPC reply. 341 + * 342 + * RPC synopsis: 343 + * nlm4_res NLMPROC4_LOCK(nlm4_lockargs) = 2; 344 + * 345 + * Permissible procedure status codes: 346 + * %NLM4_GRANTED: The requested lock was granted. 347 + * %NLM4_DENIED: The requested lock conflicted with existing 348 + * lock reservations for the file. 349 + * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources 350 + * needed to process the request. 351 + * %NLM4_BLOCKED: The blocking request cannot be granted 352 + * immediately. The server will send an 353 + * NLMPROC4_GRANTED callback to the client when 354 + * the lock can be granted. 355 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 356 + * re-establishing existing locks, and is not 357 + * yet ready to accept normal service requests. 358 + * 359 + * The Linux NLM server implementation also returns: 360 + * %NLM4_DEADLCK: The request could not be granted and 361 + * blocking would cause a deadlock. 362 + * %NLM4_STALE_FH: The request specified an invalid file handle. 363 + * %NLM4_FBIG: The request specified a length or offset 364 + * that exceeds the range supported by the 365 + * server. 366 + * %NLM4_FAILED: The request failed for an unspecified reason. 367 + */ 160 368 static __be32 161 369 nlm4svc_proc_lock(struct svc_rqst *rqstp) 162 370 { 163 - return __nlm4svc_proc_lock(rqstp, rqstp->rq_resp); 371 + return nlm4svc_do_lock(rqstp, true); 164 372 } 165 373 166 - static __be32 167 - __nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_res *resp) 168 - { 169 - struct nlm_args *argp = rqstp->rq_argp; 170 - struct nlm_host *host; 171 - struct nlm_file *file; 172 - 173 - dprintk("lockd: CANCEL called\n"); 174 - 175 - resp->cookie = argp->cookie; 176 - 177 - /* Don't accept requests during grace period */ 178 - if (locks_in_grace(SVC_NET(rqstp))) { 179 - resp->status = nlm_lck_denied_grace_period; 180 - return rpc_success; 181 - } 182 - 183 - /* Obtain client and file */ 184 - if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 185 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 186 - 187 - /* Try to cancel request. */ 188 - resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock); 189 - 190 - dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); 191 - nlmsvc_release_lockowner(&argp->lock); 192 - nlmsvc_release_host(host); 193 - nlm_release_file(file); 194 - return rpc_success; 195 - } 196 - 374 + /** 375 + * nlm4svc_proc_cancel - CANCEL: Cancel an outstanding blocked lock request 376 + * @rqstp: RPC transaction context 377 + * 378 + * Returns: 379 + * %rpc_success: RPC executed successfully 380 + * %rpc_drop_reply: Do not send an RPC reply 381 + * 382 + * RPC synopsis: 383 + * nlm4_res NLMPROC4_CANCEL(nlm4_cancargs) = 3; 384 + * 385 + * Permissible procedure status codes: 386 + * %NLM4_LCK_GRANTED: The requested lock was canceled. 387 + * %NLM4_LCK_DENIED: There was no lock to cancel. 388 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 389 + * re-establishing existing locks, and is not 390 + * yet ready to accept normal service requests. 391 + * 392 + * The Linux NLM server implementation also returns: 393 + * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated. 394 + * %NLM4_STALE_FH: The request specified an invalid file handle. 395 + * %NLM4_FBIG: The request specified a length or offset 396 + * that exceeds the range supported by the 397 + * server. 398 + * %NLM4_FAILED: The request failed for an unspecified reason. 399 + */ 197 400 static __be32 198 401 nlm4svc_proc_cancel(struct svc_rqst *rqstp) 199 402 { 200 - return __nlm4svc_proc_cancel(rqstp, rqstp->rq_resp); 201 - } 403 + struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp; 404 + unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; 405 + struct nlm4_res_wrapper *resp = rqstp->rq_resp; 406 + struct net *net = SVC_NET(rqstp); 407 + struct nlm_host *host = NULL; 408 + struct nlm_file *file = NULL; 202 409 203 - /* 204 - * UNLOCK: release a lock 205 - */ 206 - static __be32 207 - __nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_res *resp) 208 - { 209 - struct nlm_args *argp = rqstp->rq_argp; 210 - struct nlm_host *host; 211 - struct nlm_file *file; 410 + resp->xdrgen.cookie = argp->xdrgen.cookie; 212 411 213 - dprintk("lockd: UNLOCK called\n"); 412 + resp->xdrgen.stat.stat = nlm_lck_denied_grace_period; 413 + if (locks_in_grace(net)) 414 + goto out; 214 415 215 - resp->cookie = argp->cookie; 416 + resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; 417 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 418 + if (!host) 419 + goto out; 216 420 217 - /* Don't accept new lock requests during grace period */ 218 - if (locks_in_grace(SVC_NET(rqstp))) { 219 - resp->status = nlm_lck_denied_grace_period; 220 - return rpc_success; 221 - } 421 + resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock, 422 + &file, &argp->xdrgen.alock, 423 + type); 424 + if (resp->xdrgen.stat.stat) 425 + goto out; 222 426 223 - /* Obtain client and file */ 224 - if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 225 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 226 - 227 - /* Now try to remove the lock */ 228 - resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock); 229 - 230 - dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); 427 + resp->xdrgen.stat.stat = nlmsvc_cancel_blocked(net, file, &argp->lock); 231 428 nlmsvc_release_lockowner(&argp->lock); 429 + 430 + out: 431 + if (file) 432 + nlm_release_file(file); 232 433 nlmsvc_release_host(host); 233 - nlm_release_file(file); 234 - return rpc_success; 434 + return resp->xdrgen.stat.stat == nlm__int__drop_reply ? 435 + rpc_drop_reply : rpc_success; 235 436 } 236 437 438 + /** 439 + * nlm4svc_proc_unlock - UNLOCK: Remove a lock 440 + * @rqstp: RPC transaction context 441 + * 442 + * Returns: 443 + * %rpc_success: RPC executed successfully. 444 + * %rpc_drop_reply: Do not send an RPC reply. 445 + * 446 + * RPC synopsis: 447 + * nlm4_res NLMPROC4_UNLOCK(nlm4_unlockargs) = 4; 448 + * 449 + * Permissible procedure status codes: 450 + * %NLM4_GRANTED: The requested lock was released. 451 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 452 + * re-establishing existing locks, and is not 453 + * yet ready to accept normal service requests. 454 + * 455 + * The Linux NLM server implementation also returns: 456 + * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated. 457 + * %NLM4_STALE_FH: The request specified an invalid file handle. 458 + * %NLM4_FBIG: The request specified a length or offset 459 + * that exceeds the range supported by the 460 + * server. 461 + * %NLM4_FAILED: The request failed for an unspecified reason. 462 + */ 237 463 static __be32 238 464 nlm4svc_proc_unlock(struct svc_rqst *rqstp) 239 465 { 240 - return __nlm4svc_proc_unlock(rqstp, rqstp->rq_resp); 466 + struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp; 467 + struct nlm4_res_wrapper *resp = rqstp->rq_resp; 468 + struct net *net = SVC_NET(rqstp); 469 + struct nlm_host *host = NULL; 470 + struct nlm_file *file = NULL; 471 + 472 + resp->xdrgen.cookie = argp->xdrgen.cookie; 473 + 474 + resp->xdrgen.stat.stat = nlm_lck_denied_grace_period; 475 + if (locks_in_grace(net)) 476 + goto out; 477 + 478 + resp->xdrgen.stat.stat = nlm_lck_denied_nolocks; 479 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 480 + if (!host) 481 + goto out; 482 + 483 + resp->xdrgen.stat.stat = nlm4svc_lookup_file(rqstp, host, &argp->lock, 484 + &file, &argp->xdrgen.alock, 485 + F_UNLCK); 486 + if (resp->xdrgen.stat.stat) 487 + goto out; 488 + 489 + resp->xdrgen.stat.stat = nlmsvc_unlock(net, file, &argp->lock); 490 + nlmsvc_release_lockowner(&argp->lock); 491 + 492 + out: 493 + if (file) 494 + nlm_release_file(file); 495 + nlmsvc_release_host(host); 496 + return resp->xdrgen.stat.stat == nlm__int__drop_reply ? 497 + rpc_drop_reply : rpc_success; 241 498 } 242 499 243 - /* 244 - * GRANTED: A server calls us to tell that a process' lock request 245 - * was granted 500 + /** 501 + * nlm4svc_proc_granted - GRANTED: Server grants a previously blocked lock 502 + * @rqstp: RPC transaction context 503 + * 504 + * Returns: 505 + * %rpc_success: RPC executed successfully. 506 + * 507 + * RPC synopsis: 508 + * nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5; 509 + * 510 + * Permissible procedure status codes: 511 + * %NLM4_GRANTED: The requested lock was granted. 512 + * %NLM4_DENIED: The server could not allocate the resources 513 + * needed to process the request. 514 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 515 + * re-establishing existing locks, and is not 516 + * yet ready to accept normal service requests. 246 517 */ 247 - static __be32 248 - __nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_res *resp) 249 - { 250 - struct nlm_args *argp = rqstp->rq_argp; 251 - 252 - resp->cookie = argp->cookie; 253 - 254 - dprintk("lockd: GRANTED called\n"); 255 - resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock); 256 - dprintk("lockd: GRANTED status %d\n", ntohl(resp->status)); 257 - return rpc_success; 258 - } 259 - 260 518 static __be32 261 519 nlm4svc_proc_granted(struct svc_rqst *rqstp) 262 520 { 263 - return __nlm4svc_proc_granted(rqstp, rqstp->rq_resp); 521 + struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; 522 + struct nlm4_res_wrapper *resp = rqstp->rq_resp; 523 + 524 + resp->xdrgen.cookie = argp->xdrgen.cookie; 525 + 526 + resp->xdrgen.stat.stat = nlm4_lock_to_nlm_lock(&argp->lock, 527 + &argp->xdrgen.alock); 528 + if (resp->xdrgen.stat.stat) 529 + goto out; 530 + 531 + resp->xdrgen.stat.stat = nlmclnt_grant(svc_addr(rqstp), &argp->lock); 532 + 533 + out: 534 + return rpc_success; 264 535 } 265 536 266 537 /* ··· 552 281 }; 553 282 554 283 /* 555 - * `Async' versions of the above service routines. They aren't really, 556 - * because we send the callback before the reply proper. I hope this 557 - * doesn't break any clients. 284 + * Dispatch an async callback RPC to a client with a pre-resolved host. 285 + * Caller provides a reference to @host; this function takes ownership 286 + * and releases it via nlmsvc_release_host() before returning. 558 287 */ 559 - static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, 560 - __be32 (*func)(struct svc_rqst *, struct nlm_res *)) 288 + static __be32 289 + nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc, 290 + __be32 (*func)(struct svc_rqst *, struct nlm_res *)) 561 291 { 562 - struct nlm_args *argp = rqstp->rq_argp; 563 - struct nlm_host *host; 564 292 struct nlm_rqst *call; 565 293 __be32 stat; 566 - 567 - host = nlmsvc_lookup_host(rqstp, 568 - argp->lock.caller, 569 - argp->lock.len); 570 - if (host == NULL) 571 - return rpc_system_err; 572 294 573 295 call = nlm_alloc_call(host); 574 296 nlmsvc_release_host(host); ··· 580 316 return rpc_success; 581 317 } 582 318 319 + static __be32 320 + __nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_res *resp) 321 + { 322 + struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; 323 + unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; 324 + struct nlm_lockowner *owner; 325 + struct nlm_file *file = NULL; 326 + struct nlm_host *host = NULL; 327 + 328 + resp->status = nlm_lck_denied_nolocks; 329 + if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) 330 + goto out; 331 + 332 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 333 + if (!host) 334 + goto out; 335 + 336 + resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock, 337 + &file, &argp->xdrgen.alock, type); 338 + if (resp->status) 339 + goto out; 340 + 341 + owner = argp->lock.fl.c.flc_owner; 342 + resp->status = nlmsvc_testlock(rqstp, file, host, &argp->lock, 343 + &resp->lock); 344 + nlmsvc_put_lockowner(owner); 345 + 346 + out: 347 + if (file) 348 + nlm_release_file(file); 349 + nlmsvc_release_host(host); 350 + return resp->status == nlm__int__drop_reply ? rpc_drop_reply : rpc_success; 351 + } 352 + 353 + /** 354 + * nlm4svc_proc_test_msg - TEST_MSG: Check for conflicting lock 355 + * @rqstp: RPC transaction context 356 + * 357 + * Returns: 358 + * %rpc_success: RPC executed successfully. 359 + * %rpc_system_err: RPC execution failed. 360 + * 361 + * RPC synopsis: 362 + * void NLMPROC4_TEST_MSG(nlm4_testargs) = 6; 363 + * 364 + * The response to this request is delivered via the TEST_RES procedure. 365 + */ 583 366 static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp) 584 367 { 585 - dprintk("lockd: TEST_MSG called\n"); 586 - return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, __nlm4svc_proc_test); 368 + struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; 369 + struct nlm_host *host; 370 + 371 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 372 + if (!host) 373 + return rpc_system_err; 374 + 375 + return nlm4svc_callback(rqstp, host, NLMPROC4_TEST_RES, 376 + __nlm4svc_proc_test_msg); 587 377 } 588 378 379 + static __be32 380 + __nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp) 381 + { 382 + struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp; 383 + unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; 384 + struct nlm_file *file = NULL; 385 + struct nlm_host *host = NULL; 386 + 387 + resp->status = nlm_lck_denied_nolocks; 388 + if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) 389 + goto out; 390 + 391 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true); 392 + if (!host) 393 + goto out; 394 + 395 + resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock, 396 + &file, &argp->xdrgen.alock, type); 397 + if (resp->status) 398 + goto out; 399 + 400 + resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock, 401 + argp->xdrgen.block, &resp->cookie, 402 + argp->xdrgen.reclaim); 403 + nlmsvc_release_lockowner(&argp->lock); 404 + 405 + out: 406 + if (file) 407 + nlm_release_file(file); 408 + nlmsvc_release_host(host); 409 + return resp->status == nlm__int__drop_reply ? 410 + rpc_drop_reply : rpc_success; 411 + } 412 + 413 + /** 414 + * nlm4svc_proc_lock_msg - LOCK_MSG: Establish a monitored lock 415 + * @rqstp: RPC transaction context 416 + * 417 + * Returns: 418 + * %rpc_success: RPC executed successfully. 419 + * %rpc_system_err: RPC execution failed. 420 + * 421 + * RPC synopsis: 422 + * void NLMPROC4_LOCK_MSG(nlm4_lockargs) = 7; 423 + * 424 + * The response to this request is delivered via the LOCK_RES procedure. 425 + */ 589 426 static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp) 590 427 { 591 - dprintk("lockd: LOCK_MSG called\n"); 592 - return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, __nlm4svc_proc_lock); 428 + struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp; 429 + struct nlm_host *host; 430 + 431 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true); 432 + if (!host) 433 + return rpc_system_err; 434 + 435 + return nlm4svc_callback(rqstp, host, NLMPROC4_LOCK_RES, 436 + __nlm4svc_proc_lock_msg); 593 437 } 594 438 439 + static __be32 440 + __nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_res *resp) 441 + { 442 + struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp; 443 + unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK; 444 + struct net *net = SVC_NET(rqstp); 445 + struct nlm_file *file = NULL; 446 + struct nlm_host *host = NULL; 447 + 448 + resp->status = nlm_lck_denied_nolocks; 449 + if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) 450 + goto out; 451 + 452 + resp->status = nlm_lck_denied_grace_period; 453 + if (locks_in_grace(net)) 454 + goto out; 455 + 456 + resp->status = nlm_lck_denied_nolocks; 457 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 458 + if (!host) 459 + goto out; 460 + 461 + resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock, 462 + &file, &argp->xdrgen.alock, type); 463 + if (resp->status) 464 + goto out; 465 + 466 + resp->status = nlmsvc_cancel_blocked(net, file, &argp->lock); 467 + nlmsvc_release_lockowner(&argp->lock); 468 + 469 + out: 470 + if (file) 471 + nlm_release_file(file); 472 + nlmsvc_release_host(host); 473 + return resp->status == nlm__int__drop_reply ? 474 + rpc_drop_reply : rpc_success; 475 + } 476 + 477 + /** 478 + * nlm4svc_proc_cancel_msg - CANCEL_MSG: Cancel an outstanding lock request 479 + * @rqstp: RPC transaction context 480 + * 481 + * Returns: 482 + * %rpc_success: RPC executed successfully. 483 + * %rpc_system_err: RPC execution failed. 484 + * 485 + * RPC synopsis: 486 + * void NLMPROC4_CANCEL_MSG(nlm4_cancargs) = 8; 487 + * 488 + * The response to this request is delivered via the CANCEL_RES procedure. 489 + */ 595 490 static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp) 596 491 { 597 - dprintk("lockd: CANCEL_MSG called\n"); 598 - return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, __nlm4svc_proc_cancel); 492 + struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp; 493 + struct nlm_host *host; 494 + 495 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 496 + if (!host) 497 + return rpc_system_err; 498 + 499 + return nlm4svc_callback(rqstp, host, NLMPROC4_CANCEL_RES, 500 + __nlm4svc_proc_cancel_msg); 599 501 } 600 502 503 + static __be32 504 + __nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_res *resp) 505 + { 506 + struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp; 507 + struct net *net = SVC_NET(rqstp); 508 + struct nlm_file *file = NULL; 509 + struct nlm_host *host = NULL; 510 + 511 + resp->status = nlm_lck_denied_nolocks; 512 + if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) 513 + goto out; 514 + 515 + resp->status = nlm_lck_denied_grace_period; 516 + if (locks_in_grace(net)) 517 + goto out; 518 + 519 + resp->status = nlm_lck_denied_nolocks; 520 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 521 + if (!host) 522 + goto out; 523 + 524 + resp->status = nlm4svc_lookup_file(rqstp, host, &argp->lock, 525 + &file, &argp->xdrgen.alock, F_UNLCK); 526 + if (resp->status) 527 + goto out; 528 + 529 + resp->status = nlmsvc_unlock(net, file, &argp->lock); 530 + nlmsvc_release_lockowner(&argp->lock); 531 + 532 + out: 533 + if (file) 534 + nlm_release_file(file); 535 + nlmsvc_release_host(host); 536 + return resp->status == nlm__int__drop_reply ? 537 + rpc_drop_reply : rpc_success; 538 + } 539 + 540 + /** 541 + * nlm4svc_proc_unlock_msg - UNLOCK_MSG: Remove an existing lock 542 + * @rqstp: RPC transaction context 543 + * 544 + * Returns: 545 + * %rpc_success: RPC executed successfully. 546 + * %rpc_system_err: RPC execution failed. 547 + * 548 + * RPC synopsis: 549 + * void NLMPROC4_UNLOCK_MSG(nlm4_unlockargs) = 9; 550 + * 551 + * The response to this request is delivered via the UNLOCK_RES procedure. 552 + */ 601 553 static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp) 602 554 { 603 - dprintk("lockd: UNLOCK_MSG called\n"); 604 - return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, __nlm4svc_proc_unlock); 555 + struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp; 556 + struct nlm_host *host; 557 + 558 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 559 + if (!host) 560 + return rpc_system_err; 561 + 562 + return nlm4svc_callback(rqstp, host, NLMPROC4_UNLOCK_RES, 563 + __nlm4svc_proc_unlock_msg); 605 564 } 606 565 566 + static __be32 567 + __nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp) 568 + { 569 + struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; 570 + 571 + resp->status = nlm_lck_denied; 572 + if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie)) 573 + goto out; 574 + 575 + if (nlm4_lock_to_nlm_lock(&argp->lock, &argp->xdrgen.alock)) 576 + goto out; 577 + 578 + resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock); 579 + 580 + out: 581 + return rpc_success; 582 + } 583 + 584 + /** 585 + * nlm4svc_proc_granted_msg - GRANTED_MSG: Blocked lock has been granted 586 + * @rqstp: RPC transaction context 587 + * 588 + * Returns: 589 + * %rpc_success: RPC executed successfully. 590 + * %rpc_system_err: RPC execution failed. 591 + * 592 + * RPC synopsis: 593 + * void NLMPROC4_GRANTED_MSG(nlm4_testargs) = 10; 594 + * 595 + * The response to this request is delivered via the GRANTED_RES procedure. 596 + */ 607 597 static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp) 608 598 { 609 - dprintk("lockd: GRANTED_MSG called\n"); 610 - return nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, __nlm4svc_proc_granted); 599 + struct nlm4_testargs_wrapper *argp = rqstp->rq_argp; 600 + struct nlm_host *host; 601 + 602 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false); 603 + if (!host) 604 + return rpc_system_err; 605 + 606 + return nlm4svc_callback(rqstp, host, NLMPROC4_GRANTED_RES, 607 + __nlm4svc_proc_granted_msg); 611 608 } 612 609 613 - /* 614 - * SHARE: create a DOS share or alter existing share. 610 + /** 611 + * nlm4svc_proc_granted_res - GRANTED_RES: Lock Granted result 612 + * @rqstp: RPC transaction context 613 + * 614 + * Returns: 615 + * %rpc_success: RPC executed successfully. 616 + * 617 + * RPC synopsis: 618 + * void NLMPROC4_GRANTED_RES(nlm4_res) = 15; 615 619 */ 616 - static __be32 617 - nlm4svc_proc_share(struct svc_rqst *rqstp) 620 + static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp) 618 621 { 619 - struct nlm_args *argp = rqstp->rq_argp; 620 - struct nlm_res *resp = rqstp->rq_resp; 621 - struct nlm_host *host; 622 - struct nlm_file *file; 622 + struct nlm4_res_wrapper *argp = rqstp->rq_argp; 623 623 624 - dprintk("lockd: SHARE called\n"); 625 - 626 - resp->cookie = argp->cookie; 627 - 628 - /* Don't accept new lock requests during grace period */ 629 - if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) { 630 - resp->status = nlm_lck_denied_grace_period; 624 + if (!nlmsvc_ops) 631 625 return rpc_success; 632 - } 633 626 634 - /* Obtain client and file */ 635 - if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 636 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 627 + if (nlm4_netobj_to_cookie(&argp->cookie, &argp->xdrgen.cookie)) 628 + return rpc_success; 629 + nlmsvc_grant_reply(&argp->cookie, argp->xdrgen.stat.stat); 637 630 638 - /* Now try to create the share */ 639 - resp->status = nlmsvc_share_file(host, file, argp); 640 - 641 - dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); 642 - nlmsvc_release_lockowner(&argp->lock); 643 - nlmsvc_release_host(host); 644 - nlm_release_file(file); 645 631 return rpc_success; 646 632 } 647 633 648 - /* 649 - * UNSHARE: Release a DOS share. 634 + /** 635 + * nlm4svc_proc_sm_notify - SM_NOTIFY: Peer has rebooted 636 + * @rqstp: RPC transaction context 637 + * 638 + * Returns: 639 + * %rpc_success: RPC executed successfully. 640 + * %rpc_system_err: RPC execution failed. 641 + * 642 + * The SM_NOTIFY procedure is a private callback from Linux statd and is 643 + * not part of the official NLM protocol. 644 + * 645 + * RPC synopsis: 646 + * void NLMPROC4_SM_NOTIFY(nlm4_notifyargs) = 16; 650 647 */ 651 - static __be32 652 - nlm4svc_proc_unshare(struct svc_rqst *rqstp) 648 + static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp) 653 649 { 654 - struct nlm_args *argp = rqstp->rq_argp; 655 - struct nlm_res *resp = rqstp->rq_resp; 656 - struct nlm_host *host; 657 - struct nlm_file *file; 658 - 659 - dprintk("lockd: UNSHARE called\n"); 660 - 661 - resp->cookie = argp->cookie; 662 - 663 - /* Don't accept requests during grace period */ 664 - if (locks_in_grace(SVC_NET(rqstp))) { 665 - resp->status = nlm_lck_denied_grace_period; 666 - return rpc_success; 667 - } 668 - 669 - /* Obtain client and file */ 670 - if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file))) 671 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 672 - 673 - /* Now try to lock the file */ 674 - resp->status = nlmsvc_unshare_file(host, file, argp); 675 - 676 - dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); 677 - nlmsvc_release_lockowner(&argp->lock); 678 - nlmsvc_release_host(host); 679 - nlm_release_file(file); 680 - return rpc_success; 681 - } 682 - 683 - /* 684 - * NM_LOCK: Create an unmonitored lock 685 - */ 686 - static __be32 687 - nlm4svc_proc_nm_lock(struct svc_rqst *rqstp) 688 - { 689 - struct nlm_args *argp = rqstp->rq_argp; 690 - 691 - dprintk("lockd: NM_LOCK called\n"); 692 - 693 - argp->monitor = 0; /* just clean the monitor flag */ 694 - return nlm4svc_proc_lock(rqstp); 695 - } 696 - 697 - /* 698 - * FREE_ALL: Release all locks and shares held by client 699 - */ 700 - static __be32 701 - nlm4svc_proc_free_all(struct svc_rqst *rqstp) 702 - { 703 - struct nlm_args *argp = rqstp->rq_argp; 704 - struct nlm_host *host; 705 - 706 - /* Obtain client */ 707 - if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL)) 708 - return rpc_success; 709 - 710 - nlmsvc_free_host_resources(host); 711 - nlmsvc_release_host(host); 712 - return rpc_success; 713 - } 714 - 715 - /* 716 - * SM_NOTIFY: private callback from statd (not part of official NLM proto) 717 - */ 718 - static __be32 719 - nlm4svc_proc_sm_notify(struct svc_rqst *rqstp) 720 - { 721 - struct nlm_reboot *argp = rqstp->rq_argp; 722 - 723 - dprintk("lockd: SM_NOTIFY called\n"); 650 + struct nlm4_notifyargs_wrapper *argp = rqstp->rq_argp; 651 + struct nlm_reboot *reboot = &argp->reboot; 724 652 725 653 if (!nlm_privileged_requester(rqstp)) { 726 654 char buf[RPC_MAX_ADDRBUFLEN]; 727 - printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", 728 - svc_print_addr(rqstp, buf, sizeof(buf))); 655 + 656 + pr_warn("lockd: rejected NSM callback from %s\n", 657 + svc_print_addr(rqstp, buf, sizeof(buf))); 729 658 return rpc_system_err; 730 659 } 731 660 732 - nlm_host_rebooted(SVC_NET(rqstp), argp); 661 + reboot->len = argp->xdrgen.notify.name.len; 662 + reboot->mon = (char *)argp->xdrgen.notify.name.data; 663 + reboot->state = argp->xdrgen.notify.state; 664 + memcpy(&reboot->priv.data, argp->xdrgen.private, 665 + sizeof(reboot->priv.data)); 666 + 667 + nlm_host_rebooted(SVC_NET(rqstp), reboot); 668 + 733 669 return rpc_success; 734 670 } 735 671 736 - /* 737 - * client sent a GRANTED_RES, let's remove the associated block 672 + /** 673 + * nlm4svc_proc_unused - stub for unused procedures 674 + * @rqstp: RPC transaction context 675 + * 676 + * Returns: 677 + * %rpc_proc_unavail: Program can't support procedure. 738 678 */ 739 - static __be32 740 - nlm4svc_proc_granted_res(struct svc_rqst *rqstp) 741 - { 742 - struct nlm_res *argp = rqstp->rq_argp; 743 - 744 - if (!nlmsvc_ops) 745 - return rpc_success; 746 - 747 - dprintk("lockd: GRANTED_RES called\n"); 748 - 749 - nlmsvc_grant_reply(&argp->cookie, argp->status); 750 - return rpc_success; 751 - } 752 - 753 - static __be32 754 - nlm4svc_proc_unused(struct svc_rqst *rqstp) 679 + static __be32 nlm4svc_proc_unused(struct svc_rqst *rqstp) 755 680 { 756 681 return rpc_proc_unavail; 757 682 } 758 683 684 + /** 685 + * nlm4svc_proc_share - SHARE: Open a file using DOS file-sharing modes 686 + * @rqstp: RPC transaction context 687 + * 688 + * Returns: 689 + * %rpc_success: RPC executed successfully. 690 + * %rpc_drop_reply: Do not send an RPC reply. 691 + * 692 + * RPC synopsis: 693 + * nlm4_shareres NLMPROC4_SHARE(nlm4_shareargs) = 20; 694 + * 695 + * Permissible procedure status codes: 696 + * %NLM4_GRANTED: The requested share lock was granted. 697 + * %NLM4_DENIED: The requested lock conflicted with existing 698 + * lock reservations for the file. 699 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 700 + * re-establishing existing locks, and is not 701 + * yet ready to accept normal service requests. 702 + * 703 + * The Linux NLM server implementation also returns: 704 + * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated. 705 + * %NLM4_STALE_FH: The request specified an invalid file handle. 706 + * %NLM4_FBIG: The request specified a length or offset 707 + * that exceeds the range supported by the 708 + * server. 709 + * %NLM4_FAILED: The request failed for an unspecified reason. 710 + */ 711 + static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp) 712 + { 713 + struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp; 714 + struct nlm4_shareres_wrapper *resp = rqstp->rq_resp; 715 + struct nlm_lock *lock = &argp->lock; 716 + struct nlm_host *host = NULL; 717 + struct nlm_file *file = NULL; 718 + struct nlm4_lock xdr_lock = { 719 + .fh = argp->xdrgen.share.fh, 720 + .oh = argp->xdrgen.share.oh, 721 + .svid = LOCKD_SHARE_SVID, 722 + }; 723 + 724 + resp->xdrgen.cookie = argp->xdrgen.cookie; 725 + 726 + resp->xdrgen.stat = nlm_lck_denied_grace_period; 727 + if (locks_in_grace(SVC_NET(rqstp)) && !argp->xdrgen.reclaim) 728 + goto out; 729 + 730 + resp->xdrgen.stat = nlm_lck_denied_nolocks; 731 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true); 732 + if (!host) 733 + goto out; 734 + 735 + resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file, 736 + &xdr_lock, F_RDLCK); 737 + if (resp->xdrgen.stat) 738 + goto out; 739 + 740 + resp->xdrgen.stat = nlmsvc_share_file(host, file, &lock->oh, 741 + argp->xdrgen.share.access, 742 + argp->xdrgen.share.mode); 743 + 744 + nlmsvc_release_lockowner(lock); 745 + 746 + out: 747 + if (file) 748 + nlm_release_file(file); 749 + nlmsvc_release_host(host); 750 + return resp->xdrgen.stat == nlm__int__drop_reply ? 751 + rpc_drop_reply : rpc_success; 752 + } 753 + 754 + /** 755 + * nlm4svc_proc_unshare - UNSHARE: Release a share reservation 756 + * @rqstp: RPC transaction context 757 + * 758 + * Returns: 759 + * %rpc_success: RPC executed successfully. 760 + * %rpc_drop_reply: Do not send an RPC reply. 761 + * 762 + * RPC synopsis: 763 + * nlm4_shareres NLMPROC4_UNSHARE(nlm4_shareargs) = 21; 764 + * 765 + * Permissible procedure status codes: 766 + * %NLM4_GRANTED: The share reservation was released. 767 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 768 + * re-establishing existing locks, and is not 769 + * yet ready to accept normal service requests. 770 + * 771 + * The Linux NLM server implementation also returns: 772 + * %NLM4_DENIED_NOLOCKS: A needed resource could not be allocated. 773 + * %NLM4_STALE_FH: The request specified an invalid file handle. 774 + * %NLM4_FBIG: The request specified a length or offset 775 + * that exceeds the range supported by the 776 + * server. 777 + * %NLM4_FAILED: The request failed for an unspecified reason. 778 + */ 779 + static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp) 780 + { 781 + struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp; 782 + struct nlm4_shareres_wrapper *resp = rqstp->rq_resp; 783 + struct nlm_lock *lock = &argp->lock; 784 + struct nlm4_lock xdr_lock = { 785 + .fh = argp->xdrgen.share.fh, 786 + .oh = argp->xdrgen.share.oh, 787 + .svid = LOCKD_SHARE_SVID, 788 + }; 789 + struct nlm_host *host = NULL; 790 + struct nlm_file *file = NULL; 791 + 792 + resp->xdrgen.cookie = argp->xdrgen.cookie; 793 + 794 + resp->xdrgen.stat = nlm_lck_denied_grace_period; 795 + if (locks_in_grace(SVC_NET(rqstp))) 796 + goto out; 797 + 798 + resp->xdrgen.stat = nlm_lck_denied_nolocks; 799 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.share.caller_name, true); 800 + if (!host) 801 + goto out; 802 + 803 + resp->xdrgen.stat = nlm4svc_lookup_file(rqstp, host, lock, &file, 804 + &xdr_lock, F_RDLCK); 805 + if (resp->xdrgen.stat) 806 + goto out; 807 + 808 + resp->xdrgen.stat = nlmsvc_unshare_file(host, file, &lock->oh); 809 + 810 + nlmsvc_release_lockowner(lock); 811 + 812 + out: 813 + if (file) 814 + nlm_release_file(file); 815 + nlmsvc_release_host(host); 816 + return resp->xdrgen.stat == nlm__int__drop_reply ? 817 + rpc_drop_reply : rpc_success; 818 + } 819 + 820 + /** 821 + * nlm4svc_proc_nm_lock - NM_LOCK: Establish a non-monitored lock 822 + * @rqstp: RPC transaction context 823 + * 824 + * Returns: 825 + * %rpc_success: RPC executed successfully. 826 + * %rpc_drop_reply: Do not send an RPC reply. 827 + * 828 + * RPC synopsis: 829 + * nlm4_res NLMPROC4_NM_LOCK(nlm4_lockargs) = 22; 830 + * 831 + * Permissible procedure status codes: 832 + * %NLM4_GRANTED: The requested lock was granted. 833 + * %NLM4_DENIED: The requested lock conflicted with existing 834 + * lock reservations for the file. 835 + * %NLM4_DENIED_NOLOCKS: The server could not allocate the resources 836 + * needed to process the request. 837 + * %NLM4_BLOCKED: The blocking request cannot be granted 838 + * immediately. The server will send an 839 + * NLMPROC4_GRANTED callback to the client when 840 + * the lock can be granted. 841 + * %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is 842 + * re-establishing existing locks, and is not 843 + * yet ready to accept normal service requests. 844 + * 845 + * The Linux NLM server implementation also returns: 846 + * %NLM4_DEADLCK: The request could not be granted and 847 + * blocking would cause a deadlock. 848 + * %NLM4_STALE_FH: The request specified an invalid file handle. 849 + * %NLM4_FBIG: The request specified a length or offset 850 + * that exceeds the range supported by the 851 + * server. 852 + * %NLM4_FAILED: The request failed for an unspecified reason. 853 + */ 854 + static __be32 nlm4svc_proc_nm_lock(struct svc_rqst *rqstp) 855 + { 856 + return nlm4svc_do_lock(rqstp, false); 857 + } 858 + 859 + /** 860 + * nlm4svc_proc_free_all - FREE_ALL: Discard client's lock and share state 861 + * @rqstp: RPC transaction context 862 + * 863 + * Returns: 864 + * %rpc_success: RPC executed successfully. 865 + * 866 + * RPC synopsis: 867 + * void NLMPROC4_FREE_ALL(nlm4_notify) = 23; 868 + */ 869 + static __be32 nlm4svc_proc_free_all(struct svc_rqst *rqstp) 870 + { 871 + struct nlm4_notify_wrapper *argp = rqstp->rq_argp; 872 + struct nlm_host *host; 873 + 874 + host = nlm4svc_lookup_host(rqstp, argp->xdrgen.name, false); 875 + if (!host) 876 + goto out; 877 + 878 + nlmsvc_free_host_resources(host); 879 + 880 + nlmsvc_release_host(host); 881 + 882 + out: 883 + return rpc_success; 884 + } 885 + 759 886 760 887 /* 761 - * NLM Server procedures. 888 + * NLMv4 Server procedures. 762 889 */ 763 890 764 - struct nlm_void { int dummy; }; 765 - 766 - #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */ 767 - #define No (1+1024/4) /* netobj */ 768 - #define St 1 /* status */ 769 - #define Rg 4 /* range (offset + length) */ 770 - 771 - const struct svc_procedure nlmsvc_procedures4[24] = { 772 - [NLMPROC_NULL] = { 773 - .pc_func = nlm4svc_proc_null, 774 - .pc_decode = nlm4svc_decode_void, 775 - .pc_encode = nlm4svc_encode_void, 776 - .pc_argsize = sizeof(struct nlm_void), 777 - .pc_argzero = sizeof(struct nlm_void), 778 - .pc_ressize = sizeof(struct nlm_void), 779 - .pc_xdrressize = St, 780 - .pc_name = "NULL", 891 + static const struct svc_procedure nlm4svc_procedures[24] = { 892 + [NLMPROC4_NULL] = { 893 + .pc_func = nlm4svc_proc_null, 894 + .pc_decode = nlm4_svc_decode_void, 895 + .pc_encode = nlm4_svc_encode_void, 896 + .pc_argsize = XDR_void, 897 + .pc_argzero = 0, 898 + .pc_ressize = 0, 899 + .pc_xdrressize = XDR_void, 900 + .pc_name = "NULL", 781 901 }, 782 - [NLMPROC_TEST] = { 783 - .pc_func = nlm4svc_proc_test, 784 - .pc_decode = nlm4svc_decode_testargs, 785 - .pc_encode = nlm4svc_encode_testres, 786 - .pc_argsize = sizeof(struct nlm_args), 787 - .pc_argzero = sizeof(struct nlm_args), 788 - .pc_ressize = sizeof(struct nlm_res), 789 - .pc_xdrressize = Ck+St+2+No+Rg, 790 - .pc_name = "TEST", 902 + [NLMPROC4_TEST] = { 903 + .pc_func = nlm4svc_proc_test, 904 + .pc_decode = nlm4_svc_decode_nlm4_testargs, 905 + .pc_encode = nlm4_svc_encode_nlm4_testres, 906 + .pc_argsize = sizeof(struct nlm4_testargs_wrapper), 907 + .pc_argzero = 0, 908 + .pc_ressize = sizeof(struct nlm4_testres_wrapper), 909 + .pc_xdrressize = NLM4_nlm4_testres_sz, 910 + .pc_name = "TEST", 791 911 }, 792 - [NLMPROC_LOCK] = { 793 - .pc_func = nlm4svc_proc_lock, 794 - .pc_decode = nlm4svc_decode_lockargs, 795 - .pc_encode = nlm4svc_encode_res, 796 - .pc_argsize = sizeof(struct nlm_args), 797 - .pc_argzero = sizeof(struct nlm_args), 798 - .pc_ressize = sizeof(struct nlm_res), 799 - .pc_xdrressize = Ck+St, 800 - .pc_name = "LOCK", 912 + [NLMPROC4_LOCK] = { 913 + .pc_func = nlm4svc_proc_lock, 914 + .pc_decode = nlm4_svc_decode_nlm4_lockargs, 915 + .pc_encode = nlm4_svc_encode_nlm4_res, 916 + .pc_argsize = sizeof(struct nlm4_lockargs_wrapper), 917 + .pc_argzero = 0, 918 + .pc_ressize = sizeof(struct nlm4_res_wrapper), 919 + .pc_xdrressize = NLM4_nlm4_res_sz, 920 + .pc_name = "LOCK", 801 921 }, 802 - [NLMPROC_CANCEL] = { 803 - .pc_func = nlm4svc_proc_cancel, 804 - .pc_decode = nlm4svc_decode_cancargs, 805 - .pc_encode = nlm4svc_encode_res, 806 - .pc_argsize = sizeof(struct nlm_args), 807 - .pc_argzero = sizeof(struct nlm_args), 808 - .pc_ressize = sizeof(struct nlm_res), 809 - .pc_xdrressize = Ck+St, 810 - .pc_name = "CANCEL", 922 + [NLMPROC4_CANCEL] = { 923 + .pc_func = nlm4svc_proc_cancel, 924 + .pc_decode = nlm4_svc_decode_nlm4_cancargs, 925 + .pc_encode = nlm4_svc_encode_nlm4_res, 926 + .pc_argsize = sizeof(struct nlm4_cancargs_wrapper), 927 + .pc_argzero = 0, 928 + .pc_ressize = sizeof(struct nlm4_res_wrapper), 929 + .pc_xdrressize = NLM4_nlm4_res_sz, 930 + .pc_name = "CANCEL", 811 931 }, 812 - [NLMPROC_UNLOCK] = { 813 - .pc_func = nlm4svc_proc_unlock, 814 - .pc_decode = nlm4svc_decode_unlockargs, 815 - .pc_encode = nlm4svc_encode_res, 816 - .pc_argsize = sizeof(struct nlm_args), 817 - .pc_argzero = sizeof(struct nlm_args), 818 - .pc_ressize = sizeof(struct nlm_res), 819 - .pc_xdrressize = Ck+St, 820 - .pc_name = "UNLOCK", 932 + [NLMPROC4_UNLOCK] = { 933 + .pc_func = nlm4svc_proc_unlock, 934 + .pc_decode = nlm4_svc_decode_nlm4_unlockargs, 935 + .pc_encode = nlm4_svc_encode_nlm4_res, 936 + .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper), 937 + .pc_argzero = 0, 938 + .pc_ressize = sizeof(struct nlm4_res_wrapper), 939 + .pc_xdrressize = NLM4_nlm4_res_sz, 940 + .pc_name = "UNLOCK", 821 941 }, 822 - [NLMPROC_GRANTED] = { 823 - .pc_func = nlm4svc_proc_granted, 824 - .pc_decode = nlm4svc_decode_testargs, 825 - .pc_encode = nlm4svc_encode_res, 826 - .pc_argsize = sizeof(struct nlm_args), 827 - .pc_argzero = sizeof(struct nlm_args), 828 - .pc_ressize = sizeof(struct nlm_res), 829 - .pc_xdrressize = Ck+St, 830 - .pc_name = "GRANTED", 942 + [NLMPROC4_GRANTED] = { 943 + .pc_func = nlm4svc_proc_granted, 944 + .pc_decode = nlm4_svc_decode_nlm4_testargs, 945 + .pc_encode = nlm4_svc_encode_nlm4_res, 946 + .pc_argsize = sizeof(struct nlm4_testargs_wrapper), 947 + .pc_argzero = 0, 948 + .pc_ressize = sizeof(struct nlm4_res_wrapper), 949 + .pc_xdrressize = NLM4_nlm4_res_sz, 950 + .pc_name = "GRANTED", 831 951 }, 832 - [NLMPROC_TEST_MSG] = { 833 - .pc_func = nlm4svc_proc_test_msg, 834 - .pc_decode = nlm4svc_decode_testargs, 835 - .pc_encode = nlm4svc_encode_void, 836 - .pc_argsize = sizeof(struct nlm_args), 837 - .pc_argzero = sizeof(struct nlm_args), 838 - .pc_ressize = sizeof(struct nlm_void), 839 - .pc_xdrressize = St, 840 - .pc_name = "TEST_MSG", 952 + [NLMPROC4_TEST_MSG] = { 953 + .pc_func = nlm4svc_proc_test_msg, 954 + .pc_decode = nlm4_svc_decode_nlm4_testargs, 955 + .pc_encode = nlm4_svc_encode_void, 956 + .pc_argsize = sizeof(struct nlm4_testargs_wrapper), 957 + .pc_argzero = 0, 958 + .pc_ressize = 0, 959 + .pc_xdrressize = XDR_void, 960 + .pc_name = "TEST_MSG", 841 961 }, 842 - [NLMPROC_LOCK_MSG] = { 843 - .pc_func = nlm4svc_proc_lock_msg, 844 - .pc_decode = nlm4svc_decode_lockargs, 845 - .pc_encode = nlm4svc_encode_void, 846 - .pc_argsize = sizeof(struct nlm_args), 847 - .pc_argzero = sizeof(struct nlm_args), 848 - .pc_ressize = sizeof(struct nlm_void), 849 - .pc_xdrressize = St, 850 - .pc_name = "LOCK_MSG", 962 + [NLMPROC4_LOCK_MSG] = { 963 + .pc_func = nlm4svc_proc_lock_msg, 964 + .pc_decode = nlm4_svc_decode_nlm4_lockargs, 965 + .pc_encode = nlm4_svc_encode_void, 966 + .pc_argsize = sizeof(struct nlm4_lockargs_wrapper), 967 + .pc_argzero = 0, 968 + .pc_ressize = 0, 969 + .pc_xdrressize = XDR_void, 970 + .pc_name = "LOCK_MSG", 851 971 }, 852 - [NLMPROC_CANCEL_MSG] = { 853 - .pc_func = nlm4svc_proc_cancel_msg, 854 - .pc_decode = nlm4svc_decode_cancargs, 855 - .pc_encode = nlm4svc_encode_void, 856 - .pc_argsize = sizeof(struct nlm_args), 857 - .pc_argzero = sizeof(struct nlm_args), 858 - .pc_ressize = sizeof(struct nlm_void), 859 - .pc_xdrressize = St, 860 - .pc_name = "CANCEL_MSG", 972 + [NLMPROC4_CANCEL_MSG] = { 973 + .pc_func = nlm4svc_proc_cancel_msg, 974 + .pc_decode = nlm4_svc_decode_nlm4_cancargs, 975 + .pc_encode = nlm4_svc_encode_void, 976 + .pc_argsize = sizeof(struct nlm4_cancargs_wrapper), 977 + .pc_argzero = 0, 978 + .pc_ressize = 0, 979 + .pc_xdrressize = XDR_void, 980 + .pc_name = "CANCEL_MSG", 861 981 }, 862 - [NLMPROC_UNLOCK_MSG] = { 863 - .pc_func = nlm4svc_proc_unlock_msg, 864 - .pc_decode = nlm4svc_decode_unlockargs, 865 - .pc_encode = nlm4svc_encode_void, 866 - .pc_argsize = sizeof(struct nlm_args), 867 - .pc_argzero = sizeof(struct nlm_args), 868 - .pc_ressize = sizeof(struct nlm_void), 869 - .pc_xdrressize = St, 870 - .pc_name = "UNLOCK_MSG", 982 + [NLMPROC4_UNLOCK_MSG] = { 983 + .pc_func = nlm4svc_proc_unlock_msg, 984 + .pc_decode = nlm4_svc_decode_nlm4_unlockargs, 985 + .pc_encode = nlm4_svc_encode_void, 986 + .pc_argsize = sizeof(struct nlm4_unlockargs_wrapper), 987 + .pc_argzero = 0, 988 + .pc_ressize = 0, 989 + .pc_xdrressize = XDR_void, 990 + .pc_name = "UNLOCK_MSG", 871 991 }, 872 - [NLMPROC_GRANTED_MSG] = { 873 - .pc_func = nlm4svc_proc_granted_msg, 874 - .pc_decode = nlm4svc_decode_testargs, 875 - .pc_encode = nlm4svc_encode_void, 876 - .pc_argsize = sizeof(struct nlm_args), 877 - .pc_argzero = sizeof(struct nlm_args), 878 - .pc_ressize = sizeof(struct nlm_void), 879 - .pc_xdrressize = St, 880 - .pc_name = "GRANTED_MSG", 992 + [NLMPROC4_GRANTED_MSG] = { 993 + .pc_func = nlm4svc_proc_granted_msg, 994 + .pc_decode = nlm4_svc_decode_nlm4_testargs, 995 + .pc_encode = nlm4_svc_encode_void, 996 + .pc_argsize = sizeof(struct nlm4_testargs_wrapper), 997 + .pc_argzero = 0, 998 + .pc_ressize = 0, 999 + .pc_xdrressize = XDR_void, 1000 + .pc_name = "GRANTED_MSG", 881 1001 }, 882 - [NLMPROC_TEST_RES] = { 883 - .pc_func = nlm4svc_proc_null, 884 - .pc_decode = nlm4svc_decode_void, 885 - .pc_encode = nlm4svc_encode_void, 886 - .pc_argsize = sizeof(struct nlm_res), 887 - .pc_argzero = sizeof(struct nlm_res), 888 - .pc_ressize = sizeof(struct nlm_void), 889 - .pc_xdrressize = St, 890 - .pc_name = "TEST_RES", 1002 + [NLMPROC4_TEST_RES] = { 1003 + .pc_func = nlm4svc_proc_null, 1004 + .pc_decode = nlm4_svc_decode_nlm4_testres, 1005 + .pc_encode = nlm4_svc_encode_void, 1006 + .pc_argsize = sizeof(struct nlm4_testres), 1007 + .pc_argzero = 0, 1008 + .pc_ressize = 0, 1009 + .pc_xdrressize = XDR_void, 1010 + .pc_name = "TEST_RES", 891 1011 }, 892 - [NLMPROC_LOCK_RES] = { 893 - .pc_func = nlm4svc_proc_null, 894 - .pc_decode = nlm4svc_decode_void, 895 - .pc_encode = nlm4svc_encode_void, 896 - .pc_argsize = sizeof(struct nlm_res), 897 - .pc_argzero = sizeof(struct nlm_res), 898 - .pc_ressize = sizeof(struct nlm_void), 899 - .pc_xdrressize = St, 900 - .pc_name = "LOCK_RES", 1012 + [NLMPROC4_LOCK_RES] = { 1013 + .pc_func = nlm4svc_proc_null, 1014 + .pc_decode = nlm4_svc_decode_nlm4_res, 1015 + .pc_encode = nlm4_svc_encode_void, 1016 + .pc_argsize = sizeof(struct nlm4_res), 1017 + .pc_argzero = 0, 1018 + .pc_ressize = 0, 1019 + .pc_xdrressize = XDR_void, 1020 + .pc_name = "LOCK_RES", 901 1021 }, 902 - [NLMPROC_CANCEL_RES] = { 903 - .pc_func = nlm4svc_proc_null, 904 - .pc_decode = nlm4svc_decode_void, 905 - .pc_encode = nlm4svc_encode_void, 906 - .pc_argsize = sizeof(struct nlm_res), 907 - .pc_argzero = sizeof(struct nlm_res), 908 - .pc_ressize = sizeof(struct nlm_void), 909 - .pc_xdrressize = St, 910 - .pc_name = "CANCEL_RES", 1022 + [NLMPROC4_CANCEL_RES] = { 1023 + .pc_func = nlm4svc_proc_null, 1024 + .pc_decode = nlm4_svc_decode_nlm4_res, 1025 + .pc_encode = nlm4_svc_encode_void, 1026 + .pc_argsize = sizeof(struct nlm4_res), 1027 + .pc_argzero = 0, 1028 + .pc_ressize = 0, 1029 + .pc_xdrressize = XDR_void, 1030 + .pc_name = "CANCEL_RES", 911 1031 }, 912 - [NLMPROC_UNLOCK_RES] = { 913 - .pc_func = nlm4svc_proc_null, 914 - .pc_decode = nlm4svc_decode_void, 915 - .pc_encode = nlm4svc_encode_void, 916 - .pc_argsize = sizeof(struct nlm_res), 917 - .pc_argzero = sizeof(struct nlm_res), 918 - .pc_ressize = sizeof(struct nlm_void), 919 - .pc_xdrressize = St, 920 - .pc_name = "UNLOCK_RES", 1032 + [NLMPROC4_UNLOCK_RES] = { 1033 + .pc_func = nlm4svc_proc_null, 1034 + .pc_decode = nlm4_svc_decode_nlm4_res, 1035 + .pc_encode = nlm4_svc_encode_void, 1036 + .pc_argsize = sizeof(struct nlm4_res), 1037 + .pc_argzero = 0, 1038 + .pc_ressize = 0, 1039 + .pc_xdrressize = XDR_void, 1040 + .pc_name = "UNLOCK_RES", 921 1041 }, 922 - [NLMPROC_GRANTED_RES] = { 923 - .pc_func = nlm4svc_proc_granted_res, 924 - .pc_decode = nlm4svc_decode_res, 925 - .pc_encode = nlm4svc_encode_void, 926 - .pc_argsize = sizeof(struct nlm_res), 927 - .pc_argzero = sizeof(struct nlm_res), 928 - .pc_ressize = sizeof(struct nlm_void), 929 - .pc_xdrressize = St, 930 - .pc_name = "GRANTED_RES", 1042 + [NLMPROC4_GRANTED_RES] = { 1043 + .pc_func = nlm4svc_proc_granted_res, 1044 + .pc_decode = nlm4_svc_decode_nlm4_res, 1045 + .pc_encode = nlm4_svc_encode_void, 1046 + .pc_argsize = sizeof(struct nlm4_res_wrapper), 1047 + .pc_argzero = 0, 1048 + .pc_ressize = 0, 1049 + .pc_xdrressize = XDR_void, 1050 + .pc_name = "GRANTED_RES", 931 1051 }, 932 - [NLMPROC_NSM_NOTIFY] = { 933 - .pc_func = nlm4svc_proc_sm_notify, 934 - .pc_decode = nlm4svc_decode_reboot, 935 - .pc_encode = nlm4svc_encode_void, 936 - .pc_argsize = sizeof(struct nlm_reboot), 937 - .pc_argzero = sizeof(struct nlm_reboot), 938 - .pc_ressize = sizeof(struct nlm_void), 939 - .pc_xdrressize = St, 940 - .pc_name = "SM_NOTIFY", 1052 + [NLMPROC4_SM_NOTIFY] = { 1053 + .pc_func = nlm4svc_proc_sm_notify, 1054 + .pc_decode = nlm4_svc_decode_nlm4_notifyargs, 1055 + .pc_encode = nlm4_svc_encode_void, 1056 + .pc_argsize = sizeof(struct nlm4_notifyargs_wrapper), 1057 + .pc_argzero = 0, 1058 + .pc_ressize = 0, 1059 + .pc_xdrressize = XDR_void, 1060 + .pc_name = "SM_NOTIFY", 941 1061 }, 942 1062 [17] = { 943 - .pc_func = nlm4svc_proc_unused, 944 - .pc_decode = nlm4svc_decode_void, 945 - .pc_encode = nlm4svc_encode_void, 946 - .pc_argsize = sizeof(struct nlm_void), 947 - .pc_argzero = sizeof(struct nlm_void), 948 - .pc_ressize = sizeof(struct nlm_void), 949 - .pc_xdrressize = 0, 950 - .pc_name = "UNUSED", 1063 + .pc_func = nlm4svc_proc_unused, 1064 + .pc_decode = nlm4_svc_decode_void, 1065 + .pc_encode = nlm4_svc_encode_void, 1066 + .pc_argsize = 0, 1067 + .pc_argzero = 0, 1068 + .pc_ressize = 0, 1069 + .pc_xdrressize = XDR_void, 1070 + .pc_name = "UNUSED", 951 1071 }, 952 1072 [18] = { 953 - .pc_func = nlm4svc_proc_unused, 954 - .pc_decode = nlm4svc_decode_void, 955 - .pc_encode = nlm4svc_encode_void, 956 - .pc_argsize = sizeof(struct nlm_void), 957 - .pc_argzero = sizeof(struct nlm_void), 958 - .pc_ressize = sizeof(struct nlm_void), 959 - .pc_xdrressize = 0, 960 - .pc_name = "UNUSED", 1073 + .pc_func = nlm4svc_proc_unused, 1074 + .pc_decode = nlm4_svc_decode_void, 1075 + .pc_encode = nlm4_svc_encode_void, 1076 + .pc_argsize = 0, 1077 + .pc_argzero = 0, 1078 + .pc_ressize = 0, 1079 + .pc_xdrressize = XDR_void, 1080 + .pc_name = "UNUSED", 961 1081 }, 962 1082 [19] = { 963 - .pc_func = nlm4svc_proc_unused, 964 - .pc_decode = nlm4svc_decode_void, 965 - .pc_encode = nlm4svc_encode_void, 966 - .pc_argsize = sizeof(struct nlm_void), 967 - .pc_argzero = sizeof(struct nlm_void), 968 - .pc_ressize = sizeof(struct nlm_void), 969 - .pc_xdrressize = 0, 970 - .pc_name = "UNUSED", 1083 + .pc_func = nlm4svc_proc_unused, 1084 + .pc_decode = nlm4_svc_decode_void, 1085 + .pc_encode = nlm4_svc_encode_void, 1086 + .pc_argsize = 0, 1087 + .pc_argzero = 0, 1088 + .pc_ressize = 0, 1089 + .pc_xdrressize = XDR_void, 1090 + .pc_name = "UNUSED", 971 1091 }, 972 - [NLMPROC_SHARE] = { 973 - .pc_func = nlm4svc_proc_share, 974 - .pc_decode = nlm4svc_decode_shareargs, 975 - .pc_encode = nlm4svc_encode_shareres, 976 - .pc_argsize = sizeof(struct nlm_args), 977 - .pc_argzero = sizeof(struct nlm_args), 978 - .pc_ressize = sizeof(struct nlm_res), 979 - .pc_xdrressize = Ck+St+1, 980 - .pc_name = "SHARE", 1092 + [NLMPROC4_SHARE] = { 1093 + .pc_func = nlm4svc_proc_share, 1094 + .pc_decode = nlm4_svc_decode_nlm4_shareargs, 1095 + .pc_encode = nlm4_svc_encode_nlm4_shareres, 1096 + .pc_argsize = sizeof(struct nlm4_shareargs_wrapper), 1097 + .pc_argzero = 0, 1098 + .pc_ressize = sizeof(struct nlm4_shareres_wrapper), 1099 + .pc_xdrressize = NLM4_nlm4_shareres_sz, 1100 + .pc_name = "SHARE", 981 1101 }, 982 - [NLMPROC_UNSHARE] = { 983 - .pc_func = nlm4svc_proc_unshare, 984 - .pc_decode = nlm4svc_decode_shareargs, 985 - .pc_encode = nlm4svc_encode_shareres, 986 - .pc_argsize = sizeof(struct nlm_args), 987 - .pc_argzero = sizeof(struct nlm_args), 988 - .pc_ressize = sizeof(struct nlm_res), 989 - .pc_xdrressize = Ck+St+1, 990 - .pc_name = "UNSHARE", 1102 + [NLMPROC4_UNSHARE] = { 1103 + .pc_func = nlm4svc_proc_unshare, 1104 + .pc_decode = nlm4_svc_decode_nlm4_shareargs, 1105 + .pc_encode = nlm4_svc_encode_nlm4_shareres, 1106 + .pc_argsize = sizeof(struct nlm4_shareargs_wrapper), 1107 + .pc_argzero = 0, 1108 + .pc_ressize = sizeof(struct nlm4_shareres_wrapper), 1109 + .pc_xdrressize = NLM4_nlm4_shareres_sz, 1110 + .pc_name = "UNSHARE", 991 1111 }, 992 - [NLMPROC_NM_LOCK] = { 993 - .pc_func = nlm4svc_proc_nm_lock, 994 - .pc_decode = nlm4svc_decode_lockargs, 995 - .pc_encode = nlm4svc_encode_res, 996 - .pc_argsize = sizeof(struct nlm_args), 997 - .pc_argzero = sizeof(struct nlm_args), 998 - .pc_ressize = sizeof(struct nlm_res), 999 - .pc_xdrressize = Ck+St, 1000 - .pc_name = "NM_LOCK", 1112 + [NLMPROC4_NM_LOCK] = { 1113 + .pc_func = nlm4svc_proc_nm_lock, 1114 + .pc_decode = nlm4_svc_decode_nlm4_lockargs, 1115 + .pc_encode = nlm4_svc_encode_nlm4_res, 1116 + .pc_argsize = sizeof(struct nlm4_lockargs_wrapper), 1117 + .pc_argzero = 0, 1118 + .pc_ressize = sizeof(struct nlm4_res_wrapper), 1119 + .pc_xdrressize = NLM4_nlm4_res_sz, 1120 + .pc_name = "NM_LOCK", 1001 1121 }, 1002 - [NLMPROC_FREE_ALL] = { 1003 - .pc_func = nlm4svc_proc_free_all, 1004 - .pc_decode = nlm4svc_decode_notify, 1005 - .pc_encode = nlm4svc_encode_void, 1006 - .pc_argsize = sizeof(struct nlm_args), 1007 - .pc_argzero = sizeof(struct nlm_args), 1008 - .pc_ressize = sizeof(struct nlm_void), 1009 - .pc_xdrressize = St, 1010 - .pc_name = "FREE_ALL", 1122 + [NLMPROC4_FREE_ALL] = { 1123 + .pc_func = nlm4svc_proc_free_all, 1124 + .pc_decode = nlm4_svc_decode_nlm4_notify, 1125 + .pc_encode = nlm4_svc_encode_void, 1126 + .pc_argsize = sizeof(struct nlm4_notify_wrapper), 1127 + .pc_argzero = 0, 1128 + .pc_ressize = 0, 1129 + .pc_xdrressize = XDR_void, 1130 + .pc_name = "FREE_ALL", 1011 1131 }, 1132 + }; 1133 + 1134 + /* 1135 + * Storage requirements for XDR arguments and results 1136 + */ 1137 + union nlm4svc_xdrstore { 1138 + struct nlm4_testargs_wrapper testargs; 1139 + struct nlm4_lockargs_wrapper lockargs; 1140 + struct nlm4_cancargs_wrapper cancargs; 1141 + struct nlm4_unlockargs_wrapper unlockargs; 1142 + struct nlm4_notifyargs_wrapper notifyargs; 1143 + struct nlm4_shareargs_wrapper shareargs; 1144 + struct nlm4_notify_wrapper notify; 1145 + struct nlm4_testres_wrapper testres; 1146 + struct nlm4_res_wrapper res; 1147 + struct nlm4_shareres_wrapper shareres; 1148 + }; 1149 + 1150 + static DEFINE_PER_CPU_ALIGNED(unsigned long, 1151 + nlm4svc_call_counters[ARRAY_SIZE(nlm4svc_procedures)]); 1152 + 1153 + const struct svc_version nlmsvc_version4 = { 1154 + .vs_vers = 4, 1155 + .vs_nproc = ARRAY_SIZE(nlm4svc_procedures), 1156 + .vs_proc = nlm4svc_procedures, 1157 + .vs_count = nlm4svc_call_counters, 1158 + .vs_dispatch = nlmsvc_dispatch, 1159 + .vs_xdrsize = sizeof(union nlm4svc_xdrstore), 1012 1160 };
+10 -11
fs/lockd/svclock.c
··· 28 28 #include <linux/sched.h> 29 29 #include <linux/sunrpc/clnt.h> 30 30 #include <linux/sunrpc/svc_xprt.h> 31 - #include <linux/lockd/nlm.h> 32 - #include <linux/lockd/lockd.h> 31 + 32 + #include "lockd.h" 33 33 34 34 #define NLMDBG_FACILITY NLMDBG_SVCLOCK 35 - 36 - #ifdef CONFIG_LOCKD_V4 37 - #define nlm_deadlock nlm4_deadlock 38 - #else 39 - #define nlm_deadlock nlm_lck_denied 40 - #endif 41 35 42 36 static void nlmsvc_release_block(struct nlm_block *block); 43 37 static void nlmsvc_insert_block(struct nlm_block *block, unsigned long); ··· 73 79 *p = '\0'; 74 80 75 81 return buf; 82 + } 83 + #else 84 + static inline const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie) 85 + { 86 + return "???"; 76 87 } 77 88 #endif 78 89 ··· 462 463 block->b_deferred_req = 463 464 rqstp->rq_chandle.defer(block->b_cache_req); 464 465 if (block->b_deferred_req != NULL) 465 - status = nlm_drop_reply; 466 + status = nlm__int__drop_reply; 466 467 } 467 468 dprintk("lockd: nlmsvc_defer_lock_rqst block %p flags %d status %d\n", 468 469 block, block->b_flags, ntohl(status)); ··· 530 531 ret = nlm_lck_denied; 531 532 goto out; 532 533 } 533 - ret = nlm_drop_reply; 534 + ret = nlm__int__drop_reply; 534 535 goto out; 535 536 } 536 537 ··· 588 589 goto out; 589 590 case -EDEADLK: 590 591 nlmsvc_remove_block(block); 591 - ret = nlm_deadlock; 592 + ret = nlm__int__deadlock; 592 593 goto out; 593 594 default: /* includes ENOLCK */ 594 595 nlmsvc_remove_block(block);
+92 -34
fs/lockd/svcproc.c
··· 10 10 11 11 #include <linux/types.h> 12 12 #include <linux/time.h> 13 - #include <linux/lockd/lockd.h> 14 - #include <linux/lockd/share.h> 15 13 #include <linux/sunrpc/svc_xprt.h> 14 + 15 + #include "lockd.h" 16 + #include "share.h" 16 17 17 18 #define NLMDBG_FACILITY NLMDBG_CLIENT 18 19 19 20 #ifdef CONFIG_LOCKD_V4 20 - static __be32 21 - cast_to_nlm(__be32 status, u32 vers) 21 + static inline __be32 cast_status(__be32 status) 22 22 { 23 - /* Note: status is assumed to be in network byte order !!! */ 24 - if (vers != 4){ 25 - switch (status) { 26 - case nlm_granted: 27 - case nlm_lck_denied: 28 - case nlm_lck_denied_nolocks: 29 - case nlm_lck_blocked: 30 - case nlm_lck_denied_grace_period: 31 - case nlm_drop_reply: 32 - break; 33 - case nlm4_deadlock: 34 - status = nlm_lck_denied; 35 - break; 36 - default: 37 - status = nlm_lck_denied_nolocks; 38 - } 23 + switch (status) { 24 + case nlm_granted: 25 + case nlm_lck_denied: 26 + case nlm_lck_denied_nolocks: 27 + case nlm_lck_blocked: 28 + case nlm_lck_denied_grace_period: 29 + case nlm__int__drop_reply: 30 + break; 31 + case nlm__int__deadlock: 32 + status = nlm_lck_denied; 33 + break; 34 + default: 35 + status = nlm_lck_denied_nolocks; 39 36 } 40 37 41 - return (status); 38 + return status; 42 39 } 43 - #define cast_status(status) (cast_to_nlm(status, rqstp->rq_vers)) 44 40 #else 45 - #define cast_status(status) (status) 41 + static inline __be32 cast_status(__be32 status) 42 + { 43 + switch (status) { 44 + case nlm__int__deadlock: 45 + status = nlm_lck_denied; 46 + break; 47 + case nlm__int__stale_fh: 48 + case nlm__int__failed: 49 + status = nlm_lck_denied_nolocks; 50 + break; 51 + default: 52 + if (be32_to_cpu(status) >= 30000) 53 + pr_warn_once("lockd: unhandled internal status %u\n", 54 + be32_to_cpu(status)); 55 + break; 56 + } 57 + return status; 58 + } 46 59 #endif 47 60 48 61 /* ··· 137 124 138 125 /* Obtain client and file */ 139 126 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 140 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 127 + return resp->status == nlm__int__drop_reply ? 128 + rpc_drop_reply : rpc_success; 141 129 142 130 /* Now check for conflicting locks */ 143 131 resp->status = cast_status(nlmsvc_testlock(rqstp, file, host, 144 132 &argp->lock, &resp->lock)); 145 - if (resp->status == nlm_drop_reply) 133 + if (resp->status == nlm__int__drop_reply) 146 134 rc = rpc_drop_reply; 147 135 else 148 136 dprintk("lockd: TEST status %d vers %d\n", ··· 175 161 176 162 /* Obtain client and file */ 177 163 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 178 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 164 + return resp->status == nlm__int__drop_reply ? 165 + rpc_drop_reply : rpc_success; 179 166 180 167 /* Now try to lock the file */ 181 168 resp->status = cast_status(nlmsvc_lock(rqstp, file, host, &argp->lock, 182 169 argp->block, &argp->cookie, 183 170 argp->reclaim)); 184 - if (resp->status == nlm_drop_reply) 171 + if (resp->status == nlm__int__drop_reply) 185 172 rc = rpc_drop_reply; 186 173 else 187 174 dprintk("lockd: LOCK status %d\n", ntohl(resp->status)); ··· 219 204 220 205 /* Obtain client and file */ 221 206 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 222 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 207 + return resp->status == nlm__int__drop_reply ? 208 + rpc_drop_reply : rpc_success; 223 209 224 210 /* Try to cancel request. */ 225 211 resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock)); ··· 261 245 262 246 /* Obtain client and file */ 263 247 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 264 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 248 + return resp->status == nlm__int__drop_reply ? 249 + rpc_drop_reply : rpc_success; 265 250 266 251 /* Now try to remove the lock */ 267 252 resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock)); ··· 419 402 420 403 /* Obtain client and file */ 421 404 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 422 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 405 + return resp->status == nlm__int__drop_reply ? 406 + rpc_drop_reply : rpc_success; 423 407 424 408 /* Now try to create the share */ 425 - resp->status = cast_status(nlmsvc_share_file(host, file, argp)); 409 + resp->status = cast_status(nlmsvc_share_file(host, file, &argp->lock.oh, 410 + argp->fsm_access, 411 + argp->fsm_mode)); 426 412 427 413 dprintk("lockd: SHARE status %d\n", ntohl(resp->status)); 428 414 nlmsvc_release_lockowner(&argp->lock); ··· 457 437 458 438 /* Obtain client and file */ 459 439 if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file))) 460 - return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; 440 + return resp->status == nlm__int__drop_reply ? 441 + rpc_drop_reply : rpc_success; 461 442 462 443 /* Now try to unshare the file */ 463 - resp->status = cast_status(nlmsvc_unshare_file(host, file, argp)); 444 + resp->status = cast_status(nlmsvc_unshare_file(host, file, 445 + &argp->lock.oh)); 464 446 465 447 dprintk("lockd: UNSHARE status %d\n", ntohl(resp->status)); 466 448 nlmsvc_release_lockowner(&argp->lock); ··· 558 536 #define No (1+1024/4) /* Net Obj */ 559 537 #define Rg 2 /* range - offset + size */ 560 538 561 - const struct svc_procedure nlmsvc_procedures[24] = { 539 + static const struct svc_procedure nlmsvc_procedures[24] = { 562 540 [NLMPROC_NULL] = { 563 541 .pc_func = nlmsvc_proc_null, 564 542 .pc_decode = nlmsvc_decode_void, ··· 799 777 .pc_xdrressize = 0, 800 778 .pc_name = "FREE_ALL", 801 779 }, 780 + }; 781 + 782 + /* 783 + * Storage requirements for XDR arguments and results 784 + */ 785 + union nlmsvc_xdrstore { 786 + struct nlm_args args; 787 + struct nlm_res res; 788 + struct nlm_reboot reboot; 789 + }; 790 + 791 + /* 792 + * NLMv1 defines only procedures 1 - 15. Linux lockd also implements 793 + * procedures 0 (NULL) and 16 (SM_NOTIFY). 794 + */ 795 + static DEFINE_PER_CPU_ALIGNED(unsigned long, nlm1svc_call_counters[17]); 796 + 797 + const struct svc_version nlmsvc_version1 = { 798 + .vs_vers = 1, 799 + .vs_nproc = 17, 800 + .vs_proc = nlmsvc_procedures, 801 + .vs_count = nlm1svc_call_counters, 802 + .vs_dispatch = nlmsvc_dispatch, 803 + .vs_xdrsize = sizeof(union nlmsvc_xdrstore), 804 + }; 805 + 806 + static DEFINE_PER_CPU_ALIGNED(unsigned long, 807 + nlm3svc_call_counters[ARRAY_SIZE(nlmsvc_procedures)]); 808 + 809 + const struct svc_version nlmsvc_version3 = { 810 + .vs_vers = 3, 811 + .vs_nproc = ARRAY_SIZE(nlmsvc_procedures), 812 + .vs_proc = nlmsvc_procedures, 813 + .vs_count = nlm3svc_call_counters, 814 + .vs_dispatch = nlmsvc_dispatch, 815 + .vs_xdrsize = sizeof(union nlmsvc_xdrstore), 802 816 };
+26 -14
fs/lockd/svcshare.c
··· 14 14 15 15 #include <linux/sunrpc/clnt.h> 16 16 #include <linux/sunrpc/svc.h> 17 - #include <linux/lockd/lockd.h> 18 - #include <linux/lockd/share.h> 17 + 18 + #include "lockd.h" 19 + #include "share.h" 19 20 20 21 static inline int 21 22 nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh) ··· 25 24 && !memcmp(share->s_owner.data, oh->data, oh->len); 26 25 } 27 26 27 + /** 28 + * nlmsvc_share_file - create a share 29 + * @host: Network client peer 30 + * @file: File to be shared 31 + * @oh: Share owner handle 32 + * @access: Requested access mode 33 + * @mode: Requested file sharing mode 34 + * 35 + * Returns an NLM status code. 36 + */ 28 37 __be32 29 38 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, 30 - struct nlm_args *argp) 39 + struct xdr_netobj *oh, u32 access, u32 mode) 31 40 { 32 41 struct nlm_share *share; 33 - struct xdr_netobj *oh = &argp->lock.oh; 34 42 u8 *ohdata; 35 43 36 44 if (nlmsvc_file_cannot_lock(file)) ··· 48 38 for (share = file->f_shares; share; share = share->s_next) { 49 39 if (share->s_host == host && nlm_cmp_owner(share, oh)) 50 40 goto update; 51 - if ((argp->fsm_access & share->s_mode) 52 - || (argp->fsm_mode & share->s_access )) 41 + if ((access & share->s_mode) || (mode & share->s_access)) 53 42 return nlm_lck_denied; 54 43 } 55 44 56 - share = kmalloc(sizeof(*share) + oh->len, 57 - GFP_KERNEL); 45 + share = kmalloc(sizeof(*share) + oh->len, GFP_KERNEL); 58 46 if (share == NULL) 59 47 return nlm_lck_denied_nolocks; 60 48 ··· 68 60 file->f_shares = share; 69 61 70 62 update: 71 - share->s_access = argp->fsm_access; 72 - share->s_mode = argp->fsm_mode; 63 + share->s_access = access; 64 + share->s_mode = mode; 73 65 return nlm_granted; 74 66 } 75 67 76 - /* 77 - * Delete a share. 68 + /** 69 + * nlmsvc_unshare_file - delete a share 70 + * @host: Network client peer 71 + * @file: File to be unshared 72 + * @oh: Share owner handle 73 + * 74 + * Returns an NLM status code. 78 75 */ 79 76 __be32 80 77 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, 81 - struct nlm_args *argp) 78 + struct xdr_netobj *oh) 82 79 { 83 80 struct nlm_share *share, **shpp; 84 - struct xdr_netobj *oh = &argp->lock.oh; 85 81 86 82 if (nlmsvc_file_cannot_lock(file)) 87 83 return nlm_lck_denied_nolocks;
+24 -8
fs/lockd/svcsubs.c
··· 15 15 #include <linux/mutex.h> 16 16 #include <linux/sunrpc/svc.h> 17 17 #include <linux/sunrpc/addr.h> 18 - #include <linux/lockd/lockd.h> 19 - #include <linux/lockd/share.h> 20 18 #include <linux/module.h> 21 19 #include <linux/mount.h> 22 20 #include <uapi/linux/nfs2.h> 21 + 22 + #include "lockd.h" 23 + #include "share.h" 23 24 24 25 #define NLMDBG_FACILITY NLMDBG_SVCSUBS 25 26 ··· 88 87 struct nlm_file *file, int mode) 89 88 { 90 89 struct file **fp = &file->f_file[mode]; 91 - __be32 nfserr; 90 + __be32 nlmerr = nlm_granted; 91 + int error; 92 92 93 93 if (*fp) 94 - return 0; 95 - nfserr = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); 96 - if (nfserr) 97 - dprintk("lockd: open failed (error %d)\n", nfserr); 98 - return nfserr; 94 + return nlmerr; 95 + 96 + error = nlmsvc_ops->fopen(rqstp, &file->f_handle, fp, mode); 97 + if (error) { 98 + dprintk("lockd: open failed (errno %d)\n", error); 99 + switch (error) { 100 + case -EWOULDBLOCK: 101 + nlmerr = nlm__int__drop_reply; 102 + break; 103 + case -ESTALE: 104 + nlmerr = nlm__int__stale_fh; 105 + break; 106 + default: 107 + nlmerr = nlm__int__failed; 108 + break; 109 + } 110 + } 111 + 112 + return nlmerr; 99 113 } 100 114 101 115 /*
+2 -1
fs/lockd/trace.h
··· 8 8 #include <linux/tracepoint.h> 9 9 #include <linux/crc32.h> 10 10 #include <linux/nfs.h> 11 - #include <linux/lockd/lockd.h> 11 + 12 + #include "lockd.h" 12 13 13 14 #ifdef CONFIG_LOCKD_V4 14 15 #define NLM_STATUS_LIST \
+3 -3
fs/lockd/xdr.c
··· 15 15 #include <linux/sunrpc/clnt.h> 16 16 #include <linux/sunrpc/svc.h> 17 17 #include <linux/sunrpc/stats.h> 18 - #include <linux/lockd/lockd.h> 19 18 20 19 #include <uapi/linux/nfs2.h> 21 20 21 + #include "lockd.h" 22 + #include "share.h" 22 23 #include "svcxdr.h" 23 - 24 24 25 25 static inline loff_t 26 26 s32_to_loff_t(__s32 offset) ··· 275 275 276 276 memset(lock, 0, sizeof(*lock)); 277 277 locks_init_lock(&lock->fl); 278 - lock->svid = ~(u32)0; 278 + lock->svid = LOCKD_SHARE_SVID; 279 279 280 280 if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 281 281 return false;
-347
fs/lockd/xdr4.c
··· 1 - // SPDX-License-Identifier: GPL-2.0 2 - /* 3 - * linux/fs/lockd/xdr4.c 4 - * 5 - * XDR support for lockd and the lock client. 6 - * 7 - * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> 8 - * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no> 9 - */ 10 - 11 - #include <linux/types.h> 12 - #include <linux/sched.h> 13 - #include <linux/nfs.h> 14 - 15 - #include <linux/sunrpc/xdr.h> 16 - #include <linux/sunrpc/clnt.h> 17 - #include <linux/sunrpc/svc.h> 18 - #include <linux/sunrpc/stats.h> 19 - #include <linux/lockd/lockd.h> 20 - 21 - #include "svcxdr.h" 22 - 23 - static inline s64 24 - loff_t_to_s64(loff_t offset) 25 - { 26 - s64 res; 27 - if (offset > NLM4_OFFSET_MAX) 28 - res = NLM4_OFFSET_MAX; 29 - else if (offset < -NLM4_OFFSET_MAX) 30 - res = -NLM4_OFFSET_MAX; 31 - else 32 - res = offset; 33 - return res; 34 - } 35 - 36 - void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len) 37 - { 38 - s64 end = off + len - 1; 39 - 40 - fl->fl_start = off; 41 - if (len == 0 || end < 0) 42 - fl->fl_end = OFFSET_MAX; 43 - else 44 - fl->fl_end = end; 45 - } 46 - 47 - /* 48 - * NLM file handles are defined by specification to be a variable-length 49 - * XDR opaque no longer than 1024 bytes. However, this implementation 50 - * limits their length to the size of an NFSv3 file handle. 51 - */ 52 - static bool 53 - svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) 54 - { 55 - __be32 *p; 56 - u32 len; 57 - 58 - if (xdr_stream_decode_u32(xdr, &len) < 0) 59 - return false; 60 - if (len > NFS_MAXFHSIZE) 61 - return false; 62 - 63 - p = xdr_inline_decode(xdr, len); 64 - if (!p) 65 - return false; 66 - fh->size = len; 67 - memcpy(fh->data, p, len); 68 - memset(fh->data + len, 0, sizeof(fh->data) - len); 69 - 70 - return true; 71 - } 72 - 73 - static bool 74 - svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock) 75 - { 76 - struct file_lock *fl = &lock->fl; 77 - 78 - if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) 79 - return false; 80 - if (!svcxdr_decode_fhandle(xdr, &lock->fh)) 81 - return false; 82 - if (!svcxdr_decode_owner(xdr, &lock->oh)) 83 - return false; 84 - if (xdr_stream_decode_u32(xdr, &lock->svid) < 0) 85 - return false; 86 - if (xdr_stream_decode_u64(xdr, &lock->lock_start) < 0) 87 - return false; 88 - if (xdr_stream_decode_u64(xdr, &lock->lock_len) < 0) 89 - return false; 90 - 91 - locks_init_lock(fl); 92 - fl->c.flc_type = F_RDLCK; 93 - nlm4svc_set_file_lock_range(fl, lock->lock_start, lock->lock_len); 94 - return true; 95 - } 96 - 97 - static bool 98 - svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock) 99 - { 100 - const struct file_lock *fl = &lock->fl; 101 - s64 start, len; 102 - 103 - /* exclusive */ 104 - if (xdr_stream_encode_bool(xdr, fl->c.flc_type != F_RDLCK) < 0) 105 - return false; 106 - if (xdr_stream_encode_u32(xdr, lock->svid) < 0) 107 - return false; 108 - if (!svcxdr_encode_owner(xdr, &lock->oh)) 109 - return false; 110 - start = loff_t_to_s64(fl->fl_start); 111 - if (fl->fl_end == OFFSET_MAX) 112 - len = 0; 113 - else 114 - len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1); 115 - if (xdr_stream_encode_u64(xdr, start) < 0) 116 - return false; 117 - if (xdr_stream_encode_u64(xdr, len) < 0) 118 - return false; 119 - 120 - return true; 121 - } 122 - 123 - static bool 124 - svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp) 125 - { 126 - if (!svcxdr_encode_stats(xdr, resp->status)) 127 - return false; 128 - switch (resp->status) { 129 - case nlm_lck_denied: 130 - if (!svcxdr_encode_holder(xdr, &resp->lock)) 131 - return false; 132 - } 133 - 134 - return true; 135 - } 136 - 137 - 138 - /* 139 - * Decode Call arguments 140 - */ 141 - 142 - bool 143 - nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 144 - { 145 - return true; 146 - } 147 - 148 - bool 149 - nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 150 - { 151 - struct nlm_args *argp = rqstp->rq_argp; 152 - u32 exclusive; 153 - 154 - if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 155 - return false; 156 - if (xdr_stream_decode_bool(xdr, &exclusive) < 0) 157 - return false; 158 - if (!svcxdr_decode_lock(xdr, &argp->lock)) 159 - return false; 160 - if (exclusive) 161 - argp->lock.fl.c.flc_type = F_WRLCK; 162 - 163 - return true; 164 - } 165 - 166 - bool 167 - nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 168 - { 169 - struct nlm_args *argp = rqstp->rq_argp; 170 - u32 exclusive; 171 - 172 - if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 173 - return false; 174 - if (xdr_stream_decode_bool(xdr, &argp->block) < 0) 175 - return false; 176 - if (xdr_stream_decode_bool(xdr, &exclusive) < 0) 177 - return false; 178 - if (!svcxdr_decode_lock(xdr, &argp->lock)) 179 - return false; 180 - if (exclusive) 181 - argp->lock.fl.c.flc_type = F_WRLCK; 182 - if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) 183 - return false; 184 - if (xdr_stream_decode_u32(xdr, &argp->state) < 0) 185 - return false; 186 - argp->monitor = 1; /* monitor client by default */ 187 - 188 - return true; 189 - } 190 - 191 - bool 192 - nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 193 - { 194 - struct nlm_args *argp = rqstp->rq_argp; 195 - u32 exclusive; 196 - 197 - if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 198 - return false; 199 - if (xdr_stream_decode_bool(xdr, &argp->block) < 0) 200 - return false; 201 - if (xdr_stream_decode_bool(xdr, &exclusive) < 0) 202 - return false; 203 - if (!svcxdr_decode_lock(xdr, &argp->lock)) 204 - return false; 205 - if (exclusive) 206 - argp->lock.fl.c.flc_type = F_WRLCK; 207 - 208 - return true; 209 - } 210 - 211 - bool 212 - nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 213 - { 214 - struct nlm_args *argp = rqstp->rq_argp; 215 - 216 - if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 217 - return false; 218 - if (!svcxdr_decode_lock(xdr, &argp->lock)) 219 - return false; 220 - argp->lock.fl.c.flc_type = F_UNLCK; 221 - 222 - return true; 223 - } 224 - 225 - bool 226 - nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) 227 - { 228 - struct nlm_res *resp = rqstp->rq_argp; 229 - 230 - if (!svcxdr_decode_cookie(xdr, &resp->cookie)) 231 - return false; 232 - if (!svcxdr_decode_stats(xdr, &resp->status)) 233 - return false; 234 - 235 - return true; 236 - } 237 - 238 - bool 239 - nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) 240 - { 241 - struct nlm_reboot *argp = rqstp->rq_argp; 242 - __be32 *p; 243 - u32 len; 244 - 245 - if (xdr_stream_decode_u32(xdr, &len) < 0) 246 - return false; 247 - if (len > SM_MAXSTRLEN) 248 - return false; 249 - p = xdr_inline_decode(xdr, len); 250 - if (!p) 251 - return false; 252 - argp->len = len; 253 - argp->mon = (char *)p; 254 - if (xdr_stream_decode_u32(xdr, &argp->state) < 0) 255 - return false; 256 - p = xdr_inline_decode(xdr, SM_PRIV_SIZE); 257 - if (!p) 258 - return false; 259 - memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); 260 - 261 - return true; 262 - } 263 - 264 - bool 265 - nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 266 - { 267 - struct nlm_args *argp = rqstp->rq_argp; 268 - struct nlm_lock *lock = &argp->lock; 269 - 270 - locks_init_lock(&lock->fl); 271 - lock->svid = ~(u32)0; 272 - 273 - if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 274 - return false; 275 - if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) 276 - return false; 277 - if (!svcxdr_decode_fhandle(xdr, &lock->fh)) 278 - return false; 279 - if (!svcxdr_decode_owner(xdr, &lock->oh)) 280 - return false; 281 - /* XXX: Range checks are missing in the original code */ 282 - if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) 283 - return false; 284 - if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) 285 - return false; 286 - 287 - return true; 288 - } 289 - 290 - bool 291 - nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) 292 - { 293 - struct nlm_args *argp = rqstp->rq_argp; 294 - struct nlm_lock *lock = &argp->lock; 295 - 296 - if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) 297 - return false; 298 - if (xdr_stream_decode_u32(xdr, &argp->state) < 0) 299 - return false; 300 - 301 - return true; 302 - } 303 - 304 - 305 - /* 306 - * Encode Reply results 307 - */ 308 - 309 - bool 310 - nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 311 - { 312 - return true; 313 - } 314 - 315 - bool 316 - nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 317 - { 318 - struct nlm_res *resp = rqstp->rq_resp; 319 - 320 - return svcxdr_encode_cookie(xdr, &resp->cookie) && 321 - svcxdr_encode_testrply(xdr, resp); 322 - } 323 - 324 - bool 325 - nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) 326 - { 327 - struct nlm_res *resp = rqstp->rq_resp; 328 - 329 - return svcxdr_encode_cookie(xdr, &resp->cookie) && 330 - svcxdr_encode_stats(xdr, resp->status); 331 - } 332 - 333 - bool 334 - nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 335 - { 336 - struct nlm_res *resp = rqstp->rq_resp; 337 - 338 - if (!svcxdr_encode_cookie(xdr, &resp->cookie)) 339 - return false; 340 - if (!svcxdr_encode_stats(xdr, resp->status)) 341 - return false; 342 - /* sequence */ 343 - if (xdr_stream_encode_u32(xdr, 0) < 0) 344 - return false; 345 - 346 - return true; 347 - }
+21 -5
fs/locks.c
··· 1534 1534 { 1535 1535 struct file_lock_context *ctx = inode->i_flctx; 1536 1536 struct file_lease *fl, *tmp; 1537 + bool remove; 1537 1538 1538 1539 lockdep_assert_held(&ctx->flc_lock); 1539 1540 ··· 1542 1541 trace_time_out_leases(inode, fl); 1543 1542 if (past_time(fl->fl_downgrade_time)) 1544 1543 lease_modify(fl, F_RDLCK, dispose); 1545 - if (past_time(fl->fl_break_time)) 1546 - lease_modify(fl, F_UNLCK, dispose); 1544 + 1545 + remove = true; 1546 + if (past_time(fl->fl_break_time)) { 1547 + /* 1548 + * Consult the lease manager when a lease break times 1549 + * out to determine whether the lease should be disposed 1550 + * of. 1551 + */ 1552 + if (fl->fl_lmops && fl->fl_lmops->lm_breaker_timedout) 1553 + remove = fl->fl_lmops->lm_breaker_timedout(fl); 1554 + if (remove) 1555 + lease_modify(fl, F_UNLCK, dispose); 1556 + } 1547 1557 } 1548 1558 } 1549 1559 ··· 1682 1670 restart: 1683 1671 fl = list_first_entry(&ctx->flc_lease, struct file_lease, c.flc_list); 1684 1672 break_time = fl->fl_break_time; 1685 - if (break_time != 0) 1686 - break_time -= jiffies; 1687 - if (break_time == 0) 1673 + if (break_time != 0) { 1674 + if (time_after(jiffies, break_time)) { 1675 + fl->fl_break_time = jiffies + lease_break_time * HZ; 1676 + break_time = lease_break_time * HZ; 1677 + } else 1678 + break_time -= jiffies; 1679 + } else 1688 1680 break_time++; 1689 1681 locks_insert_block(&fl->c, &new_fl->c, leases_conflict); 1690 1682 trace_break_lease_block(inode, new_fl);
+1 -3
fs/nfs/blocklayout/blocklayout.c
··· 380 380 sector_t isect, extent_length = 0; 381 381 struct parallel_io *par = NULL; 382 382 loff_t offset = header->args.offset; 383 - size_t count = header->args.count; 384 383 struct page **pages = header->args.pages; 385 384 int pg_index = header->args.pgbase >> PAGE_SHIFT; 386 385 unsigned int pg_len; 387 386 struct blk_plug plug; 388 387 int i; 389 388 390 - dprintk("%s enter, %zu@%lld\n", __func__, count, offset); 389 + dprintk("%s enter, %u@%lld\n", __func__, header->args.count, offset); 391 390 392 391 /* At this point, header->page_aray is a (sequential) list of nfs_pages. 393 392 * We want to write each, and if there is an error set pnfs_error ··· 427 428 } 428 429 429 430 offset += pg_len; 430 - count -= pg_len; 431 431 isect += (pg_len >> SECTOR_SHIFT); 432 432 extent_length -= (pg_len >> SECTOR_SHIFT); 433 433 }
+1
fs/nfs/nfs3proc.c
··· 16 16 #include <linux/nfs3.h> 17 17 #include <linux/nfs_fs.h> 18 18 #include <linux/nfs_page.h> 19 + #include <linux/filelock.h> 19 20 #include <linux/lockd/bind.h> 20 21 #include <linux/nfs_mount.h> 21 22 #include <linux/freezer.h>
+1
fs/nfs/proc.c
··· 41 41 #include <linux/nfs2.h> 42 42 #include <linux/nfs_fs.h> 43 43 #include <linux/nfs_page.h> 44 + #include <linux/filelock.h> 44 45 #include <linux/lockd/bind.h> 45 46 #include <linux/freezer.h> 46 47 #include "internal.h"
+2 -2
fs/nfs/sysfs.c
··· 13 13 #include <linux/nfs_fs.h> 14 14 #include <net/net_namespace.h> 15 15 #include <linux/rcupdate.h> 16 - #include <linux/lockd/lockd.h> 16 + #include <linux/lockd/bind.h> 17 17 18 18 #include "internal.h" 19 19 #include "nfs4_fs.h" ··· 288 288 shutdown_client(server->client_acl); 289 289 290 290 if (server->nlm_host) 291 - shutdown_client(server->nlm_host->h_rpcclnt); 291 + nlmclnt_shutdown_rpc_clnt(server->nlm_host); 292 292 out: 293 293 shutdown_nfs_client(server->nfs_client); 294 294 return count;
+1 -11
fs/nfsd/Kconfig
··· 7 7 select CRC32 8 8 select CRYPTO_LIB_MD5 if NFSD_LEGACY_CLIENT_TRACKING 9 9 select CRYPTO_LIB_SHA256 if NFSD_V4 10 + select CRYPTO # required by RPCSEC_GSS_KRB5 and signed filehandles 10 11 select LOCKD 11 12 select SUNRPC 12 13 select EXPORTFS ··· 79 78 depends on NFSD && PROC_FS 80 79 select FS_POSIX_ACL 81 80 select RPCSEC_GSS_KRB5 82 - select CRYPTO # required by RPCSEC_GSS_KRB5 83 81 select GRACE_PERIOD 84 82 select NFS_V4_2_SSC_HELPER if NFS_V4_2 85 83 help ··· 176 176 These legacy client tracking methods have proven to be problematic 177 177 and will be removed in the future. Say Y here if you need support 178 178 for them in the interim. 179 - 180 - config NFSD_V4_DELEG_TIMESTAMPS 181 - bool "Support delegated timestamps" 182 - depends on NFSD_V4 183 - default n 184 - help 185 - NFSD implements delegated timestamps according to 186 - draft-ietf-nfsv4-delstid-08 "Extending the Opening of Files". This 187 - is currently an experimental feature and is therefore left disabled 188 - by default. 189 179 190 180 config NFSD_V4_POSIX_ACLS 191 181 bool "Support NFSv4 POSIX draft ACLs"
+101 -1
fs/nfsd/blocklayout.c
··· 273 273 #endif /* CONFIG_NFSD_BLOCKLAYOUT */ 274 274 275 275 #ifdef CONFIG_NFSD_SCSILAYOUT 276 + 277 + #define NFSD_MDS_PR_FENCED XA_MARK_0 278 + 279 + /* 280 + * Clear the fence flag if the device already has an entry. This occurs 281 + * when a client re-registers after a previous fence, allowing new 282 + * layouts for this device. 283 + * 284 + * Insert only on first registration. This bounds cl_dev_fences to the 285 + * count of devices this client has accessed, preventing unbounded growth. 286 + */ 287 + static inline int nfsd4_scsi_fence_insert(struct nfs4_client *clp, 288 + dev_t device) 289 + { 290 + struct xarray *xa = &clp->cl_dev_fences; 291 + int ret; 292 + 293 + xa_lock(xa); 294 + ret = __xa_insert(xa, device, XA_ZERO_ENTRY, GFP_KERNEL); 295 + if (ret == -EBUSY) { 296 + __xa_clear_mark(xa, device, NFSD_MDS_PR_FENCED); 297 + ret = 0; 298 + } 299 + xa_unlock(xa); 300 + clp->cl_fence_retry_warn = false; 301 + return ret; 302 + } 303 + 304 + static inline bool nfsd4_scsi_fence_set(struct nfs4_client *clp, dev_t device) 305 + { 306 + struct xarray *xa = &clp->cl_dev_fences; 307 + bool skip; 308 + 309 + xa_lock(xa); 310 + skip = xa_get_mark(xa, device, NFSD_MDS_PR_FENCED); 311 + if (!skip) 312 + __xa_set_mark(xa, device, NFSD_MDS_PR_FENCED); 313 + xa_unlock(xa); 314 + return skip; 315 + } 316 + 317 + static inline void nfsd4_scsi_fence_clear(struct nfs4_client *clp, dev_t device) 318 + { 319 + xa_clear_mark(&clp->cl_dev_fences, device, NFSD_MDS_PR_FENCED); 320 + } 321 + 276 322 #define NFSD_MDS_PR_KEY 0x0100000000000000ULL 277 323 278 324 /* ··· 388 342 goto out_free_dev; 389 343 } 390 344 345 + ret = nfsd4_scsi_fence_insert(clp, sb->s_bdev->bd_dev); 346 + if (ret < 0) 347 + goto out_free_dev; 348 + 391 349 ret = ops->pr_register(sb->s_bdev, 0, NFSD_MDS_PR_KEY, true); 392 350 if (ret) { 393 351 pr_err("pNFS: failed to register key for device %s.\n", ··· 444 394 return nfsd4_block_commit_blocks(inode, lcp, iomaps, nr_iomaps); 445 395 } 446 396 447 - static void 397 + /* 398 + * Perform the fence operation to prevent the client from accessing the 399 + * block device. If a fence operation is already in progress, wait for 400 + * it to complete before checking the NFSD_MDS_PR_FENCED flag. Once the 401 + * operation is complete, check the flag. If NFSD_MDS_PR_FENCED is set, 402 + * update the layout stateid by setting the ls_fenced flag to indicate 403 + * that the client has been fenced. 404 + * 405 + * The cl_fence_mutex ensures that the fence operation has been fully 406 + * completed, rather than just in progress, when returning from this 407 + * function. 408 + * 409 + * Return true if client was fenced otherwise return false. 410 + */ 411 + static bool 448 412 nfsd4_scsi_fence_client(struct nfs4_layout_stateid *ls, struct nfsd_file *file) 449 413 { 450 414 struct nfs4_client *clp = ls->ls_stid.sc_client; 451 415 struct block_device *bdev = file->nf_file->f_path.mnt->mnt_sb->s_bdev; 452 416 int status; 417 + bool ret; 418 + 419 + mutex_lock(&clp->cl_fence_mutex); 420 + if (nfsd4_scsi_fence_set(clp, bdev->bd_dev)) { 421 + mutex_unlock(&clp->cl_fence_mutex); 422 + return true; 423 + } 453 424 454 425 status = bdev->bd_disk->fops->pr_ops->pr_preempt(bdev, NFSD_MDS_PR_KEY, 455 426 nfsd4_scsi_pr_key(clp), 456 427 PR_EXCLUSIVE_ACCESS_REG_ONLY, true); 428 + /* 429 + * Reset to allow retry only when the command could not have 430 + * reached the device. Negative status means a local error 431 + * (e.g., -ENOMEM) prevented the command from being sent. 432 + * PR_STS_PATH_FAILED, PR_STS_PATH_FAST_FAILED, and 433 + * PR_STS_RETRY_PATH_FAILURE indicate transport path failures 434 + * before device delivery. 435 + * 436 + * For all other errors, the command may have reached the device 437 + * and the preempt may have succeeded. Avoid resetting, since 438 + * retrying a successful preempt returns PR_STS_IOERR or 439 + * PR_STS_RESERVATION_CONFLICT, which would cause an infinite 440 + * retry loop. 441 + */ 442 + switch (status) { 443 + case 0: 444 + case PR_STS_IOERR: 445 + case PR_STS_RESERVATION_CONFLICT: 446 + ret = true; 447 + break; 448 + default: 449 + /* retry-able and other errors */ 450 + ret = false; 451 + nfsd4_scsi_fence_clear(clp, bdev->bd_dev); 452 + break; 453 + } 454 + mutex_unlock(&clp->cl_fence_mutex); 455 + 457 456 trace_nfsd_pnfs_fence(clp, bdev->bd_disk->disk_name, status); 457 + return ret; 458 458 } 459 459 460 460 const struct nfsd4_layout_ops scsi_layout_ops = {
+4
fs/nfsd/debugfs.c
··· 140 140 141 141 debugfs_create_file("io_cache_write", 0644, nfsd_top_dir, NULL, 142 142 &nfsd_io_cache_write_fops); 143 + #ifdef CONFIG_NFSD_V4 144 + debugfs_create_bool("delegated_timestamps", 0644, nfsd_top_dir, 145 + &nfsd_delegts_enabled); 146 + #endif 143 147 }
+3 -2
fs/nfsd/export.c
··· 1362 1362 { NFSEXP_ASYNC, {"async", "sync"}}, 1363 1363 { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}}, 1364 1364 { NFSEXP_NOREADDIRPLUS, {"nordirplus", ""}}, 1365 + { NFSEXP_SECURITY_LABEL, {"security_label", ""}}, 1366 + { NFSEXP_SIGN_FH, {"sign_fh", ""}}, 1365 1367 { NFSEXP_NOHIDE, {"nohide", ""}}, 1366 - { NFSEXP_CROSSMOUNT, {"crossmnt", ""}}, 1367 1368 { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}}, 1368 1369 { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}}, 1370 + { NFSEXP_CROSSMOUNT, {"crossmnt", ""}}, 1369 1371 { NFSEXP_V4ROOT, {"v4root", ""}}, 1370 1372 { NFSEXP_PNFS, {"pnfs", ""}}, 1371 - { NFSEXP_SECURITY_LABEL, {"security_label", ""}}, 1372 1373 { 0, {"", ""}} 1373 1374 }; 1374 1375
+28 -22
fs/nfsd/lockd.c
··· 14 14 15 15 #define NFSDDBG_FACILITY NFSDDBG_LOCKD 16 16 17 - #ifdef CONFIG_LOCKD_V4 18 - #define nlm_stale_fh nlm4_stale_fh 19 - #define nlm_failed nlm4_failed 20 - #else 21 - #define nlm_stale_fh nlm_lck_denied_nolocks 22 - #define nlm_failed nlm_lck_denied_nolocks 23 - #endif 24 - /* 25 - * Note: we hold the dentry use count while the file is open. 17 + /** 18 + * nlm_fopen - Open an NFSD file 19 + * @rqstp: NLM RPC procedure execution context 20 + * @f: NFS file handle to be opened 21 + * @filp: OUT: an opened struct file 22 + * @flags: the POSIX open flags to use 23 + * 24 + * nlm_fopen() holds the dentry reference until nlm_fclose() releases it. 25 + * 26 + * Returns zero on success or a negative errno value if the file 27 + * cannot be opened. 26 28 */ 27 - static __be32 28 - nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp, 29 - int mode) 29 + static int nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, 30 + struct file **filp, int flags) 30 31 { 31 32 __be32 nfserr; 32 33 int access; ··· 48 47 * if NFSEXP_NOAUTHNLM is set. Some older clients use AUTH_NULL 49 48 * for NLM requests. 50 49 */ 51 - access = (mode == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ; 50 + access = (flags == O_WRONLY) ? NFSD_MAY_WRITE : NFSD_MAY_READ; 52 51 access |= NFSD_MAY_NLM | NFSD_MAY_OWNER_OVERRIDE | NFSD_MAY_BYPASS_GSS; 53 52 nfserr = nfsd_open(rqstp, &fh, S_IFREG, access, filp); 54 53 fh_put(&fh); 55 - /* We return nlm error codes as nlm doesn't know 56 - * about nfsd, but nfsd does know about nlm.. 57 - */ 54 + 58 55 switch (nfserr) { 59 56 case nfs_ok: 60 - return 0; 57 + break; 61 58 case nfserr_jukebox: 62 - /* this error can indicate a presence of a conflicting 59 + /* 60 + * This error can indicate a presence of a conflicting 63 61 * delegation to an NLM lock request. Options are: 64 62 * (1) For now, drop this request and make the client 65 63 * retry. When delegation is returned, client's lock retry ··· 66 66 * (2) NLM4_DENIED as per "spec" signals to the client 67 67 * that the lock is unavailable now but client can retry. 68 68 * Linux client implementation does not. It treats 69 - * NLM4_DENIED same as NLM4_FAILED and errors the request. 69 + * NLM4_DENIED same as NLM4_FAILED and fails the request. 70 70 * (3) For the future, treat this as blocked lock and try 71 71 * to callback when the delegation is returned but might 72 72 * not have a proper lock request to block on. 73 73 */ 74 - return nlm_drop_reply; 74 + return -EWOULDBLOCK; 75 75 case nfserr_stale: 76 - return nlm_stale_fh; 76 + return -ESTALE; 77 77 default: 78 - return nlm_failed; 78 + return -ENOLCK; 79 79 } 80 + 81 + return 0; 80 82 } 81 83 84 + /** 85 + * nlm_fclose - Close an NFSD file 86 + * @filp: a struct file that was opened by nlm_fopen() 87 + */ 82 88 static void 83 89 nlm_fclose(struct file *filp) 84 90 {
+3 -2
fs/nfsd/netlink.c
··· 24 24 }; 25 25 26 26 /* NFSD_CMD_THREADS_SET - do */ 27 - static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_MIN_THREADS + 1] = { 27 + static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_FH_KEY + 1] = { 28 28 [NFSD_A_SERVER_THREADS] = { .type = NLA_U32, }, 29 29 [NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, }, 30 30 [NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, }, 31 31 [NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, }, 32 32 [NFSD_A_SERVER_MIN_THREADS] = { .type = NLA_U32, }, 33 + [NFSD_A_SERVER_FH_KEY] = NLA_POLICY_EXACT_LEN(16), 33 34 }; 34 35 35 36 /* NFSD_CMD_VERSION_SET - do */ ··· 59 58 .cmd = NFSD_CMD_THREADS_SET, 60 59 .doit = nfsd_nl_threads_set_doit, 61 60 .policy = nfsd_threads_set_nl_policy, 62 - .maxattr = NFSD_A_SERVER_MIN_THREADS, 61 + .maxattr = NFSD_A_SERVER_FH_KEY, 63 62 .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, 64 63 }, 65 64 {
+7
fs/nfsd/netns.h
··· 25 25 #define SESSION_HASH_SIZE 512 26 26 27 27 struct cld_net; 28 + struct nfsd_net_cb; 28 29 struct nfsd4_client_tracking_ops; 29 30 30 31 enum { ··· 100 99 */ 101 100 struct list_head client_lru; 102 101 struct list_head close_lru; 102 + 103 + /* protects del_recall_lru and delegation hash/unhash */ 104 + spinlock_t deleg_lock ____cacheline_aligned; 103 105 struct list_head del_recall_lru; 104 106 105 107 /* protected by blocked_locks_lock */ ··· 228 224 spinlock_t local_clients_lock; 229 225 struct list_head local_clients; 230 226 #endif 227 + siphash_key_t *fh_key; 228 + 229 + struct nfsd_net_cb *nfsd_cb; 231 230 }; 232 231 233 232 /* Simple check to find out if a given net was properly initialized */
+2 -2
fs/nfsd/nfs3xdr.c
··· 1069 1069 * 1070 1070 * Return values: 1071 1071 * %0: Entry was successfully encoded. 1072 - * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err 1072 + * %-EINVAL: An encoding problem occurred, secondary status code in resp->common.err 1073 1073 * 1074 1074 * On exit, the following fields are updated: 1075 1075 * - resp->xdr ··· 1144 1144 * 1145 1145 * Return values: 1146 1146 * %0: Entry was successfully encoded. 1147 - * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err 1147 + * %-EINVAL: An encoding problem occurred, secondary status code in resp->common.err 1148 1148 * 1149 1149 * On exit, the following fields are updated: 1150 1150 * - resp->xdr
+78 -35
fs/nfsd/nfs4callback.c
··· 1016 1016 .p_decode = nfs4_xdr_dec_##restype, \ 1017 1017 .p_arglen = NFS4_enc_##argtype##_sz, \ 1018 1018 .p_replen = NFS4_dec_##restype##_sz, \ 1019 - .p_statidx = NFSPROC4_CB_##call, \ 1019 + .p_statidx = NFSPROC4_CLNT_##proc, \ 1020 1020 .p_name = #proc, \ 1021 1021 } 1022 1022 ··· 1032 1032 PROC(CB_GETATTR, COMPOUND, cb_getattr, cb_getattr), 1033 1033 }; 1034 1034 1035 - static unsigned int nfs4_cb_counts[ARRAY_SIZE(nfs4_cb_procedures)]; 1036 - static const struct rpc_version nfs_cb_version4 = { 1037 - /* 1038 - * Note on the callback rpc program version number: despite language in rfc 1039 - * 5661 section 18.36.3 requiring servers to use 4 in this field, the 1040 - * official xdr descriptions for both 4.0 and 4.1 specify version 1, and 1041 - * in practice that appears to be what implementations use. The section 1042 - * 18.36.3 language is expected to be fixed in an erratum. 1043 - */ 1044 - .number = 1, 1045 - .nrprocs = ARRAY_SIZE(nfs4_cb_procedures), 1046 - .procs = nfs4_cb_procedures, 1047 - .counts = nfs4_cb_counts, 1048 - }; 1035 + #define NFS4_CB_PROGRAM 0x40000000 1036 + #define NFS4_CB_VERSION 1 1049 1037 1050 - static const struct rpc_version *nfs_cb_version[2] = { 1051 - [1] = &nfs_cb_version4, 1052 - }; 1053 - 1054 - static const struct rpc_program cb_program; 1055 - 1056 - static struct rpc_stat cb_stats = { 1057 - .program = &cb_program 1058 - }; 1059 - 1060 - #define NFS4_CALLBACK 0x40000000 1061 - static const struct rpc_program cb_program = { 1062 - .name = "nfs4_cb", 1063 - .number = NFS4_CALLBACK, 1064 - .nrvers = ARRAY_SIZE(nfs_cb_version), 1065 - .version = nfs_cb_version, 1066 - .stats = &cb_stats, 1067 - .pipe_dir_name = "nfsd4_cb", 1038 + struct nfsd_net_cb { 1039 + struct rpc_version version4; 1040 + const struct rpc_version *versions[NFS4_CB_VERSION + 1]; 1041 + struct rpc_program program; 1042 + struct rpc_stat stat; 1068 1043 }; 1069 1044 1070 1045 static int max_cb_time(struct net *net) ··· 1115 1140 1116 1141 static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) 1117 1142 { 1143 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1118 1144 int maxtime = max_cb_time(clp->net); 1119 1145 struct rpc_timeout timeparms = { 1120 1146 .to_initval = maxtime, ··· 1128 1152 .addrsize = conn->cb_addrlen, 1129 1153 .saddress = (struct sockaddr *) &conn->cb_saddr, 1130 1154 .timeout = &timeparms, 1131 - .program = &cb_program, 1132 - .version = 1, 1155 + .version = NFS4_CB_VERSION, 1133 1156 .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), 1134 1157 .cred = current_cred(), 1135 1158 }; 1136 1159 struct rpc_clnt *client; 1137 1160 const struct cred *cred; 1138 1161 1162 + args.program = &nn->nfsd_cb->program; 1139 1163 if (clp->cl_minorversion == 0) { 1140 1164 if (!clp->cl_cred.cr_principal && 1141 1165 (clp->cl_cred.cr_flavor >= RPC_AUTH_GSS_KRB5)) { ··· 1761 1785 if (!queued) 1762 1786 nfsd41_cb_inflight_end(clp); 1763 1787 return queued; 1788 + } 1789 + 1790 + /** 1791 + * nfsd_net_cb_shutdown - release per-netns callback RPC program resources 1792 + * @nn: NFS server network namespace 1793 + * 1794 + * Frees resources allocated by nfsd_net_cb_init(). 1795 + */ 1796 + void nfsd_net_cb_shutdown(struct nfsd_net *nn) 1797 + { 1798 + struct nfsd_net_cb *cb = nn->nfsd_cb; 1799 + 1800 + if (cb) { 1801 + kfree(cb->version4.counts); 1802 + kfree(cb); 1803 + nn->nfsd_cb = NULL; 1804 + } 1805 + } 1806 + 1807 + /** 1808 + * nfsd_net_cb_init - initialize per-netns callback RPC program 1809 + * @nn: NFS server network namespace 1810 + * 1811 + * Sets up the callback RPC program, version table, procedure 1812 + * counts, and statistics structure for @nn. Caller must release 1813 + * these resources using nfsd_net_cb_shutdown(). 1814 + * 1815 + * Return: 0 on success, or -ENOMEM if allocation fails. 1816 + */ 1817 + int nfsd_net_cb_init(struct nfsd_net *nn) 1818 + { 1819 + struct nfsd_net_cb *cb; 1820 + 1821 + cb = kzalloc(sizeof(*cb), GFP_KERNEL); 1822 + if (!cb) 1823 + return -ENOMEM; 1824 + 1825 + cb->version4.counts = kzalloc_objs(unsigned int, 1826 + ARRAY_SIZE(nfs4_cb_procedures), GFP_KERNEL); 1827 + if (!cb->version4.counts) { 1828 + kfree(cb); 1829 + return -ENOMEM; 1830 + } 1831 + /* 1832 + * Note on the callback rpc program version number: despite language 1833 + * in rfc 5661 section 18.36.3 requiring servers to use 4 in this 1834 + * field, the official xdr descriptions for both 4.0 and 4.1 specify 1835 + * version 1, and in practice that appears to be what implementations 1836 + * use. The section 18.36.3 language is expected to be fixed in an 1837 + * erratum. 1838 + */ 1839 + cb->version4.number = NFS4_CB_VERSION; 1840 + cb->version4.nrprocs = ARRAY_SIZE(nfs4_cb_procedures); 1841 + cb->version4.procs = nfs4_cb_procedures; 1842 + cb->versions[NFS4_CB_VERSION] = &cb->version4; 1843 + 1844 + cb->program.name = "nfs4_cb"; 1845 + cb->program.number = NFS4_CB_PROGRAM; 1846 + cb->program.nrvers = ARRAY_SIZE(cb->versions); 1847 + cb->program.version = &cb->versions[0]; 1848 + cb->program.pipe_dir_name = "nfsd4_cb"; 1849 + cb->program.stats = &cb->stat; 1850 + cb->stat.program = &cb->program; 1851 + 1852 + nn->nfsd_cb = cb; 1853 + 1854 + return 0; 1764 1855 }
+148 -4
fs/nfsd/nfs4layouts.c
··· 27 27 static const struct nfsd4_callback_ops nfsd4_cb_layout_ops; 28 28 static const struct lease_manager_operations nfsd4_layouts_lm_ops; 29 29 30 + static void nfsd4_layout_fence_worker(struct work_struct *work); 31 + 30 32 const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = { 31 33 #ifdef CONFIG_NFSD_FLEXFILELAYOUT 32 34 [LAYOUT_FLEX_FILES] = &ff_layout_ops, ··· 179 177 180 178 trace_nfsd_layoutstate_free(&ls->ls_stid.sc_stateid); 181 179 180 + spin_lock(&ls->ls_lock); 181 + if (delayed_work_pending(&ls->ls_fence_work)) { 182 + spin_unlock(&ls->ls_lock); 183 + cancel_delayed_work_sync(&ls->ls_fence_work); 184 + } else 185 + spin_unlock(&ls->ls_lock); 186 + 182 187 spin_lock(&clp->cl_lock); 183 188 list_del_init(&ls->ls_perclnt); 184 189 spin_unlock(&clp->cl_lock); ··· 279 270 spin_lock(&fp->fi_lock); 280 271 list_add(&ls->ls_perfile, &fp->fi_lo_states); 281 272 spin_unlock(&fp->fi_lock); 273 + 274 + ls->ls_fenced = false; 275 + ls->ls_fence_delay = 0; 276 + INIT_DELAYED_WORK(&ls->ls_fence_work, nfsd4_layout_fence_worker); 282 277 283 278 trace_nfsd_layoutstate_alloc(&ls->ls_stid.sc_stateid); 284 279 return ls; ··· 760 747 nfsd4_layout_lm_break(struct file_lease *fl) 761 748 { 762 749 /* 763 - * We don't want the locks code to timeout the lease for us; 764 - * we'll remove it ourself if a layout isn't returned 765 - * in time: 750 + * Enforce break lease timeout to prevent NFSD 751 + * thread from hanging in __break_lease. 766 752 */ 767 - fl->fl_break_time = 0; 768 753 nfsd4_recall_file_layout(fl->c.flc_owner); 769 754 return false; 770 755 } ··· 793 782 return 0; 794 783 } 795 784 785 + static void 786 + nfsd4_layout_fence_worker(struct work_struct *work) 787 + { 788 + struct delayed_work *dwork = to_delayed_work(work); 789 + struct nfs4_layout_stateid *ls = container_of(dwork, 790 + struct nfs4_layout_stateid, ls_fence_work); 791 + struct nfsd_file *nf; 792 + struct block_device *bdev; 793 + struct nfs4_client *clp; 794 + struct nfsd_net *nn; 795 + 796 + /* 797 + * The workqueue clears WORK_STRUCT_PENDING before invoking 798 + * this callback. Re-arm immediately so that 799 + * delayed_work_pending() returns true while the fence 800 + * operation is in progress, preventing 801 + * lm_breaker_timedout() from taking a duplicate reference. 802 + */ 803 + mod_delayed_work(system_dfl_wq, &ls->ls_fence_work, 0); 804 + 805 + spin_lock(&ls->ls_lock); 806 + if (list_empty(&ls->ls_layouts)) { 807 + spin_unlock(&ls->ls_lock); 808 + dispose: 809 + cancel_delayed_work(&ls->ls_fence_work); 810 + /* unlock the lease so that tasks waiting on it can proceed */ 811 + nfsd4_close_layout(ls); 812 + 813 + ls->ls_fenced = true; 814 + nfs4_put_stid(&ls->ls_stid); 815 + return; 816 + } 817 + spin_unlock(&ls->ls_lock); 818 + 819 + rcu_read_lock(); 820 + nf = nfsd_file_get(ls->ls_file); 821 + rcu_read_unlock(); 822 + if (!nf) 823 + goto dispose; 824 + 825 + clp = ls->ls_stid.sc_client; 826 + nn = net_generic(clp->net, nfsd_net_id); 827 + bdev = nf->nf_file->f_path.mnt->mnt_sb->s_bdev; 828 + if (nfsd4_layout_ops[ls->ls_layout_type]->fence_client(ls, nf)) { 829 + /* fenced ok */ 830 + nfsd_file_put(nf); 831 + pr_warn("%s: FENCED client[%pISpc] clid[%d] to device[%s]\n", 832 + __func__, (struct sockaddr *)&clp->cl_addr, 833 + clp->cl_clientid.cl_id - nn->clientid_base, 834 + bdev->bd_disk->disk_name); 835 + goto dispose; 836 + } 837 + /* fence failed */ 838 + nfsd_file_put(nf); 839 + 840 + if (!clp->cl_fence_retry_warn) { 841 + pr_warn("%s: FENCE failed client[%pISpc] clid[%d] device[%s]\n", 842 + __func__, (struct sockaddr *)&clp->cl_addr, 843 + clp->cl_clientid.cl_id - nn->clientid_base, 844 + bdev->bd_disk->disk_name); 845 + clp->cl_fence_retry_warn = true; 846 + } 847 + /* 848 + * The fence worker retries the fencing operation indefinitely to 849 + * prevent data corruption. The admin needs to take the following 850 + * actions to restore access to the file for other clients: 851 + * 852 + * . shutdown or power off the client being fenced. 853 + * . manually expire the client to release all its state on the server; 854 + * echo 'expire' > /proc/fs/nfsd/clients/clid/ctl'. 855 + * 856 + * Where: 857 + * 858 + * clid: is the unique client identifier displayed in 859 + * the warning message above. 860 + */ 861 + if (!ls->ls_fence_delay) 862 + ls->ls_fence_delay = HZ; 863 + else 864 + ls->ls_fence_delay = min(ls->ls_fence_delay << 1, 865 + MAX_FENCE_DELAY); 866 + mod_delayed_work(system_dfl_wq, &ls->ls_fence_work, ls->ls_fence_delay); 867 + } 868 + 869 + /** 870 + * nfsd4_layout_lm_breaker_timedout - The layout recall has timed out. 871 + * @fl: file to check 872 + * 873 + * If the layout type supports a fence operation, schedule a worker to 874 + * fence the client from accessing the block device. 875 + * 876 + * This function runs under the protection of the spin_lock flc_lock. 877 + * At this time, the file_lease associated with the layout stateid is 878 + * on the flc_list. A reference count is incremented on the layout 879 + * stateid to prevent it from being freed while the fence worker is 880 + * executing. Once the fence worker finishes its operation, it releases 881 + * this reference. 882 + * 883 + * The fence worker continues to run until either the client has been 884 + * fenced or the layout becomes invalid. The layout can become invalid 885 + * as a result of a LAYOUTRETURN or when the CB_LAYOUT recall callback 886 + * has completed. 887 + * 888 + * Return true if the file_lease should be disposed of by the caller; 889 + * otherwise, return false. 890 + */ 891 + static bool 892 + nfsd4_layout_lm_breaker_timedout(struct file_lease *fl) 893 + { 894 + struct nfs4_layout_stateid *ls = fl->c.flc_owner; 895 + 896 + if ((!nfsd4_layout_ops[ls->ls_layout_type]->fence_client) || 897 + ls->ls_fenced) 898 + return true; 899 + if (delayed_work_pending(&ls->ls_fence_work)) 900 + return false; 901 + /* 902 + * Make sure layout has not been returned yet before 903 + * taking a reference count on the layout stateid. 904 + */ 905 + spin_lock(&ls->ls_lock); 906 + if (list_empty(&ls->ls_layouts) || 907 + !refcount_inc_not_zero(&ls->ls_stid.sc_count)) { 908 + spin_unlock(&ls->ls_lock); 909 + return true; 910 + } 911 + spin_unlock(&ls->ls_lock); 912 + 913 + mod_delayed_work(system_dfl_wq, &ls->ls_fence_work, 0); 914 + return false; 915 + } 916 + 796 917 static const struct lease_manager_operations nfsd4_layouts_lm_ops = { 797 918 .lm_break = nfsd4_layout_lm_break, 798 919 .lm_change = nfsd4_layout_lm_change, 799 920 .lm_open_conflict = nfsd4_layout_lm_open_conflict, 921 + .lm_breaker_timedout = nfsd4_layout_lm_breaker_timedout, 800 922 }; 801 923 802 924 int
+2 -1
fs/nfsd/nfs4proc.c
··· 3043 3043 struct svc_fh *current_fh = &cstate->current_fh; 3044 3044 struct svc_fh *save_fh = &cstate->save_fh; 3045 3045 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 3046 + struct nfsd_thread_local_info *ntli = rqstp->rq_private; 3046 3047 __be32 status; 3047 3048 3048 3049 resp->xdr = &rqstp->rq_res_stream; ··· 3082 3081 } 3083 3082 check_if_stalefh_allowed(args); 3084 3083 3085 - rqstp->rq_lease_breaker = (void **)&cstate->clp; 3084 + ntli->ntli_lease_breaker = &cstate->clp; 3086 3085 3087 3086 trace_nfsd_compound(rqstp, args->tag, args->taglen, args->client_opcnt); 3088 3087 while (!status && resp->opcnt < args->opcnt) {
+71 -42
fs/nfsd/nfs4state.c
··· 76 76 77 77 static u64 current_sessionid = 1; 78 78 79 + bool nfsd_delegts_enabled __read_mostly = true; 80 + 79 81 #define ZERO_STATEID(stateid) (!memcmp((stateid), &zero_stateid, sizeof(stateid_t))) 80 82 #define ONE_STATEID(stateid) (!memcmp((stateid), &one_stateid, sizeof(stateid_t))) 81 83 #define CURRENT_STATEID(stateid) (!memcmp((stateid), &currentstateid, sizeof(stateid_t))) ··· 92 90 static void deleg_reaper(struct nfsd_net *nn); 93 91 94 92 /* Locking: */ 95 - 96 - /* 97 - * Currently used for the del_recall_lru and file hash table. In an 98 - * effort to decrease the scope of the client_mutex, this spinlock may 99 - * eventually cover more: 100 - */ 101 - static DEFINE_SPINLOCK(state_lock); 102 93 103 94 enum nfsd4_st_mutex_lock_subclass { 104 95 OPEN_STATEID_MUTEX = 0, ··· 1288 1293 { 1289 1294 struct nfs4_delegation *searchdp = NULL; 1290 1295 struct nfs4_client *searchclp = NULL; 1296 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1291 1297 1292 - lockdep_assert_held(&state_lock); 1298 + lockdep_assert_held(&nn->deleg_lock); 1293 1299 lockdep_assert_held(&fp->fi_lock); 1294 1300 1295 1301 list_for_each_entry(searchdp, &fp->fi_delegations, dl_perfile) { ··· 1319 1323 hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) 1320 1324 { 1321 1325 struct nfs4_client *clp = dp->dl_stid.sc_client; 1326 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 1322 1327 1323 - lockdep_assert_held(&state_lock); 1328 + lockdep_assert_held(&nn->deleg_lock); 1324 1329 lockdep_assert_held(&fp->fi_lock); 1325 1330 lockdep_assert_held(&clp->cl_lock); 1326 1331 ··· 1343 1346 unhash_delegation_locked(struct nfs4_delegation *dp, unsigned short statusmask) 1344 1347 { 1345 1348 struct nfs4_file *fp = dp->dl_stid.sc_file; 1349 + struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 1350 + nfsd_net_id); 1346 1351 1347 - lockdep_assert_held(&state_lock); 1352 + lockdep_assert_held(&nn->deleg_lock); 1348 1353 1349 1354 if (!delegation_hashed(dp)) 1350 1355 return false; ··· 1371 1372 static void destroy_delegation(struct nfs4_delegation *dp) 1372 1373 { 1373 1374 bool unhashed; 1375 + struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, 1376 + nfsd_net_id); 1374 1377 1375 - spin_lock(&state_lock); 1378 + spin_lock(&nn->deleg_lock); 1376 1379 unhashed = unhash_delegation_locked(dp, SC_STATUS_CLOSED); 1377 - spin_unlock(&state_lock); 1380 + spin_unlock(&nn->deleg_lock); 1378 1381 if (unhashed) 1379 1382 destroy_unhashed_deleg(dp); 1380 1383 } ··· 1496 1495 } 1497 1496 } 1498 1497 1498 + /** 1499 + * nfs4_replay_free_cache - release dynamically allocated replay buffer 1500 + * @rp: replay cache to reset 1501 + * 1502 + * If @rp->rp_buf points to a kmalloc'd buffer, free it and reset 1503 + * rp_buf to the inline rp_ibuf. Always zeroes rp_buflen. 1504 + */ 1505 + void nfs4_replay_free_cache(struct nfs4_replay *rp) 1506 + { 1507 + if (rp->rp_buf != rp->rp_ibuf) 1508 + kfree(rp->rp_buf); 1509 + rp->rp_buf = rp->rp_ibuf; 1510 + rp->rp_buflen = 0; 1511 + } 1512 + 1499 1513 static inline void nfs4_free_stateowner(struct nfs4_stateowner *sop) 1500 1514 { 1515 + nfs4_replay_free_cache(&sop->so_replay); 1501 1516 kfree(sop->so_owner.data); 1502 1517 sop->so_ops->so_free(sop); 1503 1518 } ··· 1855 1838 case SC_TYPE_DELEG: 1856 1839 refcount_inc(&stid->sc_count); 1857 1840 dp = delegstateid(stid); 1858 - spin_lock(&state_lock); 1841 + spin_lock(&nn->deleg_lock); 1859 1842 if (!unhash_delegation_locked( 1860 1843 dp, SC_STATUS_ADMIN_REVOKED)) 1861 1844 dp = NULL; 1862 - spin_unlock(&state_lock); 1845 + spin_unlock(&nn->deleg_lock); 1863 1846 if (dp) 1864 1847 revoke_delegation(dp); 1865 1848 break; ··· 2399 2382 #ifdef CONFIG_NFSD_PNFS 2400 2383 INIT_LIST_HEAD(&clp->cl_lo_states); 2401 2384 #endif 2385 + #ifdef CONFIG_NFSD_SCSILAYOUT 2386 + xa_init(&clp->cl_dev_fences); 2387 + mutex_init(&clp->cl_fence_mutex); 2388 + #endif 2402 2389 INIT_LIST_HEAD(&clp->async_copies); 2403 2390 spin_lock_init(&clp->async_lock); 2404 2391 spin_lock_init(&clp->cl_lock); ··· 2525 2504 struct nfs4_delegation *dp; 2526 2505 LIST_HEAD(reaplist); 2527 2506 2528 - spin_lock(&state_lock); 2507 + spin_lock(&nn->deleg_lock); 2529 2508 while (!list_empty(&clp->cl_delegations)) { 2530 2509 dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); 2531 2510 unhash_delegation_locked(dp, SC_STATUS_CLOSED); 2532 2511 list_add(&dp->dl_recall_lru, &reaplist); 2533 2512 } 2534 - spin_unlock(&state_lock); 2513 + spin_unlock(&nn->deleg_lock); 2535 2514 while (!list_empty(&reaplist)) { 2536 2515 dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); 2537 2516 list_del_init(&dp->dl_recall_lru); ··· 2564 2543 svc_xprt_put(clp->cl_cb_conn.cb_xprt); 2565 2544 atomic_add_unless(&nn->nfs4_client_count, -1, 0); 2566 2545 nfsd4_dec_courtesy_client_count(nn, clp); 2546 + #ifdef CONFIG_NFSD_SCSILAYOUT 2547 + xa_destroy(&clp->cl_dev_fences); 2548 + #endif 2567 2549 free_client(clp); 2568 2550 wake_up_all(&expiry_wq); 2569 2551 } ··· 5442 5418 * If the dl_time != 0, then we know that it has already been 5443 5419 * queued for a lease break. Don't queue it again. 5444 5420 */ 5445 - spin_lock(&state_lock); 5421 + spin_lock(&nn->deleg_lock); 5446 5422 if (delegation_hashed(dp) && dp->dl_time == 0) { 5447 5423 dp->dl_time = ktime_get_boottime_seconds(); 5448 5424 list_add_tail(&dp->dl_recall_lru, &nn->del_recall_lru); 5449 5425 } 5450 - spin_unlock(&state_lock); 5426 + spin_unlock(&nn->deleg_lock); 5451 5427 } 5452 5428 5453 5429 static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, ··· 5559 5535 static bool nfsd_breaker_owns_lease(struct file_lease *fl) 5560 5536 { 5561 5537 struct nfs4_delegation *dl = fl->c.flc_owner; 5538 + struct nfsd_thread_local_info *ntli; 5562 5539 struct svc_rqst *rqst; 5563 5540 struct nfs4_client *clp; 5564 5541 5565 5542 rqst = nfsd_current_rqst(); 5566 5543 if (!nfsd_v4client(rqst)) 5567 5544 return false; 5568 - clp = *(rqst->rq_lease_breaker); 5545 + ntli = rqst->rq_private; 5546 + clp = *ntli->ntli_lease_breaker; 5569 5547 return dl->dl_stid.sc_client == clp; 5570 5548 } 5571 5549 ··· 6062 6036 return 0; 6063 6037 } 6064 6038 6065 - #ifdef CONFIG_NFSD_V4_DELEG_TIMESTAMPS 6039 + /* 6040 + * Timestamp delegation was introduced in RFC7862. Runtime switch for disabling 6041 + * this feature is /sys/kernel/debug/nfsd/delegated_timestamps. 6042 + */ 6066 6043 static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open) 6067 6044 { 6045 + if (!nfsd_delegts_enabled) 6046 + return false; 6068 6047 return open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS; 6069 6048 } 6070 - #else /* CONFIG_NFSD_V4_DELEG_TIMESTAMPS */ 6071 - static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open) 6072 - { 6073 - return false; 6074 - } 6075 - #endif /* CONFIG NFSD_V4_DELEG_TIMESTAMPS */ 6076 6049 6077 6050 static struct nfs4_delegation * 6078 6051 nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp, ··· 6079 6054 { 6080 6055 bool deleg_ts = nfsd4_want_deleg_timestamps(open); 6081 6056 struct nfs4_client *clp = stp->st_stid.sc_client; 6057 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 6082 6058 struct nfs4_file *fp = stp->st_stid.sc_file; 6083 6059 struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate; 6084 6060 struct nfs4_delegation *dp; ··· 6139 6113 return ERR_PTR(-EOPNOTSUPP); 6140 6114 } 6141 6115 6142 - spin_lock(&state_lock); 6116 + spin_lock(&nn->deleg_lock); 6143 6117 spin_lock(&fp->fi_lock); 6144 6118 if (nfs4_delegation_exists(clp, fp)) 6145 6119 status = -EAGAIN; ··· 6154 6128 } else 6155 6129 fp->fi_delegees++; 6156 6130 spin_unlock(&fp->fi_lock); 6157 - spin_unlock(&state_lock); 6131 + spin_unlock(&nn->deleg_lock); 6158 6132 if (nf) 6159 6133 nfsd_file_put(nf); 6160 6134 if (status) ··· 6198 6172 if (fp->fi_had_conflict) 6199 6173 goto out_unlock; 6200 6174 6201 - spin_lock(&state_lock); 6175 + spin_lock(&nn->deleg_lock); 6202 6176 spin_lock(&clp->cl_lock); 6203 6177 spin_lock(&fp->fi_lock); 6204 6178 status = hash_delegation_locked(dp, fp); 6205 6179 spin_unlock(&fp->fi_lock); 6206 6180 spin_unlock(&clp->cl_lock); 6207 - spin_unlock(&state_lock); 6181 + spin_unlock(&nn->deleg_lock); 6208 6182 6209 6183 if (status) 6210 6184 goto out_unlock; ··· 6283 6257 return (false); 6284 6258 fp = stp->st_stid.sc_file; 6285 6259 spin_lock(&fp->fi_lock); 6286 - __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); 6287 6260 if (!fp->fi_fds[O_RDONLY]) { 6261 + __nfs4_file_get_access(fp, NFS4_SHARE_ACCESS_READ); 6288 6262 fp->fi_fds[O_RDONLY] = nf; 6263 + fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); 6289 6264 nf = NULL; 6290 6265 } 6291 - fp->fi_rdeleg_file = nfsd_file_get(fp->fi_fds[O_RDONLY]); 6292 6266 spin_unlock(&fp->fi_lock); 6293 6267 if (nf) 6294 6268 nfsd_file_put(nf); ··· 6980 6954 6981 6955 nfs40_clean_admin_revoked(nn, &lt); 6982 6956 6983 - spin_lock(&state_lock); 6957 + spin_lock(&nn->deleg_lock); 6984 6958 list_for_each_safe(pos, next, &nn->del_recall_lru) { 6985 6959 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 6986 6960 if (!state_expired(&lt, dp->dl_time)) ··· 6989 6963 unhash_delegation_locked(dp, SC_STATUS_REVOKED); 6990 6964 list_add(&dp->dl_recall_lru, &reaplist); 6991 6965 } 6992 - spin_unlock(&state_lock); 6966 + spin_unlock(&nn->deleg_lock); 6993 6967 while (!list_empty(&reaplist)) { 6994 6968 dp = list_first_entry(&reaplist, struct nfs4_delegation, 6995 6969 dl_recall_lru); ··· 9012 8986 INIT_LIST_HEAD(&nn->client_lru); 9013 8987 INIT_LIST_HEAD(&nn->close_lru); 9014 8988 INIT_LIST_HEAD(&nn->del_recall_lru); 8989 + spin_lock_init(&nn->deleg_lock); 9015 8990 spin_lock_init(&nn->client_lock); 9016 8991 spin_lock_init(&nn->s2s_cp_lock); 9017 8992 idr_init(&nn->s2s_cp_stateids); ··· 9144 9117 locks_end_grace(&nn->nfsd4_manager); 9145 9118 9146 9119 INIT_LIST_HEAD(&reaplist); 9147 - spin_lock(&state_lock); 9120 + spin_lock(&nn->deleg_lock); 9148 9121 list_for_each_safe(pos, next, &nn->del_recall_lru) { 9149 9122 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 9150 9123 unhash_delegation_locked(dp, SC_STATUS_CLOSED); 9151 9124 list_add(&dp->dl_recall_lru, &reaplist); 9152 9125 } 9153 - spin_unlock(&state_lock); 9126 + spin_unlock(&nn->deleg_lock); 9154 9127 list_for_each_safe(pos, next, &reaplist) { 9155 9128 dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); 9156 9129 list_del_init(&dp->dl_recall_lru); ··· 9375 9348 nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry, 9376 9349 struct nfs4_delegation **pdp) 9377 9350 { 9378 - __be32 status; 9379 9351 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 9352 + struct nfsd_thread_local_info *ntli = rqstp->rq_private; 9380 9353 struct file_lock_context *ctx; 9381 9354 struct nfs4_delegation *dp = NULL; 9382 9355 struct file_lease *fl; 9383 9356 struct nfs4_cb_fattr *ncf; 9384 9357 struct inode *inode = d_inode(dentry); 9358 + __be32 status; 9385 9359 9386 9360 ctx = locks_inode_context(inode); 9387 9361 if (!ctx) ··· 9403 9375 break; 9404 9376 } 9405 9377 if (dp == NULL || dp == NON_NFSD_LEASE || 9406 - dp->dl_recall.cb_clp == *(rqstp->rq_lease_breaker)) { 9378 + dp->dl_recall.cb_clp == *(ntli->ntli_lease_breaker)) { 9407 9379 spin_unlock(&ctx->flc_lock); 9408 9380 if (dp == NON_NFSD_LEASE) { 9409 9381 status = nfserrno(nfsd_open_break_lease(inode, ··· 9473 9445 struct nfsd_file *nf) 9474 9446 { 9475 9447 struct nfs4_client *clp = cstate->clp; 9448 + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); 9476 9449 struct nfs4_delegation *dp; 9477 9450 struct file_lease *fl; 9478 9451 struct nfs4_file *fp, *rfp; ··· 9497 9468 } 9498 9469 9499 9470 /* if this client already has one, return that it's unavailable */ 9500 - spin_lock(&state_lock); 9471 + spin_lock(&nn->deleg_lock); 9501 9472 spin_lock(&fp->fi_lock); 9502 9473 /* existing delegation? */ 9503 9474 if (nfs4_delegation_exists(clp, fp)) { ··· 9509 9480 ++fp->fi_delegees; 9510 9481 } 9511 9482 spin_unlock(&fp->fi_lock); 9512 - spin_unlock(&state_lock); 9483 + spin_unlock(&nn->deleg_lock); 9513 9484 9514 9485 if (status) { 9515 9486 put_nfs4_file(fp); ··· 9538 9509 * trying to set a delegation on the same file. If that happens, 9539 9510 * then just say UNAVAIL. 9540 9511 */ 9541 - spin_lock(&state_lock); 9512 + spin_lock(&nn->deleg_lock); 9542 9513 spin_lock(&clp->cl_lock); 9543 9514 spin_lock(&fp->fi_lock); 9544 9515 status = hash_delegation_locked(dp, fp); 9545 9516 spin_unlock(&fp->fi_lock); 9546 9517 spin_unlock(&clp->cl_lock); 9547 - spin_unlock(&state_lock); 9518 + spin_unlock(&nn->deleg_lock); 9548 9519 9549 9520 if (!status) { 9550 9521 put_nfs4_file(fp);
+18 -8
fs/nfsd/nfs4xdr.c
··· 2598 2598 static bool 2599 2599 nfsd4_decode_compound(struct nfsd4_compoundargs *argp) 2600 2600 { 2601 + struct nfsd_thread_local_info *ntli = argp->rqstp->rq_private; 2601 2602 struct nfsd4_op *op; 2602 2603 bool cachethis = false; 2603 2604 int auth_slack= argp->rqstp->rq_auth_slack; ··· 2691 2690 if (argp->minorversion) 2692 2691 cachethis = false; 2693 2692 svc_reserve_auth(argp->rqstp, max_reply + readbytes); 2694 - argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 2693 + ntli->ntli_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; 2695 2694 2696 2695 argp->splice_ok = nfsd_read_splice_ok(argp->rqstp); 2697 2696 if (readcount > 1 || max_reply > PAGE_SIZE - auth_slack) ··· 6282 6281 int len = xdr->buf->len - (op_status_offset + XDR_UNIT); 6283 6282 6284 6283 so->so_replay.rp_status = op->status; 6285 - if (len <= NFSD4_REPLAY_ISIZE) { 6286 - so->so_replay.rp_buflen = len; 6287 - read_bytes_from_xdr_buf(xdr->buf, 6288 - op_status_offset + XDR_UNIT, 6289 - so->so_replay.rp_buf, len); 6290 - } else { 6291 - so->so_replay.rp_buflen = 0; 6284 + if (len > NFSD4_REPLAY_ISIZE) { 6285 + char *buf = kmalloc(len, GFP_KERNEL); 6286 + 6287 + nfs4_replay_free_cache(&so->so_replay); 6288 + if (buf) { 6289 + so->so_replay.rp_buf = buf; 6290 + } else { 6291 + /* rp_buflen already zeroed; skip caching */ 6292 + goto status; 6293 + } 6294 + } else if (so->so_replay.rp_buf != so->so_replay.rp_ibuf) { 6295 + nfs4_replay_free_cache(&so->so_replay); 6292 6296 } 6297 + so->so_replay.rp_buflen = len; 6298 + read_bytes_from_xdr_buf(xdr->buf, 6299 + op_status_offset + XDR_UNIT, 6300 + so->so_replay.rp_buf, len); 6293 6301 } 6294 6302 status: 6295 6303 op->status = nfsd4_map_status(op->status,
+2 -1
fs/nfsd/nfscache.c
··· 467 467 unsigned int len, struct nfsd_cacherep **cacherep) 468 468 { 469 469 struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 470 + struct nfsd_thread_local_info *ntli = rqstp->rq_private; 470 471 struct nfsd_cacherep *rp, *found; 471 472 __wsum csum; 472 473 struct nfsd_drc_bucket *b; 473 - int type = rqstp->rq_cachetype; 474 + int type = ntli->ntli_cachetype; 474 475 LIST_HEAD(dispose); 475 476 int rtn = RC_DOIT; 476 477
+43 -2
fs/nfsd/nfsctl.c
··· 11 11 #include <linux/fs_context.h> 12 12 13 13 #include <linux/sunrpc/svcsock.h> 14 - #include <linux/lockd/lockd.h> 14 + #include <linux/lockd/bind.h> 15 15 #include <linux/sunrpc/addr.h> 16 16 #include <linux/sunrpc/gss_api.h> 17 17 #include <linux/sunrpc/rpc_pipe_fs.h> ··· 1582 1582 } 1583 1583 1584 1584 /** 1585 + * nfsd_nl_fh_key_set - helper to copy fh_key from userspace 1586 + * @attr: nlattr NFSD_A_SERVER_FH_KEY 1587 + * @nn: nfsd_net 1588 + * 1589 + * Callers should hold nfsd_mutex, returns 0 on success or negative errno. 1590 + * Callers must ensure the server is shut down (sv_nrthreads == 0), 1591 + * userspace documentation asserts the key may only be set when the server 1592 + * is not running. 1593 + */ 1594 + static int nfsd_nl_fh_key_set(const struct nlattr *attr, struct nfsd_net *nn) 1595 + { 1596 + siphash_key_t *fh_key = nn->fh_key; 1597 + 1598 + if (!fh_key) { 1599 + fh_key = kmalloc(sizeof(siphash_key_t), GFP_KERNEL); 1600 + if (!fh_key) 1601 + return -ENOMEM; 1602 + nn->fh_key = fh_key; 1603 + } 1604 + 1605 + fh_key->key[0] = get_unaligned_le64(nla_data(attr)); 1606 + fh_key->key[1] = get_unaligned_le64(nla_data(attr) + 8); 1607 + return 0; 1608 + } 1609 + 1610 + /** 1585 1611 * nfsd_nl_threads_set_doit - set the number of running threads 1586 1612 * @skb: reply buffer 1587 1613 * @info: netlink metadata and command arguments ··· 1648 1622 1649 1623 if (info->attrs[NFSD_A_SERVER_GRACETIME] || 1650 1624 info->attrs[NFSD_A_SERVER_LEASETIME] || 1651 - info->attrs[NFSD_A_SERVER_SCOPE]) { 1625 + info->attrs[NFSD_A_SERVER_SCOPE] || 1626 + info->attrs[NFSD_A_SERVER_FH_KEY]) { 1652 1627 ret = -EBUSY; 1653 1628 if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads) 1654 1629 goto out_unlock; ··· 1678 1651 attr = info->attrs[NFSD_A_SERVER_SCOPE]; 1679 1652 if (attr) 1680 1653 scope = nla_data(attr); 1654 + 1655 + attr = info->attrs[NFSD_A_SERVER_FH_KEY]; 1656 + if (attr) { 1657 + ret = nfsd_nl_fh_key_set(attr, nn); 1658 + trace_nfsd_ctl_fh_key_set((const char *)nn->fh_key, ret); 1659 + if (ret) 1660 + goto out_unlock; 1661 + } 1681 1662 } 1682 1663 1683 1664 attr = info->attrs[NFSD_A_SERVER_MIN_THREADS]; ··· 2203 2168 int retval; 2204 2169 int i; 2205 2170 2171 + retval = nfsd_net_cb_init(nn); 2172 + if (retval) 2173 + return retval; 2206 2174 retval = nfsd_export_init(net); 2207 2175 if (retval) 2208 2176 goto out_export_error; ··· 2246 2208 out_idmap_error: 2247 2209 nfsd_export_shutdown(net); 2248 2210 out_export_error: 2211 + nfsd_net_cb_shutdown(nn); 2249 2212 return retval; 2250 2213 } 2251 2214 ··· 2276 2237 { 2277 2238 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 2278 2239 2240 + kfree_sensitive(nn->fh_key); 2241 + nfsd_net_cb_shutdown(nn); 2279 2242 nfsd_proc_stat_shutdown(net); 2280 2243 percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM); 2281 2244 nfsd_idmap_shutdown(net);
+6
fs/nfsd/nfsd.h
··· 82 82 83 83 extern const struct seq_operations nfs_exports_op; 84 84 85 + struct nfsd_thread_local_info { 86 + struct nfs4_client **ntli_lease_breaker; 87 + int ntli_cachetype; 88 + }; 89 + 85 90 /* 86 91 * Common void argument and result helpers 87 92 */ ··· 160 155 #endif 161 156 162 157 extern bool nfsd_disable_splice_read __read_mostly; 158 + extern bool nfsd_delegts_enabled __read_mostly; 163 159 164 160 enum { 165 161 /* Any new NFSD_IO enum value must be added at the end */
+76 -7
fs/nfsd/nfsfh.c
··· 11 11 #include <linux/exportfs.h> 12 12 13 13 #include <linux/sunrpc/svcauth_gss.h> 14 + #include <crypto/utils.h> 14 15 #include "nfsd.h" 15 16 #include "vfs.h" 16 17 #include "auth.h" ··· 106 105 { 107 106 /* Check if the request originated from a secure port. */ 108 107 if (rqstp && !nfsd_originating_port_ok(rqstp, cred, exp)) { 109 - RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); 110 - dprintk("nfsd: request from insecure port %s!\n", 111 - svc_print_addr(rqstp, buf, sizeof(buf))); 108 + if (IS_ENABLED(CONFIG_SUNRPC_DEBUG)) { 109 + char buf[RPC_MAX_ADDRBUFLEN]; 110 + 111 + dprintk("nfsd: request from insecure port %s!\n", 112 + svc_print_addr(rqstp, buf, sizeof(buf))); 113 + } 112 114 return nfserr_perm; 113 115 } 114 116 ··· 139 135 if (unlikely(dentry != exp->ex_path.dentry)) 140 136 return nfserr_stale; 141 137 return nfs_ok; 138 + } 139 + 140 + /* Size of a file handle MAC, in 4-octet words */ 141 + #define FH_MAC_WORDS (sizeof(__le64) / 4) 142 + 143 + static bool fh_append_mac(struct svc_fh *fhp, struct net *net) 144 + { 145 + struct nfsd_net *nn = net_generic(net, nfsd_net_id); 146 + struct knfsd_fh *fh = &fhp->fh_handle; 147 + siphash_key_t *fh_key = nn->fh_key; 148 + __le64 hash; 149 + 150 + if (!fh_key) 151 + goto out_no_key; 152 + if (fh->fh_size + sizeof(hash) > fhp->fh_maxsize) 153 + goto out_no_space; 154 + 155 + hash = cpu_to_le64(siphash(&fh->fh_raw, fh->fh_size, fh_key)); 156 + memcpy(&fh->fh_raw[fh->fh_size], &hash, sizeof(hash)); 157 + fh->fh_size += sizeof(hash); 158 + return true; 159 + 160 + out_no_key: 161 + pr_warn_ratelimited("NFSD: unable to sign filehandles, fh_key not set.\n"); 162 + return false; 163 + 164 + out_no_space: 165 + pr_warn_ratelimited("NFSD: unable to sign filehandles, fh_size %zu would be greater than fh_maxsize %d.\n", 166 + fh->fh_size + sizeof(hash), fhp->fh_maxsize); 167 + return false; 168 + } 169 + 170 + /* 171 + * Verify that the filehandle's MAC was hashed from this filehandle 172 + * given the server's fh_key: 173 + */ 174 + static bool fh_verify_mac(struct svc_fh *fhp, struct net *net) 175 + { 176 + struct nfsd_net *nn = net_generic(net, nfsd_net_id); 177 + struct knfsd_fh *fh = &fhp->fh_handle; 178 + siphash_key_t *fh_key = nn->fh_key; 179 + __le64 hash; 180 + 181 + if (!fh_key) { 182 + pr_warn_ratelimited("NFSD: unable to verify signed filehandles, fh_key not set.\n"); 183 + return false; 184 + } 185 + 186 + hash = cpu_to_le64(siphash(&fh->fh_raw, fh->fh_size - sizeof(hash), fh_key)); 187 + return crypto_memneq(&fh->fh_raw[fh->fh_size - sizeof(hash)], 188 + &hash, sizeof(hash)) == 0; 142 189 } 143 190 144 191 /* ··· 288 233 /* 289 234 * Look up the dentry using the NFS file handle. 290 235 */ 291 - error = nfserr_badhandle; 292 - 293 236 fileid_type = fh->fh_fileid_type; 237 + error = nfserr_stale; 294 238 295 - if (fileid_type == FILEID_ROOT) 239 + if (fileid_type == FILEID_ROOT) { 240 + /* We don't sign or verify the root, no per-file identity */ 296 241 dentry = dget(exp->ex_path.dentry); 297 - else { 242 + } else { 243 + if (exp->ex_flags & NFSEXP_SIGN_FH) { 244 + if (!fh_verify_mac(fhp, net)) { 245 + trace_nfsd_set_fh_dentry_badmac(rqstp, fhp, -ESTALE); 246 + goto out; 247 + } 248 + data_left -= FH_MAC_WORDS; 249 + } 250 + 298 251 dentry = exportfs_decode_fh_raw(exp->ex_path.mnt, fid, 299 252 data_left, fileid_type, 0, 300 253 nfsd_acceptable, exp); ··· 318 255 } 319 256 } 320 257 } 258 + 259 + error = nfserr_badhandle; 321 260 if (dentry == NULL) 322 261 goto out; 323 262 if (IS_ERR(dentry)) { ··· 560 495 fhp->fh_handle.fh_fileid_type = 561 496 fileid_type > 0 ? fileid_type : FILEID_INVALID; 562 497 fhp->fh_handle.fh_size += maxsize * 4; 498 + 499 + if (exp->ex_flags & NFSEXP_SIGN_FH) 500 + if (!fh_append_mac(fhp, exp->cd->net)) 501 + fhp->fh_handle.fh_fileid_type = FILEID_INVALID; 563 502 } else { 564 503 fhp->fh_handle.fh_fileid_type = FILEID_ROOT; 565 504 }
+8 -2
fs/nfsd/nfssvc.c
··· 887 887 struct svc_xprt *perm_sock = list_entry(rqstp->rq_server->sv_permsocks.next, typeof(struct svc_xprt), xpt_list); 888 888 struct net *net = perm_sock->xpt_net; 889 889 struct nfsd_net *nn = net_generic(net, nfsd_net_id); 890 + struct nfsd_thread_local_info ntli = { }; 890 891 bool have_mutex = false; 891 892 892 893 /* At this point, the thread shares current->fs ··· 901 900 atomic_inc(&nfsd_th_cnt); 902 901 903 902 set_freezable(); 903 + 904 + /* use dynamic allocation if ntli should ever become large */ 905 + static_assert(sizeof(struct nfsd_thread_local_info) < 256); 906 + rqstp->rq_private = &ntli; 904 907 905 908 /* 906 909 * The main request loop ··· 972 967 */ 973 968 int nfsd_dispatch(struct svc_rqst *rqstp) 974 969 { 970 + struct nfsd_thread_local_info *ntli = rqstp->rq_private; 975 971 const struct svc_procedure *proc = rqstp->rq_procinfo; 976 972 __be32 *statp = rqstp->rq_accept_statp; 977 973 struct nfsd_cacherep *rp; ··· 983 977 * Give the xdr decoder a chance to change this if it wants 984 978 * (necessary in the NFSv4.0 compound case) 985 979 */ 986 - rqstp->rq_cachetype = proc->pc_cachetype; 980 + ntli->ntli_cachetype = proc->pc_cachetype; 987 981 988 982 /* 989 983 * ->pc_decode advances the argument stream past the NFS ··· 1028 1022 */ 1029 1023 smp_store_release(&rqstp->rq_status_counter, rqstp->rq_status_counter + 1); 1030 1024 1031 - nfsd_cache_update(rqstp, rp, rqstp->rq_cachetype, nfs_reply); 1025 + nfsd_cache_update(rqstp, rp, ntli->ntli_cachetype, nfs_reply); 1032 1026 out_cached_reply: 1033 1027 return 1; 1034 1028
+1 -1
fs/nfsd/nfsxdr.c
··· 605 605 * 606 606 * Return values: 607 607 * %0: Entry was successfully encoded. 608 - * %-EINVAL: An encoding problem occured, secondary status code in resp->common.err 608 + * %-EINVAL: An encoding problem occurred, secondary status code in resp->common.err 609 609 * 610 610 * On exit, the following fields are updated: 611 611 * - resp->xdr
+4 -1
fs/nfsd/pnfs.h
··· 11 11 12 12 struct xdr_stream; 13 13 14 + /* Cap exponential backoff between fence retries at 3 minutes */ 15 + #define MAX_FENCE_DELAY ((unsigned int)(3 * 60 * HZ)) 16 + 14 17 struct nfsd4_deviceid_map { 15 18 struct list_head hash; 16 19 u64 idx; ··· 41 38 struct svc_rqst *rqstp, 42 39 struct nfsd4_layoutcommit *lcp); 43 40 44 - void (*fence_client)(struct nfs4_layout_stateid *ls, 41 + bool (*fence_client)(struct nfs4_layout_stateid *ls, 45 42 struct nfsd_file *file); 46 43 }; 47 44
+26 -6
fs/nfsd/state.h
··· 123 123 #define SC_TYPE_LAYOUT BIT(3) 124 124 unsigned short sc_type; 125 125 126 - /* state_lock protects sc_status for delegation stateids. 126 + /* nn->deleg_lock protects sc_status for delegation stateids. 127 127 * ->cl_lock protects sc_status for open and lock stateids. 128 128 * ->st_mutex also protect sc_status for open stateids. 129 129 * ->ls_lock protects sc_status for layout stateids. ··· 456 456 struct list_head cl_lru; /* tail queue */ 457 457 #ifdef CONFIG_NFSD_PNFS 458 458 struct list_head cl_lo_states; /* outstanding layout states */ 459 + bool cl_fence_retry_warn; 459 460 #endif 460 461 struct xdr_netobj cl_name; /* id generated by client */ 461 462 nfs4_verifier cl_verifier; /* generated by client */ ··· 528 527 529 528 struct nfsd4_cb_recall_any *cl_ra; 530 529 time64_t cl_ra_time; 530 + #ifdef CONFIG_NFSD_SCSILAYOUT 531 + struct xarray cl_dev_fences; 532 + struct mutex cl_fence_mutex; 533 + #endif 531 534 }; 532 535 533 536 /* struct nfs4_client_reset ··· 554 549 * ~32(deleg. ace) = 112 bytes 555 550 * 556 551 * Some responses can exceed this. A LOCK denial includes the conflicting 557 - * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). Responses 558 - * larger than REPLAY_ISIZE are not cached in rp_ibuf; only rp_status is 559 - * saved. Enlarging this constant increases the size of every 560 - * nfs4_stateowner. 552 + * lock owner, which can be up to 1024 bytes (NFS4_OPAQUE_LIMIT). When a 553 + * response exceeds REPLAY_ISIZE, a buffer is dynamically allocated. If 554 + * that allocation fails, only rp_status is saved. Enlarging this constant 555 + * increases the size of every nfs4_stateowner. 561 556 */ 562 557 563 558 #define NFSD4_REPLAY_ISIZE 112 ··· 569 564 struct nfs4_replay { 570 565 __be32 rp_status; 571 566 unsigned int rp_buflen; 572 - char *rp_buf; 567 + char *rp_buf; /* rp_ibuf or kmalloc'd */ 573 568 struct knfsd_fh rp_openfh; 574 569 int rp_locked; 575 570 char rp_ibuf[NFSD4_REPLAY_ISIZE]; 576 571 }; 572 + 573 + extern void nfs4_replay_free_cache(struct nfs4_replay *rp); 577 574 578 575 struct nfs4_stateowner; 579 576 ··· 749 742 stateid_t ls_recall_sid; 750 743 bool ls_recalled; 751 744 struct mutex ls_mutex; 745 + 746 + struct delayed_work ls_fence_work; 747 + unsigned int ls_fence_delay; 748 + bool ls_fenced; 752 749 }; 753 750 754 751 static inline struct nfs4_layout_stateid *layoutstateid(struct nfs4_stid *s) ··· 862 851 #ifdef CONFIG_NFSD_V4 863 852 void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb); 864 853 void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb); 854 + int nfsd_net_cb_init(struct nfsd_net *nn); 855 + void nfsd_net_cb_shutdown(struct nfsd_net *nn); 865 856 #else 866 857 static inline void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb) 867 858 { 868 859 } 869 860 static inline void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb) 861 + { 862 + } 863 + static inline int nfsd_net_cb_init(struct nfsd_net *nn) 864 + { 865 + return 0; 866 + } 867 + static inline void nfsd_net_cb_shutdown(struct nfsd_net *nn) 870 868 { 871 869 } 872 870 #endif
+23
fs/nfsd/trace.h
··· 373 373 374 374 DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badexport); 375 375 DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badhandle); 376 + DEFINE_NFSD_FH_ERR_EVENT(set_fh_dentry_badmac); 376 377 377 378 TRACE_EVENT(nfsd_exp_find_key, 378 379 TP_PROTO(const struct svc_expkey *key, ··· 2238 2237 __entry->netns_ino = net->ns.inum; 2239 2238 ), 2240 2239 TP_printk("nn=%d", __entry->netns_ino 2240 + ) 2241 + ); 2242 + 2243 + TRACE_EVENT(nfsd_ctl_fh_key_set, 2244 + TP_PROTO( 2245 + const char *key, 2246 + int result 2247 + ), 2248 + TP_ARGS(key, result), 2249 + TP_STRUCT__entry( 2250 + __field(u32, key_hash) 2251 + __field(int, result) 2252 + ), 2253 + TP_fast_assign( 2254 + if (key) 2255 + __entry->key_hash = ~crc32_le(0xFFFFFFFF, key, 16); 2256 + else 2257 + __entry->key_hash = 0; 2258 + __entry->result = result; 2259 + ), 2260 + TP_printk("key=0x%08x result=%d", 2261 + __entry->key_hash, __entry->result 2241 2262 ) 2242 2263 ); 2243 2264
+1
include/linux/filelock.h
··· 50 50 void (*lm_setup)(struct file_lease *, void **); 51 51 bool (*lm_breaker_owns_lease)(struct file_lease *); 52 52 int (*lm_open_conflict)(struct file *, int); 53 + bool (*lm_breaker_timedout)(struct file_lease *fl); 53 54 }; 54 55 55 56 struct lock_manager {
+13 -13
include/linux/lockd/bind.h
··· 10 10 #ifndef LINUX_LOCKD_BIND_H 11 11 #define LINUX_LOCKD_BIND_H 12 12 13 - #include <linux/lockd/nlm.h> 14 - /* need xdr-encoded error codes too, so... */ 15 - #include <linux/lockd/xdr.h> 16 - #ifdef CONFIG_LOCKD_V4 17 - #include <linux/lockd/xdr4.h> 18 - #endif 19 - 20 - /* Dummy declarations */ 13 + struct file_lock; 14 + struct nfs_fh; 21 15 struct svc_rqst; 22 16 struct rpc_task; 23 17 struct rpc_clnt; 18 + struct super_block; 24 19 25 20 /* 26 21 * This is the set of functions for lockd->nfsd communication 27 22 */ 28 23 struct nlmsvc_binding { 29 - __be32 (*fopen)(struct svc_rqst *, 30 - struct nfs_fh *, 31 - struct file **, 32 - int mode); 33 - void (*fclose)(struct file *); 24 + int (*fopen)(struct svc_rqst *rqstp, struct nfs_fh *f, 25 + struct file **filp, int flags); 26 + void (*fclose)(struct file *filp); 34 27 }; 35 28 36 29 extern const struct nlmsvc_binding *nlmsvc_ops; ··· 51 58 extern struct nlm_host *nlmclnt_init(const struct nlmclnt_initdata *nlm_init); 52 59 extern void nlmclnt_done(struct nlm_host *host); 53 60 extern struct rpc_clnt *nlmclnt_rpc_clnt(struct nlm_host *host); 61 + extern void nlmclnt_shutdown_rpc_clnt(struct nlm_host *host); 54 62 55 63 /* 56 64 * NLM client operations provide a means to modify RPC processing of NLM ··· 75 81 extern int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl, void *data); 76 82 extern int lockd_up(struct net *net, const struct cred *cred); 77 83 extern void lockd_down(struct net *net); 84 + 85 + /* 86 + * Cluster failover support 87 + */ 88 + int nlmsvc_unlock_all_by_sb(struct super_block *sb); 89 + int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr); 78 90 79 91 #endif /* LINUX_LOCKD_BIND_H */
-40
include/linux/lockd/debug.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* 3 - * linux/include/linux/lockd/debug.h 4 - * 5 - * Debugging stuff. 6 - * 7 - * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 8 - */ 9 - 10 - #ifndef LINUX_LOCKD_DEBUG_H 11 - #define LINUX_LOCKD_DEBUG_H 12 - 13 - #include <linux/sunrpc/debug.h> 14 - 15 - /* 16 - * Enable lockd debugging. 17 - * Requires RPC_DEBUG. 18 - */ 19 - #undef ifdebug 20 - #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 21 - # define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag)) 22 - #else 23 - # define ifdebug(flag) if (0) 24 - #endif 25 - 26 - /* 27 - * Debug flags 28 - */ 29 - #define NLMDBG_SVC 0x0001 30 - #define NLMDBG_CLIENT 0x0002 31 - #define NLMDBG_CLNTLOCK 0x0004 32 - #define NLMDBG_SVCLOCK 0x0008 33 - #define NLMDBG_MONITOR 0x0010 34 - #define NLMDBG_CLNTSUBS 0x0020 35 - #define NLMDBG_SVCSUBS 0x0040 36 - #define NLMDBG_HOSTCACHE 0x0080 37 - #define NLMDBG_XDR 0x0100 38 - #define NLMDBG_ALL 0x7fff 39 - 40 - #endif /* LINUX_LOCKD_DEBUG_H */
+79 -22
include/linux/lockd/lockd.h fs/lockd/lockd.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 - * linux/include/linux/lockd/lockd.h 4 - * 5 - * General-purpose lockd include file. 6 - * 7 3 * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 8 4 */ 9 5 10 - #ifndef LINUX_LOCKD_LOCKD_H 11 - #define LINUX_LOCKD_LOCKD_H 12 - 13 - /* XXX: a lot of this should really be under fs/lockd. */ 6 + #ifndef _LOCKD_LOCKD_H 7 + #define _LOCKD_LOCKD_H 14 8 15 9 #include <linux/exportfs.h> 16 10 #include <linux/in.h> ··· 14 20 #include <linux/kref.h> 15 21 #include <linux/refcount.h> 16 22 #include <linux/utsname.h> 23 + #include "nlm.h" 17 24 #include <linux/lockd/bind.h> 18 - #include <linux/lockd/xdr.h> 19 - #ifdef CONFIG_LOCKD_V4 20 - #include <linux/lockd/xdr4.h> 21 - #endif 22 - #include <linux/lockd/debug.h> 25 + #include "xdr.h" 26 + #include <linux/sunrpc/debug.h> 23 27 #include <linux/sunrpc/svc.h> 28 + 29 + /* 30 + * Enable lockd debugging. 31 + * Requires CONFIG_SUNRPC_DEBUG. 32 + */ 33 + #undef ifdebug 34 + #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 35 + # define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag)) 36 + #else 37 + # define ifdebug(flag) if (0) 38 + #endif 39 + 40 + #define NLMDBG_SVC 0x0001 41 + #define NLMDBG_CLIENT 0x0002 42 + #define NLMDBG_CLNTLOCK 0x0004 43 + #define NLMDBG_SVCLOCK 0x0008 44 + #define NLMDBG_MONITOR 0x0010 45 + #define NLMDBG_CLNTSUBS 0x0020 46 + #define NLMDBG_SVCSUBS 0x0040 47 + #define NLMDBG_HOSTCACHE 0x0080 48 + #define NLMDBG_XDR 0x0100 49 + #define NLMDBG_ALL 0x7fff 24 50 25 51 /* 26 52 * Version string ··· 51 37 * Default timeout for RPC calls (seconds) 52 38 */ 53 39 #define LOCKD_DFLT_TIMEO 10 40 + 41 + /* error codes new to NLMv4 */ 42 + #define nlm4_deadlock cpu_to_be32(NLM_DEADLCK) 43 + #define nlm4_rofs cpu_to_be32(NLM_ROFS) 44 + #define nlm4_stale_fh cpu_to_be32(NLM_STALE_FH) 45 + #define nlm4_fbig cpu_to_be32(NLM_FBIG) 46 + #define nlm4_failed cpu_to_be32(NLM_FAILED) 47 + 48 + /* 49 + * Internal-use status codes, not to be placed on the wire. 50 + * Version handlers translate these to appropriate wire values. 51 + */ 52 + #define nlm__int__drop_reply cpu_to_be32(30000) 53 + #define nlm__int__deadlock cpu_to_be32(30001) 54 + #define nlm__int__stale_fh cpu_to_be32(30002) 55 + #define nlm__int__failed cpu_to_be32(30003) 54 56 55 57 /* 56 58 * Lockd host handle (used both by the client and server personality). ··· 179 149 void * a_callback_data; /* sent to nlmclnt_operations callbacks */ 180 150 }; 181 151 152 + struct nlm_share; 153 + 182 154 /* 183 155 * This struct describes a file held open by lockd on behalf of 184 156 * an NFS client. ··· 228 196 * Global variables 229 197 */ 230 198 extern const struct rpc_program nlm_program; 231 - extern const struct svc_procedure nlmsvc_procedures[24]; 199 + extern const struct svc_version nlmsvc_version1; 200 + extern const struct svc_version nlmsvc_version3; 232 201 #ifdef CONFIG_LOCKD_V4 233 - extern const struct svc_procedure nlmsvc_procedures4[24]; 202 + extern const struct svc_version nlmsvc_version4; 234 203 #endif 235 204 extern int nlmsvc_grace_period; 236 205 extern unsigned long nlm_timeout; ··· 258 225 int nlmclnt_reclaim(struct nlm_host *, struct file_lock *, 259 226 struct nlm_rqst *); 260 227 void nlmclnt_next_cookie(struct nlm_cookie *); 228 + 229 + #ifdef CONFIG_LOCKD_V4 230 + extern const struct rpc_version nlm_version4; 231 + #endif 261 232 262 233 /* 263 234 * Host cache ··· 326 289 void nlmsvc_grant_reply(struct nlm_cookie *, __be32); 327 290 void nlmsvc_release_call(struct nlm_rqst *); 328 291 void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t); 292 + int nlmsvc_dispatch(struct svc_rqst *rqstp); 329 293 330 294 /* 331 295 * File handling for the server personality ··· 339 301 void nlmsvc_mark_resources(struct net *); 340 302 void nlmsvc_free_host_resources(struct nlm_host *); 341 303 void nlmsvc_invalidate_all(void); 342 - 343 - /* 344 - * Cluster failover support 345 - */ 346 - int nlmsvc_unlock_all_by_sb(struct super_block *sb); 347 - int nlmsvc_unlock_all_by_ip(struct sockaddr *server_addr); 348 304 349 305 static inline struct file *nlmsvc_file_file(const struct nlm_file *file) 350 306 { ··· 422 390 &&(fl1->c.flc_type == fl2->c.flc_type || fl2->c.flc_type == F_UNLCK); 423 391 } 424 392 393 + /** 394 + * lockd_set_file_lock_range4 - set the byte range of a file_lock 395 + * @fl: file_lock whose length fields are to be initialized 396 + * @off: starting offset of the lock, in bytes 397 + * @len: length of the byte range, in bytes, or zero 398 + * 399 + * The NLMv4 protocol represents lock byte ranges as (start, length), 400 + * where length zero means "lock to end of file." The kernel's file_lock 401 + * structure uses (start, end) representation. Convert from NLMv4 format 402 + * to file_lock format, clamping the starting offset and treating 403 + * arithmetic overflow as "lock to EOF." 404 + */ 405 + static inline void 406 + lockd_set_file_lock_range4(struct file_lock *fl, u64 off, u64 len) 407 + { 408 + u64 clamped_off = (off > OFFSET_MAX) ? OFFSET_MAX : off; 409 + s64 end = clamped_off + len - 1; 410 + 411 + fl->fl_start = clamped_off; 412 + if (len == 0 || end < 0) 413 + fl->fl_end = OFFSET_MAX; 414 + else 415 + fl->fl_end = end; 416 + } 417 + 425 418 extern const struct lock_manager_operations nlmsvc_lock_operations; 426 419 427 - #endif /* LINUX_LOCKD_LOCKD_H */ 420 + #endif /* _LOCKD_LOCKD_H */
+3 -5
include/linux/lockd/nlm.h fs/lockd/nlm.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 - * linux/include/linux/lockd/nlm.h 4 - * 5 3 * Declarations for the Network Lock Manager protocol. 6 4 * 7 5 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 8 6 */ 9 7 10 - #ifndef LINUX_LOCKD_NLM_H 11 - #define LINUX_LOCKD_NLM_H 8 + #ifndef _LOCKD_NLM_H 9 + #define _LOCKD_NLM_H 12 10 13 11 14 12 /* Maximum file offset in file_lock.fl_end */ ··· 53 55 #define NLMPROC_NM_LOCK 22 54 56 #define NLMPROC_FREE_ALL 23 55 57 56 - #endif /* LINUX_LOCKD_NLM_H */ 58 + #endif /* _LOCKD_NLM_H */
+10 -9
include/linux/lockd/share.h fs/lockd/share.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 - * linux/include/linux/lockd/share.h 4 - * 5 3 * DOS share management for lockd. 6 4 * 7 5 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de> 8 6 */ 9 7 10 - #ifndef LINUX_LOCKD_SHARE_H 11 - #define LINUX_LOCKD_SHARE_H 8 + #ifndef _LOCKD_SHARE_H 9 + #define _LOCKD_SHARE_H 10 + 11 + /* Synthetic svid for lockowner lookup during share operations */ 12 + #define LOCKD_SHARE_SVID (~(u32)0) 12 13 13 14 /* 14 15 * DOS share for a specific file ··· 23 22 u32 s_mode; /* deny mode */ 24 23 }; 25 24 26 - __be32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *, 27 - struct nlm_args *); 28 - __be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *, 29 - struct nlm_args *); 25 + __be32 nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file, 26 + struct xdr_netobj *oh, u32 access, u32 mode); 27 + __be32 nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file, 28 + struct xdr_netobj *oh); 30 29 void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, 31 30 nlm_host_match_fn_t); 32 31 33 - #endif /* LINUX_LOCKD_SHARE_H */ 32 + #endif /* _LOCKD_SHARE_H */
+3 -12
include/linux/lockd/xdr.h fs/lockd/xdr.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0 */ 2 2 /* 3 - * linux/include/linux/lockd/xdr.h 4 - * 5 3 * XDR types for the NLM protocol 6 4 * 7 5 * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 8 6 */ 9 7 10 - #ifndef LOCKD_XDR_H 11 - #define LOCKD_XDR_H 8 + #ifndef _LOCKD_XDR_H 9 + #define _LOCKD_XDR_H 12 10 13 11 #include <linux/fs.h> 14 12 #include <linux/filelock.h> ··· 30 32 #define nlm_lck_denied_nolocks cpu_to_be32(NLM_LCK_DENIED_NOLOCKS) 31 33 #define nlm_lck_blocked cpu_to_be32(NLM_LCK_BLOCKED) 32 34 #define nlm_lck_denied_grace_period cpu_to_be32(NLM_LCK_DENIED_GRACE_PERIOD) 33 - 34 - #define nlm_drop_reply cpu_to_be32(30000) 35 35 36 36 /* Lock info passed via NLM */ 37 37 struct nlm_lock { ··· 88 92 struct nsm_private priv; 89 93 }; 90 94 91 - /* 92 - * Contents of statd callback when monitored host rebooted 93 - */ 94 - #define NLMSVC_XDRSIZE sizeof(struct nlm_args) 95 - 96 95 bool nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 97 96 bool nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 98 97 bool nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); ··· 103 112 bool nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 104 113 bool nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); 105 114 106 - #endif /* LOCKD_XDR_H */ 115 + #endif /* _LOCKD_XDR_H */
-43
include/linux/lockd/xdr4.h
··· 1 - /* SPDX-License-Identifier: GPL-2.0 */ 2 - /* 3 - * linux/include/linux/lockd/xdr4.h 4 - * 5 - * XDR types for the NLM protocol 6 - * 7 - * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de> 8 - */ 9 - 10 - #ifndef LOCKD_XDR4_H 11 - #define LOCKD_XDR4_H 12 - 13 - #include <linux/fs.h> 14 - #include <linux/nfs.h> 15 - #include <linux/sunrpc/xdr.h> 16 - #include <linux/lockd/xdr.h> 17 - 18 - /* error codes new to NLMv4 */ 19 - #define nlm4_deadlock cpu_to_be32(NLM_DEADLCK) 20 - #define nlm4_rofs cpu_to_be32(NLM_ROFS) 21 - #define nlm4_stale_fh cpu_to_be32(NLM_STALE_FH) 22 - #define nlm4_fbig cpu_to_be32(NLM_FBIG) 23 - #define nlm4_failed cpu_to_be32(NLM_FAILED) 24 - 25 - void nlm4svc_set_file_lock_range(struct file_lock *fl, u64 off, u64 len); 26 - bool nlm4svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 27 - bool nlm4svc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 28 - bool nlm4svc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 29 - bool nlm4svc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 30 - bool nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 31 - bool nlm4svc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); 32 - bool nlm4svc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr); 33 - bool nlm4svc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr); 34 - bool nlm4svc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr); 35 - 36 - bool nlm4svc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr); 37 - bool nlm4svc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr); 38 - bool nlm4svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr); 39 - bool nlm4svc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr); 40 - 41 - extern const struct rpc_version nlm_version4; 42 - 43 - #endif /* LOCKD_XDR4_H */
+6 -1
include/linux/sunrpc/cache.h
··· 16 16 #include <linux/atomic.h> 17 17 #include <linux/kstrtox.h> 18 18 #include <linux/proc_fs.h> 19 + #include <linux/wait.h> 19 20 20 21 /* 21 22 * Each cache requires: ··· 113 112 int entries; 114 113 115 114 /* fields for communication over channel */ 116 - struct list_head queue; 115 + struct list_head requests; 116 + struct list_head readers; 117 + spinlock_t queue_lock; 118 + wait_queue_head_t queue_wait; 119 + u64 next_seqno; 117 120 118 121 atomic_t writers; /* how many time is /channel open */ 119 122 time64_t last_close; /* if no writers, when did last close */
+6 -4
include/linux/sunrpc/debug.h
··· 38 38 do { \ 39 39 ifdebug(fac) \ 40 40 __sunrpc_printk(fmt, ##__VA_ARGS__); \ 41 + else \ 42 + no_printk(fmt, ##__VA_ARGS__); \ 41 43 } while (0) 42 44 43 45 # define dfprintk_rcu(fac, fmt, ...) \ ··· 48 46 rcu_read_lock(); \ 49 47 __sunrpc_printk(fmt, ##__VA_ARGS__); \ 50 48 rcu_read_unlock(); \ 49 + } else { \ 50 + no_printk(fmt, ##__VA_ARGS__); \ 51 51 } \ 52 52 } while (0) 53 53 54 - # define RPC_IFDEBUG(x) x 55 54 #else 56 55 # define ifdebug(fac) if (0) 57 - # define dfprintk(fac, fmt, ...) do {} while (0) 58 - # define dfprintk_rcu(fac, fmt, ...) do {} while (0) 59 - # define RPC_IFDEBUG(x) 56 + # define dfprintk(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__) 57 + # define dfprintk_rcu(fac, fmt, ...) no_printk(fmt, ##__VA_ARGS__) 60 58 #endif 61 59 62 60 /*
-3
include/linux/sunrpc/sched.h
··· 95 95 int tk_rpc_status; /* Result of last RPC operation */ 96 96 unsigned short tk_flags; /* misc flags */ 97 97 unsigned short tk_timeouts; /* maj timeouts */ 98 - 99 - #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) 100 98 unsigned short tk_pid; /* debugging aid */ 101 - #endif 102 99 unsigned char tk_priority : 2,/* Task priority */ 103 100 tk_garb_retry : 2, 104 101 tk_cred_retry : 2;
+56 -26
include/linux/sunrpc/svc.h
··· 134 134 extern u32 svc_max_payload(const struct svc_rqst *rqstp); 135 135 136 136 /* 137 - * RPC Requests and replies are stored in one or more pages. 138 - * We maintain an array of pages for each server thread. 139 - * Requests are copied into these pages as they arrive. Remaining 140 - * pages are available to write the reply into. 137 + * RPC Call and Reply messages each have their own page array. 138 + * rq_pages holds the incoming Call message; rq_respages holds 139 + * the outgoing Reply message. Both arrays are sized to 140 + * svc_serv_maxpages() entries and are allocated dynamically. 141 141 * 142 - * Pages are sent using ->sendmsg with MSG_SPLICE_PAGES so each server thread 143 - * needs to allocate more to replace those used in sending. To help keep track 144 - * of these pages we have a receive list where all pages initialy live, and a 145 - * send list where pages are moved to when there are to be part of a reply. 142 + * Pages are sent using ->sendmsg with MSG_SPLICE_PAGES so each 143 + * server thread needs to allocate more to replace those used in 144 + * sending. 146 145 * 147 - * We use xdr_buf for holding responses as it fits well with NFS 148 - * read responses (that have a header, and some data pages, and possibly 149 - * a tail) and means we can share some client side routines. 146 + * rq_pages request page contract: 150 147 * 151 - * The xdr_buf.head kvec always points to the first page in the rq_*pages 152 - * list. The xdr_buf.pages pointer points to the second page on that 153 - * list. xdr_buf.tail points to the end of the first page. 154 - * This assumes that the non-page part of an rpc reply will fit 155 - * in a page - NFSd ensures this. lockd also has no trouble. 148 + * Transport receive paths that move request data pages out of 149 + * rq_pages -- TCP multi-fragment reassembly (svc_tcp_save_pages) 150 + * and RDMA Read I/O (svc_rdma_clear_rqst_pages) -- NULL those 151 + * entries to prevent svc_rqst_release_pages() from freeing pages 152 + * still in transport use, and set rq_pages_nfree to the count. 153 + * svc_alloc_arg() refills only that many rq_pages entries. 154 + * 155 + * For rq_respages, svc_rqst_release_pages() NULLs entries in 156 + * [rq_respages, rq_next_page) after each RPC. svc_alloc_arg() 157 + * refills only that range. 158 + * 159 + * xdr_buf holds responses; the structure fits NFS read responses 160 + * (header, data pages, optional tail) and enables sharing of 161 + * client-side routines. 162 + * 163 + * The xdr_buf.head kvec always points to the first page in the 164 + * rq_*pages list. The xdr_buf.pages pointer points to the second 165 + * page on that list. xdr_buf.tail points to the end of the first 166 + * page. This assumes that the non-page part of an rpc reply will 167 + * fit in a page - NFSd ensures this. lockd also has no trouble. 156 168 */ 157 169 158 170 /** ··· 174 162 * Returns a count of pages or vectors that can hold the maximum 175 163 * size RPC message for @serv. 176 164 * 177 - * Each request/reply pair can have at most one "payload", plus two 178 - * pages, one for the request, and one for the reply. 179 - * nfsd_splice_actor() might need an extra page when a READ payload 180 - * is not page-aligned. 165 + * Each page array can hold at most one payload plus two 166 + * overhead pages (one for the RPC header, one for tail data). 167 + * nfsd_splice_actor() might need an extra page when a READ 168 + * payload is not page-aligned. 181 169 */ 182 170 static inline unsigned long svc_serv_maxpages(const struct svc_serv *serv) 183 171 { ··· 187 175 /* 188 176 * The context of a single thread, including the request currently being 189 177 * processed. 178 + * 179 + * RPC programs are free to use rq_private to stash thread-local information. 180 + * The sunrpc layer will not access it. 190 181 */ 191 182 struct svc_rqst { 192 183 struct list_head rq_all; /* all threads list */ ··· 216 201 struct xdr_stream rq_res_stream; 217 202 struct folio *rq_scratch_folio; 218 203 struct xdr_buf rq_res; 219 - unsigned long rq_maxpages; /* num of entries in rq_pages */ 220 - struct page * *rq_pages; 221 - struct page * *rq_respages; /* points into rq_pages */ 204 + unsigned long rq_maxpages; /* entries per page array */ 205 + unsigned long rq_pages_nfree; /* rq_pages entries NULLed by transport */ 206 + struct page * *rq_pages; /* Call buffer pages */ 207 + struct page * *rq_respages; /* Reply buffer pages */ 222 208 struct page * *rq_next_page; /* next reply page to use */ 223 - struct page * *rq_page_end; /* one past the last page */ 209 + struct page * *rq_page_end; /* one past the last reply page */ 224 210 225 211 struct folio_batch rq_fbatch; 226 212 struct bio_vec *rq_bvec; ··· 231 215 u32 rq_vers; /* program version */ 232 216 u32 rq_proc; /* procedure number */ 233 217 u32 rq_prot; /* IP protocol */ 234 - int rq_cachetype; /* catering to nfsd */ 235 218 unsigned long rq_flags; /* flags field */ 236 219 ktime_t rq_qtime; /* enqueue time */ 237 220 ··· 266 251 unsigned long bc_to_initval; 267 252 unsigned int bc_to_retries; 268 253 unsigned int rq_status_counter; /* RPC processing counter */ 269 - void **rq_lease_breaker; /* The v4 client breaking a lease */ 254 + void *rq_private; /* For use by the service thread */ 270 255 }; 271 256 272 257 /* bits for rq_flags */ ··· 497 482 unsigned short port); 498 483 499 484 #define RPC_MAX_ADDRBUFLEN (63U) 485 + 486 + /** 487 + * svc_rqst_page_release - release a page associated with an RPC transaction 488 + * @rqstp: RPC transaction context 489 + * @page: page to release 490 + * 491 + * Released pages are batched and freed together, reducing 492 + * allocator pressure under heavy RPC workloads. 493 + */ 494 + static inline void svc_rqst_page_release(struct svc_rqst *rqstp, 495 + struct page *page) 496 + { 497 + if (!folio_batch_add(&rqstp->rq_fbatch, page_folio(page))) 498 + __folio_batch_release(&rqstp->rq_fbatch); 499 + } 500 500 501 501 /* 502 502 * When we want to reduce the size of the reserved space in the response
+20 -3
include/linux/sunrpc/svc_rdma.h
··· 84 84 85 85 atomic_t sc_sq_avail; /* SQEs ready to be consumed */ 86 86 unsigned int sc_sq_depth; /* Depth of SQ */ 87 + atomic_t sc_sq_ticket_head; /* Next ticket to issue */ 88 + atomic_t sc_sq_ticket_tail; /* Ticket currently serving */ 89 + wait_queue_head_t sc_sq_ticket_wait; /* Ticket ordering waitlist */ 87 90 __be32 sc_fc_credits; /* Forward credits */ 88 91 u32 sc_max_requests; /* Max requests */ 89 92 u32 sc_max_bc_requests;/* Backward credits */ ··· 216 213 */ 217 214 struct svc_rdma_write_info { 218 215 struct svcxprt_rdma *wi_rdma; 216 + struct list_head wi_list; 219 217 220 218 const struct svc_rdma_chunk *wi_chunk; 221 219 ··· 245 241 struct ib_cqe sc_cqe; 246 242 struct xdr_buf sc_hdrbuf; 247 243 struct xdr_stream sc_stream; 244 + 245 + struct list_head sc_write_info_list; 248 246 struct svc_rdma_write_info sc_reply_info; 247 + 249 248 void *sc_xprt_buf; 250 249 int sc_page_count; 251 250 int sc_cur_sge_no; ··· 281 274 extern void svc_rdma_cc_release(struct svcxprt_rdma *rdma, 282 275 struct svc_rdma_chunk_ctxt *cc, 283 276 enum dma_data_direction dir); 277 + extern void svc_rdma_write_chunk_release(struct svcxprt_rdma *rdma, 278 + struct svc_rdma_send_ctxt *ctxt); 284 279 extern void svc_rdma_reply_chunk_release(struct svcxprt_rdma *rdma, 285 280 struct svc_rdma_send_ctxt *ctxt); 286 - extern int svc_rdma_send_write_list(struct svcxprt_rdma *rdma, 287 - const struct svc_rdma_recv_ctxt *rctxt, 288 - const struct xdr_buf *xdr); 281 + extern int svc_rdma_prepare_write_list(struct svcxprt_rdma *rdma, 282 + const struct svc_rdma_recv_ctxt *rctxt, 283 + struct svc_rdma_send_ctxt *sctxt, 284 + const struct xdr_buf *xdr); 289 285 extern int svc_rdma_prepare_reply_chunk(struct svcxprt_rdma *rdma, 290 286 const struct svc_rdma_pcl *write_pcl, 291 287 const struct svc_rdma_pcl *reply_pcl, ··· 316 306 struct svc_rdma_recv_ctxt *rctxt, 317 307 int status); 318 308 extern void svc_rdma_wake_send_waiters(struct svcxprt_rdma *rdma, int avail); 309 + extern int svc_rdma_sq_wait(struct svcxprt_rdma *rdma, 310 + const struct rpc_rdma_cid *cid, int sqecount); 311 + extern int svc_rdma_post_send_err(struct svcxprt_rdma *rdma, 312 + const struct rpc_rdma_cid *cid, 313 + const struct ib_send_wr *bad_wr, 314 + const struct ib_send_wr *first_wr, 315 + int sqecount, int ret); 319 316 extern int svc_rdma_sendto(struct svc_rqst *); 320 317 extern int svc_rdma_result_payload(struct svc_rqst *rqstp, unsigned int offset, 321 318 unsigned int length);
+24 -24
include/linux/sunrpc/xdr.h
··· 290 290 /** 291 291 * xdr_set_scratch_folio - Attach a scratch buffer for decoding data 292 292 * @xdr: pointer to xdr_stream struct 293 - * @page: an anonymous folio 293 + * @folio: an anonymous folio 294 294 * 295 295 * See xdr_set_scratch_buffer(). 296 296 */ ··· 330 330 * xdr_stream_remaining - Return the number of bytes remaining in the stream 331 331 * @xdr: pointer to struct xdr_stream 332 332 * 333 - * Return value: 333 + * Returns: 334 334 * Number of bytes remaining in @xdr before xdr->end 335 335 */ 336 336 static inline size_t ··· 350 350 * xdr_align_size - Calculate padded size of an object 351 351 * @n: Size of an object being XDR encoded (in bytes) 352 352 * 353 - * Return value: 353 + * Returns: 354 354 * Size (in bytes) of the object including xdr padding 355 355 */ 356 356 static inline size_t ··· 368 368 * This implementation avoids the need for conditional 369 369 * branches or modulo division. 370 370 * 371 - * Return value: 371 + * Returns: 372 372 * Size (in bytes) of the needed XDR pad 373 373 */ 374 374 static inline size_t xdr_pad_size(size_t n) ··· 380 380 * xdr_stream_encode_item_present - Encode a "present" list item 381 381 * @xdr: pointer to xdr_stream 382 382 * 383 - * Return values: 383 + * Returns: 384 384 * On success, returns length in bytes of XDR buffer consumed 385 385 * %-EMSGSIZE on XDR buffer overflow 386 386 */ ··· 399 399 * xdr_stream_encode_item_absent - Encode a "not present" list item 400 400 * @xdr: pointer to xdr_stream 401 401 * 402 - * Return values: 402 + * Returns: 403 403 * On success, returns length in bytes of XDR buffer consumed 404 404 * %-EMSGSIZE on XDR buffer overflow 405 405 */ ··· 419 419 * @p: address in a buffer into which to encode 420 420 * @n: boolean value to encode 421 421 * 422 - * Return value: 422 + * Returns: 423 423 * Address of item following the encoded boolean 424 424 */ 425 425 static inline __be32 *xdr_encode_bool(__be32 *p, u32 n) ··· 433 433 * @xdr: pointer to xdr_stream 434 434 * @n: boolean value to encode 435 435 * 436 - * Return values: 436 + * Returns: 437 437 * On success, returns length in bytes of XDR buffer consumed 438 438 * %-EMSGSIZE on XDR buffer overflow 439 439 */ ··· 453 453 * @xdr: pointer to xdr_stream 454 454 * @n: integer to encode 455 455 * 456 - * Return values: 456 + * Returns: 457 457 * On success, returns length in bytes of XDR buffer consumed 458 458 * %-EMSGSIZE on XDR buffer overflow 459 459 */ ··· 474 474 * @xdr: pointer to xdr_stream 475 475 * @n: integer to encode 476 476 * 477 - * Return values: 477 + * Returns: 478 478 * On success, returns length in bytes of XDR buffer consumed 479 479 * %-EMSGSIZE on XDR buffer overflow 480 480 */ ··· 495 495 * @xdr: pointer to xdr_stream 496 496 * @n: 64-bit integer to encode 497 497 * 498 - * Return values: 498 + * Returns: 499 499 * On success, returns length in bytes of XDR buffer consumed 500 500 * %-EMSGSIZE on XDR buffer overflow 501 501 */ ··· 517 517 * @ptr: pointer to void pointer 518 518 * @len: size of object 519 519 * 520 - * Return values: 520 + * Returns: 521 521 * On success, returns length in bytes of XDR buffer consumed 522 522 * %-EMSGSIZE on XDR buffer overflow 523 523 */ ··· 542 542 * @ptr: pointer to opaque data object 543 543 * @len: size of object pointed to by @ptr 544 544 * 545 - * Return values: 545 + * Returns: 546 546 * On success, returns length in bytes of XDR buffer consumed 547 547 * %-EMSGSIZE on XDR buffer overflow 548 548 */ ··· 563 563 * @ptr: pointer to opaque data object 564 564 * @len: size of object pointed to by @ptr 565 565 * 566 - * Return values: 566 + * Returns: 567 567 * On success, returns length in bytes of XDR buffer consumed 568 568 * %-EMSGSIZE on XDR buffer overflow 569 569 */ ··· 585 585 * @array: array of integers 586 586 * @array_size: number of elements in @array 587 587 * 588 - * Return values: 588 + * Returns: 589 589 * On success, returns length in bytes of XDR buffer consumed 590 590 * %-EMSGSIZE on XDR buffer overflow 591 591 */ ··· 608 608 * xdr_item_is_absent - symbolically handle XDR discriminators 609 609 * @p: pointer to undecoded discriminator 610 610 * 611 - * Return values: 611 + * Returns: 612 612 * %true if the following XDR item is absent 613 613 * %false if the following XDR item is present 614 614 */ ··· 621 621 * xdr_item_is_present - symbolically handle XDR discriminators 622 622 * @p: pointer to undecoded discriminator 623 623 * 624 - * Return values: 624 + * Returns: 625 625 * %true if the following XDR item is present 626 626 * %false if the following XDR item is absent 627 627 */ ··· 635 635 * @xdr: pointer to xdr_stream 636 636 * @ptr: pointer to a u32 in which to store the result 637 637 * 638 - * Return values: 638 + * Returns: 639 639 * %0 on success 640 640 * %-EBADMSG on XDR buffer overflow 641 641 */ ··· 656 656 * @xdr: pointer to xdr_stream 657 657 * @ptr: location to store integer 658 658 * 659 - * Return values: 659 + * Returns: 660 660 * %0 on success 661 661 * %-EBADMSG on XDR buffer overflow 662 662 */ ··· 677 677 * @xdr: pointer to xdr_stream 678 678 * @ptr: location to store integer 679 679 * 680 - * Return values: 680 + * Returns: 681 681 * %0 on success 682 682 * %-EBADMSG on XDR buffer overflow 683 683 */ ··· 698 698 * @xdr: pointer to xdr_stream 699 699 * @ptr: location to store 64-bit integer 700 700 * 701 - * Return values: 701 + * Returns: 702 702 * %0 on success 703 703 * %-EBADMSG on XDR buffer overflow 704 704 */ ··· 720 720 * @ptr: location to store data 721 721 * @len: size of buffer pointed to by @ptr 722 722 * 723 - * Return values: 723 + * Returns: 724 724 * %0 on success 725 725 * %-EBADMSG on XDR buffer overflow 726 726 */ ··· 746 746 * on @xdr. It is therefore expected that the object it points to should 747 747 * be processed immediately. 748 748 * 749 - * Return values: 749 + * Returns: 750 750 * On success, returns size of object stored in *@ptr 751 751 * %-EBADMSG on XDR buffer overflow 752 752 * %-EMSGSIZE if the size of the object would exceed @maxlen ··· 777 777 * @array: location to store the integer array or NULL 778 778 * @array_size: number of elements to store 779 779 * 780 - * Return values: 780 + * Returns: 781 781 * On success, returns number of elements stored in @array 782 782 * %-EBADMSG on XDR buffer overflow 783 783 * %-EMSGSIZE if the size of the array exceeds @array_size
+233
include/linux/sunrpc/xdrgen/nlm4.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Generated by xdrgen. Manual edits will be lost. */ 3 + /* XDR specification file: ../../Documentation/sunrpc/xdr/nlm4.x */ 4 + /* XDR specification modification time: Thu Dec 25 13:10:19 2025 */ 5 + 6 + #ifndef _LINUX_XDRGEN_NLM4_DEF_H 7 + #define _LINUX_XDRGEN_NLM4_DEF_H 8 + 9 + #include <linux/types.h> 10 + #include <linux/sunrpc/xdrgen/_defs.h> 11 + 12 + enum { LM_MAXSTRLEN = 1024 }; 13 + 14 + enum { LM_MAXNAMELEN = 1025 }; 15 + 16 + enum { MAXNETOBJ_SZ = 1024 }; 17 + 18 + typedef opaque netobj; 19 + 20 + enum fsh4_mode { 21 + fsm_DN = 0, 22 + fsm_DR = 1, 23 + fsm_DW = 2, 24 + fsm_DRW = 3, 25 + }; 26 + 27 + typedef enum fsh4_mode fsh4_mode; 28 + 29 + enum fsh4_access { 30 + fsa_NONE = 0, 31 + fsa_R = 1, 32 + fsa_W = 2, 33 + fsa_RW = 3, 34 + }; 35 + 36 + typedef enum fsh4_access fsh4_access; 37 + 38 + enum { SM_MAXSTRLEN = 1024 }; 39 + 40 + typedef u64 uint64; 41 + 42 + typedef s64 int64; 43 + 44 + typedef u32 uint32; 45 + 46 + typedef s32 int32; 47 + 48 + enum nlm4_stats { 49 + NLM4_GRANTED = 0, 50 + NLM4_DENIED = 1, 51 + NLM4_DENIED_NOLOCKS = 2, 52 + NLM4_BLOCKED = 3, 53 + NLM4_DENIED_GRACE_PERIOD = 4, 54 + NLM4_DEADLCK = 5, 55 + NLM4_ROFS = 6, 56 + NLM4_STALE_FH = 7, 57 + NLM4_FBIG = 8, 58 + NLM4_FAILED = 9, 59 + }; 60 + 61 + typedef __be32 nlm4_stats; 62 + 63 + struct nlm4_holder { 64 + bool exclusive; 65 + int32 svid; 66 + netobj oh; 67 + uint64 l_offset; 68 + uint64 l_len; 69 + }; 70 + 71 + struct nlm4_testrply { 72 + nlm4_stats stat; 73 + union { 74 + struct nlm4_holder holder; 75 + } u; 76 + }; 77 + 78 + struct nlm4_stat { 79 + nlm4_stats stat; 80 + }; 81 + 82 + struct nlm4_res { 83 + netobj cookie; 84 + struct nlm4_stat stat; 85 + }; 86 + 87 + struct nlm4_testres { 88 + netobj cookie; 89 + struct nlm4_testrply stat; 90 + }; 91 + 92 + struct nlm4_lock { 93 + string caller_name; 94 + netobj fh; 95 + netobj oh; 96 + int32 svid; 97 + uint64 l_offset; 98 + uint64 l_len; 99 + }; 100 + 101 + struct nlm4_lockargs { 102 + netobj cookie; 103 + bool block; 104 + bool exclusive; 105 + struct nlm4_lock alock; 106 + bool reclaim; 107 + int32 state; 108 + }; 109 + 110 + struct nlm4_cancargs { 111 + netobj cookie; 112 + bool block; 113 + bool exclusive; 114 + struct nlm4_lock alock; 115 + }; 116 + 117 + struct nlm4_testargs { 118 + netobj cookie; 119 + bool exclusive; 120 + struct nlm4_lock alock; 121 + }; 122 + 123 + struct nlm4_unlockargs { 124 + netobj cookie; 125 + struct nlm4_lock alock; 126 + }; 127 + 128 + struct nlm4_share { 129 + string caller_name; 130 + netobj fh; 131 + netobj oh; 132 + fsh4_mode mode; 133 + fsh4_access access; 134 + }; 135 + 136 + struct nlm4_shareargs { 137 + netobj cookie; 138 + struct nlm4_share share; 139 + bool reclaim; 140 + }; 141 + 142 + struct nlm4_shareres { 143 + netobj cookie; 144 + nlm4_stats stat; 145 + int32 sequence; 146 + }; 147 + 148 + struct nlm4_notify { 149 + string name; 150 + int32 state; 151 + }; 152 + 153 + enum { SM_PRIV_SIZE = 16 }; 154 + 155 + struct nlm4_notifyargs { 156 + struct nlm4_notify notify; 157 + u8 private[SM_PRIV_SIZE]; 158 + }; 159 + 160 + enum { 161 + NLMPROC4_NULL = 0, 162 + NLMPROC4_TEST = 1, 163 + NLMPROC4_LOCK = 2, 164 + NLMPROC4_CANCEL = 3, 165 + NLMPROC4_UNLOCK = 4, 166 + NLMPROC4_GRANTED = 5, 167 + NLMPROC4_TEST_MSG = 6, 168 + NLMPROC4_LOCK_MSG = 7, 169 + NLMPROC4_CANCEL_MSG = 8, 170 + NLMPROC4_UNLOCK_MSG = 9, 171 + NLMPROC4_GRANTED_MSG = 10, 172 + NLMPROC4_TEST_RES = 11, 173 + NLMPROC4_LOCK_RES = 12, 174 + NLMPROC4_CANCEL_RES = 13, 175 + NLMPROC4_UNLOCK_RES = 14, 176 + NLMPROC4_GRANTED_RES = 15, 177 + NLMPROC4_SM_NOTIFY = 16, 178 + NLMPROC4_SHARE = 20, 179 + NLMPROC4_UNSHARE = 21, 180 + NLMPROC4_NM_LOCK = 22, 181 + NLMPROC4_FREE_ALL = 23, 182 + }; 183 + 184 + #ifndef NLM4_PROG 185 + #define NLM4_PROG (100021) 186 + #endif 187 + 188 + #define NLM4_netobj_sz (XDR_unsigned_int + XDR_QUADLEN(MAXNETOBJ_SZ)) 189 + #define NLM4_fsh4_mode_sz (XDR_int) 190 + #define NLM4_fsh4_access_sz (XDR_int) 191 + #define NLM4_uint64_sz \ 192 + (XDR_unsigned_hyper) 193 + #define NLM4_int64_sz \ 194 + (XDR_hyper) 195 + #define NLM4_uint32_sz \ 196 + (XDR_unsigned_long) 197 + #define NLM4_int32_sz \ 198 + (XDR_long) 199 + #define NLM4_nlm4_stats_sz (XDR_int) 200 + #define NLM4_nlm4_holder_sz \ 201 + (XDR_bool + NLM4_int32_sz + NLM4_netobj_sz + NLM4_uint64_sz + NLM4_uint64_sz) 202 + #define NLM4_nlm4_testrply_sz \ 203 + (NLM4_nlm4_stats_sz + NLM4_nlm4_holder_sz) 204 + #define NLM4_nlm4_stat_sz \ 205 + (NLM4_nlm4_stats_sz) 206 + #define NLM4_nlm4_res_sz \ 207 + (NLM4_netobj_sz + NLM4_nlm4_stat_sz) 208 + #define NLM4_nlm4_testres_sz \ 209 + (NLM4_netobj_sz + NLM4_nlm4_testrply_sz) 210 + #define NLM4_nlm4_lock_sz \ 211 + (XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM4_netobj_sz + NLM4_netobj_sz + NLM4_int32_sz + NLM4_uint64_sz + NLM4_uint64_sz) 212 + #define NLM4_nlm4_lockargs_sz \ 213 + (NLM4_netobj_sz + XDR_bool + XDR_bool + NLM4_nlm4_lock_sz + XDR_bool + NLM4_int32_sz) 214 + #define NLM4_nlm4_cancargs_sz \ 215 + (NLM4_netobj_sz + XDR_bool + XDR_bool + NLM4_nlm4_lock_sz) 216 + #define NLM4_nlm4_testargs_sz \ 217 + (NLM4_netobj_sz + XDR_bool + NLM4_nlm4_lock_sz) 218 + #define NLM4_nlm4_unlockargs_sz \ 219 + (NLM4_netobj_sz + NLM4_nlm4_lock_sz) 220 + #define NLM4_nlm4_share_sz \ 221 + (XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM4_netobj_sz + NLM4_netobj_sz + NLM4_fsh4_mode_sz + NLM4_fsh4_access_sz) 222 + #define NLM4_nlm4_shareargs_sz \ 223 + (NLM4_netobj_sz + NLM4_nlm4_share_sz + XDR_bool) 224 + #define NLM4_nlm4_shareres_sz \ 225 + (NLM4_netobj_sz + NLM4_nlm4_stats_sz + NLM4_int32_sz) 226 + #define NLM4_nlm4_notify_sz \ 227 + (XDR_unsigned_int + XDR_QUADLEN(LM_MAXNAMELEN) + NLM4_int32_sz) 228 + #define NLM4_nlm4_notifyargs_sz \ 229 + (NLM4_nlm4_notify_sz + XDR_QUADLEN(SM_PRIV_SIZE)) 230 + #define NLM4_MAX_ARGS_SZ \ 231 + (NLM4_nlm4_lockargs_sz) 232 + 233 + #endif /* _LINUX_XDRGEN_NLM4_DEF_H */
+3 -1
include/trace/events/sunrpc.h
··· 1933 1933 svc_xprt_flag(CONG_CTRL) \ 1934 1934 svc_xprt_flag(HANDSHAKE) \ 1935 1935 svc_xprt_flag(TLS_SESSION) \ 1936 - svc_xprt_flag_end(PEER_AUTH) 1936 + svc_xprt_flag(PEER_AUTH) \ 1937 + svc_xprt_flag(PEER_VALID) \ 1938 + svc_xprt_flag_end(RPCB_UNREG) 1937 1939 1938 1940 #undef svc_xprt_flag 1939 1941 #undef svc_xprt_flag_end
+2 -2
include/uapi/linux/nfsd/export.h
··· 34 34 #define NFSEXP_GATHERED_WRITES 0x0020 35 35 #define NFSEXP_NOREADDIRPLUS 0x0040 36 36 #define NFSEXP_SECURITY_LABEL 0x0080 37 - /* 0x100 currently unused */ 37 + #define NFSEXP_SIGN_FH 0x0100 38 38 #define NFSEXP_NOHIDE 0x0200 39 39 #define NFSEXP_NOSUBTREECHECK 0x0400 40 40 #define NFSEXP_NOAUTHNLM 0x0800 /* Don't authenticate NLM requests - just trust */ ··· 55 55 #define NFSEXP_PNFS 0x20000 56 56 57 57 /* All flags that we claim to support. (Note we don't support NOACL.) */ 58 - #define NFSEXP_ALLFLAGS 0x3FEFF 58 + #define NFSEXP_ALLFLAGS 0x3FFFF 59 59 60 60 /* The flags that may vary depending on security flavor: */ 61 61 #define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
+1
include/uapi/linux/nfsd_netlink.h
··· 36 36 NFSD_A_SERVER_LEASETIME, 37 37 NFSD_A_SERVER_SCOPE, 38 38 NFSD_A_SERVER_MIN_THREADS, 39 + NFSD_A_SERVER_FH_KEY, 39 40 40 41 __NFSD_A_SERVER_MAX, 41 42 NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
+51 -42
net/sunrpc/auth_gss/gss_krb5_test.c
··· 63 63 KUNIT_ASSERT_EQ(test, err, 0); 64 64 65 65 /* Assert */ 66 - KUNIT_EXPECT_EQ_MSG(test, 67 - memcmp(param->expected_result->data, 68 - derivedkey.data, derivedkey.len), 0, 69 - "key mismatch"); 66 + KUNIT_EXPECT_MEMEQ_MSG(test, 67 + param->expected_result->data, 68 + derivedkey.data, 69 + derivedkey.len, 70 + "key mismatch"); 70 71 } 71 72 72 73 static void checksum_case(struct kunit *test) ··· 112 111 KUNIT_ASSERT_EQ(test, err, 0); 113 112 114 113 /* Assert */ 115 - KUNIT_EXPECT_EQ_MSG(test, 116 - memcmp(param->expected_result->data, 117 - checksum.data, checksum.len), 0, 118 - "checksum mismatch"); 114 + KUNIT_EXPECT_MEMEQ_MSG(test, 115 + param->expected_result->data, 116 + checksum.data, 117 + checksum.len, 118 + "checksum mismatch"); 119 119 120 120 crypto_free_ahash(tfm); 121 121 } ··· 316 314 param->expected_result->len * 8, result); 317 315 318 316 /* Assert */ 319 - KUNIT_EXPECT_EQ_MSG(test, 320 - memcmp(param->expected_result->data, 321 - result, param->expected_result->len), 0, 322 - "result mismatch"); 317 + KUNIT_EXPECT_MEMEQ_MSG(test, 318 + param->expected_result->data, 319 + result, 320 + param->expected_result->len, 321 + "result mismatch"); 323 322 } 324 323 325 324 static struct kunit_case rfc3961_test_cases[] = { ··· 572 569 KUNIT_EXPECT_EQ_MSG(test, 573 570 param->expected_result->len, buf.len, 574 571 "ciphertext length mismatch"); 575 - KUNIT_EXPECT_EQ_MSG(test, 576 - memcmp(param->expected_result->data, 577 - text, param->expected_result->len), 0, 578 - "ciphertext mismatch"); 579 - KUNIT_EXPECT_EQ_MSG(test, 580 - memcmp(param->next_iv->data, iv, 581 - param->next_iv->len), 0, 582 - "IV mismatch"); 572 + KUNIT_EXPECT_MEMEQ_MSG(test, 573 + param->expected_result->data, 574 + text, 575 + param->expected_result->len, 576 + "ciphertext mismatch"); 577 + KUNIT_EXPECT_MEMEQ_MSG(test, 578 + param->next_iv->data, 579 + iv, 580 + param->next_iv->len, 581 + "IV mismatch"); 583 582 584 583 crypto_free_sync_skcipher(cts_tfm); 585 584 crypto_free_sync_skcipher(cbc_tfm); ··· 1199 1194 KUNIT_EXPECT_EQ_MSG(test, param->expected_result->len, 1200 1195 buf.len + checksum.len, 1201 1196 "ciphertext length mismatch"); 1202 - KUNIT_EXPECT_EQ_MSG(test, 1203 - memcmp(param->expected_result->data, 1204 - buf.head[0].iov_base, buf.len), 0, 1205 - "encrypted result mismatch"); 1206 - KUNIT_EXPECT_EQ_MSG(test, 1207 - memcmp(param->expected_result->data + 1208 - (param->expected_result->len - checksum.len), 1209 - checksum.data, checksum.len), 0, 1210 - "HMAC mismatch"); 1197 + KUNIT_EXPECT_MEMEQ_MSG(test, 1198 + param->expected_result->data, 1199 + buf.head[0].iov_base, 1200 + buf.len, 1201 + "encrypted result mismatch"); 1202 + KUNIT_EXPECT_MEMEQ_MSG(test, 1203 + param->expected_result->data + 1204 + (param->expected_result->len - checksum.len), 1205 + checksum.data, 1206 + checksum.len, 1207 + "HMAC mismatch"); 1211 1208 1212 1209 crypto_free_ahash(ahash_tfm); 1213 1210 crypto_free_sync_skcipher(cts_tfm); ··· 1694 1687 KUNIT_EXPECT_EQ_MSG(test, 1695 1688 param->expected_result->len, buf.len, 1696 1689 "ciphertext length mismatch"); 1697 - KUNIT_EXPECT_EQ_MSG(test, 1698 - memcmp(param->expected_result->data, 1699 - buf.head[0].iov_base, 1700 - param->expected_result->len), 0, 1701 - "ciphertext mismatch"); 1702 - KUNIT_EXPECT_EQ_MSG(test, memcmp(param->expected_hmac->data, 1703 - checksum.data, 1704 - checksum.len), 0, 1705 - "HMAC mismatch"); 1690 + KUNIT_EXPECT_MEMEQ_MSG(test, 1691 + param->expected_result->data, 1692 + buf.head[0].iov_base, 1693 + param->expected_result->len, 1694 + "ciphertext mismatch"); 1695 + KUNIT_EXPECT_MEMEQ_MSG(test, 1696 + param->expected_hmac->data, 1697 + checksum.data, 1698 + checksum.len, 1699 + "HMAC mismatch"); 1706 1700 1707 1701 crypto_free_ahash(ahash_tfm); 1708 1702 crypto_free_sync_skcipher(cts_tfm); ··· 1834 1826 KUNIT_EXPECT_EQ_MSG(test, 1835 1827 param->plaintext->len, buf.len, 1836 1828 "length mismatch"); 1837 - KUNIT_EXPECT_EQ_MSG(test, 1838 - memcmp(param->plaintext->data, 1839 - buf.head[0].iov_base, buf.len), 0, 1840 - "plaintext mismatch"); 1829 + KUNIT_EXPECT_MEMEQ_MSG(test, 1830 + param->plaintext->data, 1831 + buf.head[0].iov_base, 1832 + buf.len, 1833 + "plaintext mismatch"); 1841 1834 1842 1835 crypto_free_sync_skcipher(cts_tfm); 1843 1836 crypto_free_sync_skcipher(cbc_tfm);
+110 -141
net/sunrpc/cache.c
··· 134 134 return tmp; 135 135 } 136 136 137 + cache_get(new); 137 138 hlist_add_head_rcu(&new->cache_list, head); 138 139 detail->entries++; 139 140 if (detail->nextcheck > new->expiry_time) 140 141 detail->nextcheck = new->expiry_time + 1; 141 - cache_get(new); 142 142 spin_unlock(&detail->hash_lock); 143 143 144 144 if (freeme) ··· 233 233 234 234 spin_lock(&detail->hash_lock); 235 235 cache_entry_update(detail, tmp, new); 236 - hlist_add_head(&tmp->cache_list, &detail->hash_table[hash]); 237 - detail->entries++; 238 236 cache_get(tmp); 237 + hlist_add_head_rcu(&tmp->cache_list, &detail->hash_table[hash]); 238 + detail->entries++; 239 239 cache_fresh_locked(tmp, new->expiry_time, detail); 240 240 cache_fresh_locked(old, 0, detail); 241 241 spin_unlock(&detail->hash_lock); ··· 399 399 void sunrpc_init_cache_detail(struct cache_detail *cd) 400 400 { 401 401 spin_lock_init(&cd->hash_lock); 402 - INIT_LIST_HEAD(&cd->queue); 402 + INIT_LIST_HEAD(&cd->requests); 403 + INIT_LIST_HEAD(&cd->readers); 404 + spin_lock_init(&cd->queue_lock); 405 + init_waitqueue_head(&cd->queue_wait); 406 + cd->next_seqno = 0; 403 407 spin_lock(&cache_list_lock); 404 408 cd->nextcheck = 0; 405 409 cd->entries = 0; ··· 798 794 * On read, you get a full request, or block. 799 795 * On write, an update request is processed. 800 796 * Poll works if anything to read, and always allows write. 801 - * 802 - * Implemented by linked list of requests. Each open file has 803 - * a ->private that also exists in this list. New requests are added 804 - * to the end and may wakeup and preceding readers. 805 - * New readers are added to the head. If, on read, an item is found with 806 - * CACHE_UPCALLING clear, we free it from the list. 807 - * 808 797 */ 809 798 810 - static DEFINE_SPINLOCK(queue_lock); 811 - 812 - struct cache_queue { 813 - struct list_head list; 814 - int reader; /* if 0, then request */ 815 - }; 816 799 struct cache_request { 817 - struct cache_queue q; 800 + struct list_head list; 818 801 struct cache_head *item; 819 - char * buf; 802 + char *buf; 820 803 int len; 821 804 int readers; 805 + u64 seqno; 822 806 }; 823 807 struct cache_reader { 824 - struct cache_queue q; 808 + struct list_head list; 825 809 int offset; /* if non-0, we have a refcnt on next request */ 810 + u64 next_seqno; 826 811 }; 827 812 828 813 static int cache_request(struct cache_detail *detail, ··· 824 831 if (len < 0) 825 832 return -E2BIG; 826 833 return PAGE_SIZE - len; 834 + } 835 + 836 + static struct cache_request * 837 + cache_next_request(struct cache_detail *cd, u64 seqno) 838 + { 839 + struct cache_request *rq; 840 + 841 + list_for_each_entry(rq, &cd->requests, list) 842 + if (rq->seqno >= seqno) 843 + return rq; 844 + return NULL; 827 845 } 828 846 829 847 static ssize_t cache_read(struct file *filp, char __user *buf, size_t count, ··· 851 847 inode_lock(inode); /* protect against multiple concurrent 852 848 * readers on this file */ 853 849 again: 854 - spin_lock(&queue_lock); 850 + spin_lock(&cd->queue_lock); 855 851 /* need to find next request */ 856 - while (rp->q.list.next != &cd->queue && 857 - list_entry(rp->q.list.next, struct cache_queue, list) 858 - ->reader) { 859 - struct list_head *next = rp->q.list.next; 860 - list_move(&rp->q.list, next); 861 - } 862 - if (rp->q.list.next == &cd->queue) { 863 - spin_unlock(&queue_lock); 852 + rq = cache_next_request(cd, rp->next_seqno); 853 + if (!rq) { 854 + spin_unlock(&cd->queue_lock); 864 855 inode_unlock(inode); 865 856 WARN_ON_ONCE(rp->offset); 866 857 return 0; 867 858 } 868 - rq = container_of(rp->q.list.next, struct cache_request, q.list); 869 - WARN_ON_ONCE(rq->q.reader); 870 859 if (rp->offset == 0) 871 860 rq->readers++; 872 - spin_unlock(&queue_lock); 861 + spin_unlock(&cd->queue_lock); 873 862 874 863 if (rq->len == 0) { 875 864 err = cache_request(cd, rq); ··· 873 876 874 877 if (rp->offset == 0 && !test_bit(CACHE_PENDING, &rq->item->flags)) { 875 878 err = -EAGAIN; 876 - spin_lock(&queue_lock); 877 - list_move(&rp->q.list, &rq->q.list); 878 - spin_unlock(&queue_lock); 879 + rp->next_seqno = rq->seqno + 1; 879 880 } else { 880 881 if (rp->offset + count > rq->len) 881 882 count = rq->len - rp->offset; ··· 883 888 rp->offset += count; 884 889 if (rp->offset >= rq->len) { 885 890 rp->offset = 0; 886 - spin_lock(&queue_lock); 887 - list_move(&rp->q.list, &rq->q.list); 888 - spin_unlock(&queue_lock); 891 + rp->next_seqno = rq->seqno + 1; 889 892 } 890 893 err = 0; 891 894 } 892 895 out: 893 896 if (rp->offset == 0) { 894 897 /* need to release rq */ 895 - spin_lock(&queue_lock); 898 + spin_lock(&cd->queue_lock); 896 899 rq->readers--; 897 900 if (rq->readers == 0 && 898 901 !test_bit(CACHE_PENDING, &rq->item->flags)) { 899 - list_del(&rq->q.list); 900 - spin_unlock(&queue_lock); 902 + list_del(&rq->list); 903 + spin_unlock(&cd->queue_lock); 901 904 cache_put(rq->item, cd); 902 905 kfree(rq->buf); 903 906 kfree(rq); 904 907 } else 905 - spin_unlock(&queue_lock); 908 + spin_unlock(&cd->queue_lock); 906 909 } 907 910 if (err == -EAGAIN) 908 911 goto again; ··· 964 971 return ret; 965 972 } 966 973 967 - static DECLARE_WAIT_QUEUE_HEAD(queue_wait); 968 - 969 974 static __poll_t cache_poll(struct file *filp, poll_table *wait, 970 975 struct cache_detail *cd) 971 976 { 972 977 __poll_t mask; 973 978 struct cache_reader *rp = filp->private_data; 974 - struct cache_queue *cq; 975 979 976 - poll_wait(filp, &queue_wait, wait); 980 + poll_wait(filp, &cd->queue_wait, wait); 977 981 978 982 /* alway allow write */ 979 983 mask = EPOLLOUT | EPOLLWRNORM; ··· 978 988 if (!rp) 979 989 return mask; 980 990 981 - spin_lock(&queue_lock); 991 + spin_lock(&cd->queue_lock); 982 992 983 - for (cq= &rp->q; &cq->list != &cd->queue; 984 - cq = list_entry(cq->list.next, struct cache_queue, list)) 985 - if (!cq->reader) { 986 - mask |= EPOLLIN | EPOLLRDNORM; 987 - break; 988 - } 989 - spin_unlock(&queue_lock); 993 + if (cache_next_request(cd, rp->next_seqno)) 994 + mask |= EPOLLIN | EPOLLRDNORM; 995 + spin_unlock(&cd->queue_lock); 990 996 return mask; 991 997 } 992 998 ··· 992 1006 { 993 1007 int len = 0; 994 1008 struct cache_reader *rp = filp->private_data; 995 - struct cache_queue *cq; 1009 + struct cache_request *rq; 996 1010 997 1011 if (cmd != FIONREAD || !rp) 998 1012 return -EINVAL; 999 1013 1000 - spin_lock(&queue_lock); 1014 + spin_lock(&cd->queue_lock); 1001 1015 1002 1016 /* only find the length remaining in current request, 1003 1017 * or the length of the next request 1004 1018 */ 1005 - for (cq= &rp->q; &cq->list != &cd->queue; 1006 - cq = list_entry(cq->list.next, struct cache_queue, list)) 1007 - if (!cq->reader) { 1008 - struct cache_request *cr = 1009 - container_of(cq, struct cache_request, q); 1010 - len = cr->len - rp->offset; 1011 - break; 1012 - } 1013 - spin_unlock(&queue_lock); 1019 + rq = cache_next_request(cd, rp->next_seqno); 1020 + if (rq) 1021 + len = rq->len - rp->offset; 1022 + spin_unlock(&cd->queue_lock); 1014 1023 1015 1024 return put_user(len, (int __user *)arg); 1016 1025 } ··· 1025 1044 return -ENOMEM; 1026 1045 } 1027 1046 rp->offset = 0; 1028 - rp->q.reader = 1; 1047 + rp->next_seqno = 0; 1029 1048 1030 - spin_lock(&queue_lock); 1031 - list_add(&rp->q.list, &cd->queue); 1032 - spin_unlock(&queue_lock); 1049 + spin_lock(&cd->queue_lock); 1050 + list_add(&rp->list, &cd->readers); 1051 + spin_unlock(&cd->queue_lock); 1033 1052 } 1034 1053 if (filp->f_mode & FMODE_WRITE) 1035 1054 atomic_inc(&cd->writers); ··· 1045 1064 if (rp) { 1046 1065 struct cache_request *rq = NULL; 1047 1066 1048 - spin_lock(&queue_lock); 1067 + spin_lock(&cd->queue_lock); 1049 1068 if (rp->offset) { 1050 - struct cache_queue *cq; 1051 - for (cq = &rp->q; &cq->list != &cd->queue; 1052 - cq = list_entry(cq->list.next, 1053 - struct cache_queue, list)) 1054 - if (!cq->reader) { 1055 - struct cache_request *cr = 1056 - container_of(cq, 1057 - struct cache_request, q); 1058 - cr->readers--; 1059 - if (cr->readers == 0 && 1060 - !test_bit(CACHE_PENDING, 1061 - &cr->item->flags)) { 1062 - list_del(&cr->q.list); 1063 - rq = cr; 1064 - } 1065 - break; 1069 + struct cache_request *cr; 1070 + 1071 + cr = cache_next_request(cd, rp->next_seqno); 1072 + if (cr) { 1073 + cr->readers--; 1074 + if (cr->readers == 0 && 1075 + !test_bit(CACHE_PENDING, 1076 + &cr->item->flags)) { 1077 + list_del(&cr->list); 1078 + rq = cr; 1066 1079 } 1080 + } 1067 1081 rp->offset = 0; 1068 1082 } 1069 - list_del(&rp->q.list); 1070 - spin_unlock(&queue_lock); 1083 + list_del(&rp->list); 1084 + spin_unlock(&cd->queue_lock); 1071 1085 1072 1086 if (rq) { 1073 1087 cache_put(rq->item, cd); ··· 1085 1109 1086 1110 static void cache_dequeue(struct cache_detail *detail, struct cache_head *ch) 1087 1111 { 1088 - struct cache_queue *cq, *tmp; 1089 - struct cache_request *cr; 1112 + struct cache_request *cr, *tmp; 1090 1113 LIST_HEAD(dequeued); 1091 1114 1092 - spin_lock(&queue_lock); 1093 - list_for_each_entry_safe(cq, tmp, &detail->queue, list) 1094 - if (!cq->reader) { 1095 - cr = container_of(cq, struct cache_request, q); 1096 - if (cr->item != ch) 1097 - continue; 1098 - if (test_bit(CACHE_PENDING, &ch->flags)) 1099 - /* Lost a race and it is pending again */ 1100 - break; 1101 - if (cr->readers != 0) 1102 - continue; 1103 - list_move(&cr->q.list, &dequeued); 1104 - } 1105 - spin_unlock(&queue_lock); 1115 + spin_lock(&detail->queue_lock); 1116 + list_for_each_entry_safe(cr, tmp, &detail->requests, list) { 1117 + if (cr->item != ch) 1118 + continue; 1119 + if (test_bit(CACHE_PENDING, &ch->flags)) 1120 + /* Lost a race and it is pending again */ 1121 + break; 1122 + if (cr->readers != 0) 1123 + continue; 1124 + list_move(&cr->list, &dequeued); 1125 + } 1126 + spin_unlock(&detail->queue_lock); 1106 1127 while (!list_empty(&dequeued)) { 1107 - cr = list_entry(dequeued.next, struct cache_request, q.list); 1108 - list_del(&cr->q.list); 1128 + cr = list_entry(dequeued.next, struct cache_request, list); 1129 + list_del(&cr->list); 1109 1130 cache_put(cr->item, detail); 1110 1131 kfree(cr->buf); 1111 1132 kfree(cr); ··· 1220 1247 return -EAGAIN; 1221 1248 } 1222 1249 1223 - crq->q.reader = 0; 1224 1250 crq->buf = buf; 1225 1251 crq->len = 0; 1226 1252 crq->readers = 0; 1227 - spin_lock(&queue_lock); 1253 + spin_lock(&detail->queue_lock); 1228 1254 if (test_bit(CACHE_PENDING, &h->flags)) { 1229 1255 crq->item = cache_get(h); 1230 - list_add_tail(&crq->q.list, &detail->queue); 1256 + crq->seqno = detail->next_seqno++; 1257 + list_add_tail(&crq->list, &detail->requests); 1231 1258 trace_cache_entry_upcall(detail, h); 1232 1259 } else 1233 1260 /* Lost a race, no longer PENDING, so don't enqueue */ 1234 1261 ret = -EAGAIN; 1235 - spin_unlock(&queue_lock); 1236 - wake_up(&queue_wait); 1262 + spin_unlock(&detail->queue_lock); 1263 + wake_up(&detail->queue_wait); 1237 1264 if (ret == -EAGAIN) { 1238 1265 kfree(buf); 1239 1266 kfree(crq); ··· 1351 1378 hlist_for_each_entry_rcu(ch, &cd->hash_table[hash], cache_list) 1352 1379 if (!entry--) 1353 1380 return ch; 1354 - n &= ~((1LL<<32) - 1); 1355 - do { 1356 - hash++; 1357 - n += 1LL<<32; 1358 - } while(hash < cd->hash_size && 1359 - hlist_empty(&cd->hash_table[hash])); 1360 - if (hash >= cd->hash_size) 1361 - return NULL; 1362 - *pos = n+1; 1363 - return hlist_entry_safe(rcu_dereference_raw( 1381 + ch = NULL; 1382 + while (!ch && ++hash < cd->hash_size) 1383 + ch = hlist_entry_safe(rcu_dereference( 1364 1384 hlist_first_rcu(&cd->hash_table[hash])), 1365 1385 struct cache_head, cache_list); 1386 + 1387 + *pos = ((long long)hash << 32) + 1; 1388 + return ch; 1366 1389 } 1367 1390 1368 1391 static void *cache_seq_next(struct seq_file *m, void *p, loff_t *pos) ··· 1367 1398 int hash = (*pos >> 32); 1368 1399 struct cache_detail *cd = m->private; 1369 1400 1370 - if (p == SEQ_START_TOKEN) 1401 + if (p == SEQ_START_TOKEN) { 1371 1402 hash = 0; 1372 - else if (ch->cache_list.next == NULL) { 1373 - hash++; 1374 - *pos += 1LL<<32; 1375 - } else { 1376 - ++*pos; 1377 - return hlist_entry_safe(rcu_dereference_raw( 1403 + ch = NULL; 1404 + } 1405 + while (hash < cd->hash_size) { 1406 + if (ch) 1407 + ch = hlist_entry_safe( 1408 + rcu_dereference( 1378 1409 hlist_next_rcu(&ch->cache_list)), 1379 - struct cache_head, cache_list); 1380 - } 1381 - *pos &= ~((1LL<<32) - 1); 1382 - while (hash < cd->hash_size && 1383 - hlist_empty(&cd->hash_table[hash])) { 1384 - hash++; 1385 - *pos += 1LL<<32; 1386 - } 1387 - if (hash >= cd->hash_size) 1388 - return NULL; 1389 - ++*pos; 1390 - return hlist_entry_safe(rcu_dereference_raw( 1391 - hlist_first_rcu(&cd->hash_table[hash])), 1392 1410 struct cache_head, cache_list); 1411 + else 1412 + ch = hlist_entry_safe( 1413 + rcu_dereference( 1414 + hlist_first_rcu(&cd->hash_table[hash])), 1415 + struct cache_head, cache_list); 1416 + if (ch) { 1417 + ++*pos; 1418 + return ch; 1419 + } 1420 + hash++; 1421 + *pos = (long long)hash << 32; 1422 + } 1423 + return NULL; 1393 1424 } 1394 1425 1395 1426 void *cache_seq_start_rcu(struct seq_file *m, loff_t *pos)
+45 -21
net/sunrpc/svc.c
··· 638 638 { 639 639 rqstp->rq_maxpages = svc_serv_maxpages(serv); 640 640 641 - /* rq_pages' last entry is NULL for historical reasons. */ 641 + /* +1 for a NULL sentinel readable by nfsd_splice_actor() */ 642 642 rqstp->rq_pages = kcalloc_node(rqstp->rq_maxpages + 1, 643 643 sizeof(struct page *), 644 644 GFP_KERNEL, node); 645 645 if (!rqstp->rq_pages) 646 646 return false; 647 647 648 + /* +1 for a NULL sentinel at rq_page_end (see svc_rqst_replace_page) */ 649 + rqstp->rq_respages = kcalloc_node(rqstp->rq_maxpages + 1, 650 + sizeof(struct page *), 651 + GFP_KERNEL, node); 652 + if (!rqstp->rq_respages) { 653 + kfree(rqstp->rq_pages); 654 + rqstp->rq_pages = NULL; 655 + return false; 656 + } 657 + 658 + rqstp->rq_pages_nfree = rqstp->rq_maxpages; 659 + rqstp->rq_next_page = rqstp->rq_respages + rqstp->rq_maxpages; 648 660 return true; 649 661 } 650 662 ··· 668 656 { 669 657 unsigned long i; 670 658 671 - for (i = 0; i < rqstp->rq_maxpages; i++) 672 - if (rqstp->rq_pages[i]) 673 - put_page(rqstp->rq_pages[i]); 674 - kfree(rqstp->rq_pages); 659 + if (rqstp->rq_pages) { 660 + for (i = 0; i < rqstp->rq_maxpages; i++) 661 + if (rqstp->rq_pages[i]) 662 + put_page(rqstp->rq_pages[i]); 663 + kfree(rqstp->rq_pages); 664 + } 665 + 666 + if (rqstp->rq_respages) { 667 + for (i = 0; i < rqstp->rq_maxpages; i++) 668 + if (rqstp->rq_respages[i]) 669 + put_page(rqstp->rq_respages[i]); 670 + kfree(rqstp->rq_respages); 671 + } 675 672 } 676 673 677 674 static void ··· 955 934 EXPORT_SYMBOL_GPL(svc_set_num_threads); 956 935 957 936 /** 958 - * svc_rqst_replace_page - Replace one page in rq_pages[] 937 + * svc_rqst_replace_page - Replace one page in rq_respages[] 959 938 * @rqstp: svc_rqst with pages to replace 960 939 * @page: replacement page 961 940 * 962 - * When replacing a page in rq_pages, batch the release of the 941 + * When replacing a page in rq_respages, batch the release of the 963 942 * replaced pages to avoid hammering the page allocator. 964 943 * 965 944 * Return values: ··· 968 947 */ 969 948 bool svc_rqst_replace_page(struct svc_rqst *rqstp, struct page *page) 970 949 { 971 - struct page **begin = rqstp->rq_pages; 972 - struct page **end = &rqstp->rq_pages[rqstp->rq_maxpages]; 950 + struct page **begin = rqstp->rq_respages; 951 + struct page **end = rqstp->rq_page_end; 973 952 974 953 if (unlikely(rqstp->rq_next_page < begin || rqstp->rq_next_page > end)) { 975 954 trace_svc_replace_page_err(rqstp); 976 955 return false; 977 956 } 978 957 979 - if (*rqstp->rq_next_page) { 980 - if (!folio_batch_add(&rqstp->rq_fbatch, 981 - page_folio(*rqstp->rq_next_page))) 982 - __folio_batch_release(&rqstp->rq_fbatch); 983 - } 958 + if (*rqstp->rq_next_page) 959 + svc_rqst_page_release(rqstp, *rqstp->rq_next_page); 984 960 985 961 get_page(page); 986 962 *(rqstp->rq_next_page++) = page; ··· 989 971 * svc_rqst_release_pages - Release Reply buffer pages 990 972 * @rqstp: RPC transaction context 991 973 * 992 - * Release response pages that might still be in flight after 993 - * svc_send, and any spliced filesystem-owned pages. 974 + * Release response pages in the range [rq_respages, rq_next_page). 975 + * NULL entries in this range are skipped, allowing transports to 976 + * transfer pages to a send context before this function runs. 994 977 */ 995 978 void svc_rqst_release_pages(struct svc_rqst *rqstp) 996 979 { 997 - int i, count = rqstp->rq_next_page - rqstp->rq_respages; 980 + struct page **pp; 998 981 999 - if (count) { 1000 - release_pages(rqstp->rq_respages, count); 1001 - for (i = 0; i < count; i++) 1002 - rqstp->rq_respages[i] = NULL; 982 + for (pp = rqstp->rq_respages; pp < rqstp->rq_next_page; pp++) { 983 + if (*pp) { 984 + if (!folio_batch_add(&rqstp->rq_fbatch, 985 + page_folio(*pp))) 986 + __folio_batch_release(&rqstp->rq_fbatch); 987 + *pp = NULL; 988 + } 1003 989 } 990 + if (rqstp->rq_fbatch.nr) 991 + __folio_batch_release(&rqstp->rq_fbatch); 1004 992 } 1005 993 1006 994 /**
+37 -10
net/sunrpc/svc_xprt.c
··· 650 650 } 651 651 } 652 652 653 - static bool svc_alloc_arg(struct svc_rqst *rqstp) 653 + static bool svc_fill_pages(struct svc_rqst *rqstp, struct page **pages, 654 + unsigned long npages) 654 655 { 655 - struct xdr_buf *arg = &rqstp->rq_arg; 656 - unsigned long pages, filled, ret; 656 + unsigned long filled, ret; 657 657 658 - pages = rqstp->rq_maxpages; 659 - for (filled = 0; filled < pages; filled = ret) { 660 - ret = alloc_pages_bulk(GFP_KERNEL, pages, rqstp->rq_pages); 658 + for (filled = 0; filled < npages; filled = ret) { 659 + ret = alloc_pages_bulk(GFP_KERNEL, npages, pages); 661 660 if (ret > filled) 662 661 /* Made progress, don't sleep yet */ 663 662 continue; ··· 666 667 set_current_state(TASK_RUNNING); 667 668 return false; 668 669 } 669 - trace_svc_alloc_arg_err(pages, ret); 670 + trace_svc_alloc_arg_err(npages, ret); 670 671 memalloc_retry_wait(GFP_KERNEL); 671 672 } 672 - rqstp->rq_page_end = &rqstp->rq_pages[pages]; 673 - rqstp->rq_pages[pages] = NULL; /* this might be seen in nfsd_splice_actor() */ 673 + return true; 674 + } 675 + 676 + static bool svc_alloc_arg(struct svc_rqst *rqstp) 677 + { 678 + struct xdr_buf *arg = &rqstp->rq_arg; 679 + unsigned long pages, nfree; 680 + 681 + pages = rqstp->rq_maxpages; 682 + 683 + nfree = rqstp->rq_pages_nfree; 684 + if (nfree) { 685 + if (!svc_fill_pages(rqstp, rqstp->rq_pages, nfree)) 686 + return false; 687 + rqstp->rq_pages_nfree = 0; 688 + } 689 + 690 + if (WARN_ON_ONCE(rqstp->rq_next_page < rqstp->rq_respages)) 691 + return false; 692 + nfree = rqstp->rq_next_page - rqstp->rq_respages; 693 + if (nfree) { 694 + if (!svc_fill_pages(rqstp, rqstp->rq_respages, nfree)) 695 + return false; 696 + } 697 + 698 + rqstp->rq_next_page = rqstp->rq_respages; 699 + rqstp->rq_page_end = &rqstp->rq_respages[pages]; 700 + /* svc_rqst_replace_page() dereferences *rq_next_page even 701 + * at rq_page_end; NULL prevents releasing a garbage page. 702 + */ 703 + rqstp->rq_page_end[0] = NULL; 674 704 675 705 /* Make arg->head point to first page and arg->pages point to rest */ 676 706 arg->head[0].iov_base = page_address(rqstp->rq_pages[0]); ··· 1305 1277 rqstp->rq_addrlen = dr->addrlen; 1306 1278 /* Save off transport header len in case we get deferred again */ 1307 1279 rqstp->rq_daddr = dr->daddr; 1308 - rqstp->rq_respages = rqstp->rq_pages; 1309 1280 rqstp->rq_xprt_ctxt = dr->xprt_ctxt; 1310 1281 1311 1282 dr->xprt_ctxt = NULL;
+2 -7
net/sunrpc/svcsock.c
··· 351 351 352 352 for (i = 0, t = 0; t < buflen; i++, t += PAGE_SIZE) 353 353 bvec_set_page(&bvec[i], rqstp->rq_pages[i], PAGE_SIZE, 0); 354 - rqstp->rq_respages = &rqstp->rq_pages[i]; 355 - rqstp->rq_next_page = rqstp->rq_respages + 1; 356 354 357 355 iov_iter_bvec(&msg.msg_iter, ITER_DEST, bvec, i, buflen); 358 356 if (seek) { ··· 675 677 if (len <= rqstp->rq_arg.head[0].iov_len) { 676 678 rqstp->rq_arg.head[0].iov_len = len; 677 679 rqstp->rq_arg.page_len = 0; 678 - rqstp->rq_respages = rqstp->rq_pages+1; 679 680 } else { 680 681 rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len; 681 - rqstp->rq_respages = rqstp->rq_pages + 1 + 682 - DIV_ROUND_UP(rqstp->rq_arg.page_len, PAGE_SIZE); 683 682 } 684 - rqstp->rq_next_page = rqstp->rq_respages+1; 685 683 686 684 if (serv->sv_stats) 687 685 serv->sv_stats->netudpcnt++; ··· 988 994 npages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; 989 995 for (i = 0; i < npages; i++) { 990 996 if (rqstp->rq_pages[i] != NULL) 991 - put_page(rqstp->rq_pages[i]); 997 + svc_rqst_page_release(rqstp, rqstp->rq_pages[i]); 992 998 BUG_ON(svsk->sk_pages[i] == NULL); 993 999 rqstp->rq_pages[i] = svsk->sk_pages[i]; 994 1000 svsk->sk_pages[i] = NULL; ··· 1009 1015 svsk->sk_pages[i] = rqstp->rq_pages[i]; 1010 1016 rqstp->rq_pages[i] = NULL; 1011 1017 } 1018 + rqstp->rq_pages_nfree = npages; 1012 1019 } 1013 1020 1014 1021 static void svc_tcp_clear_pages(struct svc_sock *svsk)
+11 -17
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
··· 118 118 static struct svc_rdma_recv_ctxt * 119 119 svc_rdma_recv_ctxt_alloc(struct svcxprt_rdma *rdma) 120 120 { 121 - int node = ibdev_to_node(rdma->sc_cm_id->device); 121 + struct ib_device *device = rdma->sc_cm_id->device; 122 + int node = ibdev_to_node(device); 122 123 struct svc_rdma_recv_ctxt *ctxt; 123 124 unsigned long pages; 124 125 dma_addr_t addr; ··· 134 133 buffer = kmalloc_node(rdma->sc_max_req_size, GFP_KERNEL, node); 135 134 if (!buffer) 136 135 goto fail1; 137 - addr = ib_dma_map_single(rdma->sc_pd->device, buffer, 138 - rdma->sc_max_req_size, DMA_FROM_DEVICE); 139 - if (ib_dma_mapping_error(rdma->sc_pd->device, addr)) 136 + addr = ib_dma_map_single(device, buffer, rdma->sc_max_req_size, 137 + DMA_FROM_DEVICE); 138 + if (ib_dma_mapping_error(device, addr)) 140 139 goto fail2; 141 140 142 141 svc_rdma_recv_cid_init(rdma, &ctxt->rc_cid); ··· 168 167 static void svc_rdma_recv_ctxt_destroy(struct svcxprt_rdma *rdma, 169 168 struct svc_rdma_recv_ctxt *ctxt) 170 169 { 171 - ib_dma_unmap_single(rdma->sc_pd->device, ctxt->rc_recv_sge.addr, 170 + ib_dma_unmap_single(rdma->sc_cm_id->device, ctxt->rc_recv_sge.addr, 172 171 ctxt->rc_recv_sge.length, DMA_FROM_DEVICE); 173 172 kfree(ctxt->rc_recv_buf); 174 173 kfree(ctxt); ··· 862 861 unsigned int i; 863 862 864 863 /* Transfer the Read chunk pages into @rqstp.rq_pages, replacing 865 - * the rq_pages that were already allocated for this rqstp. 864 + * the receive buffer pages already allocated for this rqstp. 866 865 */ 867 - release_pages(rqstp->rq_respages, ctxt->rc_page_count); 866 + release_pages(rqstp->rq_pages, ctxt->rc_page_count); 868 867 for (i = 0; i < ctxt->rc_page_count; i++) 869 868 rqstp->rq_pages[i] = ctxt->rc_pages[i]; 870 - 871 - /* Update @rqstp's result send buffer to start after the 872 - * last page in the RDMA Read payload. 873 - */ 874 - rqstp->rq_respages = &rqstp->rq_pages[ctxt->rc_page_count]; 875 - rqstp->rq_next_page = rqstp->rq_respages + 1; 876 869 877 870 /* Prevent svc_rdma_recv_ctxt_put() from releasing the 878 871 * pages in ctxt::rc_pages a second time. ··· 926 931 struct svc_rdma_recv_ctxt *ctxt; 927 932 int ret; 928 933 929 - /* Prevent svc_xprt_release() from releasing pages in rq_pages 930 - * when returning 0 or an error. 934 + /* Precaution: a zero page count on error return causes 935 + * svc_rqst_release_pages() to release nothing. 931 936 */ 932 - rqstp->rq_respages = rqstp->rq_pages; 933 937 rqstp->rq_next_page = rqstp->rq_respages; 934 938 935 939 rqstp->rq_xprt_ctxt = NULL; ··· 956 962 return 0; 957 963 958 964 percpu_counter_inc(&svcrdma_stat_recv); 959 - ib_dma_sync_single_for_cpu(rdma_xprt->sc_pd->device, 965 + ib_dma_sync_single_for_cpu(rdma_xprt->sc_cm_id->device, 960 966 ctxt->rc_recv_sge.addr, ctxt->rc_byte_len, 961 967 DMA_FROM_DEVICE); 962 968 svc_rdma_build_arg_xdr(rqstp, ctxt);
+310 -64
net/sunrpc/xprtrdma/svc_rdma_rw.c
··· 252 252 } 253 253 254 254 /** 255 + * svc_rdma_write_chunk_release - Release Write chunk I/O resources 256 + * @rdma: controlling transport 257 + * @ctxt: Send context that is being released 258 + * 259 + * Write chunk resources remain live until Send completion because 260 + * Write WRs are chained to the Send WR. This function releases all 261 + * write_info structures accumulated on @ctxt->sc_write_info_list. 262 + */ 263 + void svc_rdma_write_chunk_release(struct svcxprt_rdma *rdma, 264 + struct svc_rdma_send_ctxt *ctxt) 265 + { 266 + struct svc_rdma_write_info *info; 267 + 268 + while (!list_empty(&ctxt->sc_write_info_list)) { 269 + info = list_first_entry(&ctxt->sc_write_info_list, 270 + struct svc_rdma_write_info, wi_list); 271 + list_del(&info->wi_list); 272 + svc_rdma_write_info_free(info); 273 + } 274 + } 275 + 276 + /** 255 277 * svc_rdma_reply_chunk_release - Release Reply chunk I/O resources 256 278 * @rdma: controlling transport 257 279 * @ctxt: Send context that is being released ··· 329 307 struct ib_cqe *cqe = wc->wr_cqe; 330 308 struct svc_rdma_chunk_ctxt *cc = 331 309 container_of(cqe, struct svc_rdma_chunk_ctxt, cc_cqe); 332 - struct svc_rdma_write_info *info = 333 - container_of(cc, struct svc_rdma_write_info, wi_cc); 334 310 335 311 switch (wc->status) { 336 312 case IB_WC_SUCCESS: 337 313 trace_svcrdma_wc_write(&cc->cc_cid); 338 - break; 314 + return; 339 315 case IB_WC_WR_FLUSH_ERR: 340 316 trace_svcrdma_wc_write_flush(wc, &cc->cc_cid); 341 317 break; ··· 341 321 trace_svcrdma_wc_write_err(wc, &cc->cc_cid); 342 322 } 343 323 344 - svc_rdma_wake_send_waiters(rdma, cc->cc_sqecount); 345 - 346 - if (unlikely(wc->status != IB_WC_SUCCESS)) 347 - svc_xprt_deferred_close(&rdma->sc_xprt); 348 - 349 - svc_rdma_write_info_free(info); 324 + /* The RDMA Write has flushed, so the client won't get 325 + * some of the outgoing RPC message. Signal the loss 326 + * to the client by closing the connection. 327 + */ 328 + svc_xprt_deferred_close(&rdma->sc_xprt); 350 329 } 351 330 352 331 /** ··· 424 405 cqe = NULL; 425 406 } 426 407 427 - do { 428 - if (atomic_sub_return(cc->cc_sqecount, 429 - &rdma->sc_sq_avail) > 0) { 430 - cc->cc_posttime = ktime_get(); 431 - ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr); 432 - if (ret) 433 - break; 434 - return 0; 435 - } 408 + ret = svc_rdma_sq_wait(rdma, &cc->cc_cid, cc->cc_sqecount); 409 + if (ret < 0) 410 + return ret; 436 411 437 - percpu_counter_inc(&svcrdma_stat_sq_starve); 438 - trace_svcrdma_sq_full(rdma, &cc->cc_cid); 439 - atomic_add(cc->cc_sqecount, &rdma->sc_sq_avail); 440 - wait_event(rdma->sc_send_wait, 441 - atomic_read(&rdma->sc_sq_avail) > cc->cc_sqecount); 442 - trace_svcrdma_sq_retry(rdma, &cc->cc_cid); 443 - } while (1); 444 - 445 - trace_svcrdma_sq_post_err(rdma, &cc->cc_cid, ret); 446 - svc_xprt_deferred_close(&rdma->sc_xprt); 447 - 448 - /* If even one was posted, there will be a completion. */ 449 - if (bad_wr != first_wr) 450 - return 0; 451 - 452 - atomic_add(cc->cc_sqecount, &rdma->sc_sq_avail); 453 - wake_up(&rdma->sc_send_wait); 454 - return -ENOTCONN; 412 + cc->cc_posttime = ktime_get(); 413 + ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr); 414 + if (ret) 415 + return svc_rdma_post_send_err(rdma, &cc->cc_cid, bad_wr, 416 + first_wr, cc->cc_sqecount, 417 + ret); 418 + return 0; 455 419 } 456 420 457 421 /* Build a bvec that covers one kvec in an xdr_buf. ··· 619 617 return xdr->len; 620 618 } 621 619 622 - static int svc_rdma_send_write_chunk(struct svcxprt_rdma *rdma, 623 - const struct svc_rdma_chunk *chunk, 624 - const struct xdr_buf *xdr) 620 + /* Link chunk WRs onto @sctxt's WR chain. Completion is requested 621 + * for the tail WR, which is posted first. 622 + */ 623 + static void svc_rdma_cc_link_wrs(struct svcxprt_rdma *rdma, 624 + struct svc_rdma_send_ctxt *sctxt, 625 + struct svc_rdma_chunk_ctxt *cc) 626 + { 627 + struct ib_send_wr *first_wr; 628 + struct list_head *pos; 629 + struct ib_cqe *cqe; 630 + 631 + first_wr = sctxt->sc_wr_chain; 632 + cqe = &cc->cc_cqe; 633 + list_for_each(pos, &cc->cc_rwctxts) { 634 + struct svc_rdma_rw_ctxt *rwc; 635 + 636 + rwc = list_entry(pos, struct svc_rdma_rw_ctxt, rw_list); 637 + first_wr = rdma_rw_ctx_wrs(&rwc->rw_ctx, rdma->sc_qp, 638 + rdma->sc_port_num, cqe, first_wr); 639 + cqe = NULL; 640 + } 641 + sctxt->sc_wr_chain = first_wr; 642 + sctxt->sc_sqecount += cc->cc_sqecount; 643 + } 644 + 645 + /* Link Write WRs for @chunk onto @sctxt's WR chain. 646 + */ 647 + static int svc_rdma_prepare_write_chunk(struct svcxprt_rdma *rdma, 648 + struct svc_rdma_send_ctxt *sctxt, 649 + const struct svc_rdma_chunk *chunk, 650 + const struct xdr_buf *xdr) 625 651 { 626 652 struct svc_rdma_write_info *info; 627 653 struct svc_rdma_chunk_ctxt *cc; ··· 669 639 if (ret != payload.len) 670 640 goto out_err; 671 641 672 - trace_svcrdma_post_write_chunk(&cc->cc_cid, cc->cc_sqecount); 673 - ret = svc_rdma_post_chunk_ctxt(rdma, cc); 674 - if (ret < 0) 642 + ret = -EINVAL; 643 + if (unlikely(sctxt->sc_sqecount + cc->cc_sqecount > rdma->sc_sq_depth)) 675 644 goto out_err; 645 + 646 + svc_rdma_cc_link_wrs(rdma, sctxt, cc); 647 + list_add(&info->wi_list, &sctxt->sc_write_info_list); 648 + 649 + trace_svcrdma_post_write_chunk(&cc->cc_cid, cc->cc_sqecount); 676 650 return 0; 677 651 678 652 out_err: ··· 685 651 } 686 652 687 653 /** 688 - * svc_rdma_send_write_list - Send all chunks on the Write list 654 + * svc_rdma_prepare_write_list - Construct WR chain for sending Write list 689 655 * @rdma: controlling RDMA transport 690 656 * @rctxt: Write list provisioned by the client 657 + * @sctxt: Send WR resources 691 658 * @xdr: xdr_buf containing an RPC Reply message 692 659 * 693 - * Returns zero on success, or a negative errno if one or more 694 - * Write chunks could not be sent. 660 + * Returns zero on success, or a negative errno if WR chain 661 + * construction fails for one or more Write chunks. 695 662 */ 696 - int svc_rdma_send_write_list(struct svcxprt_rdma *rdma, 697 - const struct svc_rdma_recv_ctxt *rctxt, 698 - const struct xdr_buf *xdr) 663 + int svc_rdma_prepare_write_list(struct svcxprt_rdma *rdma, 664 + const struct svc_rdma_recv_ctxt *rctxt, 665 + struct svc_rdma_send_ctxt *sctxt, 666 + const struct xdr_buf *xdr) 699 667 { 700 668 struct svc_rdma_chunk *chunk; 701 669 int ret; ··· 705 669 pcl_for_each_chunk(chunk, &rctxt->rc_write_pcl) { 706 670 if (!chunk->ch_payload_length) 707 671 break; 708 - ret = svc_rdma_send_write_chunk(rdma, chunk, xdr); 672 + ret = svc_rdma_prepare_write_chunk(rdma, sctxt, chunk, xdr); 709 673 if (ret < 0) 710 674 return ret; 711 675 } ··· 735 699 { 736 700 struct svc_rdma_write_info *info = &sctxt->sc_reply_info; 737 701 struct svc_rdma_chunk_ctxt *cc = &info->wi_cc; 738 - struct ib_send_wr *first_wr; 739 - struct list_head *pos; 740 - struct ib_cqe *cqe; 741 702 int ret; 742 703 743 704 info->wi_rdma = rdma; ··· 748 715 if (ret < 0) 749 716 return ret; 750 717 751 - first_wr = sctxt->sc_wr_chain; 752 - cqe = &cc->cc_cqe; 753 - list_for_each(pos, &cc->cc_rwctxts) { 754 - struct svc_rdma_rw_ctxt *rwc; 755 - 756 - rwc = list_entry(pos, struct svc_rdma_rw_ctxt, rw_list); 757 - first_wr = rdma_rw_ctx_wrs(&rwc->rw_ctx, rdma->sc_qp, 758 - rdma->sc_port_num, cqe, first_wr); 759 - cqe = NULL; 760 - } 761 - sctxt->sc_wr_chain = first_wr; 762 - sctxt->sc_sqecount += cc->cc_sqecount; 718 + svc_rdma_cc_link_wrs(rdma, sctxt, cc); 763 719 764 720 trace_svcrdma_post_reply_chunk(&cc->cc_cid, cc->cc_sqecount); 765 721 return xdr->len; 722 + } 723 + 724 + /* 725 + * Cap contiguous RDMA Read sink allocations at order-4. 726 + * Higher orders risk allocation failure under 727 + * __GFP_NORETRY, which would negate the benefit of the 728 + * contiguous fast path. 729 + */ 730 + #define SVC_RDMA_CONTIG_MAX_ORDER 4 731 + 732 + /** 733 + * svc_rdma_alloc_read_pages - Allocate physically contiguous pages 734 + * @nr_pages: number of pages needed 735 + * @order: on success, set to the allocation order 736 + * 737 + * Attempts a higher-order allocation, falling back to smaller orders. 738 + * The returned pages are split immediately so each sub-page has its 739 + * own refcount and can be freed independently. 740 + * 741 + * Returns a pointer to the first page on success, or NULL if even 742 + * order-1 allocation fails. 743 + */ 744 + static struct page * 745 + svc_rdma_alloc_read_pages(unsigned int nr_pages, unsigned int *order) 746 + { 747 + unsigned int o; 748 + struct page *page; 749 + 750 + o = min(get_order(nr_pages << PAGE_SHIFT), 751 + SVC_RDMA_CONTIG_MAX_ORDER); 752 + 753 + while (o >= 1) { 754 + page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN, 755 + o); 756 + if (page) { 757 + split_page(page, o); 758 + *order = o; 759 + return page; 760 + } 761 + o--; 762 + } 763 + return NULL; 764 + } 765 + 766 + /* 767 + * svc_rdma_fill_contig_bvec - Replace rq_pages with a contiguous allocation 768 + * @rqstp: RPC transaction context 769 + * @head: context for ongoing I/O 770 + * @bv: bvec entry to fill 771 + * @pages_left: number of data pages remaining in the segment 772 + * @len_left: bytes remaining in the segment 773 + * 774 + * On success, fills @bv with a bvec spanning the contiguous range and 775 + * advances rc_curpage/rc_page_count. Returns the byte length covered, 776 + * or zero if the allocation failed or would overrun rq_maxpages. 777 + */ 778 + static unsigned int 779 + svc_rdma_fill_contig_bvec(struct svc_rqst *rqstp, 780 + struct svc_rdma_recv_ctxt *head, 781 + struct bio_vec *bv, unsigned int pages_left, 782 + unsigned int len_left) 783 + { 784 + unsigned int order, npages, chunk_pages, chunk_len, i; 785 + struct page *page; 786 + 787 + page = svc_rdma_alloc_read_pages(pages_left, &order); 788 + if (!page) 789 + return 0; 790 + npages = 1 << order; 791 + 792 + if (head->rc_curpage + npages > rqstp->rq_maxpages) { 793 + for (i = 0; i < npages; i++) 794 + __free_page(page + i); 795 + return 0; 796 + } 797 + 798 + /* 799 + * Replace rq_pages[] entries with pages from the contiguous 800 + * allocation. If npages exceeds chunk_pages, the extra pages 801 + * stay in rq_pages[] for later reuse or normal rqst teardown. 802 + */ 803 + for (i = 0; i < npages; i++) { 804 + svc_rqst_page_release(rqstp, 805 + rqstp->rq_pages[head->rc_curpage + i]); 806 + rqstp->rq_pages[head->rc_curpage + i] = page + i; 807 + } 808 + 809 + chunk_pages = min(npages, pages_left); 810 + chunk_len = min_t(unsigned int, chunk_pages << PAGE_SHIFT, len_left); 811 + bvec_set_page(bv, page, chunk_len, 0); 812 + head->rc_page_count += chunk_pages; 813 + head->rc_curpage += chunk_pages; 814 + return chunk_len; 815 + } 816 + 817 + /* 818 + * svc_rdma_fill_page_bvec - Add a single rq_page to the bvec array 819 + * @head: context for ongoing I/O 820 + * @ctxt: R/W context whose bvec array is being filled 821 + * @cur: page to add 822 + * @bvec_idx: pointer to current bvec index, not advanced on merge 823 + * @len_left: bytes remaining in the segment 824 + * 825 + * If @cur is physically contiguous with the preceding bvec, it is 826 + * merged by extending that bvec's length. Otherwise a new bvec 827 + * entry is created. Returns the byte length covered. 828 + */ 829 + static unsigned int 830 + svc_rdma_fill_page_bvec(struct svc_rdma_recv_ctxt *head, 831 + struct svc_rdma_rw_ctxt *ctxt, struct page *cur, 832 + unsigned int *bvec_idx, unsigned int len_left) 833 + { 834 + unsigned int chunk_len = min_t(unsigned int, PAGE_SIZE, len_left); 835 + 836 + head->rc_page_count++; 837 + head->rc_curpage++; 838 + 839 + if (*bvec_idx > 0) { 840 + struct bio_vec *prev = &ctxt->rw_bvec[*bvec_idx - 1]; 841 + 842 + if (page_to_phys(prev->bv_page) + prev->bv_offset + 843 + prev->bv_len == page_to_phys(cur)) { 844 + prev->bv_len += chunk_len; 845 + return chunk_len; 846 + } 847 + } 848 + 849 + bvec_set_page(&ctxt->rw_bvec[*bvec_idx], cur, chunk_len, 0); 850 + (*bvec_idx)++; 851 + return chunk_len; 852 + } 853 + 854 + /** 855 + * svc_rdma_build_read_segment_contig - Build RDMA Read WR with contiguous pages 856 + * @rqstp: RPC transaction context 857 + * @head: context for ongoing I/O 858 + * @segment: co-ordinates of remote memory to be read 859 + * 860 + * Greedily allocates higher-order pages to cover the segment, 861 + * building one bvec per contiguous chunk. Each allocation is 862 + * split so sub-pages have independent refcounts. When a 863 + * higher-order allocation fails, remaining pages are covered 864 + * individually, merging adjacent pages into the preceding bvec 865 + * when they are physically contiguous. The split sub-pages 866 + * replace entries in rq_pages[] so downstream cleanup is 867 + * unchanged. 868 + * 869 + * Returns: 870 + * %0: the Read WR was constructed successfully 871 + * %-ENOMEM: allocation failed 872 + * %-EIO: a DMA mapping error occurred 873 + */ 874 + static int svc_rdma_build_read_segment_contig(struct svc_rqst *rqstp, 875 + struct svc_rdma_recv_ctxt *head, 876 + const struct svc_rdma_segment *segment) 877 + { 878 + struct svcxprt_rdma *rdma = svc_rdma_rqst_rdma(rqstp); 879 + struct svc_rdma_chunk_ctxt *cc = &head->rc_cc; 880 + unsigned int nr_data_pages, bvec_idx; 881 + struct svc_rdma_rw_ctxt *ctxt; 882 + unsigned int len_left; 883 + int ret; 884 + 885 + nr_data_pages = PAGE_ALIGN(segment->rs_length) >> PAGE_SHIFT; 886 + if (head->rc_curpage + nr_data_pages > rqstp->rq_maxpages) 887 + return -ENOMEM; 888 + 889 + ctxt = svc_rdma_get_rw_ctxt(rdma, nr_data_pages); 890 + if (!ctxt) 891 + return -ENOMEM; 892 + 893 + bvec_idx = 0; 894 + len_left = segment->rs_length; 895 + while (len_left) { 896 + unsigned int pages_left = PAGE_ALIGN(len_left) >> PAGE_SHIFT; 897 + unsigned int chunk_len = 0; 898 + 899 + if (pages_left >= 2) 900 + chunk_len = svc_rdma_fill_contig_bvec(rqstp, head, 901 + &ctxt->rw_bvec[bvec_idx], 902 + pages_left, len_left); 903 + if (chunk_len) { 904 + bvec_idx++; 905 + } else { 906 + struct page *cur = 907 + rqstp->rq_pages[head->rc_curpage]; 908 + chunk_len = svc_rdma_fill_page_bvec(head, ctxt, cur, 909 + &bvec_idx, 910 + len_left); 911 + } 912 + 913 + len_left -= chunk_len; 914 + } 915 + 916 + ctxt->rw_nents = bvec_idx; 917 + 918 + head->rc_pageoff = offset_in_page(segment->rs_length); 919 + if (head->rc_pageoff) 920 + head->rc_curpage--; 921 + 922 + ret = svc_rdma_rw_ctx_init(rdma, ctxt, segment->rs_offset, 923 + segment->rs_handle, segment->rs_length, 924 + DMA_FROM_DEVICE); 925 + if (ret < 0) 926 + return -EIO; 927 + percpu_counter_inc(&svcrdma_stat_read); 928 + 929 + list_add(&ctxt->rw_list, &cc->cc_rwctxts); 930 + cc->cc_sqecount += ret; 931 + return 0; 766 932 } 767 933 768 934 /** ··· 990 758 if (check_add_overflow(head->rc_pageoff, len, &total)) 991 759 return -EINVAL; 992 760 nr_bvec = PAGE_ALIGN(total) >> PAGE_SHIFT; 761 + 762 + if (head->rc_pageoff == 0 && nr_bvec >= 2) { 763 + ret = svc_rdma_build_read_segment_contig(rqstp, head, 764 + segment); 765 + if (ret != -ENOMEM) 766 + return ret; 767 + } 768 + 993 769 ctxt = svc_rdma_get_rw_ctxt(rdma, nr_bvec); 994 770 if (!ctxt) 995 771 return -ENOMEM; ··· 1343 1103 { 1344 1104 unsigned int i; 1345 1105 1106 + /* 1107 + * Move only pages containing RPC data into rc_pages[]. Pages 1108 + * from a contiguous allocation that were not used for the 1109 + * payload remain in rq_pages[] for subsequent reuse. 1110 + */ 1346 1111 for (i = 0; i < head->rc_page_count; i++) { 1347 1112 head->rc_pages[i] = rqstp->rq_pages[i]; 1348 1113 rqstp->rq_pages[i] = NULL; 1349 1114 } 1115 + rqstp->rq_pages_nfree = head->rc_page_count; 1350 1116 } 1351 1117 1352 1118 /**
+140 -54
net/sunrpc/xprtrdma/svc_rdma_sendto.c
··· 116 116 static struct svc_rdma_send_ctxt * 117 117 svc_rdma_send_ctxt_alloc(struct svcxprt_rdma *rdma) 118 118 { 119 - int node = ibdev_to_node(rdma->sc_cm_id->device); 119 + struct ib_device *device = rdma->sc_cm_id->device; 120 + int node = ibdev_to_node(device); 120 121 struct svc_rdma_send_ctxt *ctxt; 121 122 unsigned long pages; 122 123 dma_addr_t addr; ··· 137 136 buffer = kmalloc_node(rdma->sc_max_req_size, GFP_KERNEL, node); 138 137 if (!buffer) 139 138 goto fail2; 140 - addr = ib_dma_map_single(rdma->sc_pd->device, buffer, 141 - rdma->sc_max_req_size, DMA_TO_DEVICE); 142 - if (ib_dma_mapping_error(rdma->sc_pd->device, addr)) 139 + addr = ib_dma_map_single(device, buffer, rdma->sc_max_req_size, 140 + DMA_TO_DEVICE); 141 + if (ib_dma_mapping_error(device, addr)) 143 142 goto fail3; 144 143 145 144 svc_rdma_send_cid_init(rdma, &ctxt->sc_cid); ··· 150 149 ctxt->sc_send_wr.sg_list = ctxt->sc_sges; 151 150 ctxt->sc_send_wr.send_flags = IB_SEND_SIGNALED; 152 151 ctxt->sc_cqe.done = svc_rdma_wc_send; 152 + INIT_LIST_HEAD(&ctxt->sc_write_info_list); 153 153 ctxt->sc_xprt_buf = buffer; 154 154 xdr_buf_init(&ctxt->sc_hdrbuf, ctxt->sc_xprt_buf, 155 155 rdma->sc_max_req_size); ··· 177 175 */ 178 176 void svc_rdma_send_ctxts_destroy(struct svcxprt_rdma *rdma) 179 177 { 178 + struct ib_device *device = rdma->sc_cm_id->device; 180 179 struct svc_rdma_send_ctxt *ctxt; 181 180 struct llist_node *node; 182 181 183 182 while ((node = llist_del_first(&rdma->sc_send_ctxts)) != NULL) { 184 183 ctxt = llist_entry(node, struct svc_rdma_send_ctxt, sc_node); 185 - ib_dma_unmap_single(rdma->sc_pd->device, 186 - ctxt->sc_sges[0].addr, 187 - rdma->sc_max_req_size, 188 - DMA_TO_DEVICE); 184 + ib_dma_unmap_single(device, ctxt->sc_sges[0].addr, 185 + rdma->sc_max_req_size, DMA_TO_DEVICE); 189 186 kfree(ctxt->sc_xprt_buf); 190 187 kfree(ctxt->sc_pages); 191 188 kfree(ctxt); ··· 238 237 struct ib_device *device = rdma->sc_cm_id->device; 239 238 unsigned int i; 240 239 240 + svc_rdma_write_chunk_release(rdma, ctxt); 241 241 svc_rdma_reply_chunk_release(rdma, ctxt); 242 242 243 243 if (ctxt->sc_page_count) ··· 297 295 } 298 296 299 297 /** 298 + * svc_rdma_sq_wait - Wait for SQ slots using fair queuing 299 + * @rdma: controlling transport 300 + * @cid: completion ID for tracing 301 + * @sqecount: number of SQ entries needed 302 + * 303 + * A ticket-based system ensures fair ordering when multiple threads 304 + * wait for Send Queue capacity. Each waiter takes a ticket and is 305 + * served in order, preventing starvation. 306 + * 307 + * Protocol invariant: every ticket holder must increment 308 + * sc_sq_ticket_tail exactly once, whether the reservation 309 + * succeeds or the connection closes. Failing to advance the 310 + * tail stalls all subsequent waiters. 311 + * 312 + * The ticket counters are signed 32-bit atomics. After 313 + * wrapping through INT_MAX, the equality check 314 + * (tail == ticket) remains correct because both counters 315 + * advance monotonically and the comparison uses exact 316 + * equality rather than relational operators. 317 + * 318 + * Return values: 319 + * %0: SQ slots were reserved successfully 320 + * %-ENOTCONN: The connection was lost 321 + */ 322 + int svc_rdma_sq_wait(struct svcxprt_rdma *rdma, 323 + const struct rpc_rdma_cid *cid, int sqecount) 324 + { 325 + int ticket; 326 + 327 + /* Fast path: try to reserve SQ slots without waiting. 328 + * 329 + * A failed reservation temporarily understates sc_sq_avail 330 + * until the compensating atomic_add restores it. A Send 331 + * completion arriving in that window sees a lower count 332 + * than reality, but the value self-corrects once the add 333 + * completes. No ordering guarantee is needed here because 334 + * the slow path serializes all contended waiters. 335 + */ 336 + if (likely(atomic_sub_return(sqecount, &rdma->sc_sq_avail) >= 0)) 337 + return 0; 338 + atomic_add(sqecount, &rdma->sc_sq_avail); 339 + 340 + /* Slow path: take a ticket and wait in line */ 341 + ticket = atomic_fetch_inc(&rdma->sc_sq_ticket_head); 342 + 343 + percpu_counter_inc(&svcrdma_stat_sq_starve); 344 + trace_svcrdma_sq_full(rdma, cid); 345 + 346 + /* Wait until all earlier tickets have been served */ 347 + wait_event(rdma->sc_sq_ticket_wait, 348 + test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags) || 349 + atomic_read(&rdma->sc_sq_ticket_tail) == ticket); 350 + if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) 351 + goto out_close; 352 + 353 + /* It's our turn. Wait for enough SQ slots to be available. */ 354 + while (atomic_sub_return(sqecount, &rdma->sc_sq_avail) < 0) { 355 + atomic_add(sqecount, &rdma->sc_sq_avail); 356 + 357 + wait_event(rdma->sc_send_wait, 358 + test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags) || 359 + atomic_read(&rdma->sc_sq_avail) >= sqecount); 360 + if (test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) 361 + goto out_close; 362 + } 363 + 364 + /* Slots reserved successfully. Let the next waiter proceed. */ 365 + atomic_inc(&rdma->sc_sq_ticket_tail); 366 + wake_up(&rdma->sc_sq_ticket_wait); 367 + trace_svcrdma_sq_retry(rdma, cid); 368 + return 0; 369 + 370 + out_close: 371 + atomic_inc(&rdma->sc_sq_ticket_tail); 372 + wake_up(&rdma->sc_sq_ticket_wait); 373 + return -ENOTCONN; 374 + } 375 + 376 + /** 377 + * svc_rdma_post_send_err - Handle ib_post_send failure 378 + * @rdma: controlling transport 379 + * @cid: completion ID for tracing 380 + * @bad_wr: first WR that was not posted 381 + * @first_wr: first WR in the chain 382 + * @sqecount: number of SQ entries that were reserved 383 + * @ret: error code from ib_post_send 384 + * 385 + * Return values: 386 + * %0: At least one WR was posted; a completion handles cleanup 387 + * %-ENOTCONN: No WRs were posted; SQ slots are released 388 + */ 389 + int svc_rdma_post_send_err(struct svcxprt_rdma *rdma, 390 + const struct rpc_rdma_cid *cid, 391 + const struct ib_send_wr *bad_wr, 392 + const struct ib_send_wr *first_wr, 393 + int sqecount, int ret) 394 + { 395 + trace_svcrdma_sq_post_err(rdma, cid, ret); 396 + svc_xprt_deferred_close(&rdma->sc_xprt); 397 + 398 + /* If even one WR was posted, a Send completion will 399 + * return the reserved SQ slots. 400 + */ 401 + if (bad_wr != first_wr) 402 + return 0; 403 + 404 + svc_rdma_wake_send_waiters(rdma, sqecount); 405 + return -ENOTCONN; 406 + } 407 + 408 + /** 300 409 * svc_rdma_wc_send - Invoked by RDMA provider for each polled Send WC 301 410 * @cq: Completion Queue context 302 411 * @wc: Work Completion object ··· 449 336 * that these values remain available after the ib_post_send() call. 450 337 * In some error flow cases, svc_rdma_wc_send() releases @ctxt. 451 338 * 452 - * Note there is potential for starvation when the Send Queue is 453 - * full because there is no order to when waiting threads are 454 - * awoken. The transport is typically provisioned with a deep 455 - * enough Send Queue that SQ exhaustion should be a rare event. 456 - * 457 339 * Return values: 458 340 * %0: @ctxt's WR chain was posted successfully 459 341 * %-ENOTCONN: The connection was lost ··· 465 357 might_sleep(); 466 358 467 359 /* Sync the transport header buffer */ 468 - ib_dma_sync_single_for_device(rdma->sc_pd->device, 360 + ib_dma_sync_single_for_device(rdma->sc_cm_id->device, 469 361 send_wr->sg_list[0].addr, 470 362 send_wr->sg_list[0].length, 471 363 DMA_TO_DEVICE); 472 364 473 - /* If the SQ is full, wait until an SQ entry is available */ 474 - while (!test_bit(XPT_CLOSE, &rdma->sc_xprt.xpt_flags)) { 475 - if (atomic_sub_return(sqecount, &rdma->sc_sq_avail) < 0) { 476 - svc_rdma_wake_send_waiters(rdma, sqecount); 365 + ret = svc_rdma_sq_wait(rdma, &cid, sqecount); 366 + if (ret < 0) 367 + return ret; 477 368 478 - /* When the transport is torn down, assume 479 - * ib_drain_sq() will trigger enough Send 480 - * completions to wake us. The XPT_CLOSE test 481 - * above should then cause the while loop to 482 - * exit. 483 - */ 484 - percpu_counter_inc(&svcrdma_stat_sq_starve); 485 - trace_svcrdma_sq_full(rdma, &cid); 486 - wait_event(rdma->sc_send_wait, 487 - atomic_read(&rdma->sc_sq_avail) > 0); 488 - trace_svcrdma_sq_retry(rdma, &cid); 489 - continue; 490 - } 491 - 492 - trace_svcrdma_post_send(ctxt); 493 - ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr); 494 - if (ret) { 495 - trace_svcrdma_sq_post_err(rdma, &cid, ret); 496 - svc_xprt_deferred_close(&rdma->sc_xprt); 497 - 498 - /* If even one WR was posted, there will be a 499 - * Send completion that bumps sc_sq_avail. 500 - */ 501 - if (bad_wr == first_wr) { 502 - svc_rdma_wake_send_waiters(rdma, sqecount); 503 - break; 504 - } 505 - } 506 - return 0; 507 - } 508 - return -ENOTCONN; 369 + trace_svcrdma_post_send(ctxt); 370 + ret = ib_post_send(rdma->sc_qp, first_wr, &bad_wr); 371 + if (ret) 372 + return svc_rdma_post_send_err(rdma, &cid, bad_wr, 373 + first_wr, sqecount, ret); 374 + return 0; 509 375 } 510 376 511 377 /** ··· 940 858 941 859 /* The svc_rqst and all resources it owns are released as soon as 942 860 * svc_rdma_sendto returns. Transfer pages under I/O to the ctxt 943 - * so they are released by the Send completion handler. 861 + * so they are released only after Send completion, and not by 862 + * svc_rqst_release_pages(). 944 863 */ 945 864 static void svc_rdma_save_io_pages(struct svc_rqst *rqstp, 946 865 struct svc_rdma_send_ctxt *ctxt) ··· 953 870 ctxt->sc_pages[i] = rqstp->rq_respages[i]; 954 871 rqstp->rq_respages[i] = NULL; 955 872 } 956 - 957 - /* Prevent svc_xprt_release from releasing pages in rq_pages */ 958 - rqstp->rq_next_page = rqstp->rq_respages; 959 873 } 960 874 961 875 /* Prepare the portion of the RPC Reply that will be transmitted ··· 1056 976 sctxt->sc_send_wr.num_sge = 1; 1057 977 sctxt->sc_send_wr.opcode = IB_WR_SEND; 1058 978 sctxt->sc_sges[0].length = sctxt->sc_hdrbuf.len; 979 + 980 + /* Ensure only the error message is posted, not any previously 981 + * prepared Write chunk WRs. 982 + */ 983 + sctxt->sc_wr_chain = &sctxt->sc_send_wr; 984 + sctxt->sc_sqecount = 1; 1059 985 if (svc_rdma_post_send(rdma, sctxt)) 1060 986 goto put_ctxt; 1061 987 return; ··· 1109 1023 if (!p) 1110 1024 goto put_ctxt; 1111 1025 1112 - ret = svc_rdma_send_write_list(rdma, rctxt, &rqstp->rq_res); 1026 + ret = svc_rdma_prepare_write_list(rdma, rctxt, sctxt, &rqstp->rq_res); 1113 1027 if (ret < 0) 1114 1028 goto put_ctxt; 1115 1029
+19 -14
net/sunrpc/xprtrdma/svc_rdma_transport.c
··· 179 179 init_llist_head(&cma_xprt->sc_recv_ctxts); 180 180 init_llist_head(&cma_xprt->sc_rw_ctxts); 181 181 init_waitqueue_head(&cma_xprt->sc_send_wait); 182 + init_waitqueue_head(&cma_xprt->sc_sq_ticket_wait); 182 183 183 184 spin_lock_init(&cma_xprt->sc_lock); 184 185 spin_lock_init(&cma_xprt->sc_rq_dto_lock); ··· 415 414 struct ib_qp_init_attr qp_attr; 416 415 struct ib_device *dev; 417 416 int ret = 0; 418 - RPC_IFDEBUG(struct sockaddr *sap); 419 417 420 418 listen_rdma = container_of(xprt, struct svcxprt_rdma, sc_xprt); 421 419 clear_bit(XPT_CONN, &xprt->xpt_flags); ··· 478 478 if (newxprt->sc_sq_depth > dev->attrs.max_qp_wr) 479 479 newxprt->sc_sq_depth = dev->attrs.max_qp_wr; 480 480 atomic_set(&newxprt->sc_sq_avail, newxprt->sc_sq_depth); 481 + atomic_set(&newxprt->sc_sq_ticket_head, 0); 482 + atomic_set(&newxprt->sc_sq_ticket_tail, 0); 481 483 482 484 newxprt->sc_pd = ib_alloc_pd(dev, 0); 483 485 if (IS_ERR(newxprt->sc_pd)) { ··· 562 560 goto errout; 563 561 } 564 562 565 - #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) 566 - dprintk("svcrdma: new connection accepted on device %s:\n", dev->name); 567 - sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr; 568 - dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap)); 569 - sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr; 570 - dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap)); 571 - dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges); 572 - dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth); 573 - dprintk(" rdma_rw_ctxs : %d\n", ctxts); 574 - dprintk(" max_requests : %d\n", newxprt->sc_max_requests); 575 - dprintk(" ord : %d\n", conn_param.initiator_depth); 576 - #endif 563 + if (IS_ENABLED(CONFIG_SUNRPC_DEBUG)) { 564 + struct sockaddr *sap; 565 + 566 + dprintk("svcrdma: new connection accepted on device %s:\n", dev->name); 567 + sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.src_addr; 568 + dprintk(" local address : %pIS:%u\n", sap, rpc_get_port(sap)); 569 + sap = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr; 570 + dprintk(" remote address : %pIS:%u\n", sap, rpc_get_port(sap)); 571 + dprintk(" max_sge : %d\n", newxprt->sc_max_send_sges); 572 + dprintk(" sq_depth : %d\n", newxprt->sc_sq_depth); 573 + dprintk(" rdma_rw_ctxs : %d\n", ctxts); 574 + dprintk(" max_requests : %d\n", newxprt->sc_max_requests); 575 + dprintk(" ord : %d\n", conn_param.initiator_depth); 576 + } 577 577 578 578 return &newxprt->sc_xprt; 579 579 ··· 652 648 * If there are already waiters on the SQ, 653 649 * return false. 654 650 */ 655 - if (waitqueue_active(&rdma->sc_send_wait)) 651 + if (waitqueue_active(&rdma->sc_send_wait) || 652 + waitqueue_active(&rdma->sc_sq_ticket_wait)) 656 653 return 0; 657 654 658 655 /* Otherwise return true. */