mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Merge tag 'nfsd-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux
Pull nfsd updates from Chuck Lever: "Jeff Layton wired up netlink upcalls for the auth.unix.ip and auth.unix.gid caches in SunRPC and the svc_export and nfsd.fh caches in NFSD. The new kernel-user API is more extensible and lays the groundwork for retiring the old pipe interface. The default NFS r/w block size rises to 4MB on hosts with at least 16GB of RAM, reducing per-RPC overhead on fast networks. Smaller machines keep their previously computed default, and the value remains tunable through /proc/fs/nfsd/max_block_size. Chuck Lever converted the server's RPCSEC GSS Kerberos code to the kernel's shared crypto/krb5 library. The conversion retires and removes SunRPC's bespoke implementation of Kerberos v5, but keeps RPCSEC GSS-API. Continuing the xdrgen migration that converted the NLMv4 server XDR layer in v7.1, Chuck Lever converted the NLM version 3 server-side XDR layer from hand-written C to xdrgen-generated code. As with the NLMv4 conversion in v7.1, the goals are improved memory safety, lower maintenance burden, and groundwork for generation of Rust code for this layer instead of C. Chuck Lever fixed an issue where lingering NFSv4 state pins a mounted file system after it is unexported. A new netlink-based mechanism can now release NLM locks and NFSv4 state by client address, by filesystem, and by export. Now an administrator can quiesce an export cleanly before unmounting it. The remaining patches are bug fixes, clean-ups, and minor optimizations, including a batch of memory-leak and use-after-free fixes in the ACL, lockd, and TLS handshake paths, many of them reported by Chris Mason. Sincere thanks to all contributors, reviewers, testers, and bug reporters who participated in the v7.2 NFSD development cycle" * tag 'nfsd-7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (106 commits) svcrdma: wake sq waiters when the transport closes nfsd: reset write verifier on deferred writeback errors nfsd: avoid leaking pre-allocated openowner on unconfirmed retry race sunrpc: wait for in-flight TLS handshake callback when cancel loses race sunrpc: pin svc_xprt across the asynchronous TLS handshake callback nfsd: fix posix_acl leak on SETACL decode failure nfsd: fix posix_acl leak and ignored error in nfsd4_create_file nfsd: check get_user() return when reading princhashlen nfsd: fix inverted cp_ttl check in async copy reaper nfsd: fix dead ACL conflict guard in nfsd4_create NFSD: Fix SECINFO_NO_NAME decode error cleanup sunrpc: harden rq_procinfo lifecycle to prevent double-free SUNRPC: Return an error from xdr_buf_to_bvec() on overflow SUNRPC: Bound-check xdr_buf_to_bvec() stores before writing nfsd: release layout stid on setlease failure lockd: Avoid hashing uninitialized bytes in nlm4svc_lookup_file() lockd: Plug nlm_file refcount leak on cached nlm_do_fopen() failure lockd: Plug nlm_file leak when nlm_do_fopen() fails Revert "NFSD: Defer sub-object cleanup in export put callbacks" Revert "svcrdma: Use contiguous pages for RDMA Read sink buffers" ...
This commit is contained in:
6
.mailmap
6
.mailmap
@@ -202,9 +202,9 @@ Christophe Ricard <christophe.ricard@gmail.com>
|
||||
Christopher Obbard <christopher.obbard@linaro.org> <chris.obbard@collabora.com>
|
||||
Christoph Hellwig <hch@lst.de>
|
||||
Christoph Manszewski <c.manszewski@gmail.com> <christoph.manszewski@intel.com>
|
||||
Chuck Lever <chuck.lever@oracle.com> <cel@kernel.org>
|
||||
Chuck Lever <chuck.lever@oracle.com> <cel@netapp.com>
|
||||
Chuck Lever <chuck.lever@oracle.com> <cel@citi.umich.edu>
|
||||
Chuck Lever <cel@kernel.org> <chuck.lever@oracle.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@netapp.com>
|
||||
Chuck Lever <cel@kernel.org> <cel@citi.umich.edu>
|
||||
Claudiu Beznea <claudiu.beznea@tuxon.dev> <claudiu.beznea@microchip.com>
|
||||
Colin Ian King <colin.i.king@gmail.com> <colin.king@canonical.com>
|
||||
Corey Minyard <minyard@acm.org>
|
||||
|
||||
@@ -6,7 +6,51 @@ uapi-header: linux/nfsd_netlink.h
|
||||
|
||||
doc: NFSD configuration over generic netlink.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: flags
|
||||
name: cache-type
|
||||
entries: [svc_export, expkey]
|
||||
-
|
||||
type: flags
|
||||
name: export-flags
|
||||
doc: These flags are ordered to match the NFSEXP_* flags in include/linux/nfsd/export.h
|
||||
entries:
|
||||
- readonly
|
||||
- insecure-port
|
||||
- rootsquash
|
||||
- allsquash
|
||||
- async
|
||||
- gathered-writes
|
||||
- noreaddirplus
|
||||
- security-label
|
||||
- sign-fh
|
||||
- nohide
|
||||
- nosubtreecheck
|
||||
- noauthnlm
|
||||
- msnfs
|
||||
- fsid
|
||||
- crossmount
|
||||
- noacl
|
||||
- v4root
|
||||
- pnfs
|
||||
-
|
||||
type: flags
|
||||
name: xprtsec-mode
|
||||
doc: These flags are ordered to match the NFSEXP_XPRTSEC_* flags in include/linux/nfsd/export.h
|
||||
entries:
|
||||
- none
|
||||
- tls
|
||||
- mtls
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: cache-notify
|
||||
attributes:
|
||||
-
|
||||
name: cache-type
|
||||
type: u32
|
||||
enum: cache-type
|
||||
-
|
||||
name: rpc-status
|
||||
attributes:
|
||||
@@ -132,6 +176,160 @@ attribute-sets:
|
||||
-
|
||||
name: npools
|
||||
type: u32
|
||||
-
|
||||
name: fslocation
|
||||
attributes:
|
||||
-
|
||||
name: host
|
||||
type: string
|
||||
-
|
||||
name: path
|
||||
type: string
|
||||
-
|
||||
name: fslocations
|
||||
attributes:
|
||||
-
|
||||
name: location
|
||||
type: nest
|
||||
nested-attributes: fslocation
|
||||
multi-attr: true
|
||||
-
|
||||
name: auth-flavor
|
||||
attributes:
|
||||
-
|
||||
name: pseudoflavor
|
||||
type: u32
|
||||
-
|
||||
name: flags
|
||||
type: u32
|
||||
enum: export-flags
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: svc-export
|
||||
attributes:
|
||||
-
|
||||
name: seqno
|
||||
type: u64
|
||||
-
|
||||
name: client
|
||||
type: string
|
||||
-
|
||||
name: path
|
||||
type: string
|
||||
-
|
||||
name: negative
|
||||
type: flag
|
||||
-
|
||||
name: expiry
|
||||
type: u64
|
||||
-
|
||||
name: anon-uid
|
||||
type: u32
|
||||
-
|
||||
name: anon-gid
|
||||
type: u32
|
||||
-
|
||||
name: fslocations
|
||||
type: nest
|
||||
nested-attributes: fslocations
|
||||
-
|
||||
name: uuid
|
||||
type: binary
|
||||
-
|
||||
name: secinfo
|
||||
type: nest
|
||||
nested-attributes: auth-flavor
|
||||
multi-attr: true
|
||||
-
|
||||
name: xprtsec
|
||||
type: u32
|
||||
enum: xprtsec-mode
|
||||
multi-attr: true
|
||||
-
|
||||
name: flags
|
||||
type: u32
|
||||
enum: export-flags
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: fsid
|
||||
type: s32
|
||||
-
|
||||
name: svc-export-reqs
|
||||
attributes:
|
||||
-
|
||||
name: requests
|
||||
type: nest
|
||||
nested-attributes: svc-export
|
||||
multi-attr: true
|
||||
-
|
||||
name: expkey
|
||||
attributes:
|
||||
-
|
||||
name: seqno
|
||||
type: u64
|
||||
-
|
||||
name: client
|
||||
type: string
|
||||
-
|
||||
name: fsidtype
|
||||
type: u8
|
||||
-
|
||||
name: fsid
|
||||
type: binary
|
||||
-
|
||||
name: negative
|
||||
type: flag
|
||||
-
|
||||
name: expiry
|
||||
type: u64
|
||||
-
|
||||
name: path
|
||||
type: string
|
||||
-
|
||||
name: expkey-reqs
|
||||
attributes:
|
||||
-
|
||||
name: requests
|
||||
type: nest
|
||||
nested-attributes: expkey
|
||||
multi-attr: true
|
||||
-
|
||||
name: cache-flush
|
||||
attributes:
|
||||
-
|
||||
name: mask
|
||||
type: u32
|
||||
enum: cache-type
|
||||
enum-as-flags: true
|
||||
-
|
||||
name: unlock-ip
|
||||
attributes:
|
||||
-
|
||||
name: address
|
||||
type: binary
|
||||
doc: struct sockaddr_in or struct sockaddr_in6.
|
||||
checks:
|
||||
min-len: 16
|
||||
-
|
||||
name: unlock-filesystem
|
||||
attributes:
|
||||
-
|
||||
name: path
|
||||
type: string
|
||||
doc: Filesystem path whose state should be released.
|
||||
-
|
||||
name: unlock-export
|
||||
attributes:
|
||||
-
|
||||
name: path
|
||||
type: string
|
||||
doc: >-
|
||||
Export path whose NFSv4 state should be revoked.
|
||||
All state (opens, locks, delegations, layouts) acquired
|
||||
through any export of this path is revoked, regardless
|
||||
of which client holds the state. Intended for use after
|
||||
all clients have been unexported from a given path,
|
||||
enabling the underlying filesystem to be unmounted.
|
||||
|
||||
operations:
|
||||
list:
|
||||
@@ -233,3 +431,95 @@ operations:
|
||||
attributes:
|
||||
- mode
|
||||
- npools
|
||||
-
|
||||
name: cache-notify
|
||||
doc: Notification that there are cache requests that need servicing
|
||||
attribute-set: cache-notify
|
||||
mcgrp: exportd
|
||||
event:
|
||||
attributes:
|
||||
- cache-type
|
||||
-
|
||||
name: svc-export-get-reqs
|
||||
doc: Dump all pending svc_export requests
|
||||
attribute-set: svc-export-reqs
|
||||
flags: [admin-perm]
|
||||
dump:
|
||||
reply:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: svc-export-set-reqs
|
||||
doc: Respond to one or more svc_export requests
|
||||
attribute-set: svc-export-reqs
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: expkey-get-reqs
|
||||
doc: Dump all pending expkey requests
|
||||
attribute-set: expkey-reqs
|
||||
flags: [admin-perm]
|
||||
dump:
|
||||
reply:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: expkey-set-reqs
|
||||
doc: Respond to one or more expkey requests
|
||||
attribute-set: expkey-reqs
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: cache-flush
|
||||
doc: Flush nfsd caches (svc_export and/or expkey)
|
||||
attribute-set: cache-flush
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- mask
|
||||
-
|
||||
name: unlock-ip
|
||||
doc: release NLM locks held by an IP address
|
||||
attribute-set: unlock-ip
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- address
|
||||
-
|
||||
name: unlock-filesystem
|
||||
doc: revoke NFS state under a filesystem path
|
||||
attribute-set: unlock-filesystem
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- path
|
||||
-
|
||||
name: unlock-export
|
||||
doc: >-
|
||||
Revoke NFSv4 state acquired through exports of a given path.
|
||||
Unlike unlock-filesystem, which operates at superblock granularity,
|
||||
this command targets only state associated with a specific export
|
||||
path. Userspace (exportfs -u) sends this after removing the last
|
||||
client for a path so the underlying filesystem can be unmounted.
|
||||
attribute-set: unlock-export
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- path
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: none
|
||||
-
|
||||
name: exportd
|
||||
|
||||
149
Documentation/netlink/specs/sunrpc_cache.yaml
Normal file
149
Documentation/netlink/specs/sunrpc_cache.yaml
Normal file
@@ -0,0 +1,149 @@
|
||||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
---
|
||||
name: sunrpc
|
||||
protocol: genetlink
|
||||
uapi-header: linux/sunrpc_netlink.h
|
||||
|
||||
doc: SUNRPC cache upcall support over generic netlink.
|
||||
|
||||
definitions:
|
||||
-
|
||||
type: flags
|
||||
name: cache-type
|
||||
entries: [ip_map, unix_gid]
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: cache-notify
|
||||
attributes:
|
||||
-
|
||||
name: cache-type
|
||||
type: u32
|
||||
enum: cache-type
|
||||
-
|
||||
name: ip-map
|
||||
attributes:
|
||||
-
|
||||
name: seqno
|
||||
type: u64
|
||||
-
|
||||
name: class
|
||||
type: string
|
||||
-
|
||||
name: addr
|
||||
type: string
|
||||
-
|
||||
name: domain
|
||||
type: string
|
||||
-
|
||||
name: negative
|
||||
type: flag
|
||||
-
|
||||
name: expiry
|
||||
type: u64
|
||||
-
|
||||
name: ip-map-reqs
|
||||
attributes:
|
||||
-
|
||||
name: requests
|
||||
type: nest
|
||||
nested-attributes: ip-map
|
||||
multi-attr: true
|
||||
-
|
||||
name: unix-gid
|
||||
attributes:
|
||||
-
|
||||
name: seqno
|
||||
type: u64
|
||||
-
|
||||
name: uid
|
||||
type: u32
|
||||
-
|
||||
name: gids
|
||||
type: u32
|
||||
multi-attr: true
|
||||
-
|
||||
name: negative
|
||||
type: flag
|
||||
-
|
||||
name: expiry
|
||||
type: u64
|
||||
-
|
||||
name: unix-gid-reqs
|
||||
attributes:
|
||||
-
|
||||
name: requests
|
||||
type: nest
|
||||
nested-attributes: unix-gid
|
||||
multi-attr: true
|
||||
-
|
||||
name: cache-flush
|
||||
attributes:
|
||||
-
|
||||
name: mask
|
||||
type: u32
|
||||
enum: cache-type
|
||||
enum-as-flags: true
|
||||
|
||||
operations:
|
||||
list:
|
||||
-
|
||||
name: cache-notify
|
||||
doc: Notification that there are cache requests that need servicing
|
||||
attribute-set: cache-notify
|
||||
mcgrp: exportd
|
||||
event:
|
||||
attributes:
|
||||
- cache-type
|
||||
-
|
||||
name: ip-map-get-reqs
|
||||
doc: Dump all pending ip_map requests
|
||||
attribute-set: ip-map-reqs
|
||||
flags: [admin-perm]
|
||||
dump:
|
||||
reply:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: ip-map-set-reqs
|
||||
doc: Respond to one or more ip_map requests
|
||||
attribute-set: ip-map-reqs
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: unix-gid-get-reqs
|
||||
doc: Dump all pending unix_gid requests
|
||||
attribute-set: unix-gid-reqs
|
||||
flags: [admin-perm]
|
||||
dump:
|
||||
reply:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: unix-gid-set-reqs
|
||||
doc: Respond to one or more unix_gid requests
|
||||
attribute-set: unix-gid-reqs
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- requests
|
||||
-
|
||||
name: cache-flush
|
||||
doc: Flush sunrpc caches (ip_map and/or unix_gid)
|
||||
attribute-set: cache-flush
|
||||
flags: [admin-perm]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- mask
|
||||
|
||||
mcast-groups:
|
||||
list:
|
||||
-
|
||||
name: none
|
||||
-
|
||||
name: exportd
|
||||
168
Documentation/sunrpc/xdr/nlm3.x
Normal file
168
Documentation/sunrpc/xdr/nlm3.x
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* This file was extracted by hand from
|
||||
* https://pubs.opengroup.org/onlinepubs/9629799/chap10.htm#tagcjh_11_03
|
||||
*/
|
||||
|
||||
/*
|
||||
* The NLMv3 protocol
|
||||
*/
|
||||
|
||||
pragma header nlm3;
|
||||
|
||||
const LM_MAXSTRLEN = 1024;
|
||||
|
||||
const LM_MAXNAMELEN = 1025;
|
||||
|
||||
const MAXNETOBJ_SZ = 1024;
|
||||
|
||||
typedef opaque netobj<MAXNETOBJ_SZ>;
|
||||
|
||||
enum nlm_stats {
|
||||
LCK_GRANTED = 0,
|
||||
LCK_DENIED = 1,
|
||||
LCK_DENIED_NOLOCKS = 2,
|
||||
LCK_BLOCKED = 3,
|
||||
LCK_DENIED_GRACE_PERIOD = 4
|
||||
};
|
||||
|
||||
pragma big_endian nlm_stats;
|
||||
|
||||
struct nlm_stat {
|
||||
nlm_stats stat;
|
||||
};
|
||||
|
||||
struct nlm_res {
|
||||
netobj cookie;
|
||||
nlm_stat stat;
|
||||
};
|
||||
|
||||
struct nlm_holder {
|
||||
bool exclusive;
|
||||
int uppid;
|
||||
netobj oh;
|
||||
unsigned int l_offset;
|
||||
unsigned int l_len;
|
||||
};
|
||||
|
||||
union nlm_testrply switch (nlm_stats stat) {
|
||||
case LCK_DENIED:
|
||||
nlm_holder holder;
|
||||
default:
|
||||
void;
|
||||
};
|
||||
|
||||
struct nlm_testres {
|
||||
netobj cookie;
|
||||
nlm_testrply test_stat;
|
||||
};
|
||||
|
||||
struct nlm_lock {
|
||||
string caller_name<LM_MAXSTRLEN>;
|
||||
netobj fh;
|
||||
netobj oh;
|
||||
int uppid;
|
||||
unsigned int l_offset;
|
||||
unsigned int l_len;
|
||||
};
|
||||
|
||||
struct nlm_lockargs {
|
||||
netobj cookie;
|
||||
bool block;
|
||||
bool exclusive;
|
||||
nlm_lock alock;
|
||||
bool reclaim;
|
||||
int state;
|
||||
};
|
||||
|
||||
struct nlm_cancargs {
|
||||
netobj cookie;
|
||||
bool block;
|
||||
bool exclusive;
|
||||
nlm_lock alock;
|
||||
};
|
||||
|
||||
struct nlm_testargs {
|
||||
netobj cookie;
|
||||
bool exclusive;
|
||||
nlm_lock alock;
|
||||
};
|
||||
|
||||
struct nlm_unlockargs {
|
||||
netobj cookie;
|
||||
nlm_lock alock;
|
||||
};
|
||||
|
||||
enum fsh_mode {
|
||||
fsm_DN = 0,
|
||||
fsm_DR = 1,
|
||||
fsm_DW = 2,
|
||||
fsm_DRW = 3
|
||||
};
|
||||
|
||||
enum fsh_access {
|
||||
fsa_NONE = 0,
|
||||
fsa_R = 1,
|
||||
fsa_W = 2,
|
||||
fsa_RW = 3
|
||||
};
|
||||
|
||||
struct nlm_share {
|
||||
string caller_name<LM_MAXSTRLEN>;
|
||||
netobj fh;
|
||||
netobj oh;
|
||||
fsh_mode mode;
|
||||
fsh_access access;
|
||||
};
|
||||
|
||||
struct nlm_shareargs {
|
||||
netobj cookie;
|
||||
nlm_share share;
|
||||
bool reclaim;
|
||||
};
|
||||
|
||||
struct nlm_shareres {
|
||||
netobj cookie;
|
||||
nlm_stats stat;
|
||||
int sequence;
|
||||
};
|
||||
|
||||
struct nlm_notify {
|
||||
string name<LM_MAXNAMELEN>;
|
||||
long state;
|
||||
};
|
||||
|
||||
/*
|
||||
* Argument for the Linux-private SM_NOTIFY procedure
|
||||
*/
|
||||
const SM_PRIV_SIZE = 16;
|
||||
|
||||
struct nlm_notifyargs {
|
||||
nlm_notify notify;
|
||||
opaque private[SM_PRIV_SIZE];
|
||||
};
|
||||
|
||||
program NLM_PROG {
|
||||
version NLM_VERS {
|
||||
void NLM_NULL(void) = 0;
|
||||
nlm_testres NLM_TEST(nlm_testargs) = 1;
|
||||
nlm_res NLM_LOCK(nlm_lockargs) = 2;
|
||||
nlm_res NLM_CANCEL(nlm_cancargs) = 3;
|
||||
nlm_res NLM_UNLOCK(nlm_unlockargs) = 4;
|
||||
nlm_res NLM_GRANTED(nlm_testargs) = 5;
|
||||
void NLM_TEST_MSG(nlm_testargs) = 6;
|
||||
void NLM_LOCK_MSG(nlm_lockargs) = 7;
|
||||
void NLM_CANCEL_MSG(nlm_cancargs) = 8;
|
||||
void NLM_UNLOCK_MSG(nlm_unlockargs) = 9;
|
||||
void NLM_GRANTED_MSG(nlm_testargs) = 10;
|
||||
void NLM_TEST_RES(nlm_testres) = 11;
|
||||
void NLM_LOCK_RES(nlm_res) = 12;
|
||||
void NLM_CANCEL_RES(nlm_res) = 13;
|
||||
void NLM_UNLOCK_RES(nlm_res) = 14;
|
||||
void NLM_GRANTED_RES(nlm_res) = 15;
|
||||
void NLM_SM_NOTIFY(nlm_notifyargs) = 16;
|
||||
nlm_shareres NLM_SHARE(nlm_shareargs) = 20;
|
||||
nlm_shareres NLM_UNSHARE(nlm_shareargs) = 21;
|
||||
nlm_res NLM_NM_LOCK(nlm_lockargs) = 22;
|
||||
void NLM_FREE_ALL(nlm_notify) = 23;
|
||||
} = 3;
|
||||
} = 100021;
|
||||
@@ -9902,7 +9902,7 @@ F: include/uapi/scsi/fc/
|
||||
|
||||
FILE LOCKING (flock() and fcntl()/lockf())
|
||||
M: Jeff Layton <jlayton@kernel.org>
|
||||
M: Chuck Lever <chuck.lever@oracle.com>
|
||||
M: Chuck Lever <cel@kernel.org>
|
||||
R: Alexander Aring <alex.aring@gmail.com>
|
||||
L: linux-fsdevel@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -9943,7 +9943,7 @@ F: init/do_mounts*
|
||||
F: init/*initramfs*
|
||||
|
||||
FILESYSTEMS [EXPORTFS]
|
||||
M: Chuck Lever <chuck.lever@oracle.com>
|
||||
M: Chuck Lever <cel@kernel.org>
|
||||
M: Jeff Layton <jlayton@kernel.org>
|
||||
R: Amir Goldstein <amir73il@gmail.com>
|
||||
L: linux-fsdevel@vger.kernel.org
|
||||
@@ -11306,7 +11306,7 @@ Q: http://patchwork.linuxtv.org/project/linux-media/list/
|
||||
F: drivers/media/usb/hackrf/
|
||||
|
||||
HANDSHAKE UPCALL FOR TRANSPORT LAYER SECURITY
|
||||
M: Chuck Lever <chuck.lever@oracle.com>
|
||||
M: Chuck Lever <cel@kernel.org>
|
||||
L: kernel-tls-handshake@lists.linux.dev
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
@@ -14000,7 +14000,7 @@ S: Odd Fixes
|
||||
W: http://kernelnewbies.org/KernelJanitors
|
||||
|
||||
KERNEL NFSD, SUNRPC, AND LOCKD SERVERS
|
||||
M: Chuck Lever <chuck.lever@oracle.com>
|
||||
M: Chuck Lever <cel@kernel.org>
|
||||
M: Jeff Layton <jlayton@kernel.org>
|
||||
R: NeilBrown <neil@brown.name>
|
||||
R: Olga Kornievskaia <okorniev@redhat.com>
|
||||
|
||||
@@ -8,7 +8,8 @@ ccflags-y += -I$(src) # needed for trace events
|
||||
obj-$(CONFIG_LOCKD) += lockd.o
|
||||
|
||||
lockd-y := clntlock.o clntproc.o clntxdr.o host.o svc.o svclock.o \
|
||||
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o
|
||||
svcshare.o svcproc.o svcsubs.o mon.o trace.o netlink.o \
|
||||
nlm3xdr_gen.o
|
||||
lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o svc4proc.o nlm4xdr_gen.o
|
||||
lockd-$(CONFIG_PROC_FS) += procfs.o
|
||||
|
||||
@@ -25,17 +26,27 @@ lockd-$(CONFIG_PROC_FS) += procfs.o
|
||||
|
||||
XDRGEN = ../../tools/net/sunrpc/xdrgen/xdrgen
|
||||
|
||||
XDRGEN_DEFINITIONS = ../../include/linux/sunrpc/xdrgen/nlm4.h
|
||||
XDRGEN_DECLARATIONS = nlm4xdr_gen.h
|
||||
XDRGEN_SOURCE = nlm4xdr_gen.c
|
||||
XDRGEN_DEFINITIONS = ../../include/linux/sunrpc/xdrgen/nlm4.h \
|
||||
../../include/linux/sunrpc/xdrgen/nlm3.h
|
||||
XDRGEN_DECLARATIONS = nlm4xdr_gen.h nlm3xdr_gen.h
|
||||
XDRGEN_SOURCE = nlm4xdr_gen.c nlm3xdr_gen.c
|
||||
|
||||
xdrgen: $(XDRGEN_DEFINITIONS) $(XDRGEN_DECLARATIONS) $(XDRGEN_SOURCE)
|
||||
|
||||
../../include/linux/sunrpc/xdrgen/nlm4.h: ../../Documentation/sunrpc/xdr/nlm4.x
|
||||
$(XDRGEN) definitions $< > $@
|
||||
|
||||
../../include/linux/sunrpc/xdrgen/nlm3.h: ../../Documentation/sunrpc/xdr/nlm3.x
|
||||
$(XDRGEN) definitions $< > $@
|
||||
|
||||
nlm4xdr_gen.h: ../../Documentation/sunrpc/xdr/nlm4.x
|
||||
$(XDRGEN) declarations $< > $@
|
||||
|
||||
nlm3xdr_gen.h: ../../Documentation/sunrpc/xdr/nlm3.x
|
||||
$(XDRGEN) declarations $< > $@
|
||||
|
||||
nlm4xdr_gen.c: ../../Documentation/sunrpc/xdr/nlm4.x
|
||||
$(XDRGEN) source --peer server $< > $@
|
||||
|
||||
nlm3xdr_gen.c: ../../Documentation/sunrpc/xdr/nlm3.x
|
||||
$(XDRGEN) source --peer server $< > $@
|
||||
|
||||
@@ -63,7 +63,7 @@ static s64 loff_t_to_s64(loff_t offset)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void nlm4_compute_offsets(const struct nlm_lock *lock,
|
||||
static void nlm4_compute_offsets(const struct lockd_lock *lock,
|
||||
u64 *l_offset, u64 *l_len)
|
||||
{
|
||||
const struct file_lock *fl = &lock->fl;
|
||||
@@ -132,13 +132,13 @@ static int decode_netobj(struct xdr_stream *xdr,
|
||||
* netobj cookie;
|
||||
*/
|
||||
static void encode_cookie(struct xdr_stream *xdr,
|
||||
const struct nlm_cookie *cookie)
|
||||
const struct lockd_cookie *cookie)
|
||||
{
|
||||
encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
|
||||
}
|
||||
|
||||
static int decode_cookie(struct xdr_stream *xdr,
|
||||
struct nlm_cookie *cookie)
|
||||
struct lockd_cookie *cookie)
|
||||
{
|
||||
u32 length;
|
||||
__be32 *p;
|
||||
@@ -238,9 +238,9 @@ static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat)
|
||||
* };
|
||||
*/
|
||||
static void encode_nlm4_holder(struct xdr_stream *xdr,
|
||||
const struct nlm_res *result)
|
||||
const struct lockd_res *result)
|
||||
{
|
||||
const struct nlm_lock *lock = &result->lock;
|
||||
const struct lockd_lock *lock = &result->lock;
|
||||
u64 l_offset, l_len;
|
||||
__be32 *p;
|
||||
|
||||
@@ -254,9 +254,9 @@ static void encode_nlm4_holder(struct xdr_stream *xdr,
|
||||
xdr_encode_hyper(p, l_len);
|
||||
}
|
||||
|
||||
static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result)
|
||||
static int decode_nlm4_holder(struct xdr_stream *xdr, struct lockd_res *result)
|
||||
{
|
||||
struct nlm_lock *lock = &result->lock;
|
||||
struct lockd_lock *lock = &result->lock;
|
||||
struct file_lock *fl = &lock->fl;
|
||||
u64 l_offset, l_len;
|
||||
u32 exclusive;
|
||||
@@ -317,7 +317,7 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name)
|
||||
* };
|
||||
*/
|
||||
static void encode_nlm4_lock(struct xdr_stream *xdr,
|
||||
const struct nlm_lock *lock)
|
||||
const struct lockd_lock *lock)
|
||||
{
|
||||
u64 l_offset, l_len;
|
||||
__be32 *p;
|
||||
@@ -354,8 +354,8 @@ static void nlm4_xdr_enc_testargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
|
||||
@@ -376,8 +376,8 @@ static void nlm4_xdr_enc_lockargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_bool(xdr, args->block);
|
||||
@@ -399,8 +399,8 @@ static void nlm4_xdr_enc_cancargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_bool(xdr, args->block);
|
||||
@@ -418,8 +418,8 @@ static void nlm4_xdr_enc_unlockargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_nlm4_lock(xdr, lock);
|
||||
@@ -435,7 +435,7 @@ static void nlm4_xdr_enc_res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_res *result = data;
|
||||
const struct lockd_res *result = data;
|
||||
|
||||
encode_cookie(xdr, &result->cookie);
|
||||
encode_nlm4_stat(xdr, result->status);
|
||||
@@ -458,7 +458,7 @@ static void nlm4_xdr_enc_testres(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_res *result = data;
|
||||
const struct lockd_res *result = data;
|
||||
|
||||
encode_cookie(xdr, &result->cookie);
|
||||
encode_nlm4_stat(xdr, result->status);
|
||||
@@ -489,7 +489,7 @@ static void nlm4_xdr_enc_testres(struct rpc_rqst *req,
|
||||
* };
|
||||
*/
|
||||
static int decode_nlm4_testrply(struct xdr_stream *xdr,
|
||||
struct nlm_res *result)
|
||||
struct lockd_res *result)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -506,7 +506,7 @@ static int nlm4_xdr_dec_testres(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct nlm_res *result = data;
|
||||
struct lockd_res *result = data;
|
||||
int error;
|
||||
|
||||
error = decode_cookie(xdr, &result->cookie);
|
||||
@@ -527,7 +527,7 @@ static int nlm4_xdr_dec_res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct nlm_res *result = data;
|
||||
struct lockd_res *result = data;
|
||||
int error;
|
||||
|
||||
error = decode_cookie(xdr, &result->cookie);
|
||||
|
||||
@@ -158,7 +158,7 @@ int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
|
||||
/*
|
||||
* The server lockd has called us back to tell us the lock was granted
|
||||
*/
|
||||
__be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
|
||||
__be32 nlmclnt_grant(const struct sockaddr *addr, const struct lockd_lock *lock)
|
||||
{
|
||||
const struct file_lock *fl = &lock->fl;
|
||||
const struct nfs_fh *fh = &lock->fh;
|
||||
|
||||
@@ -42,7 +42,7 @@ static const struct rpc_call_ops nlmclnt_cancel_ops;
|
||||
*/
|
||||
static atomic_t nlm_cookie = ATOMIC_INIT(0x1234);
|
||||
|
||||
void nlmclnt_next_cookie(struct nlm_cookie *c)
|
||||
void nlmclnt_next_cookie(struct lockd_cookie *c)
|
||||
{
|
||||
u32 cookie = atomic_inc_return(&nlm_cookie);
|
||||
|
||||
@@ -128,8 +128,8 @@ static struct nlm_lockowner *nlmclnt_find_lockowner(struct nlm_host *host, fl_ow
|
||||
*/
|
||||
static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
|
||||
{
|
||||
struct nlm_args *argp = &req->a_args;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
struct lockd_args *argp = &req->a_args;
|
||||
struct lockd_lock *lock = &argp->lock;
|
||||
char *nodename = req->a_host->h_rpcclnt->cl_nodename;
|
||||
|
||||
nlmclnt_next_cookie(&argp->cookie);
|
||||
@@ -266,8 +266,8 @@ nlmclnt_call(const struct cred *cred, struct nlm_rqst *req, u32 proc)
|
||||
{
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct rpc_clnt *clnt;
|
||||
struct nlm_args *argp = &req->a_args;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
struct lockd_args *argp = &req->a_args;
|
||||
struct lockd_res *resp = &req->a_res;
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = argp,
|
||||
.rpc_resp = resp,
|
||||
@@ -523,7 +523,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
{
|
||||
const struct cred *cred = nfs_file_cred(fl->c.flc_file);
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
struct lockd_res *resp = &req->a_res;
|
||||
struct nlm_wait block;
|
||||
unsigned char flags = fl->c.flc_flags;
|
||||
unsigned char type;
|
||||
@@ -686,7 +686,7 @@ static int
|
||||
nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
|
||||
{
|
||||
struct nlm_host *host = req->a_host;
|
||||
struct nlm_res *resp = &req->a_res;
|
||||
struct lockd_res *resp = &req->a_res;
|
||||
int status;
|
||||
unsigned char flags = fl->c.flc_flags;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ static s32 loff_t_to_s32(loff_t offset)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void nlm_compute_offsets(const struct nlm_lock *lock,
|
||||
static void nlm_compute_offsets(const struct lockd_lock *lock,
|
||||
u32 *l_offset, u32 *l_len)
|
||||
{
|
||||
const struct file_lock *fl = &lock->fl;
|
||||
@@ -130,13 +130,13 @@ static int decode_netobj(struct xdr_stream *xdr,
|
||||
* netobj cookie;
|
||||
*/
|
||||
static void encode_cookie(struct xdr_stream *xdr,
|
||||
const struct nlm_cookie *cookie)
|
||||
const struct lockd_cookie *cookie)
|
||||
{
|
||||
encode_netobj(xdr, (u8 *)&cookie->data, cookie->len);
|
||||
}
|
||||
|
||||
static int decode_cookie(struct xdr_stream *xdr,
|
||||
struct nlm_cookie *cookie)
|
||||
struct lockd_cookie *cookie)
|
||||
{
|
||||
u32 length;
|
||||
__be32 *p;
|
||||
@@ -234,9 +234,9 @@ static int decode_nlm_stat(struct xdr_stream *xdr,
|
||||
* };
|
||||
*/
|
||||
static void encode_nlm_holder(struct xdr_stream *xdr,
|
||||
const struct nlm_res *result)
|
||||
const struct lockd_res *result)
|
||||
{
|
||||
const struct nlm_lock *lock = &result->lock;
|
||||
const struct lockd_lock *lock = &result->lock;
|
||||
u32 l_offset, l_len;
|
||||
__be32 *p;
|
||||
|
||||
@@ -250,9 +250,9 @@ static void encode_nlm_holder(struct xdr_stream *xdr,
|
||||
*p = cpu_to_be32(l_len);
|
||||
}
|
||||
|
||||
static int decode_nlm_holder(struct xdr_stream *xdr, struct nlm_res *result)
|
||||
static int decode_nlm_holder(struct xdr_stream *xdr, struct lockd_res *result)
|
||||
{
|
||||
struct nlm_lock *lock = &result->lock;
|
||||
struct lockd_lock *lock = &result->lock;
|
||||
struct file_lock *fl = &lock->fl;
|
||||
u32 exclusive, l_offset, l_len;
|
||||
int error;
|
||||
@@ -319,7 +319,7 @@ static void encode_caller_name(struct xdr_stream *xdr, const char *name)
|
||||
* };
|
||||
*/
|
||||
static void encode_nlm_lock(struct xdr_stream *xdr,
|
||||
const struct nlm_lock *lock)
|
||||
const struct lockd_lock *lock)
|
||||
{
|
||||
u32 l_offset, l_len;
|
||||
__be32 *p;
|
||||
@@ -355,8 +355,8 @@ static void nlm_xdr_enc_testargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_bool(xdr, lock->fl.c.flc_type == F_WRLCK);
|
||||
@@ -377,8 +377,8 @@ static void nlm_xdr_enc_lockargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_bool(xdr, args->block);
|
||||
@@ -400,8 +400,8 @@ static void nlm_xdr_enc_cancargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_bool(xdr, args->block);
|
||||
@@ -419,8 +419,8 @@ static void nlm_xdr_enc_unlockargs(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_args *args = data;
|
||||
const struct nlm_lock *lock = &args->lock;
|
||||
const struct lockd_args *args = data;
|
||||
const struct lockd_lock *lock = &args->lock;
|
||||
|
||||
encode_cookie(xdr, &args->cookie);
|
||||
encode_nlm_lock(xdr, lock);
|
||||
@@ -436,7 +436,7 @@ static void nlm_xdr_enc_res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_res *result = data;
|
||||
const struct lockd_res *result = data;
|
||||
|
||||
encode_cookie(xdr, &result->cookie);
|
||||
encode_nlm_stat(xdr, result->status);
|
||||
@@ -456,7 +456,7 @@ static void nlm_xdr_enc_res(struct rpc_rqst *req,
|
||||
* };
|
||||
*/
|
||||
static void encode_nlm_testrply(struct xdr_stream *xdr,
|
||||
const struct nlm_res *result)
|
||||
const struct lockd_res *result)
|
||||
{
|
||||
if (result->status == nlm_lck_denied)
|
||||
encode_nlm_holder(xdr, result);
|
||||
@@ -466,7 +466,7 @@ static void nlm_xdr_enc_testres(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
const void *data)
|
||||
{
|
||||
const struct nlm_res *result = data;
|
||||
const struct lockd_res *result = data;
|
||||
|
||||
encode_cookie(xdr, &result->cookie);
|
||||
encode_nlm_stat(xdr, result->status);
|
||||
@@ -495,7 +495,7 @@ static void nlm_xdr_enc_testres(struct rpc_rqst *req,
|
||||
* };
|
||||
*/
|
||||
static int decode_nlm_testrply(struct xdr_stream *xdr,
|
||||
struct nlm_res *result)
|
||||
struct lockd_res *result)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -512,7 +512,7 @@ static int nlm_xdr_dec_testres(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct nlm_res *result = data;
|
||||
struct lockd_res *result = data;
|
||||
int error;
|
||||
|
||||
error = decode_cookie(xdr, &result->cookie);
|
||||
@@ -533,7 +533,7 @@ static int nlm_xdr_dec_res(struct rpc_rqst *req,
|
||||
struct xdr_stream *xdr,
|
||||
void *data)
|
||||
{
|
||||
struct nlm_res *result = data;
|
||||
struct lockd_res *result = data;
|
||||
int error;
|
||||
|
||||
error = decode_cookie(xdr, &result->cookie);
|
||||
|
||||
@@ -552,7 +552,7 @@ struct nlm_host * nlm_get_host(struct nlm_host *host)
|
||||
|
||||
static struct nlm_host *next_host_state(struct hlist_head *cache,
|
||||
struct nsm_handle *nsm,
|
||||
const struct nlm_reboot *info)
|
||||
const struct lockd_reboot *info)
|
||||
{
|
||||
struct nlm_host *host;
|
||||
struct hlist_head *chain;
|
||||
@@ -582,7 +582,7 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
|
||||
* We were notified that the specified host has rebooted. Release
|
||||
* all resources held by that peer.
|
||||
*/
|
||||
void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
|
||||
void nlm_host_rebooted(const struct net *net, const struct lockd_reboot *info)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
struct nlm_host *host;
|
||||
|
||||
@@ -52,6 +52,14 @@
|
||||
*/
|
||||
#define LOCKD_DFLT_TIMEO 10
|
||||
|
||||
/*
|
||||
* Number of leading bytes of nfs_fh.data that file_hash()
|
||||
* digests when bucketing nlm_files[]. Sized for historical
|
||||
* NFSv2 handles; nfs_fh.data must be initialized at least
|
||||
* this far before lookup, regardless of fh.size.
|
||||
*/
|
||||
#define LOCKD_FH_HASH_SIZE 32
|
||||
|
||||
/* error codes new to NLMv4 */
|
||||
#define nlm4_deadlock cpu_to_be32(NLM_DEADLCK)
|
||||
#define nlm4_rofs cpu_to_be32(NLM_ROFS)
|
||||
@@ -171,15 +179,15 @@ struct nlm_rqst {
|
||||
refcount_t a_count;
|
||||
unsigned int a_flags; /* initial RPC task flags */
|
||||
struct nlm_host * a_host; /* host handle */
|
||||
struct nlm_args a_args; /* arguments */
|
||||
struct nlm_res a_res; /* result */
|
||||
struct lockd_args a_args; /* arguments */
|
||||
struct lockd_res a_res; /* result */
|
||||
struct nlm_block * a_block;
|
||||
unsigned int a_retries; /* Retry count */
|
||||
u8 a_owner[NLMCLNT_OHSIZE];
|
||||
void * a_callback_data; /* sent to nlmclnt_operations callbacks */
|
||||
};
|
||||
|
||||
struct nlm_share;
|
||||
struct lockd_share;
|
||||
|
||||
/*
|
||||
* This struct describes a file held open by lockd on behalf of
|
||||
@@ -190,7 +198,7 @@ struct nlm_file {
|
||||
struct nfs_fh f_handle; /* NFS file handle */
|
||||
struct file * f_file[2]; /* VFS file pointers,
|
||||
indexed by O_ flags */
|
||||
struct nlm_share * f_shares; /* DOS shares */
|
||||
struct lockd_share * f_shares; /* DOS shares */
|
||||
struct list_head f_blocks; /* blocked locks */
|
||||
unsigned int f_locks; /* guesstimate # of locks */
|
||||
unsigned int f_count; /* reference count */
|
||||
@@ -253,11 +261,11 @@ void nlmclnt_queue_block(struct nlm_wait *block);
|
||||
__be32 nlmclnt_dequeue_block(struct nlm_wait *block);
|
||||
int nlmclnt_wait(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
|
||||
__be32 nlmclnt_grant(const struct sockaddr *addr,
|
||||
const struct nlm_lock *lock);
|
||||
const struct lockd_lock *lock);
|
||||
void nlmclnt_recovery(struct nlm_host *);
|
||||
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *,
|
||||
struct nlm_rqst *);
|
||||
void nlmclnt_next_cookie(struct nlm_cookie *);
|
||||
void nlmclnt_next_cookie(struct lockd_cookie *);
|
||||
|
||||
#ifdef CONFIG_LOCKD_V4
|
||||
extern const struct rpc_version nlm_version4;
|
||||
@@ -285,7 +293,7 @@ struct nlm_host * nlm_get_host(struct nlm_host *);
|
||||
void nlm_shutdown_hosts(void);
|
||||
void nlm_shutdown_hosts_net(struct net *net);
|
||||
void nlm_host_rebooted(const struct net *net,
|
||||
const struct nlm_reboot *);
|
||||
const struct lockd_reboot *);
|
||||
|
||||
/*
|
||||
* Host monitoring
|
||||
@@ -299,7 +307,7 @@ struct nsm_handle *nsm_get_handle(const struct net *net,
|
||||
const char *hostname,
|
||||
const size_t hostname_len);
|
||||
struct nsm_handle *nsm_reboot_lookup(const struct net *net,
|
||||
const struct nlm_reboot *info);
|
||||
const struct lockd_reboot *info);
|
||||
void nsm_release(struct nsm_handle *nsm);
|
||||
|
||||
/*
|
||||
@@ -313,17 +321,17 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
|
||||
*/
|
||||
int lock_to_openmode(struct file_lock *);
|
||||
__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
|
||||
struct nlm_host *, struct nlm_lock *, int,
|
||||
struct nlm_cookie *, int);
|
||||
__be32 nlmsvc_unlock(struct net *net, struct nlm_file *, struct nlm_lock *);
|
||||
struct nlm_host *, struct lockd_lock *, int,
|
||||
struct lockd_cookie *, int);
|
||||
__be32 nlmsvc_unlock(struct net *net, struct nlm_file *, struct lockd_lock *);
|
||||
__be32 nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||
struct nlm_host *host, struct nlm_lock *lock,
|
||||
struct nlm_lock *conflock);
|
||||
__be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *);
|
||||
struct nlm_host *host, struct lockd_lock *lock,
|
||||
struct lockd_lock *conflock);
|
||||
__be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct lockd_lock *);
|
||||
void nlmsvc_retry_blocked(struct svc_rqst *rqstp);
|
||||
void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
|
||||
nlm_host_match_fn_t match);
|
||||
void nlmsvc_grant_reply(struct nlm_cookie *, __be32);
|
||||
void nlmsvc_grant_reply(struct lockd_cookie *, __be32);
|
||||
void nlmsvc_release_call(struct nlm_rqst *);
|
||||
void nlmsvc_locks_init_private(struct file_lock *, struct nlm_host *, pid_t);
|
||||
int nlmsvc_dispatch(struct svc_rqst *rqstp);
|
||||
@@ -332,10 +340,10 @@ int nlmsvc_dispatch(struct svc_rqst *rqstp);
|
||||
* File handling for the server personality
|
||||
*/
|
||||
__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
|
||||
struct nlm_lock *, int);
|
||||
struct lockd_lock *, int);
|
||||
void nlm_release_file(struct nlm_file *);
|
||||
void nlmsvc_put_lockowner(struct nlm_lockowner *);
|
||||
void nlmsvc_release_lockowner(struct nlm_lock *);
|
||||
void nlmsvc_release_lockowner(struct lockd_lock *);
|
||||
void nlmsvc_mark_resources(struct net *);
|
||||
void nlmsvc_free_host_resources(struct nlm_host *);
|
||||
void nlmsvc_invalidate_all(void);
|
||||
@@ -422,6 +430,29 @@ static inline int nlm_compare_locks(const struct file_lock *fl1,
|
||||
&&(fl1->c.flc_type == fl2->c.flc_type || fl2->c.flc_type == F_UNLCK);
|
||||
}
|
||||
|
||||
/**
|
||||
* lockd_set_file_lock_range3 - set the byte range of a file_lock
|
||||
* @fl: file_lock whose length fields are to be initialized
|
||||
* @off: starting offset of the lock, in bytes
|
||||
* @len: length of the byte range, in bytes, or zero
|
||||
*
|
||||
* NLMv3 uses a (start, length) representation for lock byte ranges,
|
||||
* while the kernel's file_lock uses (start, end). Treat a length of
|
||||
* zero or arithmetic overflow (end wrapping negative when the sum
|
||||
* exceeds S32_MAX) as "lock to end of file."
|
||||
*/
|
||||
static inline void
|
||||
lockd_set_file_lock_range3(struct file_lock *fl, u32 off, u32 len)
|
||||
{
|
||||
s32 end = off + len - 1;
|
||||
|
||||
fl->fl_start = off;
|
||||
if (len == 0 || end < 0)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
else
|
||||
fl->fl_end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* lockd_set_file_lock_range4 - set the byte range of a file_lock
|
||||
* @fl: file_lock whose length fields are to be initialized
|
||||
|
||||
@@ -377,7 +377,7 @@ struct nsm_handle *nsm_get_handle(const struct net *net,
|
||||
* error occurred.
|
||||
*/
|
||||
struct nsm_handle *nsm_reboot_lookup(const struct net *net,
|
||||
const struct nlm_reboot *info)
|
||||
const struct lockd_reboot *info)
|
||||
{
|
||||
struct nsm_handle *cached;
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
|
||||
714
fs/lockd/nlm3xdr_gen.c
Normal file
714
fs/lockd/nlm3xdr_gen.c
Normal file
@@ -0,0 +1,714 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Generated by xdrgen. Manual edits will be lost.
|
||||
// XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x
|
||||
// XDR specification modification time: Thu Apr 23 10:56:34 2026
|
||||
|
||||
#include <linux/sunrpc/svc.h>
|
||||
|
||||
#include "nlm3xdr_gen.h"
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_netobj(struct xdr_stream *xdr, netobj *ptr)
|
||||
{
|
||||
return xdrgen_decode_opaque(xdr, ptr, MAXNETOBJ_SZ);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_stats(struct xdr_stream *xdr, nlm_stats *ptr)
|
||||
{
|
||||
__be32 raw;
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_be32(xdr, &raw) < 0)
|
||||
return false;
|
||||
val = be32_to_cpu(raw);
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case LCK_GRANTED:
|
||||
case LCK_DENIED:
|
||||
case LCK_DENIED_NOLOCKS:
|
||||
case LCK_BLOCKED:
|
||||
case LCK_DENIED_GRACE_PERIOD:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = raw;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_stat(struct xdr_stream *xdr, struct nlm_stat *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_nlm_stats(xdr, &ptr->stat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_res(struct xdr_stream *xdr, struct nlm_res *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_stat(xdr, &ptr->stat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_holder(struct xdr_stream *xdr, struct nlm_holder *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_decode_int(xdr, &ptr->uppid))
|
||||
return false;
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->oh))
|
||||
return false;
|
||||
if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_offset))
|
||||
return false;
|
||||
if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_len))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_testrply(struct xdr_stream *xdr, struct nlm_testrply *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_nlm_stats(xdr, &ptr->stat))
|
||||
return false;
|
||||
switch (ptr->stat) {
|
||||
case __constant_cpu_to_be32(LCK_DENIED):
|
||||
if (!xdrgen_decode_nlm_holder(xdr, &ptr->u.holder))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_testres(struct xdr_stream *xdr, struct nlm_testres *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_testrply(xdr, &ptr->test_stat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_lock(struct xdr_stream *xdr, struct nlm_lock *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN))
|
||||
return false;
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->fh))
|
||||
return false;
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->oh))
|
||||
return false;
|
||||
if (!xdrgen_decode_int(xdr, &ptr->uppid))
|
||||
return false;
|
||||
if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_offset))
|
||||
return false;
|
||||
if (!xdrgen_decode_unsigned_int(xdr, &ptr->l_len))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_lockargs(struct xdr_stream *xdr, struct nlm_lockargs *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->block))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->reclaim))
|
||||
return false;
|
||||
if (!xdrgen_decode_int(xdr, &ptr->state))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_cancargs(struct xdr_stream *xdr, struct nlm_cancargs *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->block))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_testargs(struct xdr_stream *xdr, struct nlm_testargs *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_unlockargs(struct xdr_stream *xdr, struct nlm_unlockargs *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_lock(xdr, &ptr->alock))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fsh_mode(struct xdr_stream *xdr, fsh_mode *ptr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case fsm_DN:
|
||||
case fsm_DR:
|
||||
case fsm_DW:
|
||||
case fsm_DRW:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_fsh_access(struct xdr_stream *xdr, fsh_access *ptr)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &val) < 0)
|
||||
return false;
|
||||
/* Compiler may optimize to a range check for dense enums */
|
||||
switch (val) {
|
||||
case fsa_NONE:
|
||||
case fsa_R:
|
||||
case fsa_W:
|
||||
case fsa_RW:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
*ptr = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_share(struct xdr_stream *xdr, struct nlm_share *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXSTRLEN))
|
||||
return false;
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->fh))
|
||||
return false;
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->oh))
|
||||
return false;
|
||||
if (!xdrgen_decode_fsh_mode(xdr, &ptr->mode))
|
||||
return false;
|
||||
if (!xdrgen_decode_fsh_access(xdr, &ptr->access))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_shareargs(struct xdr_stream *xdr, struct nlm_shareargs *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_share(xdr, &ptr->share))
|
||||
return false;
|
||||
if (!xdrgen_decode_bool(xdr, &ptr->reclaim))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_shareres(struct xdr_stream *xdr, struct nlm_shareres *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_netobj(xdr, &ptr->cookie))
|
||||
return false;
|
||||
if (!xdrgen_decode_nlm_stats(xdr, &ptr->stat))
|
||||
return false;
|
||||
if (!xdrgen_decode_int(xdr, &ptr->sequence))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_notify(struct xdr_stream *xdr, struct nlm_notify *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_string(xdr, (string *)ptr, LM_MAXNAMELEN))
|
||||
return false;
|
||||
if (!xdrgen_decode_long(xdr, &ptr->state))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_decode_nlm_notifyargs(struct xdr_stream *xdr, struct nlm_notifyargs *ptr)
|
||||
{
|
||||
if (!xdrgen_decode_nlm_notify(xdr, &ptr->notify))
|
||||
return false;
|
||||
if (xdr_stream_decode_opaque_fixed(xdr, ptr->private, SM_PRIV_SIZE) < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_void - Decode a void argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
return xdrgen_decode_void(xdr);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_testargs - Decode a nlm_testargs argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_testargs *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_testargs(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_lockargs - Decode a nlm_lockargs argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_lockargs *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_lockargs(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_cancargs - Decode a nlm_cancargs argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_cancargs *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_cancargs(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_unlockargs - Decode a nlm_unlockargs argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_unlockargs *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_unlockargs(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_testres - Decode a nlm_testres argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_testres *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_testres(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_res - Decode a nlm_res argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_res *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_res(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_notifyargs - Decode a nlm_notifyargs argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_notifyargs *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_notifyargs(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_shareargs - Decode a nlm_shareargs argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_shareargs *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_shareargs(xdr, argp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_decode_nlm_notify - Decode a nlm_notify argument
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: source XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure arguments decoded successfully
|
||||
* %false: decode failed
|
||||
*/
|
||||
bool nlm_svc_decode_nlm_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_notify *argp = rqstp->rq_argp;
|
||||
|
||||
return xdrgen_decode_nlm_notify(xdr, argp);
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_netobj(struct xdr_stream *xdr, const netobj value)
|
||||
{
|
||||
return xdr_stream_encode_opaque(xdr, value.data, value.len) >= 0;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_stats(struct xdr_stream *xdr, nlm_stats value)
|
||||
{
|
||||
return xdr_stream_encode_be32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_stat(struct xdr_stream *xdr, const struct nlm_stat *value)
|
||||
{
|
||||
if (!xdrgen_encode_nlm_stats(xdr, value->stat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_res(struct xdr_stream *xdr, const struct nlm_res *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_stat(xdr, &value->stat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_holder(struct xdr_stream *xdr, const struct nlm_holder *value)
|
||||
{
|
||||
if (!xdrgen_encode_bool(xdr, value->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_encode_int(xdr, value->uppid))
|
||||
return false;
|
||||
if (!xdrgen_encode_netobj(xdr, value->oh))
|
||||
return false;
|
||||
if (!xdrgen_encode_unsigned_int(xdr, value->l_offset))
|
||||
return false;
|
||||
if (!xdrgen_encode_unsigned_int(xdr, value->l_len))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_testrply(struct xdr_stream *xdr, const struct nlm_testrply *ptr)
|
||||
{
|
||||
if (!xdrgen_encode_nlm_stats(xdr, ptr->stat))
|
||||
return false;
|
||||
switch (ptr->stat) {
|
||||
case __constant_cpu_to_be32(LCK_DENIED):
|
||||
if (!xdrgen_encode_nlm_holder(xdr, &ptr->u.holder))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_testres(struct xdr_stream *xdr, const struct nlm_testres *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_testrply(xdr, &value->test_stat))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_lock(struct xdr_stream *xdr, const struct nlm_lock *value)
|
||||
{
|
||||
if (value->caller_name.len > LM_MAXSTRLEN)
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0)
|
||||
return false;
|
||||
if (!xdrgen_encode_netobj(xdr, value->fh))
|
||||
return false;
|
||||
if (!xdrgen_encode_netobj(xdr, value->oh))
|
||||
return false;
|
||||
if (!xdrgen_encode_int(xdr, value->uppid))
|
||||
return false;
|
||||
if (!xdrgen_encode_unsigned_int(xdr, value->l_offset))
|
||||
return false;
|
||||
if (!xdrgen_encode_unsigned_int(xdr, value->l_len))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_lockargs(struct xdr_stream *xdr, const struct nlm_lockargs *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->block))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_lock(xdr, &value->alock))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->reclaim))
|
||||
return false;
|
||||
if (!xdrgen_encode_int(xdr, value->state))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_cancargs(struct xdr_stream *xdr, const struct nlm_cancargs *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->block))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_lock(xdr, &value->alock))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_testargs(struct xdr_stream *xdr, const struct nlm_testargs *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->exclusive))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_lock(xdr, &value->alock))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_unlockargs(struct xdr_stream *xdr, const struct nlm_unlockargs *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_lock(xdr, &value->alock))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fsh_mode(struct xdr_stream *xdr, fsh_mode value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_fsh_access(struct xdr_stream *xdr, fsh_access value)
|
||||
{
|
||||
return xdr_stream_encode_u32(xdr, value) == XDR_UNIT;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_share(struct xdr_stream *xdr, const struct nlm_share *value)
|
||||
{
|
||||
if (value->caller_name.len > LM_MAXSTRLEN)
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->caller_name.data, value->caller_name.len) < 0)
|
||||
return false;
|
||||
if (!xdrgen_encode_netobj(xdr, value->fh))
|
||||
return false;
|
||||
if (!xdrgen_encode_netobj(xdr, value->oh))
|
||||
return false;
|
||||
if (!xdrgen_encode_fsh_mode(xdr, value->mode))
|
||||
return false;
|
||||
if (!xdrgen_encode_fsh_access(xdr, value->access))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_shareargs(struct xdr_stream *xdr, const struct nlm_shareargs *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_share(xdr, &value->share))
|
||||
return false;
|
||||
if (!xdrgen_encode_bool(xdr, value->reclaim))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_shareres(struct xdr_stream *xdr, const struct nlm_shareres *value)
|
||||
{
|
||||
if (!xdrgen_encode_netobj(xdr, value->cookie))
|
||||
return false;
|
||||
if (!xdrgen_encode_nlm_stats(xdr, value->stat))
|
||||
return false;
|
||||
if (!xdrgen_encode_int(xdr, value->sequence))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_notify(struct xdr_stream *xdr, const struct nlm_notify *value)
|
||||
{
|
||||
if (value->name.len > LM_MAXNAMELEN)
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque(xdr, value->name.data, value->name.len) < 0)
|
||||
return false;
|
||||
if (!xdrgen_encode_long(xdr, value->state))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __maybe_unused
|
||||
xdrgen_encode_nlm_notifyargs(struct xdr_stream *xdr, const struct nlm_notifyargs *value)
|
||||
{
|
||||
if (!xdrgen_encode_nlm_notify(xdr, &value->notify))
|
||||
return false;
|
||||
if (xdr_stream_encode_opaque_fixed(xdr, value->private, SM_PRIV_SIZE) < 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_encode_void - Encode a void result
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: target XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure results encoded successfully
|
||||
* %false: encode failed
|
||||
*/
|
||||
bool nlm_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
return xdrgen_encode_void(xdr);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_encode_nlm_testres - Encode a nlm_testres result
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: target XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure results encoded successfully
|
||||
* %false: encode failed
|
||||
*/
|
||||
bool nlm_svc_encode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_testres *resp = rqstp->rq_resp;
|
||||
|
||||
return xdrgen_encode_nlm_testres(xdr, resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_encode_nlm_res - Encode a nlm_res result
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: target XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure results encoded successfully
|
||||
* %false: encode failed
|
||||
*/
|
||||
bool nlm_svc_encode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return xdrgen_encode_nlm_res(xdr, resp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nlm_svc_encode_nlm_shareres - Encode a nlm_shareres result
|
||||
* @rqstp: RPC transaction context
|
||||
* @xdr: target XDR data stream
|
||||
*
|
||||
* Return values:
|
||||
* %true: procedure results encoded successfully
|
||||
* %false: encode failed
|
||||
*/
|
||||
bool nlm_svc_encode_nlm_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_shareres *resp = rqstp->rq_resp;
|
||||
|
||||
return xdrgen_encode_nlm_shareres(xdr, resp);
|
||||
}
|
||||
32
fs/lockd/nlm3xdr_gen.h
Normal file
32
fs/lockd/nlm3xdr_gen.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x */
|
||||
/* XDR specification modification time: Thu Apr 23 10:56:34 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NLM3_DECL_H
|
||||
#define _LINUX_XDRGEN_NLM3_DECL_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/xdrgen/_defs.h>
|
||||
#include <linux/sunrpc/xdrgen/_builtins.h>
|
||||
#include <linux/sunrpc/xdrgen/nlm3.h>
|
||||
|
||||
bool nlm_svc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_notifyargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_decode_nlm_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
|
||||
bool nlm_svc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_encode_nlm_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_encode_nlm_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlm_svc_encode_nlm_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
|
||||
#endif /* _LINUX_XDRGEN_NLM3_DECL_H */
|
||||
@@ -14,8 +14,8 @@
|
||||
/*
|
||||
* DOS share for a specific file
|
||||
*/
|
||||
struct nlm_share {
|
||||
struct nlm_share * s_next; /* linked list */
|
||||
struct lockd_share {
|
||||
struct lockd_share * s_next; /* linked list */
|
||||
struct nlm_host * s_host; /* client host */
|
||||
struct nlm_file * s_file; /* shared file */
|
||||
struct xdr_netobj s_owner; /* owner handle */
|
||||
|
||||
@@ -26,42 +26,42 @@
|
||||
#include "nlm4xdr_gen.h"
|
||||
|
||||
/*
|
||||
* Wrapper structures combine xdrgen types with legacy nlm_lock.
|
||||
* Wrapper structures combine xdrgen types with legacy lockd_lock.
|
||||
* The xdrgen field must be first so the structure can be cast
|
||||
* to its XDR type for the RPC dispatch layer.
|
||||
*/
|
||||
struct nlm4_testargs_wrapper {
|
||||
struct nlm4_testargs xdrgen;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_testargs_wrapper, xdrgen) == 0);
|
||||
|
||||
struct nlm4_lockargs_wrapper {
|
||||
struct nlm4_lockargs xdrgen;
|
||||
struct nlm_cookie cookie;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_cookie cookie;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_lockargs_wrapper, xdrgen) == 0);
|
||||
|
||||
struct nlm4_cancargs_wrapper {
|
||||
struct nlm4_cancargs xdrgen;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_cancargs_wrapper, xdrgen) == 0);
|
||||
|
||||
struct nlm4_unlockargs_wrapper {
|
||||
struct nlm4_unlockargs xdrgen;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_unlockargs_wrapper, xdrgen) == 0);
|
||||
|
||||
struct nlm4_notifyargs_wrapper {
|
||||
struct nlm4_notifyargs xdrgen;
|
||||
struct nlm_reboot reboot;
|
||||
struct lockd_reboot reboot;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_notifyargs_wrapper, xdrgen) == 0);
|
||||
@@ -74,12 +74,12 @@ static_assert(offsetof(struct nlm4_notify_wrapper, xdrgen) == 0);
|
||||
|
||||
struct nlm4_testres_wrapper {
|
||||
struct nlm4_testres xdrgen;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
struct nlm4_shareargs_wrapper {
|
||||
struct nlm4_shareargs xdrgen;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_shareargs_wrapper, xdrgen) == 0);
|
||||
@@ -88,7 +88,7 @@ static_assert(offsetof(struct nlm4_testres_wrapper, xdrgen) == 0);
|
||||
|
||||
struct nlm4_res_wrapper {
|
||||
struct nlm4_res xdrgen;
|
||||
struct nlm_cookie cookie;
|
||||
struct lockd_cookie cookie;
|
||||
};
|
||||
|
||||
static_assert(offsetof(struct nlm4_res_wrapper, xdrgen) == 0);
|
||||
@@ -100,7 +100,7 @@ struct nlm4_shareres_wrapper {
|
||||
static_assert(offsetof(struct nlm4_shareres_wrapper, xdrgen) == 0);
|
||||
|
||||
static __be32
|
||||
nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
|
||||
nlm4_netobj_to_cookie(struct lockd_cookie *cookie, netobj *object)
|
||||
{
|
||||
if (object->len > NLM_MAXCOOKIELEN)
|
||||
return nlm_lck_denied_nolocks;
|
||||
@@ -110,7 +110,7 @@ nlm4_netobj_to_cookie(struct nlm_cookie *cookie, netobj *object)
|
||||
}
|
||||
|
||||
static __be32
|
||||
nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock)
|
||||
nlm4_lock_to_lockd_lock(struct lockd_lock *lock, struct nlm4_lock *alock)
|
||||
{
|
||||
if (alock->fh.len > NFS_MAXFHSIZE)
|
||||
return nlm_lck_denied;
|
||||
@@ -119,7 +119,6 @@ nlm4_lock_to_nlm_lock(struct nlm_lock *lock, struct nlm4_lock *alock)
|
||||
lock->oh.len = alock->oh.len;
|
||||
lock->oh.data = alock->oh.data;
|
||||
lock->svid = alock->svid;
|
||||
locks_init_lock(&lock->fl);
|
||||
lockd_set_file_lock_range4(&lock->fl, alock->l_offset, alock->l_len);
|
||||
return nlm_granted;
|
||||
}
|
||||
@@ -143,7 +142,7 @@ nlm4svc_lookup_host(struct svc_rqst *rqstp, string caller, bool monitored)
|
||||
|
||||
static __be32
|
||||
nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
||||
struct nlm_lock *lock, struct nlm_file **filp,
|
||||
struct lockd_lock *lock, struct nlm_file **filp,
|
||||
struct nlm4_lock *xdr_lock, unsigned char type)
|
||||
{
|
||||
bool is_test = (rqstp->rq_proc == NLMPROC4_TEST ||
|
||||
@@ -157,6 +156,9 @@ nlm4svc_lookup_file(struct svc_rqst *rqstp, struct nlm_host *host,
|
||||
return nlm_lck_denied_nolocks;
|
||||
lock->fh.size = xdr_lock->fh.len;
|
||||
memcpy(lock->fh.data, xdr_lock->fh.data, xdr_lock->fh.len);
|
||||
if (xdr_lock->fh.len < LOCKD_FH_HASH_SIZE)
|
||||
memset(lock->fh.data + xdr_lock->fh.len, 0,
|
||||
LOCKD_FH_HASH_SIZE - xdr_lock->fh.len);
|
||||
|
||||
lock->oh.len = xdr_lock->oh.len;
|
||||
lock->oh.data = xdr_lock->oh.data;
|
||||
@@ -270,7 +272,7 @@ static __be32 nlm4svc_proc_test(struct svc_rqst *rqstp)
|
||||
nlmsvc_release_lockowner(&argp->lock);
|
||||
|
||||
if (resp->xdrgen.stat.stat == nlm_lck_denied) {
|
||||
struct nlm_lock *conf = &resp->lock;
|
||||
struct lockd_lock *conf = &resp->lock;
|
||||
struct nlm4_holder *holder = &resp->xdrgen.stat.u.holder;
|
||||
|
||||
holder->exclusive = (conf->fl.c.flc_type != F_RDLCK);
|
||||
@@ -513,12 +515,12 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp)
|
||||
* nlm4_res NLMPROC4_GRANTED(nlm4_testargs) = 5;
|
||||
*
|
||||
* Permissible procedure status codes:
|
||||
* %NLM4_GRANTED: The requested lock was granted.
|
||||
* %NLM4_DENIED: The server could not allocate the resources
|
||||
* needed to process the request.
|
||||
* %NLM4_DENIED_GRACE_PERIOD: The server has recently restarted and is
|
||||
* re-establishing existing locks, and is not
|
||||
* yet ready to accept normal service requests.
|
||||
* %NLM4_GRANTED: The granted lock was accepted.
|
||||
* %NLM4_DENIED: The procedure failed, possibly due to
|
||||
* internal resource constraints.
|
||||
* %NLM4_DENIED_GRACE_PERIOD: The client host recently restarted and
|
||||
* its NLM is re-establishing existing locks,
|
||||
* so it is not yet ready to accept callbacks.
|
||||
*/
|
||||
static __be32
|
||||
nlm4svc_proc_granted(struct svc_rqst *rqstp)
|
||||
@@ -528,8 +530,8 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp)
|
||||
|
||||
resp->xdrgen.cookie = argp->xdrgen.cookie;
|
||||
|
||||
resp->xdrgen.stat.stat = nlm4_lock_to_nlm_lock(&argp->lock,
|
||||
&argp->xdrgen.alock);
|
||||
resp->xdrgen.stat.stat = nlm4_lock_to_lockd_lock(&argp->lock,
|
||||
&argp->xdrgen.alock);
|
||||
if (resp->xdrgen.stat.stat)
|
||||
goto out;
|
||||
|
||||
@@ -563,7 +565,7 @@ static const struct rpc_call_ops nlm4svc_callback_ops = {
|
||||
*/
|
||||
static __be32
|
||||
nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc,
|
||||
__be32 (*func)(struct svc_rqst *, struct nlm_res *))
|
||||
__be32 (*func)(struct svc_rqst *, struct lockd_res *))
|
||||
{
|
||||
struct nlm_rqst *call;
|
||||
__be32 stat;
|
||||
@@ -586,7 +588,7 @@ nlm4svc_callback(struct svc_rqst *rqstp, struct nlm_host *host, u32 proc,
|
||||
}
|
||||
|
||||
static __be32
|
||||
__nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
__nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct lockd_res *resp)
|
||||
{
|
||||
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
||||
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
||||
@@ -646,7 +648,7 @@ static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
static __be32
|
||||
__nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
__nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct lockd_res *resp)
|
||||
{
|
||||
struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
|
||||
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
||||
@@ -669,6 +671,8 @@ __nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
resp->status = nlmsvc_lock(rqstp, file, host, &argp->lock,
|
||||
argp->xdrgen.block, &resp->cookie,
|
||||
argp->xdrgen.reclaim);
|
||||
if (resp->status == nlm__int__deadlock)
|
||||
resp->status = nlm4_deadlock;
|
||||
nlmsvc_release_lockowner(&argp->lock);
|
||||
|
||||
out:
|
||||
@@ -697,7 +701,7 @@ static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
|
||||
struct nlm4_lockargs_wrapper *argp = rqstp->rq_argp;
|
||||
struct nlm_host *host;
|
||||
|
||||
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, true);
|
||||
host = nlm4svc_lookup_host(rqstp, argp->xdrgen.alock.caller_name, false);
|
||||
if (!host)
|
||||
return rpc_system_err;
|
||||
|
||||
@@ -706,7 +710,7 @@ static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
static __be32
|
||||
__nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
__nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct lockd_res *resp)
|
||||
{
|
||||
struct nlm4_cancargs_wrapper *argp = rqstp->rq_argp;
|
||||
unsigned char type = argp->xdrgen.exclusive ? F_WRLCK : F_RDLCK;
|
||||
@@ -770,7 +774,7 @@ static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
static __be32
|
||||
__nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
__nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct lockd_res *resp)
|
||||
{
|
||||
struct nlm4_unlockargs_wrapper *argp = rqstp->rq_argp;
|
||||
struct net *net = SVC_NET(rqstp);
|
||||
@@ -833,7 +837,7 @@ static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
static __be32
|
||||
__nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
__nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct lockd_res *resp)
|
||||
{
|
||||
struct nlm4_testargs_wrapper *argp = rqstp->rq_argp;
|
||||
|
||||
@@ -841,7 +845,7 @@ __nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_res *resp)
|
||||
if (nlm4_netobj_to_cookie(&resp->cookie, &argp->xdrgen.cookie))
|
||||
goto out;
|
||||
|
||||
if (nlm4_lock_to_nlm_lock(&argp->lock, &argp->xdrgen.alock))
|
||||
if (nlm4_lock_to_lockd_lock(&argp->lock, &argp->xdrgen.alock))
|
||||
goto out;
|
||||
|
||||
resp->status = nlmclnt_grant(svc_addr(rqstp), &argp->lock);
|
||||
@@ -917,7 +921,7 @@ static __be32 nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
|
||||
static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nlm4_notifyargs_wrapper *argp = rqstp->rq_argp;
|
||||
struct nlm_reboot *reboot = &argp->reboot;
|
||||
struct lockd_reboot *reboot = &argp->reboot;
|
||||
|
||||
if (!nlm_privileged_requester(rqstp)) {
|
||||
char buf[RPC_MAX_ADDRBUFLEN];
|
||||
@@ -981,7 +985,7 @@ static __be32 nlm4svc_proc_share(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
|
||||
struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
struct lockd_lock *lock = &argp->lock;
|
||||
struct nlm_host *host = NULL;
|
||||
struct nlm_file *file = NULL;
|
||||
struct nlm4_lock xdr_lock = {
|
||||
@@ -1049,7 +1053,7 @@ static __be32 nlm4svc_proc_unshare(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nlm4_shareargs_wrapper *argp = rqstp->rq_argp;
|
||||
struct nlm4_shareres_wrapper *resp = rqstp->rq_resp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
struct lockd_lock *lock = &argp->lock;
|
||||
struct nlm4_lock xdr_lock = {
|
||||
.fh = argp->xdrgen.share.fh,
|
||||
.oh = argp->xdrgen.share.oh,
|
||||
|
||||
@@ -37,7 +37,7 @@ static void nlmsvc_release_block(struct nlm_block *block);
|
||||
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
|
||||
static void nlmsvc_remove_block(struct nlm_block *block);
|
||||
|
||||
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
|
||||
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct lockd_lock *lock);
|
||||
static void nlmsvc_freegrantargs(struct nlm_rqst *call);
|
||||
static const struct rpc_call_ops nlmsvc_grant_ops;
|
||||
|
||||
@@ -48,7 +48,7 @@ static LIST_HEAD(nlm_blocked);
|
||||
static DEFINE_SPINLOCK(nlm_blocked_lock);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
|
||||
static const char *nlmdbg_cookie2a(const struct lockd_cookie *cookie)
|
||||
{
|
||||
/*
|
||||
* We can get away with a static buffer because this is only called
|
||||
@@ -75,7 +75,7 @@ static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
|
||||
return buf;
|
||||
}
|
||||
#else
|
||||
static inline const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
|
||||
static inline const char *nlmdbg_cookie2a(const struct lockd_cookie *cookie)
|
||||
{
|
||||
return "???";
|
||||
}
|
||||
@@ -142,7 +142,7 @@ nlmsvc_remove_block(struct nlm_block *block)
|
||||
* Find a block for a given lock
|
||||
*/
|
||||
static struct nlm_block *
|
||||
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
|
||||
nlmsvc_lookup_block(struct nlm_file *file, struct lockd_lock *lock)
|
||||
{
|
||||
struct nlm_block *block;
|
||||
struct file_lock *fl;
|
||||
@@ -171,7 +171,7 @@ nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
|
||||
static int lockd_cookie_match(struct lockd_cookie *a, struct lockd_cookie *b)
|
||||
{
|
||||
if (a->len != b->len)
|
||||
return 0;
|
||||
@@ -184,13 +184,13 @@ static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
|
||||
* Find a block with a given NLM cookie.
|
||||
*/
|
||||
static inline struct nlm_block *
|
||||
nlmsvc_find_block(struct nlm_cookie *cookie)
|
||||
nlmsvc_find_block(struct lockd_cookie *cookie)
|
||||
{
|
||||
struct nlm_block *block;
|
||||
|
||||
spin_lock(&nlm_blocked_lock);
|
||||
list_for_each_entry(block, &nlm_blocked, b_list) {
|
||||
if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
|
||||
if (lockd_cookie_match(&block->b_call->a_args.cookie, cookie))
|
||||
goto found;
|
||||
}
|
||||
spin_unlock(&nlm_blocked_lock);
|
||||
@@ -221,8 +221,8 @@ nlmsvc_find_block(struct nlm_cookie *cookie)
|
||||
*/
|
||||
static struct nlm_block *
|
||||
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_host *host,
|
||||
struct nlm_file *file, struct nlm_lock *lock,
|
||||
struct nlm_cookie *cookie)
|
||||
struct nlm_file *file, struct lockd_lock *lock,
|
||||
struct lockd_cookie *cookie)
|
||||
{
|
||||
struct nlm_block *block;
|
||||
struct nlm_rqst *call = NULL;
|
||||
@@ -399,7 +399,7 @@ static struct nlm_lockowner *nlmsvc_find_lockowner(struct nlm_host *host, pid_t
|
||||
}
|
||||
|
||||
void
|
||||
nlmsvc_release_lockowner(struct nlm_lock *lock)
|
||||
nlmsvc_release_lockowner(struct lockd_lock *lock)
|
||||
{
|
||||
if (lock->fl.c.flc_owner)
|
||||
nlmsvc_put_lockowner(lock->fl.c.flc_owner);
|
||||
@@ -415,7 +415,7 @@ void nlmsvc_locks_init_private(struct file_lock *fl, struct nlm_host *host,
|
||||
* Initialize arguments for GRANTED call. The nlm_rqst structure
|
||||
* has been cleared already.
|
||||
*/
|
||||
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
|
||||
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct lockd_lock *lock)
|
||||
{
|
||||
locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
|
||||
memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
|
||||
@@ -476,8 +476,8 @@ nlmsvc_defer_lock_rqst(struct svc_rqst *rqstp, struct nlm_block *block)
|
||||
*/
|
||||
__be32
|
||||
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||
struct nlm_host *host, struct nlm_lock *lock, int wait,
|
||||
struct nlm_cookie *cookie, int reclaim)
|
||||
struct nlm_host *host, struct lockd_lock *lock, int wait,
|
||||
struct lockd_cookie *cookie, int reclaim)
|
||||
{
|
||||
struct inode *inode __maybe_unused = nlmsvc_file_inode(file);
|
||||
struct nlm_block *block = NULL;
|
||||
@@ -609,8 +609,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||
*/
|
||||
__be32
|
||||
nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||
struct nlm_host *host, struct nlm_lock *lock,
|
||||
struct nlm_lock *conflock)
|
||||
struct nlm_host *host, struct lockd_lock *lock,
|
||||
struct lockd_lock *conflock)
|
||||
{
|
||||
int error;
|
||||
__be32 ret;
|
||||
@@ -669,7 +669,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
|
||||
* must be removed.
|
||||
*/
|
||||
__be32
|
||||
nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
|
||||
nlmsvc_unlock(struct net *net, struct nlm_file *file, struct lockd_lock *lock)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
@@ -707,7 +707,7 @@ nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
|
||||
* The calling procedure must check whether the file can be closed.
|
||||
*/
|
||||
__be32
|
||||
nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
|
||||
nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct lockd_lock *lock)
|
||||
{
|
||||
struct nlm_block *block;
|
||||
int status = 0;
|
||||
@@ -848,7 +848,7 @@ static void
|
||||
nlmsvc_grant_blocked(struct nlm_block *block)
|
||||
{
|
||||
struct nlm_file *file = block->b_file;
|
||||
struct nlm_lock *lock = &block->b_call->a_args.lock;
|
||||
struct lockd_lock *lock = &block->b_call->a_args.lock;
|
||||
int mode;
|
||||
int error;
|
||||
loff_t fl_start, fl_end;
|
||||
@@ -982,7 +982,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops = {
|
||||
* block.
|
||||
*/
|
||||
void
|
||||
nlmsvc_grant_reply(struct nlm_cookie *cookie, __be32 status)
|
||||
nlmsvc_grant_reply(struct lockd_cookie *cookie, __be32 status)
|
||||
{
|
||||
struct nlm_block *block;
|
||||
struct file_lock *fl;
|
||||
|
||||
1844
fs/lockd/svcproc.c
1844
fs/lockd/svcproc.c
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@
|
||||
#include "share.h"
|
||||
|
||||
static inline int
|
||||
nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh)
|
||||
nlm_cmp_owner(struct lockd_share *share, struct xdr_netobj *oh)
|
||||
{
|
||||
return share->s_owner.len == oh->len
|
||||
&& !memcmp(share->s_owner.data, oh->data, oh->len);
|
||||
@@ -39,7 +39,7 @@ __be32
|
||||
nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
|
||||
struct xdr_netobj *oh, u32 access, u32 mode)
|
||||
{
|
||||
struct nlm_share *share;
|
||||
struct lockd_share *share;
|
||||
u8 *ohdata;
|
||||
|
||||
if (nlmsvc_file_cannot_lock(file))
|
||||
@@ -85,7 +85,7 @@ __be32
|
||||
nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
|
||||
struct xdr_netobj *oh)
|
||||
{
|
||||
struct nlm_share *share, **shpp;
|
||||
struct lockd_share *share, **shpp;
|
||||
|
||||
if (nlmsvc_file_cannot_lock(file))
|
||||
return nlm_lck_denied_nolocks;
|
||||
@@ -111,7 +111,7 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
|
||||
void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
|
||||
nlm_host_match_fn_t match)
|
||||
{
|
||||
struct nlm_share *share, **shpp;
|
||||
struct lockd_share *share, **shpp;
|
||||
|
||||
shpp = &file->f_shares;
|
||||
while ((share = *shpp) != NULL) {
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mount.h>
|
||||
#include <uapi/linux/nfs2.h>
|
||||
|
||||
#include "lockd.h"
|
||||
#include "share.h"
|
||||
@@ -67,7 +66,7 @@ static inline unsigned int file_hash(struct nfs_fh *f)
|
||||
{
|
||||
unsigned int tmp=0;
|
||||
int i;
|
||||
for (i=0; i<NFS2_FHSIZE;i++)
|
||||
for (i = 0; i < LOCKD_FH_HASH_SIZE; i++)
|
||||
tmp += f->data[i];
|
||||
return tmp & (FILE_NRHASH - 1);
|
||||
}
|
||||
@@ -132,7 +131,7 @@ static __be32 nlm_do_fopen(struct svc_rqst *rqstp,
|
||||
*/
|
||||
__be32
|
||||
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
|
||||
struct nlm_lock *lock, int mode)
|
||||
struct lockd_lock *lock, int mode)
|
||||
{
|
||||
struct nlm_file *file;
|
||||
unsigned int hash;
|
||||
@@ -150,6 +149,8 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
|
||||
mutex_lock(&file->f_mutex);
|
||||
nfserr = nlm_do_fopen(rqstp, file, mode);
|
||||
mutex_unlock(&file->f_mutex);
|
||||
if (nfserr)
|
||||
goto out_unlock;
|
||||
goto found;
|
||||
}
|
||||
nlm_debug_print_fh("creating file for", &lock->fh);
|
||||
@@ -166,7 +167,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
|
||||
|
||||
nfserr = nlm_do_fopen(rqstp, file, mode);
|
||||
if (nfserr)
|
||||
goto out_unlock;
|
||||
goto out_free;
|
||||
|
||||
hlist_add_head(&file->f_list, &nlm_files[hash]);
|
||||
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Encode/decode NLM basic data types
|
||||
*
|
||||
* Basic NLMv3 XDR data types are not defined in an IETF standards
|
||||
* document. X/Open has a description of these data types that
|
||||
* is useful. See Chapter 10 of "Protocols for Interworking:
|
||||
* XNFS, Version 3W".
|
||||
*
|
||||
* Basic NLMv4 XDR data types are defined in Appendix II.1.4 of
|
||||
* RFC 1813: "NFS Version 3 Protocol Specification".
|
||||
*
|
||||
* Author: Chuck Lever <chuck.lever@oracle.com>
|
||||
*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates.
|
||||
*/
|
||||
|
||||
#ifndef _LOCKD_SVCXDR_H_
|
||||
#define _LOCKD_SVCXDR_H_
|
||||
|
||||
static inline bool
|
||||
svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
p = xdr_inline_decode(xdr, XDR_UNIT);
|
||||
if (!p)
|
||||
return false;
|
||||
*status = *p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
p = xdr_reserve_space(xdr, XDR_UNIT);
|
||||
if (!p)
|
||||
return false;
|
||||
*p = status;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > NLM_MAXSTRLEN)
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
*data_len = len;
|
||||
*data = (char *)p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* NLM cookies are defined by specification to be a variable-length
|
||||
* XDR opaque no longer than 1024 bytes. However, this implementation
|
||||
* limits their length to 32 bytes, and treats zero-length cookies
|
||||
* specially.
|
||||
*/
|
||||
static inline bool
|
||||
svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > NLM_MAXCOOKIELEN)
|
||||
return false;
|
||||
if (!len)
|
||||
goto out_hpux;
|
||||
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
cookie->len = len;
|
||||
memcpy(cookie->data, p, len);
|
||||
|
||||
return true;
|
||||
|
||||
/* apparently HPUX can return empty cookies */
|
||||
out_hpux:
|
||||
cookie->len = 4;
|
||||
memset(cookie->data, 0, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie)
|
||||
{
|
||||
__be32 *p;
|
||||
|
||||
if (xdr_stream_encode_u32(xdr, cookie->len) < 0)
|
||||
return false;
|
||||
p = xdr_reserve_space(xdr, cookie->len);
|
||||
if (!p)
|
||||
return false;
|
||||
memcpy(p, cookie->data, cookie->len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > XDR_MAX_NETOBJ)
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
obj->len = len;
|
||||
obj->data = (u8 *)p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj)
|
||||
{
|
||||
if (obj->len > XDR_MAX_NETOBJ)
|
||||
return false;
|
||||
return xdr_stream_encode_opaque(xdr, obj->data, obj->len) > 0;
|
||||
}
|
||||
|
||||
#endif /* _LOCKD_SVCXDR_H_ */
|
||||
@@ -48,7 +48,7 @@ NLM_STATUS_LIST
|
||||
|
||||
DECLARE_EVENT_CLASS(nlmclnt_lock_event,
|
||||
TP_PROTO(
|
||||
const struct nlm_lock *lock,
|
||||
const struct lockd_lock *lock,
|
||||
const struct sockaddr *addr,
|
||||
unsigned int addrlen,
|
||||
__be32 status
|
||||
@@ -61,8 +61,8 @@ DECLARE_EVENT_CLASS(nlmclnt_lock_event,
|
||||
__field(u32, svid)
|
||||
__field(u32, fh)
|
||||
__field(unsigned long, status)
|
||||
__field(u64, start)
|
||||
__field(u64, len)
|
||||
__field(loff_t, start)
|
||||
__field(loff_t, end)
|
||||
__sockaddr(addr, addrlen)
|
||||
),
|
||||
|
||||
@@ -70,16 +70,16 @@ DECLARE_EVENT_CLASS(nlmclnt_lock_event,
|
||||
__entry->oh = ~crc32_le(0xffffffff, lock->oh.data, lock->oh.len);
|
||||
__entry->svid = lock->svid;
|
||||
__entry->fh = nfs_fhandle_hash(&lock->fh);
|
||||
__entry->start = lock->lock_start;
|
||||
__entry->len = lock->lock_len;
|
||||
__entry->start = lock->fl.fl_start;
|
||||
__entry->end = lock->fl.fl_end;
|
||||
__entry->status = be32_to_cpu(status);
|
||||
__assign_sockaddr(addr, addr, addrlen);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"addr=%pISpc oh=0x%08x svid=0x%08x fh=0x%08x start=%llu len=%llu status=%s",
|
||||
"addr=%pISpc oh=0x%08x svid=0x%08x fh=0x%08x start=%lld end=%lld status=%s",
|
||||
__get_sockaddr(addr), __entry->oh, __entry->svid,
|
||||
__entry->fh, __entry->start, __entry->len,
|
||||
__entry->fh, __entry->start, __entry->end,
|
||||
show_nlm_status(__entry->status)
|
||||
)
|
||||
);
|
||||
@@ -87,7 +87,7 @@ DECLARE_EVENT_CLASS(nlmclnt_lock_event,
|
||||
#define DEFINE_NLMCLNT_EVENT(name) \
|
||||
DEFINE_EVENT(nlmclnt_lock_event, name, \
|
||||
TP_PROTO( \
|
||||
const struct nlm_lock *lock, \
|
||||
const struct lockd_lock *lock, \
|
||||
const struct sockaddr *addr, \
|
||||
unsigned int addrlen, \
|
||||
__be32 status \
|
||||
|
||||
354
fs/lockd/xdr.c
354
fs/lockd/xdr.c
@@ -1,354 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* linux/fs/lockd/xdr.c
|
||||
*
|
||||
* XDR support for lockd and the lock client.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/nfs.h>
|
||||
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/sunrpc/clnt.h>
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
|
||||
#include <uapi/linux/nfs2.h>
|
||||
|
||||
#include "lockd.h"
|
||||
#include "share.h"
|
||||
#include "svcxdr.h"
|
||||
|
||||
static inline loff_t
|
||||
s32_to_loff_t(__s32 offset)
|
||||
{
|
||||
return (loff_t)offset;
|
||||
}
|
||||
|
||||
static inline __s32
|
||||
loff_t_to_s32(loff_t offset)
|
||||
{
|
||||
__s32 res;
|
||||
if (offset >= NLM_OFFSET_MAX)
|
||||
res = NLM_OFFSET_MAX;
|
||||
else if (offset <= -NLM_OFFSET_MAX)
|
||||
res = -NLM_OFFSET_MAX;
|
||||
else
|
||||
res = offset;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* NLM file handles are defined by specification to be a variable-length
|
||||
* XDR opaque no longer than 1024 bytes. However, this implementation
|
||||
* constrains their length to exactly the length of an NFSv2 file
|
||||
* handle.
|
||||
*/
|
||||
static bool
|
||||
svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
|
||||
{
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len != NFS2_FHSIZE)
|
||||
return false;
|
||||
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
fh->size = NFS2_FHSIZE;
|
||||
memcpy(fh->data, p, len);
|
||||
memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
|
||||
{
|
||||
struct file_lock *fl = &lock->fl;
|
||||
s32 start, len, end;
|
||||
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return false;
|
||||
if (!svcxdr_decode_fhandle(xdr, &lock->fh))
|
||||
return false;
|
||||
if (!svcxdr_decode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &start) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
|
||||
locks_init_lock(fl);
|
||||
fl->c.flc_flags = FL_POSIX;
|
||||
fl->c.flc_type = F_RDLCK;
|
||||
end = start + len - 1;
|
||||
fl->fl_start = s32_to_loff_t(start);
|
||||
if (len == 0 || end < 0)
|
||||
fl->fl_end = OFFSET_MAX;
|
||||
else
|
||||
fl->fl_end = s32_to_loff_t(end);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
|
||||
{
|
||||
const struct file_lock *fl = &lock->fl;
|
||||
s32 start, len;
|
||||
|
||||
/* exclusive */
|
||||
if (xdr_stream_encode_bool(xdr, fl->c.flc_type != F_RDLCK) < 0)
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
|
||||
return false;
|
||||
if (!svcxdr_encode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
start = loff_t_to_s32(fl->fl_start);
|
||||
if (fl->fl_end == OFFSET_MAX)
|
||||
len = 0;
|
||||
else
|
||||
len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
|
||||
if (xdr_stream_encode_u32(xdr, start) < 0)
|
||||
return false;
|
||||
if (xdr_stream_encode_u32(xdr, len) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
|
||||
{
|
||||
if (!svcxdr_encode_stats(xdr, resp->status))
|
||||
return false;
|
||||
switch (resp->status) {
|
||||
case nlm_lck_denied:
|
||||
if (!svcxdr_encode_holder(xdr, &resp->lock))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Decode Call arguments
|
||||
*/
|
||||
|
||||
bool
|
||||
nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return false;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return false;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return false;
|
||||
if (exclusive)
|
||||
argp->lock.fl.c.flc_type = F_WRLCK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return false;
|
||||
if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return false;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return false;
|
||||
if (exclusive)
|
||||
argp->lock.fl.c.flc_type = F_WRLCK;
|
||||
if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return false;
|
||||
argp->monitor = 1; /* monitor client by default */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
u32 exclusive;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return false;
|
||||
if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
|
||||
return false;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return false;
|
||||
if (exclusive)
|
||||
argp->lock.fl.c.flc_type = F_WRLCK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return false;
|
||||
if (!svcxdr_decode_lock(xdr, &argp->lock))
|
||||
return false;
|
||||
argp->lock.fl.c.flc_type = F_UNLCK;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_argp;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &resp->cookie))
|
||||
return false;
|
||||
if (!svcxdr_decode_stats(xdr, &resp->status))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_reboot *argp = rqstp->rq_argp;
|
||||
__be32 *p;
|
||||
u32 len;
|
||||
|
||||
if (xdr_stream_decode_u32(xdr, &len) < 0)
|
||||
return false;
|
||||
if (len > SM_MAXSTRLEN)
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, len);
|
||||
if (!p)
|
||||
return false;
|
||||
argp->len = len;
|
||||
argp->mon = (char *)p;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return false;
|
||||
p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
|
||||
if (!p)
|
||||
return false;
|
||||
memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
memset(lock, 0, sizeof(*lock));
|
||||
locks_init_lock(&lock->fl);
|
||||
lock->svid = LOCKD_SHARE_SVID;
|
||||
|
||||
if (!svcxdr_decode_cookie(xdr, &argp->cookie))
|
||||
return false;
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return false;
|
||||
if (!svcxdr_decode_fhandle(xdr, &lock->fh))
|
||||
return false;
|
||||
if (!svcxdr_decode_owner(xdr, &lock->oh))
|
||||
return false;
|
||||
/* XXX: Range checks are missing in the original code */
|
||||
if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_args *argp = rqstp->rq_argp;
|
||||
struct nlm_lock *lock = &argp->lock;
|
||||
|
||||
if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
|
||||
return false;
|
||||
if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encode Reply results
|
||||
*/
|
||||
|
||||
bool
|
||||
nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return svcxdr_encode_cookie(xdr, &resp->cookie) &&
|
||||
svcxdr_encode_testrply(xdr, resp);
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
return svcxdr_encode_cookie(xdr, &resp->cookie) &&
|
||||
svcxdr_encode_stats(xdr, resp->status);
|
||||
}
|
||||
|
||||
bool
|
||||
nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
|
||||
{
|
||||
struct nlm_res *resp = rqstp->rq_resp;
|
||||
|
||||
if (!svcxdr_encode_cookie(xdr, &resp->cookie))
|
||||
return false;
|
||||
if (!svcxdr_encode_stats(xdr, resp->status))
|
||||
return false;
|
||||
/* sequence */
|
||||
if (xdr_stream_encode_u32(xdr, 0) < 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -20,8 +20,6 @@ struct nsm_private {
|
||||
unsigned char data[SM_PRIV_SIZE];
|
||||
};
|
||||
|
||||
struct svc_rqst;
|
||||
|
||||
#define NLM_MAXCOOKIELEN 32
|
||||
#define NLM_MAXSTRLEN 1024
|
||||
|
||||
@@ -32,7 +30,7 @@ struct svc_rqst;
|
||||
#define nlm_lck_denied_grace_period cpu_to_be32(NLM_LCK_DENIED_GRACE_PERIOD)
|
||||
|
||||
/* Lock info passed via NLM */
|
||||
struct nlm_lock {
|
||||
struct lockd_lock {
|
||||
char * caller;
|
||||
unsigned int len; /* length of "caller" */
|
||||
struct nfs_fh fh;
|
||||
@@ -49,8 +47,7 @@ struct nlm_lock {
|
||||
* 32 bytes.
|
||||
*/
|
||||
|
||||
struct nlm_cookie
|
||||
{
|
||||
struct lockd_cookie {
|
||||
unsigned char data[NLM_MAXCOOKIELEN];
|
||||
unsigned int len;
|
||||
};
|
||||
@@ -58,49 +55,31 @@ struct nlm_cookie
|
||||
/*
|
||||
* Generic lockd arguments for all but sm_notify
|
||||
*/
|
||||
struct nlm_args {
|
||||
struct nlm_cookie cookie;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_args {
|
||||
struct lockd_cookie cookie;
|
||||
struct lockd_lock lock;
|
||||
u32 block;
|
||||
u32 reclaim;
|
||||
u32 state;
|
||||
u32 monitor;
|
||||
u32 fsm_access;
|
||||
u32 fsm_mode;
|
||||
};
|
||||
|
||||
/*
|
||||
* Generic lockd result
|
||||
*/
|
||||
struct nlm_res {
|
||||
struct nlm_cookie cookie;
|
||||
struct lockd_res {
|
||||
struct lockd_cookie cookie;
|
||||
__be32 status;
|
||||
struct nlm_lock lock;
|
||||
struct lockd_lock lock;
|
||||
};
|
||||
|
||||
/*
|
||||
* statd callback when client has rebooted
|
||||
*/
|
||||
struct nlm_reboot {
|
||||
struct lockd_reboot {
|
||||
char *mon;
|
||||
unsigned int len;
|
||||
u32 state;
|
||||
struct nsm_private priv;
|
||||
};
|
||||
|
||||
bool nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
|
||||
bool nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
bool nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr);
|
||||
|
||||
#endif /* _LOCKD_XDR_H */
|
||||
|
||||
@@ -156,7 +156,7 @@ static int nfs_dns_upcall(struct cache_detail *cd,
|
||||
if (!nfs_cache_upcall(cd, key->hostname))
|
||||
return 0;
|
||||
clear_bit(CACHE_PENDING, &ch->flags);
|
||||
return sunrpc_cache_pipe_upcall_timeout(cd, ch);
|
||||
return sunrpc_cache_upcall_warn(cd, ch);
|
||||
}
|
||||
|
||||
static int nfs_dns_match(struct cache_head *ca,
|
||||
|
||||
781
fs/nfsd/export.c
781
fs/nfsd/export.c
@@ -17,6 +17,8 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/exportfs.h>
|
||||
#include <linux/sunrpc/svc_xprt.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <uapi/linux/nfsd_netlink.h>
|
||||
|
||||
#include "nfsd.h"
|
||||
#include "nfsfh.h"
|
||||
@@ -24,6 +26,7 @@
|
||||
#include "pnfs.h"
|
||||
#include "filecache.h"
|
||||
#include "trace.h"
|
||||
#include "netlink.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_EXPORT
|
||||
|
||||
@@ -36,35 +39,24 @@
|
||||
* second map contains a reference to the entry in the first map.
|
||||
*/
|
||||
|
||||
static struct workqueue_struct *nfsd_export_wq;
|
||||
|
||||
#define EXPKEY_HASHBITS 8
|
||||
#define EXPKEY_HASHMAX (1 << EXPKEY_HASHBITS)
|
||||
#define EXPKEY_HASHMASK (EXPKEY_HASHMAX -1)
|
||||
|
||||
static void expkey_release(struct work_struct *work)
|
||||
{
|
||||
struct svc_expkey *key = container_of(to_rcu_work(work),
|
||||
struct svc_expkey, ek_rwork);
|
||||
|
||||
if (test_bit(CACHE_VALID, &key->h.flags) &&
|
||||
!test_bit(CACHE_NEGATIVE, &key->h.flags))
|
||||
path_put(&key->ek_path);
|
||||
auth_domain_put(key->ek_client);
|
||||
kfree(key);
|
||||
}
|
||||
|
||||
static void expkey_put(struct kref *ref)
|
||||
{
|
||||
struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
|
||||
|
||||
INIT_RCU_WORK(&key->ek_rwork, expkey_release);
|
||||
queue_rcu_work(nfsd_export_wq, &key->ek_rwork);
|
||||
if (test_bit(CACHE_VALID, &key->h.flags) &&
|
||||
!test_bit(CACHE_NEGATIVE, &key->h.flags))
|
||||
path_put(&key->ek_path);
|
||||
auth_domain_put(key->ek_client);
|
||||
kfree_rcu(key, ek_rcu);
|
||||
}
|
||||
|
||||
static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h);
|
||||
return sunrpc_cache_upcall(cd, h);
|
||||
}
|
||||
|
||||
static void expkey_request(struct cache_detail *cd,
|
||||
@@ -263,12 +255,18 @@ static void expkey_flush(void)
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
}
|
||||
|
||||
static int expkey_notify(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return nfsd_cache_notify(cd, h, NFSD_CACHE_TYPE_EXPKEY);
|
||||
}
|
||||
|
||||
static const struct cache_detail svc_expkey_cache_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.hash_size = EXPKEY_HASHMAX,
|
||||
.name = "nfsd.fh",
|
||||
.cache_put = expkey_put,
|
||||
.cache_upcall = expkey_upcall,
|
||||
.cache_notify = expkey_notify,
|
||||
.cache_request = expkey_request,
|
||||
.cache_parse = expkey_parse,
|
||||
.cache_show = expkey_show,
|
||||
@@ -319,6 +317,266 @@ svc_expkey_update(struct cache_detail *cd, struct svc_expkey *new,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_expkey_get_reqs_dumpit - dump pending expkey requests
|
||||
* @skb: reply buffer
|
||||
* @cb: netlink metadata and command arguments
|
||||
*
|
||||
* Walk the expkey cache's pending request list and create a netlink
|
||||
* message with a nested entry for each cache_request, containing the
|
||||
* seqno, client string, fsidtype and fsid.
|
||||
*
|
||||
* Uses cb->args[0] as a seqno cursor for dump continuation across
|
||||
* multiple netlink messages.
|
||||
*
|
||||
* Returns the size of the reply or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_expkey_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct nfsd_net *nn;
|
||||
struct cache_detail *cd;
|
||||
struct cache_head **items;
|
||||
u64 *seqnos;
|
||||
int cnt, i, emitted;
|
||||
void *hdr;
|
||||
int ret;
|
||||
|
||||
nn = net_generic(sock_net(skb->sk), nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
cd = nn->svc_expkey_cache;
|
||||
if (!cd) {
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
cnt = sunrpc_cache_requests_count(cd);
|
||||
if (!cnt) {
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
items = kcalloc(cnt, sizeof(*items), GFP_KERNEL);
|
||||
seqnos = kcalloc(cnt, sizeof(*seqnos), GFP_KERNEL);
|
||||
if (!items || !seqnos) {
|
||||
ret = -ENOMEM;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
cnt = sunrpc_cache_requests_snapshot(cd, items, seqnos, cnt,
|
||||
cb->args[0]);
|
||||
if (!cnt) {
|
||||
ret = 0;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, &nfsd_nl_family,
|
||||
NLM_F_MULTI, NFSD_CMD_EXPKEY_GET_REQS);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
emitted = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct svc_expkey *ek;
|
||||
struct nlattr *nest;
|
||||
|
||||
ek = container_of(items[i], struct svc_expkey, h);
|
||||
|
||||
nest = nla_nest_start(skb, NFSD_A_EXPKEY_REQS_REQUESTS);
|
||||
if (!nest)
|
||||
break;
|
||||
|
||||
if (nla_put_u64_64bit(skb, NFSD_A_EXPKEY_SEQNO,
|
||||
seqnos[i], 0) ||
|
||||
nla_put_string(skb, NFSD_A_EXPKEY_CLIENT,
|
||||
ek->ek_client->name) ||
|
||||
nla_put_u8(skb, NFSD_A_EXPKEY_FSIDTYPE,
|
||||
ek->ek_fsidtype) ||
|
||||
nla_put(skb, NFSD_A_EXPKEY_FSID,
|
||||
key_len(ek->ek_fsidtype), ek->ek_fsid)) {
|
||||
nla_nest_cancel(skb, nest);
|
||||
break;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
cb->args[0] = seqnos[i];
|
||||
emitted++;
|
||||
}
|
||||
|
||||
if (!emitted) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
ret = -EMSGSIZE;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
ret = skb->len;
|
||||
out_put:
|
||||
for (i = 0; i < cnt; i++)
|
||||
cache_put(items[i], cd);
|
||||
out_alloc:
|
||||
kfree(seqnos);
|
||||
kfree(items);
|
||||
out_unlock:
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_parse_one_expkey - parse one expkey entry from netlink
|
||||
* @cd: cache_detail for the expkey cache
|
||||
* @attr: nested attribute containing expkey fields
|
||||
*
|
||||
* Parses one expkey entry from a netlink message and updates the
|
||||
* cache. Mirrors the logic in expkey_parse().
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
static int nfsd_nl_parse_one_expkey(struct cache_detail *cd,
|
||||
struct nlattr *attr)
|
||||
{
|
||||
struct nlattr *tb[NFSD_A_EXPKEY_PATH + 1];
|
||||
struct auth_domain *dom = NULL;
|
||||
struct svc_expkey key;
|
||||
struct svc_expkey *ek = NULL;
|
||||
struct timespec64 boot;
|
||||
int err;
|
||||
u8 fsidtype;
|
||||
int fsid_len;
|
||||
|
||||
err = nla_parse_nested(tb, NFSD_A_EXPKEY_PATH, attr,
|
||||
nfsd_expkey_nl_policy, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* client (required) */
|
||||
if (!tb[NFSD_A_EXPKEY_CLIENT])
|
||||
return -EINVAL;
|
||||
|
||||
dom = auth_domain_find(nla_data(tb[NFSD_A_EXPKEY_CLIENT]));
|
||||
if (!dom)
|
||||
return -ENOENT;
|
||||
|
||||
/* fsidtype (required) */
|
||||
if (!tb[NFSD_A_EXPKEY_FSIDTYPE]) {
|
||||
err = -EINVAL;
|
||||
goto out_dom;
|
||||
}
|
||||
fsidtype = nla_get_u8(tb[NFSD_A_EXPKEY_FSIDTYPE]);
|
||||
if (key_len(fsidtype) == 0) {
|
||||
err = -EINVAL;
|
||||
goto out_dom;
|
||||
}
|
||||
|
||||
/* fsid (required) */
|
||||
if (!tb[NFSD_A_EXPKEY_FSID]) {
|
||||
err = -EINVAL;
|
||||
goto out_dom;
|
||||
}
|
||||
fsid_len = nla_len(tb[NFSD_A_EXPKEY_FSID]);
|
||||
if (fsid_len != key_len(fsidtype)) {
|
||||
err = -EINVAL;
|
||||
goto out_dom;
|
||||
}
|
||||
|
||||
/* expiry (required, wallclock seconds) */
|
||||
if (!tb[NFSD_A_EXPKEY_EXPIRY]) {
|
||||
err = -EINVAL;
|
||||
goto out_dom;
|
||||
}
|
||||
|
||||
key.h.flags = 0;
|
||||
getboottime64(&boot);
|
||||
key.h.expiry_time = nla_get_u64(tb[NFSD_A_EXPKEY_EXPIRY]) -
|
||||
boot.tv_sec;
|
||||
key.ek_client = dom;
|
||||
key.ek_fsidtype = fsidtype;
|
||||
memcpy(key.ek_fsid, nla_data(tb[NFSD_A_EXPKEY_FSID]), fsid_len);
|
||||
|
||||
ek = svc_expkey_lookup(cd, &key);
|
||||
if (!ek) {
|
||||
err = -ENOMEM;
|
||||
goto out_dom;
|
||||
}
|
||||
|
||||
if (tb[NFSD_A_EXPKEY_NEGATIVE]) {
|
||||
set_bit(CACHE_NEGATIVE, &key.h.flags);
|
||||
ek = svc_expkey_update(cd, &key, ek);
|
||||
if (ek)
|
||||
trace_nfsd_expkey_update(ek, NULL);
|
||||
else
|
||||
err = -ENOMEM;
|
||||
} else if (tb[NFSD_A_EXPKEY_PATH]) {
|
||||
err = kern_path(nla_data(tb[NFSD_A_EXPKEY_PATH]), 0,
|
||||
&key.ek_path);
|
||||
if (err)
|
||||
goto out_ek;
|
||||
ek = svc_expkey_update(cd, &key, ek);
|
||||
if (ek)
|
||||
trace_nfsd_expkey_update(ek,
|
||||
nla_data(tb[NFSD_A_EXPKEY_PATH]));
|
||||
else
|
||||
err = -ENOMEM;
|
||||
path_put(&key.ek_path);
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
goto out_ek;
|
||||
}
|
||||
|
||||
cache_flush();
|
||||
|
||||
out_ek:
|
||||
if (ek)
|
||||
cache_put(&ek->h, cd);
|
||||
out_dom:
|
||||
auth_domain_put(dom);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_expkey_set_reqs_doit - respond to expkey requests
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Parse one or more expkey cache responses from userspace and
|
||||
* update the expkey cache accordingly.
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_expkey_set_reqs_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct nfsd_net *nn;
|
||||
struct cache_detail *cd;
|
||||
const struct nlattr *attr;
|
||||
int rem, ret = 0;
|
||||
|
||||
nn = net_generic(genl_info_net(info), nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
cd = nn->svc_expkey_cache;
|
||||
if (!cd) {
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
nlmsg_for_each_attr_type(attr, NFSD_A_EXPKEY_REQS_REQUESTS,
|
||||
info->nlhdr, GENL_HDRLEN, rem) {
|
||||
ret = nfsd_nl_parse_one_expkey(cd, (struct nlattr *)attr);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define EXPORT_HASHBITS 8
|
||||
#define EXPORT_HASHMAX (1<< EXPORT_HASHBITS)
|
||||
@@ -364,13 +622,11 @@ static void export_stats_destroy(struct export_stats *stats)
|
||||
EXP_STATS_COUNTERS_NUM);
|
||||
}
|
||||
|
||||
static void svc_export_release(struct work_struct *work)
|
||||
static void svc_export_release(struct rcu_head *rcu_head)
|
||||
{
|
||||
struct svc_export *exp = container_of(to_rcu_work(work),
|
||||
struct svc_export, ex_rwork);
|
||||
struct svc_export *exp = container_of(rcu_head, struct svc_export,
|
||||
ex_rcu);
|
||||
|
||||
path_put(&exp->ex_path);
|
||||
auth_domain_put(exp->ex_client);
|
||||
nfsd4_fslocs_free(&exp->ex_fslocs);
|
||||
export_stats_destroy(exp->ex_stats);
|
||||
kfree(exp->ex_stats);
|
||||
@@ -382,13 +638,450 @@ static void svc_export_put(struct kref *ref)
|
||||
{
|
||||
struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
|
||||
|
||||
INIT_RCU_WORK(&exp->ex_rwork, svc_export_release);
|
||||
queue_rcu_work(nfsd_export_wq, &exp->ex_rwork);
|
||||
path_put(&exp->ex_path);
|
||||
auth_domain_put(exp->ex_client);
|
||||
call_rcu(&exp->ex_rcu, svc_export_release);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_svc_export_get_reqs_dumpit - dump pending svc_export requests
|
||||
* @skb: reply buffer
|
||||
* @cb: netlink metadata and command arguments
|
||||
*
|
||||
* Walk the svc_export cache's pending request list and create a netlink
|
||||
* message with a nested entry for each cache_request, containing the
|
||||
* seqno, client string, and path.
|
||||
*
|
||||
* Uses cb->args[0] as a seqno cursor for dump continuation across
|
||||
* multiple netlink messages.
|
||||
*
|
||||
* Returns the size of the reply or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_svc_export_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct nfsd_net *nn;
|
||||
struct cache_detail *cd;
|
||||
struct cache_head **items;
|
||||
u64 *seqnos;
|
||||
int cnt, i, emitted;
|
||||
char *pathbuf;
|
||||
void *hdr;
|
||||
int ret;
|
||||
|
||||
nn = net_generic(sock_net(skb->sk), nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
cd = nn->svc_export_cache;
|
||||
if (!cd) {
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
cnt = sunrpc_cache_requests_count(cd);
|
||||
if (!cnt) {
|
||||
ret = 0;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
items = kcalloc(cnt, sizeof(*items), GFP_KERNEL);
|
||||
seqnos = kcalloc(cnt, sizeof(*seqnos), GFP_KERNEL);
|
||||
pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (!items || !seqnos || !pathbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
cnt = sunrpc_cache_requests_snapshot(cd, items, seqnos, cnt,
|
||||
cb->args[0]);
|
||||
if (!cnt) {
|
||||
ret = 0;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, &nfsd_nl_family,
|
||||
NLM_F_MULTI, NFSD_CMD_SVC_EXPORT_GET_REQS);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
emitted = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct svc_export *exp;
|
||||
struct nlattr *nest;
|
||||
char *pth;
|
||||
|
||||
exp = container_of(items[i], struct svc_export, h);
|
||||
|
||||
pth = d_path(&exp->ex_path, pathbuf, PATH_MAX);
|
||||
if (IS_ERR(pth))
|
||||
continue;
|
||||
|
||||
nest = nla_nest_start(skb,
|
||||
NFSD_A_SVC_EXPORT_REQS_REQUESTS);
|
||||
if (!nest)
|
||||
break;
|
||||
|
||||
if (nla_put_u64_64bit(skb, NFSD_A_SVC_EXPORT_SEQNO,
|
||||
seqnos[i], 0) ||
|
||||
nla_put_string(skb, NFSD_A_SVC_EXPORT_CLIENT,
|
||||
exp->ex_client->name) ||
|
||||
nla_put_string(skb, NFSD_A_SVC_EXPORT_PATH, pth)) {
|
||||
nla_nest_cancel(skb, nest);
|
||||
break;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
cb->args[0] = seqnos[i];
|
||||
emitted++;
|
||||
}
|
||||
|
||||
if (!emitted) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
ret = -EMSGSIZE;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
ret = skb->len;
|
||||
out_put:
|
||||
for (i = 0; i < cnt; i++)
|
||||
cache_put(items[i], cd);
|
||||
out_alloc:
|
||||
kfree(pathbuf);
|
||||
kfree(seqnos);
|
||||
kfree(items);
|
||||
out_unlock:
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_parse_fslocations - parse fslocations from netlink
|
||||
* @attr: NFSD_A_SVC_EXPORT_FSLOCATIONS nested attribute
|
||||
* @fsloc: fslocations struct to fill in
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
static int nfsd_nl_parse_fslocations(struct nlattr *attr,
|
||||
struct nfsd4_fs_locations *fsloc)
|
||||
{
|
||||
struct nlattr *loc_attr;
|
||||
int rem, count = 0;
|
||||
int err;
|
||||
|
||||
if (fsloc->locations)
|
||||
return -EINVAL;
|
||||
|
||||
/* Count locations first */
|
||||
nla_for_each_nested_type(loc_attr, NFSD_A_FSLOCATIONS_LOCATION,
|
||||
attr, rem)
|
||||
count++;
|
||||
|
||||
if (count > MAX_FS_LOCATIONS)
|
||||
return -EINVAL;
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
fsloc->locations = kcalloc(count, sizeof(struct nfsd4_fs_location),
|
||||
GFP_KERNEL);
|
||||
if (!fsloc->locations)
|
||||
return -ENOMEM;
|
||||
|
||||
nla_for_each_nested_type(loc_attr, NFSD_A_FSLOCATIONS_LOCATION,
|
||||
attr, rem) {
|
||||
struct nlattr *tb[NFSD_A_FSLOCATION_PATH + 1];
|
||||
struct nfsd4_fs_location *loc;
|
||||
|
||||
err = nla_parse_nested(tb, NFSD_A_FSLOCATION_PATH, loc_attr,
|
||||
nfsd_fslocation_nl_policy, NULL);
|
||||
if (err)
|
||||
goto out_free;
|
||||
|
||||
if (!tb[NFSD_A_FSLOCATION_HOST] ||
|
||||
!tb[NFSD_A_FSLOCATION_PATH]) {
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
loc = &fsloc->locations[fsloc->locations_count++];
|
||||
loc->hosts = kstrdup(nla_data(tb[NFSD_A_FSLOCATION_HOST]),
|
||||
GFP_KERNEL);
|
||||
loc->path = kstrdup(nla_data(tb[NFSD_A_FSLOCATION_PATH]),
|
||||
GFP_KERNEL);
|
||||
if (!loc->hosts || !loc->path) {
|
||||
err = -ENOMEM;
|
||||
goto out_free;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_free:
|
||||
nfsd4_fslocs_free(fsloc);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct svc_export *svc_export_update(struct svc_export *new,
|
||||
struct svc_export *old);
|
||||
static struct svc_export *svc_export_lookup(struct svc_export *);
|
||||
static int check_export(const struct path *path, int *flags,
|
||||
unsigned char *uuid);
|
||||
|
||||
/**
|
||||
* nfsd_nl_parse_one_export - parse one svc_export entry from a netlink message
|
||||
* @cd: cache_detail for the svc_export cache
|
||||
* @attr: nested attribute containing svc-export fields
|
||||
*
|
||||
* Parses one svc-export entry from a netlink message and updates the
|
||||
* cache. Mirrors the logic in svc_export_parse().
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
static int nfsd_nl_parse_one_export(struct cache_detail *cd,
|
||||
struct nlattr *attr)
|
||||
{
|
||||
struct nlattr *tb[NFSD_A_SVC_EXPORT_FSID + 1];
|
||||
struct auth_domain *dom = NULL;
|
||||
struct svc_export exp = {}, *expp;
|
||||
struct nlattr *secinfo_attr;
|
||||
struct timespec64 boot;
|
||||
int err, rem;
|
||||
|
||||
err = nla_parse_nested(tb, NFSD_A_SVC_EXPORT_FSID, attr,
|
||||
nfsd_svc_export_nl_policy, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* client (required) */
|
||||
if (!tb[NFSD_A_SVC_EXPORT_CLIENT])
|
||||
return -EINVAL;
|
||||
|
||||
dom = auth_domain_find(nla_data(tb[NFSD_A_SVC_EXPORT_CLIENT]));
|
||||
if (!dom)
|
||||
return -ENOENT;
|
||||
|
||||
/* path (required) */
|
||||
if (!tb[NFSD_A_SVC_EXPORT_PATH]) {
|
||||
err = -EINVAL;
|
||||
goto out_dom;
|
||||
}
|
||||
|
||||
err = kern_path(nla_data(tb[NFSD_A_SVC_EXPORT_PATH]), 0,
|
||||
&exp.ex_path);
|
||||
if (err)
|
||||
goto out_dom;
|
||||
|
||||
exp.ex_client = dom;
|
||||
exp.cd = cd;
|
||||
exp.ex_devid_map = NULL;
|
||||
exp.ex_xprtsec_modes = NFSEXP_XPRTSEC_ALL;
|
||||
|
||||
/* expiry (required, wallclock seconds) */
|
||||
if (!tb[NFSD_A_SVC_EXPORT_EXPIRY]) {
|
||||
err = -EINVAL;
|
||||
goto out_path;
|
||||
}
|
||||
getboottime64(&boot);
|
||||
exp.h.expiry_time = nla_get_u64(tb[NFSD_A_SVC_EXPORT_EXPIRY]) -
|
||||
boot.tv_sec;
|
||||
|
||||
if (tb[NFSD_A_SVC_EXPORT_NEGATIVE]) {
|
||||
set_bit(CACHE_NEGATIVE, &exp.h.flags);
|
||||
} else {
|
||||
/* flags */
|
||||
if (tb[NFSD_A_SVC_EXPORT_FLAGS])
|
||||
exp.ex_flags = nla_get_u32(tb[NFSD_A_SVC_EXPORT_FLAGS]);
|
||||
|
||||
/* anon uid */
|
||||
if (tb[NFSD_A_SVC_EXPORT_ANON_UID]) {
|
||||
u32 uid = nla_get_u32(tb[NFSD_A_SVC_EXPORT_ANON_UID]);
|
||||
|
||||
exp.ex_anon_uid = make_kuid(current_user_ns(), uid);
|
||||
}
|
||||
|
||||
/* anon gid */
|
||||
if (tb[NFSD_A_SVC_EXPORT_ANON_GID]) {
|
||||
u32 gid = nla_get_u32(tb[NFSD_A_SVC_EXPORT_ANON_GID]);
|
||||
|
||||
exp.ex_anon_gid = make_kgid(current_user_ns(), gid);
|
||||
}
|
||||
|
||||
/* fsid */
|
||||
if (tb[NFSD_A_SVC_EXPORT_FSID])
|
||||
exp.ex_fsid = nla_get_s32(tb[NFSD_A_SVC_EXPORT_FSID]);
|
||||
|
||||
/* fslocations */
|
||||
if (tb[NFSD_A_SVC_EXPORT_FSLOCATIONS]) {
|
||||
struct nlattr *fsl = tb[NFSD_A_SVC_EXPORT_FSLOCATIONS];
|
||||
|
||||
err = nfsd_nl_parse_fslocations(fsl,
|
||||
&exp.ex_fslocs);
|
||||
if (err)
|
||||
goto out_path;
|
||||
}
|
||||
|
||||
/* uuid */
|
||||
if (tb[NFSD_A_SVC_EXPORT_UUID]) {
|
||||
if (nla_len(tb[NFSD_A_SVC_EXPORT_UUID]) !=
|
||||
EX_UUID_LEN) {
|
||||
err = -EINVAL;
|
||||
goto out_fslocs;
|
||||
}
|
||||
exp.ex_uuid = kmemdup(nla_data(tb[NFSD_A_SVC_EXPORT_UUID]),
|
||||
EX_UUID_LEN, GFP_KERNEL);
|
||||
if (!exp.ex_uuid) {
|
||||
err = -ENOMEM;
|
||||
goto out_fslocs;
|
||||
}
|
||||
}
|
||||
|
||||
/* secinfo (multi-attr) */
|
||||
nla_for_each_nested_type(secinfo_attr,
|
||||
NFSD_A_SVC_EXPORT_SECINFO,
|
||||
attr, rem) {
|
||||
struct nlattr *ftb[NFSD_A_AUTH_FLAVOR_FLAGS + 1];
|
||||
struct exp_flavor_info *f;
|
||||
|
||||
if (exp.ex_nflavors >= MAX_SECINFO_LIST) {
|
||||
err = -EINVAL;
|
||||
goto out_uuid;
|
||||
}
|
||||
|
||||
err = nla_parse_nested(ftb,
|
||||
NFSD_A_AUTH_FLAVOR_FLAGS,
|
||||
secinfo_attr,
|
||||
nfsd_auth_flavor_nl_policy,
|
||||
NULL);
|
||||
if (err)
|
||||
goto out_uuid;
|
||||
|
||||
f = &exp.ex_flavors[exp.ex_nflavors++];
|
||||
|
||||
if (ftb[NFSD_A_AUTH_FLAVOR_PSEUDOFLAVOR])
|
||||
f->pseudoflavor = nla_get_u32(ftb[NFSD_A_AUTH_FLAVOR_PSEUDOFLAVOR]);
|
||||
|
||||
if (ftb[NFSD_A_AUTH_FLAVOR_FLAGS])
|
||||
f->flags = nla_get_u32(ftb[NFSD_A_AUTH_FLAVOR_FLAGS]);
|
||||
|
||||
/* Only some flags are allowed to differ between flavors: */
|
||||
if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp.ex_flags)) {
|
||||
err = -EINVAL;
|
||||
goto out_uuid;
|
||||
}
|
||||
}
|
||||
|
||||
/* xprtsec (multi-attr u32) */
|
||||
if (tb[NFSD_A_SVC_EXPORT_XPRTSEC]) {
|
||||
struct nlattr *xp_attr;
|
||||
|
||||
exp.ex_xprtsec_modes = 0;
|
||||
nla_for_each_nested_type(xp_attr,
|
||||
NFSD_A_SVC_EXPORT_XPRTSEC,
|
||||
attr, rem) {
|
||||
u32 mode = nla_get_u32(xp_attr);
|
||||
|
||||
if (mode > NFSEXP_XPRTSEC_MTLS) {
|
||||
err = -EINVAL;
|
||||
goto out_uuid;
|
||||
}
|
||||
exp.ex_xprtsec_modes |= mode;
|
||||
}
|
||||
}
|
||||
|
||||
err = check_export(&exp.ex_path, &exp.ex_flags,
|
||||
exp.ex_uuid);
|
||||
if (err)
|
||||
goto out_uuid;
|
||||
|
||||
if (exp.h.expiry_time < seconds_since_boot())
|
||||
goto out_uuid;
|
||||
|
||||
err = -EINVAL;
|
||||
if (!uid_valid(exp.ex_anon_uid))
|
||||
goto out_uuid;
|
||||
if (!gid_valid(exp.ex_anon_gid))
|
||||
goto out_uuid;
|
||||
err = 0;
|
||||
|
||||
nfsd4_setup_layout_type(&exp);
|
||||
}
|
||||
|
||||
expp = svc_export_lookup(&exp);
|
||||
if (!expp) {
|
||||
err = -ENOMEM;
|
||||
goto out_uuid;
|
||||
}
|
||||
expp = svc_export_update(&exp, expp);
|
||||
if (expp) {
|
||||
trace_nfsd_export_update(expp);
|
||||
cache_flush();
|
||||
exp_put(expp);
|
||||
} else {
|
||||
err = -ENOMEM;
|
||||
}
|
||||
|
||||
out_uuid:
|
||||
kfree(exp.ex_uuid);
|
||||
out_fslocs:
|
||||
nfsd4_fslocs_free(&exp.ex_fslocs);
|
||||
out_path:
|
||||
path_put(&exp.ex_path);
|
||||
out_dom:
|
||||
auth_domain_put(dom);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_svc_export_set_reqs_doit - respond to svc_export requests
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Parse one or more svc_export cache responses from userspace and
|
||||
* update the export cache accordingly.
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_svc_export_set_reqs_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct nfsd_net *nn;
|
||||
struct cache_detail *cd;
|
||||
const struct nlattr *attr;
|
||||
int rem, ret = 0;
|
||||
|
||||
nn = net_generic(genl_info_net(info), nfsd_net_id);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
cd = nn->svc_export_cache;
|
||||
if (!cd) {
|
||||
ret = -ENODEV;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
nlmsg_for_each_attr_type(attr, NFSD_A_SVC_EXPORT_REQS_REQUESTS,
|
||||
info->nlhdr, GENL_HDRLEN, rem) {
|
||||
ret = nfsd_nl_parse_one_export(cd, (struct nlattr *)attr);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h);
|
||||
return sunrpc_cache_upcall(cd, h);
|
||||
}
|
||||
|
||||
static int svc_export_notify(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return nfsd_cache_notify(cd, h, NFSD_CACHE_TYPE_SVC_EXPORT);
|
||||
}
|
||||
|
||||
static void svc_export_request(struct cache_detail *cd,
|
||||
@@ -410,10 +1103,6 @@ static void svc_export_request(struct cache_detail *cd,
|
||||
(*bpp)[-1] = '\n';
|
||||
}
|
||||
|
||||
static struct svc_export *svc_export_update(struct svc_export *new,
|
||||
struct svc_export *old);
|
||||
static struct svc_export *svc_export_lookup(struct svc_export *);
|
||||
|
||||
static int check_export(const struct path *path, int *flags, unsigned char *uuid)
|
||||
{
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
@@ -908,6 +1597,7 @@ static const struct cache_detail svc_export_cache_template = {
|
||||
.name = "nfsd.export",
|
||||
.cache_put = svc_export_put,
|
||||
.cache_upcall = svc_export_upcall,
|
||||
.cache_notify = svc_export_notify,
|
||||
.cache_request = svc_export_request,
|
||||
.cache_parse = svc_export_parse,
|
||||
.cache_show = svc_export_show,
|
||||
@@ -1493,36 +2183,6 @@ const struct seq_operations nfs_exports_op = {
|
||||
.show = e_show,
|
||||
};
|
||||
|
||||
/**
|
||||
* nfsd_export_wq_init - allocate the export release workqueue
|
||||
*
|
||||
* Called once at module load. The workqueue runs deferred svc_export and
|
||||
* svc_expkey release work scheduled by queue_rcu_work() in the cache put
|
||||
* callbacks.
|
||||
*
|
||||
* Return values:
|
||||
* %0: workqueue allocated
|
||||
* %-ENOMEM: allocation failed
|
||||
*/
|
||||
int nfsd_export_wq_init(void)
|
||||
{
|
||||
nfsd_export_wq = alloc_workqueue("nfsd_export", WQ_UNBOUND, 0);
|
||||
if (!nfsd_export_wq)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_export_wq_shutdown - drain and free the export release workqueue
|
||||
*
|
||||
* Called once at module unload. Per-namespace teardown in
|
||||
* nfsd_export_shutdown() has already drained all deferred work.
|
||||
*/
|
||||
void nfsd_export_wq_shutdown(void)
|
||||
{
|
||||
destroy_workqueue(nfsd_export_wq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the exports module.
|
||||
*/
|
||||
@@ -1584,9 +2244,6 @@ nfsd_export_shutdown(struct net *net)
|
||||
|
||||
cache_unregister_net(nn->svc_expkey_cache, net);
|
||||
cache_unregister_net(nn->svc_export_cache, net);
|
||||
/* Drain deferred export and expkey release work. */
|
||||
rcu_barrier();
|
||||
flush_workqueue(nfsd_export_wq);
|
||||
cache_destroy_net(nn->svc_expkey_cache, net);
|
||||
cache_destroy_net(nn->svc_export_cache, net);
|
||||
svcauth_unix_purge(net);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
#include <linux/sunrpc/cache.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <uapi/linux/nfsd/export.h>
|
||||
#include <linux/nfs4.h>
|
||||
|
||||
@@ -76,7 +75,7 @@ struct svc_export {
|
||||
u32 ex_layout_types;
|
||||
struct nfsd4_deviceid_map *ex_devid_map;
|
||||
struct cache_detail *cd;
|
||||
struct rcu_work ex_rwork;
|
||||
struct rcu_head ex_rcu;
|
||||
unsigned long ex_xprtsec_modes;
|
||||
struct export_stats *ex_stats;
|
||||
};
|
||||
@@ -93,7 +92,7 @@ struct svc_expkey {
|
||||
u32 ek_fsid[6];
|
||||
|
||||
struct path ek_path;
|
||||
struct rcu_work ek_rwork;
|
||||
struct rcu_head ek_rcu;
|
||||
};
|
||||
|
||||
#define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
|
||||
@@ -111,8 +110,6 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp,
|
||||
/*
|
||||
* Function declarations
|
||||
*/
|
||||
int nfsd_export_wq_init(void);
|
||||
void nfsd_export_wq_shutdown(void);
|
||||
int nfsd_export_init(struct net *);
|
||||
void nfsd_export_shutdown(struct net *);
|
||||
void nfsd_export_flush(struct net *);
|
||||
|
||||
@@ -724,6 +724,52 @@ nfsd_file_close_inode_sync(struct inode *inode)
|
||||
nfsd_file_dispose_list(&dispose);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_file_close_export - close cached file handles for an export
|
||||
* @net: net namespace in which to operate
|
||||
* @path: export path whose cached files should be closed
|
||||
*
|
||||
* Close out GC-managed nfsd_file entries whose underlying file is on
|
||||
* the same filesystem as, and a descendant of, @path. nfsd_file
|
||||
* entries do not carry an export reference, so the check uses the
|
||||
* file's dentry ancestry. False positives (closing a cached handle
|
||||
* that did not originate from the target export) are harmless -- the
|
||||
* handle is simply reopened on the next access.
|
||||
*
|
||||
* Called from the NFSD_CMD_UNLOCK_EXPORT handler before revoking
|
||||
* NFSv4 state, to ensure that cached file handles do not hold the
|
||||
* filesystem busy.
|
||||
*/
|
||||
void nfsd_file_close_export(struct net *net, const struct path *path)
|
||||
{
|
||||
struct rhashtable_iter iter;
|
||||
struct nfsd_file *nf;
|
||||
LIST_HEAD(dispose);
|
||||
|
||||
rhltable_walk_enter(&nfsd_file_rhltable, &iter);
|
||||
do {
|
||||
rhashtable_walk_start(&iter);
|
||||
|
||||
nf = rhashtable_walk_next(&iter);
|
||||
while (!IS_ERR_OR_NULL(nf)) {
|
||||
if (nf->nf_net == net &&
|
||||
test_bit(NFSD_FILE_GC, &nf->nf_flags) &&
|
||||
nf->nf_file &&
|
||||
file_inode(nf->nf_file)->i_sb ==
|
||||
path->dentry->d_sb &&
|
||||
is_subdir(nf->nf_file->f_path.dentry,
|
||||
path->dentry))
|
||||
nfsd_file_cond_queue(nf, &dispose);
|
||||
nf = rhashtable_walk_next(&iter);
|
||||
}
|
||||
|
||||
rhashtable_walk_stop(&iter);
|
||||
} while (nf == ERR_PTR(-EAGAIN));
|
||||
rhashtable_walk_exit(&iter);
|
||||
|
||||
nfsd_file_dispose_list(&dispose);
|
||||
}
|
||||
|
||||
static int
|
||||
nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg,
|
||||
void *data)
|
||||
|
||||
@@ -70,6 +70,7 @@ struct net *nfsd_file_put_local(struct nfsd_file __rcu **nf);
|
||||
struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
|
||||
struct file *nfsd_file_file(struct nfsd_file *nf);
|
||||
void nfsd_file_close_inode_sync(struct inode *inode);
|
||||
void nfsd_file_close_export(struct net *net, const struct path *path);
|
||||
void nfsd_file_net_dispose(struct nfsd_net *nn);
|
||||
bool nfsd_file_is_cached(struct inode *inode);
|
||||
__be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
|
||||
@@ -12,11 +12,51 @@
|
||||
#include <uapi/linux/nfsd_netlink.h>
|
||||
|
||||
/* Common nested types */
|
||||
const struct nla_policy nfsd_auth_flavor_nl_policy[NFSD_A_AUTH_FLAVOR_FLAGS + 1] = {
|
||||
[NFSD_A_AUTH_FLAVOR_PSEUDOFLAVOR] = { .type = NLA_U32, },
|
||||
[NFSD_A_AUTH_FLAVOR_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x3ffff),
|
||||
};
|
||||
|
||||
const struct nla_policy nfsd_expkey_nl_policy[NFSD_A_EXPKEY_PATH + 1] = {
|
||||
[NFSD_A_EXPKEY_SEQNO] = { .type = NLA_U64, },
|
||||
[NFSD_A_EXPKEY_CLIENT] = { .type = NLA_NUL_STRING, },
|
||||
[NFSD_A_EXPKEY_FSIDTYPE] = { .type = NLA_U8, },
|
||||
[NFSD_A_EXPKEY_FSID] = { .type = NLA_BINARY, },
|
||||
[NFSD_A_EXPKEY_NEGATIVE] = { .type = NLA_FLAG, },
|
||||
[NFSD_A_EXPKEY_EXPIRY] = { .type = NLA_U64, },
|
||||
[NFSD_A_EXPKEY_PATH] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
const struct nla_policy nfsd_fslocation_nl_policy[NFSD_A_FSLOCATION_PATH + 1] = {
|
||||
[NFSD_A_FSLOCATION_HOST] = { .type = NLA_NUL_STRING, },
|
||||
[NFSD_A_FSLOCATION_PATH] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
const struct nla_policy nfsd_fslocations_nl_policy[NFSD_A_FSLOCATIONS_LOCATION + 1] = {
|
||||
[NFSD_A_FSLOCATIONS_LOCATION] = NLA_POLICY_NESTED(nfsd_fslocation_nl_policy),
|
||||
};
|
||||
|
||||
const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1] = {
|
||||
[NFSD_A_SOCK_ADDR] = { .type = NLA_BINARY, },
|
||||
[NFSD_A_SOCK_TRANSPORT_NAME] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_FSID + 1] = {
|
||||
[NFSD_A_SVC_EXPORT_SEQNO] = { .type = NLA_U64, },
|
||||
[NFSD_A_SVC_EXPORT_CLIENT] = { .type = NLA_NUL_STRING, },
|
||||
[NFSD_A_SVC_EXPORT_PATH] = { .type = NLA_NUL_STRING, },
|
||||
[NFSD_A_SVC_EXPORT_NEGATIVE] = { .type = NLA_FLAG, },
|
||||
[NFSD_A_SVC_EXPORT_EXPIRY] = { .type = NLA_U64, },
|
||||
[NFSD_A_SVC_EXPORT_ANON_UID] = { .type = NLA_U32, },
|
||||
[NFSD_A_SVC_EXPORT_ANON_GID] = { .type = NLA_U32, },
|
||||
[NFSD_A_SVC_EXPORT_FSLOCATIONS] = NLA_POLICY_NESTED(nfsd_fslocations_nl_policy),
|
||||
[NFSD_A_SVC_EXPORT_UUID] = { .type = NLA_BINARY, },
|
||||
[NFSD_A_SVC_EXPORT_SECINFO] = NLA_POLICY_NESTED(nfsd_auth_flavor_nl_policy),
|
||||
[NFSD_A_SVC_EXPORT_XPRTSEC] = NLA_POLICY_MASK(NLA_U32, 0x7),
|
||||
[NFSD_A_SVC_EXPORT_FLAGS] = NLA_POLICY_MASK(NLA_U32, 0x3ffff),
|
||||
[NFSD_A_SVC_EXPORT_FSID] = { .type = NLA_S32, },
|
||||
};
|
||||
|
||||
const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
|
||||
[NFSD_A_VERSION_MAJOR] = { .type = NLA_U32, },
|
||||
[NFSD_A_VERSION_MINOR] = { .type = NLA_U32, },
|
||||
@@ -48,6 +88,36 @@ static const struct nla_policy nfsd_pool_mode_set_nl_policy[NFSD_A_POOL_MODE_MOD
|
||||
[NFSD_A_POOL_MODE_MODE] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
/* NFSD_CMD_SVC_EXPORT_SET_REQS - do */
|
||||
static const struct nla_policy nfsd_svc_export_set_reqs_nl_policy[NFSD_A_SVC_EXPORT_REQS_REQUESTS + 1] = {
|
||||
[NFSD_A_SVC_EXPORT_REQS_REQUESTS] = NLA_POLICY_NESTED(nfsd_svc_export_nl_policy),
|
||||
};
|
||||
|
||||
/* NFSD_CMD_EXPKEY_SET_REQS - do */
|
||||
static const struct nla_policy nfsd_expkey_set_reqs_nl_policy[NFSD_A_EXPKEY_REQS_REQUESTS + 1] = {
|
||||
[NFSD_A_EXPKEY_REQS_REQUESTS] = NLA_POLICY_NESTED(nfsd_expkey_nl_policy),
|
||||
};
|
||||
|
||||
/* NFSD_CMD_CACHE_FLUSH - do */
|
||||
static const struct nla_policy nfsd_cache_flush_nl_policy[NFSD_A_CACHE_FLUSH_MASK + 1] = {
|
||||
[NFSD_A_CACHE_FLUSH_MASK] = NLA_POLICY_MASK(NLA_U32, 0x3),
|
||||
};
|
||||
|
||||
/* NFSD_CMD_UNLOCK_IP - do */
|
||||
static const struct nla_policy nfsd_unlock_ip_nl_policy[NFSD_A_UNLOCK_IP_ADDRESS + 1] = {
|
||||
[NFSD_A_UNLOCK_IP_ADDRESS] = NLA_POLICY_MIN_LEN(16),
|
||||
};
|
||||
|
||||
/* NFSD_CMD_UNLOCK_FILESYSTEM - do */
|
||||
static const struct nla_policy nfsd_unlock_filesystem_nl_policy[NFSD_A_UNLOCK_FILESYSTEM_PATH + 1] = {
|
||||
[NFSD_A_UNLOCK_FILESYSTEM_PATH] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
/* NFSD_CMD_UNLOCK_EXPORT - do */
|
||||
static const struct nla_policy nfsd_unlock_export_nl_policy[NFSD_A_UNLOCK_EXPORT_PATH + 1] = {
|
||||
[NFSD_A_UNLOCK_EXPORT_PATH] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
/* Ops table for nfsd */
|
||||
static const struct genl_split_ops nfsd_nl_ops[] = {
|
||||
{
|
||||
@@ -103,6 +173,63 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
|
||||
.doit = nfsd_nl_pool_mode_get_doit,
|
||||
.flags = GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_SVC_EXPORT_GET_REQS,
|
||||
.dumpit = nfsd_nl_svc_export_get_reqs_dumpit,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_SVC_EXPORT_SET_REQS,
|
||||
.doit = nfsd_nl_svc_export_set_reqs_doit,
|
||||
.policy = nfsd_svc_export_set_reqs_nl_policy,
|
||||
.maxattr = NFSD_A_SVC_EXPORT_REQS_REQUESTS,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_EXPKEY_GET_REQS,
|
||||
.dumpit = nfsd_nl_expkey_get_reqs_dumpit,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_EXPKEY_SET_REQS,
|
||||
.doit = nfsd_nl_expkey_set_reqs_doit,
|
||||
.policy = nfsd_expkey_set_reqs_nl_policy,
|
||||
.maxattr = NFSD_A_EXPKEY_REQS_REQUESTS,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_CACHE_FLUSH,
|
||||
.doit = nfsd_nl_cache_flush_doit,
|
||||
.policy = nfsd_cache_flush_nl_policy,
|
||||
.maxattr = NFSD_A_CACHE_FLUSH_MASK,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_UNLOCK_IP,
|
||||
.doit = nfsd_nl_unlock_ip_doit,
|
||||
.policy = nfsd_unlock_ip_nl_policy,
|
||||
.maxattr = NFSD_A_UNLOCK_IP_ADDRESS,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_UNLOCK_FILESYSTEM,
|
||||
.doit = nfsd_nl_unlock_filesystem_doit,
|
||||
.policy = nfsd_unlock_filesystem_nl_policy,
|
||||
.maxattr = NFSD_A_UNLOCK_FILESYSTEM_PATH,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_UNLOCK_EXPORT,
|
||||
.doit = nfsd_nl_unlock_export_doit,
|
||||
.policy = nfsd_unlock_export_nl_policy,
|
||||
.maxattr = NFSD_A_UNLOCK_EXPORT_PATH,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group nfsd_nl_mcgrps[] = {
|
||||
[NFSD_NLGRP_NONE] = { "none", },
|
||||
[NFSD_NLGRP_EXPORTD] = { "exportd", },
|
||||
};
|
||||
|
||||
struct genl_family nfsd_nl_family __ro_after_init = {
|
||||
@@ -113,4 +240,6 @@ struct genl_family nfsd_nl_family __ro_after_init = {
|
||||
.module = THIS_MODULE,
|
||||
.split_ops = nfsd_nl_ops,
|
||||
.n_split_ops = ARRAY_SIZE(nfsd_nl_ops),
|
||||
.mcgrps = nfsd_nl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(nfsd_nl_mcgrps),
|
||||
};
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
#include <uapi/linux/nfsd_netlink.h>
|
||||
|
||||
/* Common nested types */
|
||||
extern const struct nla_policy nfsd_auth_flavor_nl_policy[NFSD_A_AUTH_FLAVOR_FLAGS + 1];
|
||||
extern const struct nla_policy nfsd_expkey_nl_policy[NFSD_A_EXPKEY_PATH + 1];
|
||||
extern const struct nla_policy nfsd_fslocation_nl_policy[NFSD_A_FSLOCATION_PATH + 1];
|
||||
extern const struct nla_policy nfsd_fslocations_nl_policy[NFSD_A_FSLOCATIONS_LOCATION + 1];
|
||||
extern const struct nla_policy nfsd_sock_nl_policy[NFSD_A_SOCK_TRANSPORT_NAME + 1];
|
||||
extern const struct nla_policy nfsd_svc_export_nl_policy[NFSD_A_SVC_EXPORT_FSID + 1];
|
||||
extern const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1];
|
||||
|
||||
int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
|
||||
@@ -26,6 +31,22 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_pool_mode_set_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_pool_mode_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_svc_export_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb);
|
||||
int nfsd_nl_svc_export_set_reqs_doit(struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
int nfsd_nl_expkey_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb);
|
||||
int nfsd_nl_expkey_set_reqs_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_unlock_ip_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_unlock_filesystem_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_unlock_export_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
enum {
|
||||
NFSD_NLGRP_NONE,
|
||||
NFSD_NLGRP_EXPORTD,
|
||||
};
|
||||
|
||||
extern struct genl_family nfsd_nl_family;
|
||||
|
||||
|
||||
@@ -131,10 +131,7 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
|
||||
resp->status = fh_getattr(fh, &resp->stat);
|
||||
|
||||
out:
|
||||
/* argp->acl_{access,default} may have been allocated in
|
||||
nfssvc_decode_setaclargs. */
|
||||
posix_acl_release(argp->acl_access);
|
||||
posix_acl_release(argp->acl_default);
|
||||
/* argp->acl_{access,default} are released in nfsaclsvc_release_setacl. */
|
||||
return rpc_success;
|
||||
|
||||
out_drop_lock:
|
||||
@@ -310,6 +307,16 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
|
||||
fh_put(&resp->fh);
|
||||
}
|
||||
|
||||
static void nfsaclsvc_release_setacl(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_setaclargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
fh_put(&resp->fh);
|
||||
posix_acl_release(argp->acl_access);
|
||||
posix_acl_release(argp->acl_default);
|
||||
}
|
||||
|
||||
#define ST 1 /* status*/
|
||||
#define AT 21 /* attributes */
|
||||
#define pAT (1+AT) /* post attributes - conditional */
|
||||
@@ -343,7 +350,7 @@ static const struct svc_procedure nfsd_acl_procedures2[5] = {
|
||||
.pc_func = nfsacld_proc_setacl,
|
||||
.pc_decode = nfsaclsvc_decode_setaclargs,
|
||||
.pc_encode = nfssvc_encode_attrstatres,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_release = nfsaclsvc_release_setacl,
|
||||
.pc_argsize = sizeof(struct nfsd3_setaclargs),
|
||||
.pc_argzero = sizeof(struct nfsd3_setaclargs),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
|
||||
@@ -118,10 +118,7 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
|
||||
out_errno:
|
||||
resp->status = nfserrno(error);
|
||||
out:
|
||||
/* argp->acl_{access,default} may have been allocated in
|
||||
nfs3svc_decode_setaclargs. */
|
||||
posix_acl_release(argp->acl_access);
|
||||
posix_acl_release(argp->acl_default);
|
||||
/* argp->acl_{access,default} are released in nfs3svc_release_setacl. */
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
@@ -223,6 +220,16 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
|
||||
posix_acl_release(resp->acl_default);
|
||||
}
|
||||
|
||||
static void nfs3svc_release_setacl(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_setaclargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
fh_put(&resp->fh);
|
||||
posix_acl_release(argp->acl_access);
|
||||
posix_acl_release(argp->acl_default);
|
||||
}
|
||||
|
||||
#define ST 1 /* status*/
|
||||
#define AT 21 /* attributes */
|
||||
#define pAT (1+AT) /* post attributes - conditional */
|
||||
@@ -256,7 +263,7 @@ static const struct svc_procedure nfsd_acl_procedures3[3] = {
|
||||
.pc_func = nfsd3_proc_setacl,
|
||||
.pc_decode = nfs3svc_decode_setaclargs,
|
||||
.pc_encode = nfs3svc_encode_setaclres,
|
||||
.pc_release = nfs3svc_release_fhandle,
|
||||
.pc_release = nfs3svc_release_setacl,
|
||||
.pc_argsize = sizeof(struct nfsd3_setaclargs),
|
||||
.pc_argzero = sizeof(struct nfsd3_setaclargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_attrstat),
|
||||
|
||||
@@ -126,7 +126,7 @@ idtoname_hash(struct ent *ent)
|
||||
static int
|
||||
idtoname_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall_timeout(cd, h);
|
||||
return sunrpc_cache_upcall_warn(cd, h);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -306,7 +306,7 @@ nametoid_hash(struct ent *ent)
|
||||
static int
|
||||
nametoid_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall_timeout(cd, h);
|
||||
return sunrpc_cache_upcall_warn(cd, h);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -234,6 +234,8 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
||||
|
||||
get_nfs4_file(fp);
|
||||
stp->sc_file = fp;
|
||||
if (parent->sc_export)
|
||||
stp->sc_export = exp_get(parent->sc_export);
|
||||
|
||||
ls = layoutstateid(stp);
|
||||
INIT_LIST_HEAD(&ls->ls_perclnt);
|
||||
@@ -251,10 +253,12 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
||||
ls->ls_file = find_any_file(fp);
|
||||
BUG_ON(!ls->ls_file);
|
||||
|
||||
ls->ls_fenced = false;
|
||||
ls->ls_fence_delay = 0;
|
||||
INIT_DELAYED_WORK(&ls->ls_fence_work, nfsd4_layout_fence_worker);
|
||||
|
||||
if (nfsd4_layout_setlease(ls)) {
|
||||
nfsd_file_put(ls->ls_file);
|
||||
put_nfs4_file(fp);
|
||||
kmem_cache_free(nfs4_layout_stateid_cache, ls);
|
||||
nfs4_put_stid(stp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -267,10 +271,6 @@ nfsd4_alloc_layout_stateid(struct nfsd4_compound_state *cstate,
|
||||
list_add(&ls->ls_perfile, &fp->fi_lo_states);
|
||||
spin_unlock(&fp->fi_lock);
|
||||
|
||||
ls->ls_fenced = false;
|
||||
ls->ls_fence_delay = 0;
|
||||
INIT_DELAYED_WORK(&ls->ls_fence_work, nfsd4_layout_fence_worker);
|
||||
|
||||
trace_nfsd_layoutstate_alloc(&ls->ls_stid.sc_stateid);
|
||||
return ls;
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
.na_iattr = iap,
|
||||
.na_seclabel = &open->op_label,
|
||||
};
|
||||
struct dentry *parent, *child;
|
||||
struct dentry *parent, *child = ERR_PTR(-EINVAL);
|
||||
__u32 v_mtime, v_atime;
|
||||
struct inode *inode;
|
||||
__be32 status;
|
||||
@@ -277,10 +277,14 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
if (open->op_acl) {
|
||||
if (open->op_dpacl || open->op_pacl) {
|
||||
status = nfserr_inval;
|
||||
goto out_write;
|
||||
goto out;
|
||||
}
|
||||
if (is_create_with_attrs(open)) {
|
||||
status = nfsd4_acl_to_attr(NF4REG, open->op_acl,
|
||||
&attrs);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
if (is_create_with_attrs(open))
|
||||
nfsd4_acl_to_attr(NF4REG, open->op_acl, &attrs);
|
||||
} else if (is_create_with_attrs(open)) {
|
||||
/* The dpacl and pacl will get released by nfsd_attrs_free(). */
|
||||
attrs.na_dpacl = open->op_dpacl;
|
||||
@@ -293,7 +297,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
&QSTR_LEN(open->op_fname, open->op_fnamelen));
|
||||
if (IS_ERR(child)) {
|
||||
status = nfserrno(PTR_ERR(child));
|
||||
goto out_write;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (d_really_is_negative(child)) {
|
||||
@@ -407,7 +411,6 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
out:
|
||||
end_creating(child);
|
||||
nfsd_attrs_free(&attrs);
|
||||
out_write:
|
||||
fh_drop_write(fhp);
|
||||
return status;
|
||||
}
|
||||
@@ -837,7 +840,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
goto out_aftermask;
|
||||
|
||||
if (create->cr_acl) {
|
||||
if (create->cr_dpacl || create->cr_pacl) {
|
||||
if (attrs.na_dpacl || attrs.na_pacl) {
|
||||
status = nfserr_inval;
|
||||
goto out_aftermask;
|
||||
}
|
||||
@@ -1470,7 +1473,7 @@ void nfsd4_async_copy_reaper(struct nfsd_net *nn)
|
||||
list_for_each_safe(pos, next, &clp->async_copies) {
|
||||
copy = list_entry(pos, struct nfsd4_copy, copies);
|
||||
if (test_bit(NFSD4_COPY_F_OFFLOAD_DONE, ©->cp_flags)) {
|
||||
if (--copy->cp_ttl) {
|
||||
if (!--copy->cp_ttl) {
|
||||
list_del_init(©->copies);
|
||||
list_add(©->copies, &reaplist);
|
||||
}
|
||||
|
||||
@@ -718,7 +718,8 @@ __cld_pipe_inprogress_downcall(const struct cld_msg_v2 __user *cmsg,
|
||||
return PTR_ERR(namecopy);
|
||||
name.data = namecopy;
|
||||
name.len = namelen;
|
||||
get_user(princhashlen, &ci->cc_princhash.cp_len);
|
||||
if (get_user(princhashlen, &ci->cc_princhash.cp_len))
|
||||
return -EFAULT;
|
||||
if (princhashlen > 0) {
|
||||
princhashcopy = memdup_user(
|
||||
&ci->cc_princhash.cp_data,
|
||||
|
||||
@@ -1168,6 +1168,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_file *fp,
|
||||
void
|
||||
nfs4_put_stid(struct nfs4_stid *s)
|
||||
{
|
||||
struct svc_export *exp = s->sc_export;
|
||||
struct nfs4_file *fp = s->sc_file;
|
||||
struct nfs4_client *clp = s->sc_client;
|
||||
|
||||
@@ -1183,6 +1184,8 @@ nfs4_put_stid(struct nfs4_stid *s)
|
||||
nfs4_free_cpntf_statelist(clp->net, s);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
s->sc_free(s);
|
||||
if (exp)
|
||||
exp_put(exp);
|
||||
if (fp)
|
||||
put_nfs4_file(fp);
|
||||
}
|
||||
@@ -1376,7 +1379,8 @@ static void destroy_delegation(struct nfs4_delegation *dp)
|
||||
* stateid or it's called from a laundromat thread (nfsd4_landromat()) that
|
||||
* determined that this specific state has expired and needs to be revoked
|
||||
* (both mark state with the appropriate stid sc_status mode). It is also
|
||||
* assumed that a reference was taken on the @dp state.
|
||||
* assumed that a reference was taken on the @dp state. This function
|
||||
* consumes that reference.
|
||||
*
|
||||
* If this function finds that the @dp state is SC_STATUS_FREED it means
|
||||
* that a FREE_STATEID operation for this stateid has been processed and
|
||||
@@ -1745,21 +1749,119 @@ static struct nfs4_stid *find_one_sb_stid(struct nfs4_client *clp,
|
||||
struct super_block *sb,
|
||||
unsigned int sc_types)
|
||||
{
|
||||
unsigned long id, tmp;
|
||||
unsigned long id = 0;
|
||||
struct nfs4_stid *stid;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
idr_for_each_entry_ul(&clp->cl_stateids, stid, tmp, id)
|
||||
while ((stid = idr_get_next_ul(&clp->cl_stateids, &id)) != NULL) {
|
||||
if ((stid->sc_type & sc_types) &&
|
||||
stid->sc_status == 0 &&
|
||||
stid->sc_file->fi_inode->i_sb == sb) {
|
||||
refcount_inc(&stid->sc_count);
|
||||
break;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
return stid;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release the export reference an admin-revoked stateid holds,
|
||||
* so the svc_export (and its vfsmount) is not pinned until the
|
||||
* client issues FREE_STATEID. sc_export is no longer consulted
|
||||
* once SC_STATUS_ADMIN_REVOKED is set.
|
||||
*/
|
||||
static void drop_stid_export(struct nfs4_client *clp,
|
||||
struct nfs4_stid *stid)
|
||||
{
|
||||
struct svc_export *exp;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
exp = stid->sc_export;
|
||||
stid->sc_export = NULL;
|
||||
spin_unlock(&clp->cl_lock);
|
||||
if (exp)
|
||||
exp_put(exp);
|
||||
}
|
||||
|
||||
static void revoke_ol_stid(struct nfs4_client *clp,
|
||||
struct nfs4_ol_stateid *stp)
|
||||
{
|
||||
struct nfs4_stid *stid = &stp->st_stid;
|
||||
|
||||
lockdep_assert_held(&stp->st_mutex);
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (stid->sc_status == 0) {
|
||||
stid->sc_status |= SC_STATUS_ADMIN_REVOKED;
|
||||
atomic_inc(&clp->cl_admin_revoked);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
if (stid->sc_type == SC_TYPE_LOCK) {
|
||||
struct nfs4_lockowner *lo =
|
||||
lockowner(stp->st_stateowner);
|
||||
struct nfsd_file *nf;
|
||||
|
||||
nf = find_any_file(stp->st_stid.sc_file);
|
||||
if (nf) {
|
||||
get_file(nf->nf_file);
|
||||
filp_close(nf->nf_file, (fl_owner_t)lo);
|
||||
nfsd_file_put(nf);
|
||||
}
|
||||
}
|
||||
release_all_access(stp);
|
||||
drop_stid_export(clp, stid);
|
||||
} else
|
||||
spin_unlock(&clp->cl_lock);
|
||||
}
|
||||
|
||||
static void revoke_one_stid(struct nfsd_net *nn, struct nfs4_client *clp,
|
||||
struct nfs4_stid *stid)
|
||||
{
|
||||
struct nfs4_ol_stateid *stp;
|
||||
struct nfs4_delegation *dp;
|
||||
|
||||
switch (stid->sc_type) {
|
||||
case SC_TYPE_OPEN:
|
||||
stp = openlockstateid(stid);
|
||||
mutex_lock_nested(&stp->st_mutex, OPEN_STATEID_MUTEX);
|
||||
revoke_ol_stid(clp, stp);
|
||||
mutex_unlock(&stp->st_mutex);
|
||||
break;
|
||||
case SC_TYPE_LOCK:
|
||||
stp = openlockstateid(stid);
|
||||
mutex_lock_nested(&stp->st_mutex, LOCK_STATEID_MUTEX);
|
||||
revoke_ol_stid(clp, stp);
|
||||
mutex_unlock(&stp->st_mutex);
|
||||
break;
|
||||
case SC_TYPE_DELEG:
|
||||
/*
|
||||
* Extra reference guards against concurrent FREE_STATEID.
|
||||
*/
|
||||
refcount_inc(&stid->sc_count);
|
||||
dp = delegstateid(stid);
|
||||
spin_lock(&nn->deleg_lock);
|
||||
if (!unhash_delegation_locked(dp, SC_STATUS_ADMIN_REVOKED))
|
||||
dp = NULL;
|
||||
spin_unlock(&nn->deleg_lock);
|
||||
if (dp) {
|
||||
revoke_delegation(dp);
|
||||
drop_stid_export(clp, stid);
|
||||
} else
|
||||
nfs4_put_stid(stid);
|
||||
break;
|
||||
case SC_TYPE_LAYOUT:
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (stid->sc_status == 0) {
|
||||
stid->sc_status |= SC_STATUS_ADMIN_REVOKED;
|
||||
atomic_inc(&clp->cl_admin_revoked);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfsd4_close_layout(layoutstateid(stid));
|
||||
drop_stid_export(clp, stid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd4_revoke_states - revoke all nfsv4 states associated with given filesystem
|
||||
* @nn: used to identify instance of nfsd (there is one per net namespace)
|
||||
@@ -1790,77 +1892,8 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
||||
struct nfs4_stid *stid = find_one_sb_stid(clp, sb,
|
||||
sc_types);
|
||||
if (stid) {
|
||||
struct nfs4_ol_stateid *stp;
|
||||
struct nfs4_delegation *dp;
|
||||
struct nfs4_layout_stateid *ls;
|
||||
|
||||
spin_unlock(&nn->client_lock);
|
||||
switch (stid->sc_type) {
|
||||
case SC_TYPE_OPEN:
|
||||
stp = openlockstateid(stid);
|
||||
mutex_lock_nested(&stp->st_mutex,
|
||||
OPEN_STATEID_MUTEX);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (stid->sc_status == 0) {
|
||||
stid->sc_status |=
|
||||
SC_STATUS_ADMIN_REVOKED;
|
||||
atomic_inc(&clp->cl_admin_revoked);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
release_all_access(stp);
|
||||
} else
|
||||
spin_unlock(&clp->cl_lock);
|
||||
mutex_unlock(&stp->st_mutex);
|
||||
break;
|
||||
case SC_TYPE_LOCK:
|
||||
stp = openlockstateid(stid);
|
||||
mutex_lock_nested(&stp->st_mutex,
|
||||
LOCK_STATEID_MUTEX);
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (stid->sc_status == 0) {
|
||||
struct nfs4_lockowner *lo =
|
||||
lockowner(stp->st_stateowner);
|
||||
struct nfsd_file *nf;
|
||||
|
||||
stid->sc_status |=
|
||||
SC_STATUS_ADMIN_REVOKED;
|
||||
atomic_inc(&clp->cl_admin_revoked);
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nf = find_any_file(stp->st_stid.sc_file);
|
||||
if (nf) {
|
||||
get_file(nf->nf_file);
|
||||
filp_close(nf->nf_file,
|
||||
(fl_owner_t)lo);
|
||||
nfsd_file_put(nf);
|
||||
}
|
||||
release_all_access(stp);
|
||||
} else
|
||||
spin_unlock(&clp->cl_lock);
|
||||
mutex_unlock(&stp->st_mutex);
|
||||
break;
|
||||
case SC_TYPE_DELEG:
|
||||
refcount_inc(&stid->sc_count);
|
||||
dp = delegstateid(stid);
|
||||
spin_lock(&nn->deleg_lock);
|
||||
if (!unhash_delegation_locked(
|
||||
dp, SC_STATUS_ADMIN_REVOKED))
|
||||
dp = NULL;
|
||||
spin_unlock(&nn->deleg_lock);
|
||||
if (dp)
|
||||
revoke_delegation(dp);
|
||||
break;
|
||||
case SC_TYPE_LAYOUT:
|
||||
ls = layoutstateid(stid);
|
||||
spin_lock(&clp->cl_lock);
|
||||
if (stid->sc_status == 0) {
|
||||
stid->sc_status |=
|
||||
SC_STATUS_ADMIN_REVOKED;
|
||||
atomic_inc(&clp->cl_admin_revoked);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
nfsd4_close_layout(ls);
|
||||
break;
|
||||
}
|
||||
revoke_one_stid(nn, clp, stid);
|
||||
nfs4_put_stid(stid);
|
||||
spin_lock(&nn->client_lock);
|
||||
if (clp->cl_minorversion == 0)
|
||||
@@ -1878,6 +1911,73 @@ void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
||||
spin_unlock(&nn->client_lock);
|
||||
}
|
||||
|
||||
static struct nfs4_stid *find_one_export_stid(struct nfs4_client *clp,
|
||||
const struct path *path,
|
||||
unsigned int sc_types)
|
||||
{
|
||||
unsigned long id = 0;
|
||||
struct nfs4_stid *stid;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
while ((stid = idr_get_next_ul(&clp->cl_stateids, &id)) != NULL) {
|
||||
if ((stid->sc_type & sc_types) &&
|
||||
stid->sc_status == 0 &&
|
||||
stid->sc_export &&
|
||||
path_equal(&stid->sc_export->ex_path, path)) {
|
||||
refcount_inc(&stid->sc_count);
|
||||
break;
|
||||
}
|
||||
id++;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
return stid;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd4_revoke_export_states - revoke nfsv4 states acquired through an export
|
||||
* @nn: used to identify instance of nfsd (there is one per net namespace)
|
||||
* @path: export path whose states should be revoked
|
||||
*
|
||||
* All nfs4 states (open, lock, delegation, layout) acquired through any
|
||||
* export matching @path are revoked, regardless of which client holds
|
||||
* them. Matching is by path identity (dentry + vfsmount), so multiple
|
||||
* svc_export objects for the same path -- one per auth_domain -- are
|
||||
* handled correctly.
|
||||
*
|
||||
* Userspace (exportfs -u) sends this after removing the last client
|
||||
* for a path, enabling the underlying filesystem to be unmounted.
|
||||
*/
|
||||
void nfsd4_revoke_export_states(struct nfsd_net *nn, const struct path *path)
|
||||
{
|
||||
unsigned int idhashval;
|
||||
unsigned int sc_types;
|
||||
|
||||
sc_types = SC_TYPE_OPEN | SC_TYPE_LOCK | SC_TYPE_DELEG | SC_TYPE_LAYOUT;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
for (idhashval = 0; idhashval < CLIENT_HASH_SIZE; idhashval++) {
|
||||
struct list_head *head = &nn->conf_id_hashtbl[idhashval];
|
||||
struct nfs4_client *clp;
|
||||
retry:
|
||||
list_for_each_entry(clp, head, cl_idhash) {
|
||||
struct nfs4_stid *stid = find_one_export_stid(
|
||||
clp, path,
|
||||
sc_types);
|
||||
if (stid) {
|
||||
spin_unlock(&nn->client_lock);
|
||||
revoke_one_stid(nn, clp, stid);
|
||||
nfs4_put_stid(stid);
|
||||
spin_lock(&nn->client_lock);
|
||||
if (clp->cl_minorversion == 0)
|
||||
nn->nfs40_last_revoke =
|
||||
ktime_get_boottime_seconds();
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hash_sessionid(struct nfs4_sessionid *sessionid)
|
||||
{
|
||||
@@ -5049,6 +5149,7 @@ static void nfsd4_drop_revoked_stid(struct nfs4_stid *s)
|
||||
{
|
||||
struct nfs4_client *cl = s->sc_client;
|
||||
LIST_HEAD(reaplist);
|
||||
struct nfs4_layout_stateid *ls;
|
||||
struct nfs4_ol_stateid *stp;
|
||||
struct nfs4_delegation *dp;
|
||||
bool unhashed;
|
||||
@@ -5074,6 +5175,12 @@ static void nfsd4_drop_revoked_stid(struct nfs4_stid *s)
|
||||
spin_unlock(&cl->cl_lock);
|
||||
nfs4_put_stid(s);
|
||||
break;
|
||||
case SC_TYPE_LAYOUT:
|
||||
ls = layoutstateid(s);
|
||||
list_del_init(&ls->ls_perclnt);
|
||||
spin_unlock(&cl->cl_lock);
|
||||
nfs4_put_stid(s);
|
||||
break;
|
||||
default:
|
||||
spin_unlock(&cl->cl_lock);
|
||||
}
|
||||
@@ -5169,6 +5276,7 @@ find_or_alloc_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
|
||||
/* Replace unconfirmed owners without checking for replay. */
|
||||
release_openowner(oo);
|
||||
oo = NULL;
|
||||
goto retry;
|
||||
}
|
||||
if (oo) {
|
||||
if (new)
|
||||
@@ -6157,6 +6265,8 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
|
||||
dp = alloc_init_deleg(clp, fp, odstate, dl_type);
|
||||
if (!dp)
|
||||
goto out_delegees;
|
||||
if (stp->st_stid.sc_export)
|
||||
dp->dl_stid.sc_export = exp_get(stp->st_stid.sc_export);
|
||||
|
||||
fl = nfs4_alloc_init_lease(dp);
|
||||
if (!fl)
|
||||
@@ -6490,8 +6600,11 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!open->op_stp)
|
||||
if (!open->op_stp) {
|
||||
new_stp = true;
|
||||
stp->st_stid.sc_export =
|
||||
exp_get(current_fh->fh_export);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -8187,6 +8300,9 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
|
||||
stp->st_stateowner = nfs4_get_stateowner(&lo->lo_owner);
|
||||
get_nfs4_file(fp);
|
||||
stp->st_stid.sc_file = fp;
|
||||
if (open_stp->st_stid.sc_export)
|
||||
stp->st_stid.sc_export =
|
||||
exp_get(open_stp->st_stid.sc_export);
|
||||
stp->st_access_bmap = 0;
|
||||
stp->st_deny_bmap = open_stp->st_deny_bmap;
|
||||
stp->st_openstp = open_stp;
|
||||
@@ -9517,6 +9633,9 @@ nfsd_get_dir_deleg(struct nfsd4_compound_state *cstate,
|
||||
dp = alloc_init_deleg(clp, fp, NULL, NFS4_OPEN_DELEGATE_READ);
|
||||
if (!dp)
|
||||
goto out_delegees;
|
||||
if (cstate->current_fh.fh_export)
|
||||
dp->dl_stid.sc_export =
|
||||
exp_get(cstate->current_fh.fh_export);
|
||||
|
||||
fl = nfs4_alloc_init_lease(dp);
|
||||
if (!fl)
|
||||
|
||||
@@ -2008,10 +2008,11 @@ static __be32 nfsd4_decode_secinfo_no_name(struct nfsd4_compoundargs *argp,
|
||||
union nfsd4_op_u *u)
|
||||
{
|
||||
struct nfsd4_secinfo_no_name *sin = &u->secinfo_no_name;
|
||||
|
||||
sin->sin_exp = NULL;
|
||||
if (xdr_stream_decode_u32(argp->xdr, &sin->sin_style) < 0)
|
||||
return nfserr_bad_xdr;
|
||||
|
||||
sin->sin_exp = NULL;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
|
||||
213
fs/nfsd/nfsctl.c
213
fs/nfsd/nfsctl.c
@@ -10,6 +10,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/fs_context.h>
|
||||
|
||||
#include <linux/sunrpc/cache.h>
|
||||
#include <linux/sunrpc/svcsock.h>
|
||||
#include <linux/lockd/bind.h>
|
||||
#include <linux/sunrpc/addr.h>
|
||||
@@ -246,7 +247,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
|
||||
if (rpc_pton(net, fo_path, size, sap, salen) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
trace_nfsd_ctl_unlock_ip(net, buf);
|
||||
trace_nfsd_ctl_unlock_ip(net, sap, svc_addr_len(sap));
|
||||
return nlmsvc_unlock_all_by_ip(sap);
|
||||
}
|
||||
|
||||
@@ -1412,6 +1413,21 @@ static int create_proc_exports_entry(void)
|
||||
|
||||
unsigned int nfsd_net_id;
|
||||
|
||||
struct nfsd_genl_rqstp {
|
||||
struct sockaddr rq_daddr;
|
||||
struct sockaddr rq_saddr;
|
||||
unsigned long rq_flags;
|
||||
ktime_t rq_stime;
|
||||
__be32 rq_xid;
|
||||
u32 rq_vers;
|
||||
u32 rq_prog;
|
||||
u32 rq_proc;
|
||||
|
||||
/* NFSv4 compound */
|
||||
u32 rq_opcnt;
|
||||
u32 rq_opnum[16];
|
||||
};
|
||||
|
||||
static int nfsd_genl_rpc_status_compose_msg(struct sk_buff *skb,
|
||||
struct netlink_callback *cb,
|
||||
struct nfsd_genl_rqstp *genl_rqstp)
|
||||
@@ -2197,6 +2213,193 @@ int nfsd_nl_pool_mode_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_cache_flush_doit - flush nfsd caches via netlink
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Flush the svc_export and/or expkey caches. If NFSD_A_CACHE_FLUSH_MASK
|
||||
* is provided, only flush the caches indicated by the bitmask (bit 0 =
|
||||
* svc_export, bit 1 = expkey). If omitted, flush both.
|
||||
*
|
||||
* Return 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net *net = genl_info_net(info);
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
u32 mask = ~0U;
|
||||
|
||||
if (info->attrs[NFSD_A_CACHE_FLUSH_MASK])
|
||||
mask = nla_get_u32(info->attrs[NFSD_A_CACHE_FLUSH_MASK]);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
if ((mask & NFSD_CACHE_TYPE_SVC_EXPORT) &&
|
||||
nn->svc_export_cache)
|
||||
cache_purge(nn->svc_export_cache);
|
||||
|
||||
if ((mask & NFSD_CACHE_TYPE_EXPKEY) &&
|
||||
nn->svc_expkey_cache)
|
||||
cache_purge(nn->svc_expkey_cache);
|
||||
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nfsd_cache_notify(struct cache_detail *cd, struct cache_head *h, u32 cache_type)
|
||||
{
|
||||
struct genlmsghdr *hdr;
|
||||
struct sk_buff *msg;
|
||||
|
||||
if (!genl_has_listeners(&nfsd_nl_family, cd->net, NFSD_NLGRP_EXPORTD))
|
||||
return -ENOLINK;
|
||||
|
||||
msg = genlmsg_new(nla_total_size(sizeof(u32)), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, 0, &nfsd_nl_family, 0, NFSD_CMD_CACHE_NOTIFY);
|
||||
if (!hdr) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, NFSD_A_CACHE_NOTIFY_CACHE_TYPE, cache_type)) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return genlmsg_multicast_netns(&nfsd_nl_family, cd->net, msg, 0,
|
||||
NFSD_NLGRP_EXPORTD, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_unlock_ip_doit - release NLM locks held by an IP address
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Return: 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_unlock_ip_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct sockaddr *sap;
|
||||
|
||||
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_UNLOCK_IP_ADDRESS))
|
||||
return -EINVAL;
|
||||
sap = nla_data(info->attrs[NFSD_A_UNLOCK_IP_ADDRESS]);
|
||||
switch (sap->sa_family) {
|
||||
case AF_INET:
|
||||
if (nla_len(info->attrs[NFSD_A_UNLOCK_IP_ADDRESS]) <
|
||||
sizeof(struct sockaddr_in))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (nla_len(info->attrs[NFSD_A_UNLOCK_IP_ADDRESS]) <
|
||||
sizeof(struct sockaddr_in6))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
/*
|
||||
* nlmsvc_unlock_all_by_ip() releases matching locks
|
||||
* across all network namespaces because lockd operates
|
||||
* a single global instance.
|
||||
*/
|
||||
trace_nfsd_ctl_unlock_ip(genl_info_net(info), sap,
|
||||
svc_addr_len(sap));
|
||||
return nlmsvc_unlock_all_by_ip(sap);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_unlock_filesystem_doit - revoke NFS state under a filesystem path
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Return: 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_unlock_filesystem_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct net *net = genl_info_net(info);
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_UNLOCK_FILESYSTEM_PATH))
|
||||
return -EINVAL;
|
||||
|
||||
trace_nfsd_ctl_unlock_fs(net,
|
||||
nla_data(info->attrs[NFSD_A_UNLOCK_FILESYSTEM_PATH]));
|
||||
error = kern_path(
|
||||
nla_data(info->attrs[NFSD_A_UNLOCK_FILESYSTEM_PATH]),
|
||||
0, &path);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
nfsd4_cancel_copy_by_sb(net, path.dentry->d_sb);
|
||||
error = nlmsvc_unlock_all_by_sb(path.dentry->d_sb);
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
if (nn->nfsd_serv)
|
||||
nfsd4_revoke_states(nn, path.dentry->d_sb);
|
||||
else
|
||||
error = -EINVAL;
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_unlock_export_doit - revoke NFSv4 state for an export path
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Revokes all NFSv4 state (opens, locks, delegations, layouts) acquired
|
||||
* through any export of the given path, regardless of which client holds
|
||||
* the state. Userspace (exportfs -u) sends this after removing the last
|
||||
* client for a path so the underlying filesystem can be unmounted.
|
||||
*
|
||||
* Unlike NFSD_CMD_UNLOCK_FILESYSTEM, which operates at superblock
|
||||
* granularity, this command revokes only the state associated with
|
||||
* exports of a specific path.
|
||||
*
|
||||
* Return: 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_unlock_export_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net *net = genl_info_net(info);
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_UNLOCK_EXPORT_PATH))
|
||||
return -EINVAL;
|
||||
|
||||
trace_nfsd_ctl_unlock_export(net,
|
||||
nla_data(info->attrs[NFSD_A_UNLOCK_EXPORT_PATH]));
|
||||
error = kern_path(
|
||||
nla_data(info->attrs[NFSD_A_UNLOCK_EXPORT_PATH]),
|
||||
0, &path);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
if (nn->nfsd_serv) {
|
||||
nfsd_file_close_export(net, &path);
|
||||
nfsd4_revoke_export_states(nn, &path);
|
||||
} else
|
||||
error = -EINVAL;
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
|
||||
path_put(&path);
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
|
||||
* @net: a freshly-created network namespace
|
||||
@@ -2320,12 +2523,9 @@ static int __init init_nfsd(void)
|
||||
if (retval)
|
||||
goto out_free_pnfs;
|
||||
nfsd_lockd_init(); /* lockd->nfsd callbacks */
|
||||
retval = nfsd_export_wq_init();
|
||||
if (retval)
|
||||
goto out_free_lockd;
|
||||
retval = register_pernet_subsys(&nfsd_net_ops);
|
||||
if (retval < 0)
|
||||
goto out_free_export_wq;
|
||||
goto out_free_lockd;
|
||||
retval = register_cld_notifier();
|
||||
if (retval)
|
||||
goto out_free_subsys;
|
||||
@@ -2354,8 +2554,6 @@ static int __init init_nfsd(void)
|
||||
unregister_cld_notifier();
|
||||
out_free_subsys:
|
||||
unregister_pernet_subsys(&nfsd_net_ops);
|
||||
out_free_export_wq:
|
||||
nfsd_export_wq_shutdown();
|
||||
out_free_lockd:
|
||||
nfsd_lockd_shutdown();
|
||||
nfsd_drc_slab_free();
|
||||
@@ -2376,7 +2574,6 @@ static void __exit exit_nfsd(void)
|
||||
nfsd4_destroy_laundry_wq();
|
||||
unregister_cld_notifier();
|
||||
unregister_pernet_subsys(&nfsd_net_ops);
|
||||
nfsd_export_wq_shutdown();
|
||||
nfsd_drc_slab_free();
|
||||
nfsd_lockd_shutdown();
|
||||
nfsd4_free_slabs();
|
||||
|
||||
@@ -45,11 +45,10 @@ bool nfsd_support_version(int vers);
|
||||
|
||||
/*
|
||||
* Default and maximum payload size (NFS READ or WRITE), in bytes.
|
||||
* The default is historical, and the maximum is an implementation
|
||||
* limit.
|
||||
* The maximum is an implementation limit.
|
||||
*/
|
||||
enum {
|
||||
NFSSVC_DEFBLKSIZE = 1 * 1024 * 1024,
|
||||
NFSSVC_DEFBLKSIZE = 4 * 1024 * 1024,
|
||||
NFSSVC_MAXBLKSIZE = RPCSVC_MAXPAYLOAD,
|
||||
};
|
||||
|
||||
@@ -60,21 +59,6 @@ struct readdir_cd {
|
||||
/* Maximum number of operations per session compound */
|
||||
#define NFSD_MAX_OPS_PER_COMPOUND 200
|
||||
|
||||
struct nfsd_genl_rqstp {
|
||||
struct sockaddr rq_daddr;
|
||||
struct sockaddr rq_saddr;
|
||||
unsigned long rq_flags;
|
||||
ktime_t rq_stime;
|
||||
__be32 rq_xid;
|
||||
u32 rq_vers;
|
||||
u32 rq_prog;
|
||||
u32 rq_proc;
|
||||
|
||||
/* NFSv4 compound */
|
||||
u32 rq_opcnt;
|
||||
u32 rq_opnum[16];
|
||||
};
|
||||
|
||||
extern struct svc_program nfsd_programs[];
|
||||
extern const struct svc_version nfsd_version2, nfsd_version3, nfsd_version4;
|
||||
extern struct mutex nfsd_mutex;
|
||||
@@ -123,7 +107,7 @@ struct dentry *nfsd_client_mkdir(struct nfsd_net *nn,
|
||||
const struct tree_descr *,
|
||||
struct dentry **fdentries);
|
||||
void nfsd_client_rmdir(struct dentry *dentry);
|
||||
|
||||
int nfsd_cache_notify(struct cache_detail *cd, struct cache_head *h, u32 cache_type);
|
||||
|
||||
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
|
||||
#ifdef CONFIG_NFSD_V2_ACL
|
||||
|
||||
@@ -145,6 +145,7 @@ struct nfs4_stid {
|
||||
spinlock_t sc_lock;
|
||||
struct nfs4_client *sc_client;
|
||||
struct nfs4_file *sc_file;
|
||||
struct svc_export *sc_export;
|
||||
void (*sc_free)(struct nfs4_stid *);
|
||||
};
|
||||
|
||||
@@ -862,6 +863,7 @@ struct nfsd_file *find_any_file(struct nfs4_file *f);
|
||||
|
||||
#ifdef CONFIG_NFSD_V4
|
||||
void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb);
|
||||
void nfsd4_revoke_export_states(struct nfsd_net *nn, const struct path *path);
|
||||
void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb);
|
||||
int nfsd_net_cb_init(struct nfsd_net *nn);
|
||||
void nfsd_net_cb_shutdown(struct nfsd_net *nn);
|
||||
@@ -869,6 +871,10 @@ void nfsd_net_cb_shutdown(struct nfsd_net *nn);
|
||||
static inline void nfsd4_revoke_states(struct nfsd_net *nn, struct super_block *sb)
|
||||
{
|
||||
}
|
||||
static inline void nfsd4_revoke_export_states(struct nfsd_net *nn,
|
||||
const struct path *path)
|
||||
{
|
||||
}
|
||||
static inline void nfsd4_cancel_copy_by_sb(struct net *net, struct super_block *sb)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1985,19 +1985,20 @@ TRACE_EVENT(nfsd_cb_recall_any_done,
|
||||
TRACE_EVENT(nfsd_ctl_unlock_ip,
|
||||
TP_PROTO(
|
||||
const struct net *net,
|
||||
const char *address
|
||||
const struct sockaddr *addr,
|
||||
const unsigned int addrlen
|
||||
),
|
||||
TP_ARGS(net, address),
|
||||
TP_ARGS(net, addr, addrlen),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, netns_ino)
|
||||
__string(address, address)
|
||||
__sockaddr(addr, addrlen)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->netns_ino = net->ns.inum;
|
||||
__assign_str(address);
|
||||
__assign_sockaddr(addr, addr, addrlen);
|
||||
),
|
||||
TP_printk("address=%s",
|
||||
__get_str(address)
|
||||
TP_printk("addr=%pISpc",
|
||||
__get_sockaddr(addr)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -2020,6 +2021,25 @@ TRACE_EVENT(nfsd_ctl_unlock_fs,
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_ctl_unlock_export,
|
||||
TP_PROTO(
|
||||
const struct net *net,
|
||||
const char *path
|
||||
),
|
||||
TP_ARGS(net, path),
|
||||
TP_STRUCT__entry(
|
||||
__field(unsigned int, netns_ino)
|
||||
__string(path, path)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->netns_ino = net->ns.inum;
|
||||
__assign_str(path);
|
||||
),
|
||||
TP_printk("path=%s",
|
||||
__get_str(path)
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(nfsd_ctl_filehandle,
|
||||
TP_PROTO(
|
||||
const struct net *net,
|
||||
|
||||
@@ -1440,7 +1440,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
unsigned long exp_op_flags = 0;
|
||||
unsigned int pflags = current->flags;
|
||||
bool restore_flags = false;
|
||||
unsigned int nvecs;
|
||||
int nvecs;
|
||||
|
||||
trace_nfsd_write_opened(rqstp, fhp, offset, *cnt);
|
||||
|
||||
@@ -1480,6 +1480,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
}
|
||||
|
||||
nvecs = xdr_buf_to_bvec(rqstp->rq_bvec, rqstp->rq_maxpages, payload);
|
||||
if (nvecs < 0) {
|
||||
host_err = nvecs;
|
||||
goto out_nfserr;
|
||||
}
|
||||
|
||||
since = READ_ONCE(file->f_wb_err);
|
||||
if (verf)
|
||||
@@ -1509,8 +1513,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
nfsd_stats_io_write_add(nn, exp, *cnt);
|
||||
fsnotify_modify(file);
|
||||
host_err = filemap_check_wb_err(file->f_mapping, since);
|
||||
if (host_err < 0)
|
||||
if (host_err < 0) {
|
||||
commit_reset_write_verifier(nn, rqstp, host_err);
|
||||
goto out_nfserr;
|
||||
}
|
||||
|
||||
if (stable && fhp->fh_use_wgather) {
|
||||
host_err = wait_for_concurrent_writes(file);
|
||||
@@ -1690,6 +1696,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
|
||||
nfsd_copy_write_verifier(verf, nn);
|
||||
err2 = filemap_check_wb_err(nf->nf_file->f_mapping,
|
||||
since);
|
||||
if (err2 < 0)
|
||||
commit_reset_write_verifier(nn, rqstp, err2);
|
||||
err = nfserrno(err2);
|
||||
break;
|
||||
case -EINVAL:
|
||||
|
||||
@@ -80,6 +80,9 @@ struct cache_detail {
|
||||
int (*cache_upcall)(struct cache_detail *,
|
||||
struct cache_head *);
|
||||
|
||||
int (*cache_notify)(struct cache_detail *cd,
|
||||
struct cache_head *h);
|
||||
|
||||
void (*cache_request)(struct cache_detail *cd,
|
||||
struct cache_head *ch,
|
||||
char **bpp, int *blen);
|
||||
@@ -189,9 +192,9 @@ sunrpc_cache_update(struct cache_detail *detail,
|
||||
struct cache_head *new, struct cache_head *old, int hash);
|
||||
|
||||
extern int
|
||||
sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h);
|
||||
sunrpc_cache_upcall(struct cache_detail *detail, struct cache_head *h);
|
||||
extern int
|
||||
sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
|
||||
sunrpc_cache_upcall_warn(struct cache_detail *detail,
|
||||
struct cache_head *h);
|
||||
|
||||
|
||||
@@ -248,6 +251,14 @@ extern int sunrpc_cache_register_pipefs(struct dentry *parent, const char *,
|
||||
extern void sunrpc_cache_unregister_pipefs(struct cache_detail *);
|
||||
extern void sunrpc_cache_unhash(struct cache_detail *, struct cache_head *);
|
||||
|
||||
int sunrpc_cache_requests_count(struct cache_detail *cd);
|
||||
int sunrpc_cache_requests_snapshot(struct cache_detail *cd,
|
||||
struct cache_head **items,
|
||||
u64 *seqnos, int max,
|
||||
u64 min_seqno);
|
||||
int sunrpc_cache_notify(struct cache_detail *cd, struct cache_head *h,
|
||||
u32 cache_type);
|
||||
|
||||
/* Must store cache_detail in seq_file->private if using next three functions */
|
||||
extern void *cache_seq_start_rcu(struct seq_file *file, loff_t *pos);
|
||||
extern void *cache_seq_next_rcu(struct seq_file *file, void *p, loff_t *pos);
|
||||
|
||||
@@ -37,13 +37,9 @@
|
||||
#ifndef _LINUX_SUNRPC_GSS_KRB5_H
|
||||
#define _LINUX_SUNRPC_GSS_KRB5_H
|
||||
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/sunrpc/auth_gss.h>
|
||||
#include <linux/sunrpc/gss_err.h>
|
||||
|
||||
/* Length of constant used in key derivation */
|
||||
#define GSS_KRB5_K5CLENGTH (5)
|
||||
|
||||
/* Maximum key length (in bytes) for the supported crypto algorithms */
|
||||
#define GSS_KRB5_MAX_KEYLEN (32)
|
||||
|
||||
@@ -56,11 +52,6 @@
|
||||
/* The length of the Kerberos GSS token header */
|
||||
#define GSS_KRB5_TOK_HDR_LEN (16)
|
||||
|
||||
#define KG_TOK_MIC_MSG 0x0101
|
||||
#define KG_TOK_WRAP_MSG 0x0201
|
||||
|
||||
#define KG2_TOK_INITIAL 0x0101
|
||||
#define KG2_TOK_RESPONSE 0x0202
|
||||
#define KG2_TOK_MIC 0x0404
|
||||
#define KG2_TOK_WRAP 0x0504
|
||||
|
||||
@@ -68,102 +59,6 @@
|
||||
#define KG2_TOKEN_FLAG_SEALED 0x02
|
||||
#define KG2_TOKEN_FLAG_ACCEPTORSUBKEY 0x04
|
||||
|
||||
#define KG2_RESP_FLAG_ERROR 0x0001
|
||||
#define KG2_RESP_FLAG_DELEG_OK 0x0002
|
||||
|
||||
enum sgn_alg {
|
||||
SGN_ALG_DES_MAC_MD5 = 0x0000,
|
||||
SGN_ALG_MD2_5 = 0x0001,
|
||||
SGN_ALG_DES_MAC = 0x0002,
|
||||
SGN_ALG_3 = 0x0003, /* not published */
|
||||
SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004
|
||||
};
|
||||
enum seal_alg {
|
||||
SEAL_ALG_NONE = 0xffff,
|
||||
SEAL_ALG_DES = 0x0000,
|
||||
SEAL_ALG_1 = 0x0001, /* not published */
|
||||
SEAL_ALG_DES3KD = 0x0002
|
||||
};
|
||||
|
||||
/*
|
||||
* These values are assigned by IANA and published via the
|
||||
* subregistry at the link below:
|
||||
*
|
||||
* https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-2
|
||||
*/
|
||||
#define CKSUMTYPE_CRC32 0x0001
|
||||
#define CKSUMTYPE_RSA_MD4 0x0002
|
||||
#define CKSUMTYPE_RSA_MD4_DES 0x0003
|
||||
#define CKSUMTYPE_DESCBC 0x0004
|
||||
#define CKSUMTYPE_RSA_MD5 0x0007
|
||||
#define CKSUMTYPE_RSA_MD5_DES 0x0008
|
||||
#define CKSUMTYPE_NIST_SHA 0x0009
|
||||
#define CKSUMTYPE_HMAC_SHA1_DES3 0x000c
|
||||
#define CKSUMTYPE_HMAC_SHA1_96_AES128 0x000f
|
||||
#define CKSUMTYPE_HMAC_SHA1_96_AES256 0x0010
|
||||
#define CKSUMTYPE_CMAC_CAMELLIA128 0x0011
|
||||
#define CKSUMTYPE_CMAC_CAMELLIA256 0x0012
|
||||
#define CKSUMTYPE_HMAC_SHA256_128_AES128 0x0013
|
||||
#define CKSUMTYPE_HMAC_SHA384_192_AES256 0x0014
|
||||
#define CKSUMTYPE_HMAC_MD5_ARCFOUR -138 /* Microsoft md5 hmac cksumtype */
|
||||
|
||||
/* from gssapi_err_krb5.h */
|
||||
#define KG_CCACHE_NOMATCH (39756032L)
|
||||
#define KG_KEYTAB_NOMATCH (39756033L)
|
||||
#define KG_TGT_MISSING (39756034L)
|
||||
#define KG_NO_SUBKEY (39756035L)
|
||||
#define KG_CONTEXT_ESTABLISHED (39756036L)
|
||||
#define KG_BAD_SIGN_TYPE (39756037L)
|
||||
#define KG_BAD_LENGTH (39756038L)
|
||||
#define KG_CTX_INCOMPLETE (39756039L)
|
||||
#define KG_CONTEXT (39756040L)
|
||||
#define KG_CRED (39756041L)
|
||||
#define KG_ENC_DESC (39756042L)
|
||||
#define KG_BAD_SEQ (39756043L)
|
||||
#define KG_EMPTY_CCACHE (39756044L)
|
||||
#define KG_NO_CTYPES (39756045L)
|
||||
|
||||
/* per Kerberos v5 protocol spec crypto types from the wire.
|
||||
* these get mapped to linux kernel crypto routines.
|
||||
*
|
||||
* These values are assigned by IANA and published via the
|
||||
* subregistry at the link below:
|
||||
*
|
||||
* https://www.iana.org/assignments/kerberos-parameters/kerberos-parameters.xhtml#kerberos-parameters-1
|
||||
*/
|
||||
#define ENCTYPE_NULL 0x0000
|
||||
#define ENCTYPE_DES_CBC_CRC 0x0001 /* DES cbc mode with CRC-32 */
|
||||
#define ENCTYPE_DES_CBC_MD4 0x0002 /* DES cbc mode with RSA-MD4 */
|
||||
#define ENCTYPE_DES_CBC_MD5 0x0003 /* DES cbc mode with RSA-MD5 */
|
||||
#define ENCTYPE_DES_CBC_RAW 0x0004 /* DES cbc mode raw */
|
||||
/* XXX deprecated? */
|
||||
#define ENCTYPE_DES3_CBC_SHA 0x0005 /* DES-3 cbc mode with NIST-SHA */
|
||||
#define ENCTYPE_DES3_CBC_RAW 0x0006 /* DES-3 cbc mode raw */
|
||||
#define ENCTYPE_DES_HMAC_SHA1 0x0008
|
||||
#define ENCTYPE_DES3_CBC_SHA1 0x0010
|
||||
#define ENCTYPE_AES128_CTS_HMAC_SHA1_96 0x0011
|
||||
#define ENCTYPE_AES256_CTS_HMAC_SHA1_96 0x0012
|
||||
#define ENCTYPE_AES128_CTS_HMAC_SHA256_128 0x0013
|
||||
#define ENCTYPE_AES256_CTS_HMAC_SHA384_192 0x0014
|
||||
#define ENCTYPE_ARCFOUR_HMAC 0x0017
|
||||
#define ENCTYPE_ARCFOUR_HMAC_EXP 0x0018
|
||||
#define ENCTYPE_CAMELLIA128_CTS_CMAC 0x0019
|
||||
#define ENCTYPE_CAMELLIA256_CTS_CMAC 0x001A
|
||||
#define ENCTYPE_UNKNOWN 0x01ff
|
||||
|
||||
/*
|
||||
* Constants used for key derivation
|
||||
*/
|
||||
/* for 3DES */
|
||||
#define KG_USAGE_SEAL (22)
|
||||
#define KG_USAGE_SIGN (23)
|
||||
#define KG_USAGE_SEQ (24)
|
||||
|
||||
/* from rfc3961 */
|
||||
#define KEY_USAGE_SEED_CHECKSUM (0x99)
|
||||
#define KEY_USAGE_SEED_ENCRYPTION (0xAA)
|
||||
#define KEY_USAGE_SEED_INTEGRITY (0x55)
|
||||
|
||||
/* from rfc4121 */
|
||||
#define KG_USAGE_ACCEPTOR_SEAL (22)
|
||||
#define KG_USAGE_ACCEPTOR_SIGN (23)
|
||||
|
||||
@@ -66,7 +66,6 @@ extern unsigned int svcrdma_ord;
|
||||
extern unsigned int svcrdma_max_requests;
|
||||
extern unsigned int svcrdma_max_bc_requests;
|
||||
extern unsigned int svcrdma_max_req_size;
|
||||
extern struct workqueue_struct *svcrdma_wq;
|
||||
|
||||
extern struct percpu_counter svcrdma_stat_read;
|
||||
extern struct percpu_counter svcrdma_stat_recv;
|
||||
@@ -117,6 +116,8 @@ struct svcxprt_rdma {
|
||||
|
||||
struct llist_head sc_recv_ctxts;
|
||||
|
||||
struct llist_head sc_send_release_list;
|
||||
|
||||
atomic_t sc_completion_ids;
|
||||
};
|
||||
/* sc_flags */
|
||||
@@ -230,13 +231,11 @@ struct svc_rdma_write_info {
|
||||
unsigned int wi_next_off;
|
||||
|
||||
struct svc_rdma_chunk_ctxt wi_cc;
|
||||
struct work_struct wi_work;
|
||||
};
|
||||
|
||||
struct svc_rdma_send_ctxt {
|
||||
struct llist_node sc_node;
|
||||
struct rpc_rdma_cid sc_cid;
|
||||
struct work_struct sc_work;
|
||||
|
||||
struct svcxprt_rdma *sc_rdma;
|
||||
struct ib_send_wr sc_send_wr;
|
||||
@@ -300,6 +299,7 @@ extern int svc_rdma_process_read_list(struct svcxprt_rdma *rdma,
|
||||
|
||||
/* svc_rdma_sendto.c */
|
||||
extern void svc_rdma_send_ctxts_destroy(struct svcxprt_rdma *rdma);
|
||||
extern void svc_rdma_send_ctxts_drain(struct svcxprt_rdma *rdma);
|
||||
extern struct svc_rdma_send_ctxt *
|
||||
svc_rdma_send_ctxt_get(struct svcxprt_rdma *rdma);
|
||||
extern void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma,
|
||||
@@ -328,6 +328,7 @@ extern int svc_rdma_result_payload(struct svc_rqst *rqstp, unsigned int offset,
|
||||
unsigned int length);
|
||||
|
||||
/* svc_rdma_transport.c */
|
||||
extern void svc_rdma_xprt_deferred_close(struct svcxprt_rdma *rdma);
|
||||
extern struct svc_xprt_class svc_rdma_class;
|
||||
#ifdef CONFIG_SUNRPC_BACKCHANNEL
|
||||
extern struct svc_xprt_class svc_rdma_bc_class;
|
||||
|
||||
@@ -138,8 +138,23 @@ void xdr_terminate_string(const struct xdr_buf *, const u32);
|
||||
size_t xdr_buf_pagecount(const struct xdr_buf *buf);
|
||||
int xdr_alloc_bvec(struct xdr_buf *buf, gfp_t gfp);
|
||||
void xdr_free_bvec(struct xdr_buf *buf);
|
||||
unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
|
||||
const struct xdr_buf *xdr);
|
||||
int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
|
||||
const struct xdr_buf *xdr);
|
||||
int xdr_buf_to_sg(const struct xdr_buf *buf, unsigned int offset,
|
||||
unsigned int len, struct scatterlist *sg, unsigned int nsg);
|
||||
int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
|
||||
unsigned int len, struct scatterlist *sg_head,
|
||||
unsigned int sg_head_nents,
|
||||
struct scatterlist **sg_overflow, gfp_t gfp);
|
||||
|
||||
/*
|
||||
* Inline scatterlist entries for xdr_buf_to_sg_alloc(). Sized to cover the
|
||||
* head kvec, tail kvec, and a few page fragments without any heap allocation.
|
||||
*/
|
||||
enum {
|
||||
XDR_BUF_TO_SG_NENTS = 8,
|
||||
};
|
||||
|
||||
|
||||
static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
|
||||
{
|
||||
@@ -260,7 +275,6 @@ extern void xdr_finish_decode(struct xdr_stream *xdr);
|
||||
extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
|
||||
extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
|
||||
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
|
||||
extern int xdr_process_buf(const struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data);
|
||||
extern void xdr_set_pagelen(struct xdr_stream *, unsigned int len);
|
||||
extern bool xdr_stream_subsegment(struct xdr_stream *xdr, struct xdr_buf *subbuf,
|
||||
unsigned int len);
|
||||
|
||||
210
include/linux/sunrpc/xdrgen/nlm3.h
Normal file
210
include/linux/sunrpc/xdrgen/nlm3.h
Normal file
@@ -0,0 +1,210 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/* Generated by xdrgen. Manual edits will be lost. */
|
||||
/* XDR specification file: ../../Documentation/sunrpc/xdr/nlm3.x */
|
||||
/* XDR specification modification time: Thu Apr 23 10:56:34 2026 */
|
||||
|
||||
#ifndef _LINUX_XDRGEN_NLM3_DEF_H
|
||||
#define _LINUX_XDRGEN_NLM3_DEF_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sunrpc/xdrgen/_defs.h>
|
||||
|
||||
enum { LM_MAXSTRLEN = 1024 };
|
||||
|
||||
enum { LM_MAXNAMELEN = 1025 };
|
||||
|
||||
enum { MAXNETOBJ_SZ = 1024 };
|
||||
|
||||
typedef opaque netobj;
|
||||
|
||||
enum nlm_stats {
|
||||
LCK_GRANTED = 0,
|
||||
LCK_DENIED = 1,
|
||||
LCK_DENIED_NOLOCKS = 2,
|
||||
LCK_BLOCKED = 3,
|
||||
LCK_DENIED_GRACE_PERIOD = 4,
|
||||
};
|
||||
|
||||
typedef __be32 nlm_stats;
|
||||
|
||||
struct nlm_stat {
|
||||
nlm_stats stat;
|
||||
};
|
||||
|
||||
struct nlm_res {
|
||||
netobj cookie;
|
||||
struct nlm_stat stat;
|
||||
};
|
||||
|
||||
struct nlm_holder {
|
||||
bool exclusive;
|
||||
s32 uppid;
|
||||
netobj oh;
|
||||
u32 l_offset;
|
||||
u32 l_len;
|
||||
};
|
||||
|
||||
struct nlm_testrply {
|
||||
nlm_stats stat;
|
||||
union {
|
||||
struct nlm_holder holder;
|
||||
} u;
|
||||
};
|
||||
|
||||
struct nlm_testres {
|
||||
netobj cookie;
|
||||
struct nlm_testrply test_stat;
|
||||
};
|
||||
|
||||
struct nlm_lock {
|
||||
string caller_name;
|
||||
netobj fh;
|
||||
netobj oh;
|
||||
s32 uppid;
|
||||
u32 l_offset;
|
||||
u32 l_len;
|
||||
};
|
||||
|
||||
struct nlm_lockargs {
|
||||
netobj cookie;
|
||||
bool block;
|
||||
bool exclusive;
|
||||
struct nlm_lock alock;
|
||||
bool reclaim;
|
||||
s32 state;
|
||||
};
|
||||
|
||||
struct nlm_cancargs {
|
||||
netobj cookie;
|
||||
bool block;
|
||||
bool exclusive;
|
||||
struct nlm_lock alock;
|
||||
};
|
||||
|
||||
struct nlm_testargs {
|
||||
netobj cookie;
|
||||
bool exclusive;
|
||||
struct nlm_lock alock;
|
||||
};
|
||||
|
||||
struct nlm_unlockargs {
|
||||
netobj cookie;
|
||||
struct nlm_lock alock;
|
||||
};
|
||||
|
||||
enum fsh_mode {
|
||||
fsm_DN = 0,
|
||||
fsm_DR = 1,
|
||||
fsm_DW = 2,
|
||||
fsm_DRW = 3,
|
||||
};
|
||||
|
||||
typedef enum fsh_mode fsh_mode;
|
||||
|
||||
enum fsh_access {
|
||||
fsa_NONE = 0,
|
||||
fsa_R = 1,
|
||||
fsa_W = 2,
|
||||
fsa_RW = 3,
|
||||
};
|
||||
|
||||
typedef enum fsh_access fsh_access;
|
||||
|
||||
struct nlm_share {
|
||||
string caller_name;
|
||||
netobj fh;
|
||||
netobj oh;
|
||||
fsh_mode mode;
|
||||
fsh_access access;
|
||||
};
|
||||
|
||||
struct nlm_shareargs {
|
||||
netobj cookie;
|
||||
struct nlm_share share;
|
||||
bool reclaim;
|
||||
};
|
||||
|
||||
struct nlm_shareres {
|
||||
netobj cookie;
|
||||
nlm_stats stat;
|
||||
s32 sequence;
|
||||
};
|
||||
|
||||
struct nlm_notify {
|
||||
string name;
|
||||
s32 state;
|
||||
};
|
||||
|
||||
enum { SM_PRIV_SIZE = 16 };
|
||||
|
||||
struct nlm_notifyargs {
|
||||
struct nlm_notify notify;
|
||||
u8 private[SM_PRIV_SIZE];
|
||||
};
|
||||
|
||||
enum {
|
||||
NLM_NULL = 0,
|
||||
NLM_TEST = 1,
|
||||
NLM_LOCK = 2,
|
||||
NLM_CANCEL = 3,
|
||||
NLM_UNLOCK = 4,
|
||||
NLM_GRANTED = 5,
|
||||
NLM_TEST_MSG = 6,
|
||||
NLM_LOCK_MSG = 7,
|
||||
NLM_CANCEL_MSG = 8,
|
||||
NLM_UNLOCK_MSG = 9,
|
||||
NLM_GRANTED_MSG = 10,
|
||||
NLM_TEST_RES = 11,
|
||||
NLM_LOCK_RES = 12,
|
||||
NLM_CANCEL_RES = 13,
|
||||
NLM_UNLOCK_RES = 14,
|
||||
NLM_GRANTED_RES = 15,
|
||||
NLM_SM_NOTIFY = 16,
|
||||
NLM_SHARE = 20,
|
||||
NLM_UNSHARE = 21,
|
||||
NLM_NM_LOCK = 22,
|
||||
NLM_FREE_ALL = 23,
|
||||
};
|
||||
|
||||
#ifndef NLM_PROG
|
||||
#define NLM_PROG (100021)
|
||||
#endif
|
||||
|
||||
#define NLM3_netobj_sz (XDR_unsigned_int + XDR_QUADLEN(MAXNETOBJ_SZ))
|
||||
#define NLM3_nlm_stats_sz (XDR_int)
|
||||
#define NLM3_nlm_stat_sz \
|
||||
(NLM3_nlm_stats_sz)
|
||||
#define NLM3_nlm_res_sz \
|
||||
(NLM3_netobj_sz + NLM3_nlm_stat_sz)
|
||||
#define NLM3_nlm_holder_sz \
|
||||
(XDR_bool + XDR_int + NLM3_netobj_sz + XDR_unsigned_int + XDR_unsigned_int)
|
||||
#define NLM3_nlm_testrply_sz \
|
||||
(NLM3_nlm_stats_sz + NLM3_nlm_holder_sz)
|
||||
#define NLM3_nlm_testres_sz \
|
||||
(NLM3_netobj_sz + NLM3_nlm_testrply_sz)
|
||||
#define NLM3_nlm_lock_sz \
|
||||
(XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM3_netobj_sz + NLM3_netobj_sz + XDR_int + XDR_unsigned_int + XDR_unsigned_int)
|
||||
#define NLM3_nlm_lockargs_sz \
|
||||
(NLM3_netobj_sz + XDR_bool + XDR_bool + NLM3_nlm_lock_sz + XDR_bool + XDR_int)
|
||||
#define NLM3_nlm_cancargs_sz \
|
||||
(NLM3_netobj_sz + XDR_bool + XDR_bool + NLM3_nlm_lock_sz)
|
||||
#define NLM3_nlm_testargs_sz \
|
||||
(NLM3_netobj_sz + XDR_bool + NLM3_nlm_lock_sz)
|
||||
#define NLM3_nlm_unlockargs_sz \
|
||||
(NLM3_netobj_sz + NLM3_nlm_lock_sz)
|
||||
#define NLM3_fsh_mode_sz (XDR_int)
|
||||
#define NLM3_fsh_access_sz (XDR_int)
|
||||
#define NLM3_nlm_share_sz \
|
||||
(XDR_unsigned_int + XDR_QUADLEN(LM_MAXSTRLEN) + NLM3_netobj_sz + NLM3_netobj_sz + NLM3_fsh_mode_sz + NLM3_fsh_access_sz)
|
||||
#define NLM3_nlm_shareargs_sz \
|
||||
(NLM3_netobj_sz + NLM3_nlm_share_sz + XDR_bool)
|
||||
#define NLM3_nlm_shareres_sz \
|
||||
(NLM3_netobj_sz + NLM3_nlm_stats_sz + XDR_int)
|
||||
#define NLM3_nlm_notify_sz \
|
||||
(XDR_unsigned_int + XDR_QUADLEN(LM_MAXNAMELEN) + XDR_long)
|
||||
#define NLM3_nlm_notifyargs_sz \
|
||||
(NLM3_nlm_notify_sz + XDR_QUADLEN(SM_PRIV_SIZE))
|
||||
#define NLM3_MAX_ARGS_SZ \
|
||||
(NLM3_nlm_lockargs_sz)
|
||||
|
||||
#endif /* _LINUX_XDRGEN_NLM3_DEF_H */
|
||||
@@ -10,6 +10,53 @@
|
||||
#define NFSD_FAMILY_NAME "nfsd"
|
||||
#define NFSD_FAMILY_VERSION 1
|
||||
|
||||
enum nfsd_cache_type {
|
||||
NFSD_CACHE_TYPE_SVC_EXPORT = 1,
|
||||
NFSD_CACHE_TYPE_EXPKEY = 2,
|
||||
};
|
||||
|
||||
/*
|
||||
* These flags are ordered to match the NFSEXP_* flags in
|
||||
* include/linux/nfsd/export.h
|
||||
*/
|
||||
enum nfsd_export_flags {
|
||||
NFSD_EXPORT_FLAGS_READONLY = 1,
|
||||
NFSD_EXPORT_FLAGS_INSECURE_PORT = 2,
|
||||
NFSD_EXPORT_FLAGS_ROOTSQUASH = 4,
|
||||
NFSD_EXPORT_FLAGS_ALLSQUASH = 8,
|
||||
NFSD_EXPORT_FLAGS_ASYNC = 16,
|
||||
NFSD_EXPORT_FLAGS_GATHERED_WRITES = 32,
|
||||
NFSD_EXPORT_FLAGS_NOREADDIRPLUS = 64,
|
||||
NFSD_EXPORT_FLAGS_SECURITY_LABEL = 128,
|
||||
NFSD_EXPORT_FLAGS_SIGN_FH = 256,
|
||||
NFSD_EXPORT_FLAGS_NOHIDE = 512,
|
||||
NFSD_EXPORT_FLAGS_NOSUBTREECHECK = 1024,
|
||||
NFSD_EXPORT_FLAGS_NOAUTHNLM = 2048,
|
||||
NFSD_EXPORT_FLAGS_MSNFS = 4096,
|
||||
NFSD_EXPORT_FLAGS_FSID = 8192,
|
||||
NFSD_EXPORT_FLAGS_CROSSMOUNT = 16384,
|
||||
NFSD_EXPORT_FLAGS_NOACL = 32768,
|
||||
NFSD_EXPORT_FLAGS_V4ROOT = 65536,
|
||||
NFSD_EXPORT_FLAGS_PNFS = 131072,
|
||||
};
|
||||
|
||||
/*
|
||||
* These flags are ordered to match the NFSEXP_XPRTSEC_* flags in
|
||||
* include/linux/nfsd/export.h
|
||||
*/
|
||||
enum nfsd_xprtsec_mode {
|
||||
NFSD_XPRTSEC_MODE_NONE = 1,
|
||||
NFSD_XPRTSEC_MODE_TLS = 2,
|
||||
NFSD_XPRTSEC_MODE_MTLS = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_CACHE_NOTIFY_CACHE_TYPE = 1,
|
||||
|
||||
__NFSD_A_CACHE_NOTIFY_MAX,
|
||||
NFSD_A_CACHE_NOTIFY_MAX = (__NFSD_A_CACHE_NOTIFY_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_RPC_STATUS_XID = 1,
|
||||
NFSD_A_RPC_STATUS_FLAGS,
|
||||
@@ -81,6 +128,103 @@ enum {
|
||||
NFSD_A_POOL_MODE_MAX = (__NFSD_A_POOL_MODE_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_FSLOCATION_HOST = 1,
|
||||
NFSD_A_FSLOCATION_PATH,
|
||||
|
||||
__NFSD_A_FSLOCATION_MAX,
|
||||
NFSD_A_FSLOCATION_MAX = (__NFSD_A_FSLOCATION_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_FSLOCATIONS_LOCATION = 1,
|
||||
|
||||
__NFSD_A_FSLOCATIONS_MAX,
|
||||
NFSD_A_FSLOCATIONS_MAX = (__NFSD_A_FSLOCATIONS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_AUTH_FLAVOR_PSEUDOFLAVOR = 1,
|
||||
NFSD_A_AUTH_FLAVOR_FLAGS,
|
||||
|
||||
__NFSD_A_AUTH_FLAVOR_MAX,
|
||||
NFSD_A_AUTH_FLAVOR_MAX = (__NFSD_A_AUTH_FLAVOR_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_SVC_EXPORT_SEQNO = 1,
|
||||
NFSD_A_SVC_EXPORT_CLIENT,
|
||||
NFSD_A_SVC_EXPORT_PATH,
|
||||
NFSD_A_SVC_EXPORT_NEGATIVE,
|
||||
NFSD_A_SVC_EXPORT_EXPIRY,
|
||||
NFSD_A_SVC_EXPORT_ANON_UID,
|
||||
NFSD_A_SVC_EXPORT_ANON_GID,
|
||||
NFSD_A_SVC_EXPORT_FSLOCATIONS,
|
||||
NFSD_A_SVC_EXPORT_UUID,
|
||||
NFSD_A_SVC_EXPORT_SECINFO,
|
||||
NFSD_A_SVC_EXPORT_XPRTSEC,
|
||||
NFSD_A_SVC_EXPORT_FLAGS,
|
||||
NFSD_A_SVC_EXPORT_FSID,
|
||||
|
||||
__NFSD_A_SVC_EXPORT_MAX,
|
||||
NFSD_A_SVC_EXPORT_MAX = (__NFSD_A_SVC_EXPORT_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_SVC_EXPORT_REQS_REQUESTS = 1,
|
||||
|
||||
__NFSD_A_SVC_EXPORT_REQS_MAX,
|
||||
NFSD_A_SVC_EXPORT_REQS_MAX = (__NFSD_A_SVC_EXPORT_REQS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_EXPKEY_SEQNO = 1,
|
||||
NFSD_A_EXPKEY_CLIENT,
|
||||
NFSD_A_EXPKEY_FSIDTYPE,
|
||||
NFSD_A_EXPKEY_FSID,
|
||||
NFSD_A_EXPKEY_NEGATIVE,
|
||||
NFSD_A_EXPKEY_EXPIRY,
|
||||
NFSD_A_EXPKEY_PATH,
|
||||
|
||||
__NFSD_A_EXPKEY_MAX,
|
||||
NFSD_A_EXPKEY_MAX = (__NFSD_A_EXPKEY_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_EXPKEY_REQS_REQUESTS = 1,
|
||||
|
||||
__NFSD_A_EXPKEY_REQS_MAX,
|
||||
NFSD_A_EXPKEY_REQS_MAX = (__NFSD_A_EXPKEY_REQS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_CACHE_FLUSH_MASK = 1,
|
||||
|
||||
__NFSD_A_CACHE_FLUSH_MAX,
|
||||
NFSD_A_CACHE_FLUSH_MAX = (__NFSD_A_CACHE_FLUSH_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_UNLOCK_IP_ADDRESS = 1,
|
||||
|
||||
__NFSD_A_UNLOCK_IP_MAX,
|
||||
NFSD_A_UNLOCK_IP_MAX = (__NFSD_A_UNLOCK_IP_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_UNLOCK_FILESYSTEM_PATH = 1,
|
||||
|
||||
__NFSD_A_UNLOCK_FILESYSTEM_MAX,
|
||||
NFSD_A_UNLOCK_FILESYSTEM_MAX = (__NFSD_A_UNLOCK_FILESYSTEM_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_UNLOCK_EXPORT_PATH = 1,
|
||||
|
||||
__NFSD_A_UNLOCK_EXPORT_MAX,
|
||||
NFSD_A_UNLOCK_EXPORT_MAX = (__NFSD_A_UNLOCK_EXPORT_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_CMD_RPC_STATUS_GET = 1,
|
||||
NFSD_CMD_THREADS_SET,
|
||||
@@ -91,9 +235,21 @@ enum {
|
||||
NFSD_CMD_LISTENER_GET,
|
||||
NFSD_CMD_POOL_MODE_SET,
|
||||
NFSD_CMD_POOL_MODE_GET,
|
||||
NFSD_CMD_CACHE_NOTIFY,
|
||||
NFSD_CMD_SVC_EXPORT_GET_REQS,
|
||||
NFSD_CMD_SVC_EXPORT_SET_REQS,
|
||||
NFSD_CMD_EXPKEY_GET_REQS,
|
||||
NFSD_CMD_EXPKEY_SET_REQS,
|
||||
NFSD_CMD_CACHE_FLUSH,
|
||||
NFSD_CMD_UNLOCK_IP,
|
||||
NFSD_CMD_UNLOCK_FILESYSTEM,
|
||||
NFSD_CMD_UNLOCK_EXPORT,
|
||||
|
||||
__NFSD_CMD_MAX,
|
||||
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)
|
||||
};
|
||||
|
||||
#define NFSD_MCGRP_NONE "none"
|
||||
#define NFSD_MCGRP_EXPORTD "exportd"
|
||||
|
||||
#endif /* _UAPI_LINUX_NFSD_NETLINK_H */
|
||||
|
||||
84
include/uapi/linux/sunrpc_netlink.h
Normal file
84
include/uapi/linux/sunrpc_netlink.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/sunrpc_cache.yaml */
|
||||
/* YNL-GEN uapi header */
|
||||
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
|
||||
|
||||
#ifndef _UAPI_LINUX_SUNRPC_NETLINK_H
|
||||
#define _UAPI_LINUX_SUNRPC_NETLINK_H
|
||||
|
||||
#define SUNRPC_FAMILY_NAME "sunrpc"
|
||||
#define SUNRPC_FAMILY_VERSION 1
|
||||
|
||||
enum sunrpc_cache_type {
|
||||
SUNRPC_CACHE_TYPE_IP_MAP = 1,
|
||||
SUNRPC_CACHE_TYPE_UNIX_GID = 2,
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_A_CACHE_NOTIFY_CACHE_TYPE = 1,
|
||||
|
||||
__SUNRPC_A_CACHE_NOTIFY_MAX,
|
||||
SUNRPC_A_CACHE_NOTIFY_MAX = (__SUNRPC_A_CACHE_NOTIFY_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_A_IP_MAP_SEQNO = 1,
|
||||
SUNRPC_A_IP_MAP_CLASS,
|
||||
SUNRPC_A_IP_MAP_ADDR,
|
||||
SUNRPC_A_IP_MAP_DOMAIN,
|
||||
SUNRPC_A_IP_MAP_NEGATIVE,
|
||||
SUNRPC_A_IP_MAP_EXPIRY,
|
||||
|
||||
__SUNRPC_A_IP_MAP_MAX,
|
||||
SUNRPC_A_IP_MAP_MAX = (__SUNRPC_A_IP_MAP_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_A_IP_MAP_REQS_REQUESTS = 1,
|
||||
|
||||
__SUNRPC_A_IP_MAP_REQS_MAX,
|
||||
SUNRPC_A_IP_MAP_REQS_MAX = (__SUNRPC_A_IP_MAP_REQS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_A_UNIX_GID_SEQNO = 1,
|
||||
SUNRPC_A_UNIX_GID_UID,
|
||||
SUNRPC_A_UNIX_GID_GIDS,
|
||||
SUNRPC_A_UNIX_GID_NEGATIVE,
|
||||
SUNRPC_A_UNIX_GID_EXPIRY,
|
||||
|
||||
__SUNRPC_A_UNIX_GID_MAX,
|
||||
SUNRPC_A_UNIX_GID_MAX = (__SUNRPC_A_UNIX_GID_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_A_UNIX_GID_REQS_REQUESTS = 1,
|
||||
|
||||
__SUNRPC_A_UNIX_GID_REQS_MAX,
|
||||
SUNRPC_A_UNIX_GID_REQS_MAX = (__SUNRPC_A_UNIX_GID_REQS_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_A_CACHE_FLUSH_MASK = 1,
|
||||
|
||||
__SUNRPC_A_CACHE_FLUSH_MAX,
|
||||
SUNRPC_A_CACHE_FLUSH_MAX = (__SUNRPC_A_CACHE_FLUSH_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
SUNRPC_CMD_CACHE_NOTIFY = 1,
|
||||
SUNRPC_CMD_IP_MAP_GET_REQS,
|
||||
SUNRPC_CMD_IP_MAP_SET_REQS,
|
||||
SUNRPC_CMD_UNIX_GID_GET_REQS,
|
||||
SUNRPC_CMD_UNIX_GID_SET_REQS,
|
||||
SUNRPC_CMD_CACHE_FLUSH,
|
||||
|
||||
__SUNRPC_CMD_MAX,
|
||||
SUNRPC_CMD_MAX = (__SUNRPC_CMD_MAX - 1)
|
||||
};
|
||||
|
||||
#define SUNRPC_MCGRP_NONE "none"
|
||||
#define SUNRPC_MCGRP_EXPORTD "exportd"
|
||||
|
||||
#endif /* _UAPI_LINUX_SUNRPC_NETLINK_H */
|
||||
@@ -1,29 +0,0 @@
|
||||
CONFIG_KUNIT=y
|
||||
CONFIG_UBSAN=y
|
||||
CONFIG_STACKTRACE=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_NETWORK_FILESYSTEMS=y
|
||||
CONFIG_INET=y
|
||||
CONFIG_FILE_LOCKING=y
|
||||
CONFIG_MULTIUSER=y
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
CONFIG_CRYPTO_CMAC=y
|
||||
CONFIG_CRYPTO_MD5=y
|
||||
CONFIG_CRYPTO_SHA1=y
|
||||
CONFIG_CRYPTO_SHA256=y
|
||||
CONFIG_CRYPTO_SHA512=y
|
||||
CONFIG_CRYPTO_DES=y
|
||||
CONFIG_CRYPTO_AES=y
|
||||
CONFIG_CRYPTO_CAMELLIA=y
|
||||
CONFIG_NFS_FS=y
|
||||
CONFIG_SUNRPC=y
|
||||
CONFIG_SUNRPC_GSS=y
|
||||
CONFIG_RPCSEC_GSS_KRB5=y
|
||||
CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1=y
|
||||
CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA=y
|
||||
CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2=y
|
||||
CONFIG_RPCSEC_GSS_KRB5_KUNIT_TEST=y
|
||||
@@ -21,8 +21,7 @@ config RPCSEC_GSS_KRB5
|
||||
depends on SUNRPC && CRYPTO
|
||||
default y
|
||||
select SUNRPC_GSS
|
||||
select CRYPTO_SKCIPHER
|
||||
select CRYPTO_HASH
|
||||
select CRYPTO_KRB5
|
||||
help
|
||||
Choose Y here to enable Secure RPC using the Kerberos version 5
|
||||
GSS-API mechanism (RFC 1964).
|
||||
@@ -34,59 +33,6 @@ config RPCSEC_GSS_KRB5
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1
|
||||
bool "Enable Kerberos enctypes based on AES and SHA-1"
|
||||
depends on RPCSEC_GSS_KRB5
|
||||
depends on CRYPTO_CBC && CRYPTO_CTS
|
||||
depends on CRYPTO_HMAC && CRYPTO_SHA1
|
||||
depends on CRYPTO_AES
|
||||
default y
|
||||
help
|
||||
Choose Y to enable the use of Kerberos 5 encryption types
|
||||
that utilize Advanced Encryption Standard (AES) ciphers and
|
||||
SHA-1 digests. These include aes128-cts-hmac-sha1-96 and
|
||||
aes256-cts-hmac-sha1-96.
|
||||
|
||||
config RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA
|
||||
bool "Enable Kerberos encryption types based on Camellia and CMAC"
|
||||
depends on RPCSEC_GSS_KRB5
|
||||
depends on CRYPTO_CBC && CRYPTO_CTS && CRYPTO_CAMELLIA
|
||||
depends on CRYPTO_CMAC
|
||||
default n
|
||||
help
|
||||
Choose Y to enable the use of Kerberos 5 encryption types
|
||||
that utilize Camellia ciphers (RFC 3713) and CMAC digests
|
||||
(NIST Special Publication 800-38B). These include
|
||||
camellia128-cts-cmac and camellia256-cts-cmac.
|
||||
|
||||
config RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2
|
||||
bool "Enable Kerberos enctypes based on AES and SHA-2"
|
||||
depends on RPCSEC_GSS_KRB5
|
||||
depends on CRYPTO_CBC && CRYPTO_CTS
|
||||
depends on CRYPTO_HMAC && CRYPTO_SHA256 && CRYPTO_SHA512
|
||||
depends on CRYPTO_AES
|
||||
default n
|
||||
help
|
||||
Choose Y to enable the use of Kerberos 5 encryption types
|
||||
that utilize Advanced Encryption Standard (AES) ciphers and
|
||||
SHA-2 digests. These include aes128-cts-hmac-sha256-128 and
|
||||
aes256-cts-hmac-sha384-192.
|
||||
|
||||
config RPCSEC_GSS_KRB5_KUNIT_TEST
|
||||
tristate "KUnit tests for RPCSEC GSS Kerberos" if !KUNIT_ALL_TESTS
|
||||
depends on RPCSEC_GSS_KRB5 && KUNIT
|
||||
default KUNIT_ALL_TESTS
|
||||
help
|
||||
This builds the KUnit tests for RPCSEC GSS Kerberos 5.
|
||||
|
||||
KUnit tests run during boot and output the results to the debug
|
||||
log in TAP format (https://testanything.org/). Only useful for
|
||||
kernel devs running KUnit test harness and are not for inclusion
|
||||
into a production build.
|
||||
|
||||
For more information on KUnit and unit tests in general, refer
|
||||
to the KUnit documentation in Documentation/dev-tools/kunit/.
|
||||
|
||||
config SUNRPC_DEBUG
|
||||
bool "RPC: Enable dprintk debugging"
|
||||
depends on SUNRPC && SYSCTL
|
||||
|
||||
@@ -14,7 +14,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
|
||||
addr.o rpcb_clnt.o timer.o xdr.o \
|
||||
sunrpc_syms.o cache.o rpc_pipe.o sysfs.o \
|
||||
svc_xprt.o \
|
||||
xprtmultipath.o
|
||||
xprtmultipath.o netlink.o
|
||||
sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o
|
||||
sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o
|
||||
sunrpc-$(CONFIG_PROC_FS) += stats.o
|
||||
|
||||
@@ -12,6 +12,4 @@ auth_rpcgss-y := auth_gss.o \
|
||||
obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
|
||||
|
||||
rpcsec_gss_krb5-y := gss_krb5_mech.o gss_krb5_seal.o gss_krb5_unseal.o \
|
||||
gss_krb5_wrap.o gss_krb5_crypto.o gss_krb5_keys.o
|
||||
|
||||
obj-$(CONFIG_RPCSEC_GSS_KRB5_KUNIT_TEST) += gss_krb5_test.o
|
||||
gss_krb5_wrap.o gss_krb5_crypto.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,51 +8,10 @@
|
||||
#ifndef _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H
|
||||
#define _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H
|
||||
|
||||
/*
|
||||
* The RFCs often specify payload lengths in bits. This helper
|
||||
* converts a specified bit-length to the number of octets/bytes.
|
||||
*/
|
||||
#define BITS2OCTETS(x) ((x) / 8)
|
||||
#include <crypto/krb5.h>
|
||||
|
||||
struct krb5_ctx;
|
||||
|
||||
struct gss_krb5_enctype {
|
||||
const u32 etype; /* encryption (key) type */
|
||||
const u32 ctype; /* checksum type */
|
||||
const char *name; /* "friendly" name */
|
||||
const char *encrypt_name; /* crypto encrypt name */
|
||||
const char *aux_cipher; /* aux encrypt cipher name */
|
||||
const char *cksum_name; /* crypto checksum name */
|
||||
const u16 signalg; /* signing algorithm */
|
||||
const u16 sealalg; /* sealing algorithm */
|
||||
const u32 cksumlength; /* checksum length */
|
||||
const u32 keyed_cksum; /* is it a keyed cksum? */
|
||||
const u32 keybytes; /* raw key len, in bytes */
|
||||
const u32 keylength; /* protocol key length, in octets */
|
||||
const u32 Kc_length; /* checksum subkey length, in octets */
|
||||
const u32 Ke_length; /* encryption subkey length, in octets */
|
||||
const u32 Ki_length; /* integrity subkey length, in octets */
|
||||
|
||||
int (*derive_key)(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *in,
|
||||
struct xdr_netobj *out,
|
||||
const struct xdr_netobj *label,
|
||||
gfp_t gfp_mask);
|
||||
u32 (*encrypt)(struct krb5_ctx *kctx, u32 offset,
|
||||
struct xdr_buf *buf, struct page **pages);
|
||||
u32 (*decrypt)(struct krb5_ctx *kctx, u32 offset, u32 len,
|
||||
struct xdr_buf *buf, u32 *headskip, u32 *tailskip);
|
||||
u32 (*get_mic)(struct krb5_ctx *kctx, struct xdr_buf *text,
|
||||
struct xdr_netobj *token);
|
||||
u32 (*verify_mic)(struct krb5_ctx *kctx, struct xdr_buf *message_buffer,
|
||||
struct xdr_netobj *read_token);
|
||||
u32 (*wrap)(struct krb5_ctx *kctx, int offset,
|
||||
struct xdr_buf *buf, struct page **pages);
|
||||
u32 (*unwrap)(struct krb5_ctx *kctx, int offset, int len,
|
||||
struct xdr_buf *buf, unsigned int *slack,
|
||||
unsigned int *align);
|
||||
};
|
||||
|
||||
/* krb5_ctx flags definitions */
|
||||
#define KRB5_CTX_FLAG_INITIATOR 0x00000001
|
||||
#define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY 0x00000004
|
||||
@@ -61,20 +20,12 @@ struct krb5_ctx {
|
||||
int initiate; /* 1 = initiating, 0 = accepting */
|
||||
u32 enctype;
|
||||
u32 flags;
|
||||
const struct gss_krb5_enctype *gk5e; /* enctype-specific info */
|
||||
struct crypto_sync_skcipher *enc;
|
||||
struct crypto_sync_skcipher *seq;
|
||||
struct crypto_sync_skcipher *acceptor_enc;
|
||||
struct crypto_sync_skcipher *initiator_enc;
|
||||
struct crypto_sync_skcipher *acceptor_enc_aux;
|
||||
struct crypto_sync_skcipher *initiator_enc_aux;
|
||||
struct crypto_ahash *acceptor_sign;
|
||||
struct crypto_ahash *initiator_sign;
|
||||
struct crypto_ahash *initiator_integ;
|
||||
struct crypto_ahash *acceptor_integ;
|
||||
const struct krb5_enctype *krb5e; /* crypto/krb5 enctype */
|
||||
struct crypto_aead *initiator_enc_aead;
|
||||
struct crypto_aead *acceptor_enc_aead;
|
||||
struct crypto_shash *initiator_sign_shash;
|
||||
struct crypto_shash *acceptor_sign_shash;
|
||||
u8 Ksess[GSS_KRB5_MAX_KEYLEN]; /* session key */
|
||||
u8 cksum[GSS_KRB5_MAX_KEYLEN];
|
||||
atomic_t seq_send;
|
||||
atomic64_t seq_send64;
|
||||
time64_t endtime;
|
||||
struct xdr_netobj mech_used;
|
||||
@@ -101,95 +52,21 @@ u32 gss_krb5_unwrap_v2(struct krb5_ctx *kctx, int offset, int len,
|
||||
* Implementation internal functions
|
||||
*/
|
||||
|
||||
/* Key Derivation Functions */
|
||||
|
||||
int krb5_derive_key_v2(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
const struct xdr_netobj *label,
|
||||
gfp_t gfp_mask);
|
||||
|
||||
int krb5_kdf_hmac_sha2(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
const struct xdr_netobj *in_constant,
|
||||
gfp_t gfp_mask);
|
||||
|
||||
int krb5_kdf_feedback_cmac(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
const struct xdr_netobj *in_constant,
|
||||
gfp_t gfp_mask);
|
||||
|
||||
/**
|
||||
* krb5_derive_key - Derive a subkey from a protocol key
|
||||
* @kctx: Kerberos 5 context
|
||||
* @inkey: base protocol key
|
||||
* @outkey: OUT: derived key
|
||||
* @usage: key usage value
|
||||
* @seed: key usage seed (one octet)
|
||||
* @gfp_mask: memory allocation control flags
|
||||
*
|
||||
* Caller sets @outkey->len to the desired length of the derived key.
|
||||
*
|
||||
* On success, returns 0 and fills in @outkey. A negative errno value
|
||||
* is returned on failure.
|
||||
*/
|
||||
static inline int krb5_derive_key(struct krb5_ctx *kctx,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
u32 usage, u8 seed, gfp_t gfp_mask)
|
||||
{
|
||||
const struct gss_krb5_enctype *gk5e = kctx->gk5e;
|
||||
u8 label_data[GSS_KRB5_K5CLENGTH];
|
||||
struct xdr_netobj label = {
|
||||
.len = sizeof(label_data),
|
||||
.data = label_data,
|
||||
};
|
||||
__be32 *p = (__be32 *)label_data;
|
||||
|
||||
*p = cpu_to_be32(usage);
|
||||
label_data[4] = seed;
|
||||
return gk5e->derive_key(gk5e, inkey, outkey, &label, gfp_mask);
|
||||
}
|
||||
|
||||
void krb5_make_confounder(u8 *p, int conflen);
|
||||
|
||||
u32 gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
|
||||
const struct xdr_buf *body, int body_offset,
|
||||
struct xdr_netobj *cksumout);
|
||||
|
||||
u32 krb5_encrypt(struct crypto_sync_skcipher *key, void *iv, void *in,
|
||||
void *out, int length);
|
||||
|
||||
int xdr_extend_head(struct xdr_buf *buf, unsigned int base,
|
||||
unsigned int shiftlen);
|
||||
|
||||
u32 gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset,
|
||||
struct xdr_buf *buf, struct page **pages);
|
||||
u32 gss_krb5_errno_to_status(int err);
|
||||
|
||||
u32 gss_krb5_aes_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
|
||||
struct xdr_buf *buf, u32 *plainoffset, u32 *plainlen);
|
||||
int gss_krb5_mic_build_sg(const struct xdr_buf *body,
|
||||
void *cksum, unsigned int cksum_len,
|
||||
void *hdr,
|
||||
struct scatterlist *sg_head,
|
||||
struct scatterlist **sg_overflow);
|
||||
|
||||
u32 krb5_etm_encrypt(struct krb5_ctx *kctx, u32 offset, struct xdr_buf *buf,
|
||||
struct page **pages);
|
||||
u32 gss_krb5_aead_encrypt(struct krb5_ctx *kctx, u32 offset,
|
||||
struct xdr_buf *buf, struct page **pages);
|
||||
u32 gss_krb5_aead_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
|
||||
struct xdr_buf *buf, u32 *headskip, u32 *tailskip);
|
||||
|
||||
u32 krb5_etm_decrypt(struct krb5_ctx *kctx, u32 offset, u32 len,
|
||||
struct xdr_buf *buf, u32 *headskip, u32 *tailskip);
|
||||
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
void krb5_nfold(u32 inbits, const u8 *in, u32 outbits, u8 *out);
|
||||
const struct gss_krb5_enctype *gss_krb5_lookup_enctype(u32 etype);
|
||||
int krb5_cbc_cts_encrypt(struct crypto_sync_skcipher *cts_tfm,
|
||||
struct crypto_sync_skcipher *cbc_tfm, u32 offset,
|
||||
struct xdr_buf *buf, struct page **pages,
|
||||
u8 *iv, unsigned int ivsize);
|
||||
int krb5_cbc_cts_decrypt(struct crypto_sync_skcipher *cts_tfm,
|
||||
struct crypto_sync_skcipher *cbc_tfm,
|
||||
u32 offset, struct xdr_buf *buf);
|
||||
u32 krb5_etm_checksum(struct crypto_sync_skcipher *cipher,
|
||||
struct crypto_ahash *tfm, const struct xdr_buf *body,
|
||||
int body_offset, struct xdr_netobj *cksumout);
|
||||
#endif
|
||||
|
||||
#endif /* _NET_SUNRPC_AUTH_GSS_KRB5_INTERNAL_H */
|
||||
|
||||
@@ -1,546 +0,0 @@
|
||||
/*
|
||||
* COPYRIGHT (c) 2008
|
||||
* The Regents of the University of Michigan
|
||||
* ALL RIGHTS RESERVED
|
||||
*
|
||||
* Permission is granted to use, copy, create derivative works
|
||||
* and redistribute this software and such derivative works
|
||||
* for any purpose, so long as the name of The University of
|
||||
* Michigan is not used in any advertising or publicity
|
||||
* pertaining to the use of distribution of this software
|
||||
* without specific, written prior authorization. If the
|
||||
* above copyright notice or any other identification of the
|
||||
* University of Michigan is included in any copy of any
|
||||
* portion of this software, then the disclaimer below must
|
||||
* also be included.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
|
||||
* FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
|
||||
* PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
|
||||
* MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
|
||||
* WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
||||
* REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
|
||||
* FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
|
||||
* CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
|
||||
* OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
|
||||
* IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 1998 by the FundsXpress, INC.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Export of this software from the United States of America may require
|
||||
* a specific license from the United States Government. It is the
|
||||
* responsibility of any person or organization contemplating export to
|
||||
* obtain such a license before exporting.
|
||||
*
|
||||
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
|
||||
* distribute this software and its documentation for any purpose and
|
||||
* without fee is hereby granted, provided that the above copyright
|
||||
* notice appear in all copies and that both that copyright notice and
|
||||
* this permission notice appear in supporting documentation, and that
|
||||
* the name of FundsXpress. not be used in advertising or publicity pertaining
|
||||
* to distribution of the software without specific, written prior
|
||||
* permission. FundsXpress makes no representations about the suitability of
|
||||
* this software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/lcm.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <kunit/visibility.h>
|
||||
|
||||
#include "gss_krb5_internal.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
# define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
#endif
|
||||
|
||||
/**
|
||||
* krb5_nfold - n-fold function
|
||||
* @inbits: number of bits in @in
|
||||
* @in: buffer containing input to fold
|
||||
* @outbits: number of bits in the output buffer
|
||||
* @out: buffer to hold the result
|
||||
*
|
||||
* This is the n-fold function as described in rfc3961, sec 5.1
|
||||
* Taken from MIT Kerberos and modified.
|
||||
*/
|
||||
VISIBLE_IF_KUNIT
|
||||
void krb5_nfold(u32 inbits, const u8 *in, u32 outbits, u8 *out)
|
||||
{
|
||||
unsigned long ulcm;
|
||||
int byte, i, msbit;
|
||||
|
||||
/* the code below is more readable if I make these bytes
|
||||
instead of bits */
|
||||
|
||||
inbits >>= 3;
|
||||
outbits >>= 3;
|
||||
|
||||
/* first compute lcm(n,k) */
|
||||
ulcm = lcm(inbits, outbits);
|
||||
|
||||
/* now do the real work */
|
||||
|
||||
memset(out, 0, outbits);
|
||||
byte = 0;
|
||||
|
||||
/* this will end up cycling through k lcm(k,n)/k times, which
|
||||
is correct */
|
||||
for (i = ulcm-1; i >= 0; i--) {
|
||||
/* compute the msbit in k which gets added into this byte */
|
||||
msbit = (
|
||||
/* first, start with the msbit in the first,
|
||||
* unrotated byte */
|
||||
((inbits << 3) - 1)
|
||||
/* then, for each byte, shift to the right
|
||||
* for each repetition */
|
||||
+ (((inbits << 3) + 13) * (i/inbits))
|
||||
/* last, pick out the correct byte within
|
||||
* that shifted repetition */
|
||||
+ ((inbits - (i % inbits)) << 3)
|
||||
) % (inbits << 3);
|
||||
|
||||
/* pull out the byte value itself */
|
||||
byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)|
|
||||
(in[((inbits) - (msbit >> 3)) % inbits]))
|
||||
>> ((msbit & 7) + 1)) & 0xff;
|
||||
|
||||
/* do the addition */
|
||||
byte += out[i % outbits];
|
||||
out[i % outbits] = byte & 0xff;
|
||||
|
||||
/* keep around the carry bit, if any */
|
||||
byte >>= 8;
|
||||
|
||||
}
|
||||
|
||||
/* if there's a carry bit left over, add it back in */
|
||||
if (byte) {
|
||||
for (i = outbits - 1; i >= 0; i--) {
|
||||
/* do the addition */
|
||||
byte += out[i];
|
||||
out[i] = byte & 0xff;
|
||||
|
||||
/* keep around the carry bit, if any */
|
||||
byte >>= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(krb5_nfold);
|
||||
|
||||
/*
|
||||
* This is the DK (derive_key) function as described in rfc3961, sec 5.1
|
||||
* Taken from MIT Kerberos and modified.
|
||||
*/
|
||||
static int krb5_DK(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey, u8 *rawkey,
|
||||
const struct xdr_netobj *in_constant, gfp_t gfp_mask)
|
||||
{
|
||||
size_t blocksize, keybytes, keylength, n;
|
||||
unsigned char *inblockdata, *outblockdata;
|
||||
struct xdr_netobj inblock, outblock;
|
||||
struct crypto_sync_skcipher *cipher;
|
||||
int ret = -EINVAL;
|
||||
|
||||
keybytes = gk5e->keybytes;
|
||||
keylength = gk5e->keylength;
|
||||
|
||||
if (inkey->len != keylength)
|
||||
goto err_return;
|
||||
|
||||
cipher = crypto_alloc_sync_skcipher(gk5e->encrypt_name, 0, 0);
|
||||
if (IS_ERR(cipher))
|
||||
goto err_return;
|
||||
blocksize = crypto_sync_skcipher_blocksize(cipher);
|
||||
if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len))
|
||||
goto err_free_cipher;
|
||||
|
||||
ret = -ENOMEM;
|
||||
inblockdata = kmalloc(blocksize, gfp_mask);
|
||||
if (inblockdata == NULL)
|
||||
goto err_free_cipher;
|
||||
|
||||
outblockdata = kmalloc(blocksize, gfp_mask);
|
||||
if (outblockdata == NULL)
|
||||
goto err_free_in;
|
||||
|
||||
inblock.data = (char *) inblockdata;
|
||||
inblock.len = blocksize;
|
||||
|
||||
outblock.data = (char *) outblockdata;
|
||||
outblock.len = blocksize;
|
||||
|
||||
/* initialize the input block */
|
||||
|
||||
if (in_constant->len == inblock.len) {
|
||||
memcpy(inblock.data, in_constant->data, inblock.len);
|
||||
} else {
|
||||
krb5_nfold(in_constant->len * 8, in_constant->data,
|
||||
inblock.len * 8, inblock.data);
|
||||
}
|
||||
|
||||
/* loop encrypting the blocks until enough key bytes are generated */
|
||||
|
||||
n = 0;
|
||||
while (n < keybytes) {
|
||||
krb5_encrypt(cipher, NULL, inblock.data, outblock.data,
|
||||
inblock.len);
|
||||
|
||||
if ((keybytes - n) <= outblock.len) {
|
||||
memcpy(rawkey + n, outblock.data, (keybytes - n));
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(rawkey + n, outblock.data, outblock.len);
|
||||
memcpy(inblock.data, outblock.data, outblock.len);
|
||||
n += outblock.len;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
kfree_sensitive(outblockdata);
|
||||
err_free_in:
|
||||
kfree_sensitive(inblockdata);
|
||||
err_free_cipher:
|
||||
crypto_free_sync_skcipher(cipher);
|
||||
err_return:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the identity function, with some sanity checking.
|
||||
*/
|
||||
static int krb5_random_to_key_v2(const struct gss_krb5_enctype *gk5e,
|
||||
struct xdr_netobj *randombits,
|
||||
struct xdr_netobj *key)
|
||||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
if (key->len != 16 && key->len != 32) {
|
||||
dprintk("%s: key->len is %d\n", __func__, key->len);
|
||||
goto err_out;
|
||||
}
|
||||
if (randombits->len != 16 && randombits->len != 32) {
|
||||
dprintk("%s: randombits->len is %d\n",
|
||||
__func__, randombits->len);
|
||||
goto err_out;
|
||||
}
|
||||
if (randombits->len != key->len) {
|
||||
dprintk("%s: randombits->len is %d, key->len is %d\n",
|
||||
__func__, randombits->len, key->len);
|
||||
goto err_out;
|
||||
}
|
||||
memcpy(key->data, randombits->data, key->len);
|
||||
ret = 0;
|
||||
err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* krb5_derive_key_v2 - Derive a subkey for an RFC 3962 enctype
|
||||
* @gk5e: Kerberos 5 enctype profile
|
||||
* @inkey: base protocol key
|
||||
* @outkey: OUT: derived key
|
||||
* @label: subkey usage label
|
||||
* @gfp_mask: memory allocation control flags
|
||||
*
|
||||
* Caller sets @outkey->len to the desired length of the derived key.
|
||||
*
|
||||
* On success, returns 0 and fills in @outkey. A negative errno value
|
||||
* is returned on failure.
|
||||
*/
|
||||
int krb5_derive_key_v2(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
const struct xdr_netobj *label,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct xdr_netobj inblock;
|
||||
int ret;
|
||||
|
||||
inblock.len = gk5e->keybytes;
|
||||
inblock.data = kmalloc(inblock.len, gfp_mask);
|
||||
if (!inblock.data)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = krb5_DK(gk5e, inkey, inblock.data, label, gfp_mask);
|
||||
if (!ret)
|
||||
ret = krb5_random_to_key_v2(gk5e, &inblock, outkey);
|
||||
|
||||
kfree_sensitive(inblock.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
|
||||
*
|
||||
* i: A block counter is used with a length of 4 bytes, represented
|
||||
* in big-endian order.
|
||||
*
|
||||
* constant: The label input to the KDF is the usage constant supplied
|
||||
* to the key derivation function
|
||||
*
|
||||
* k: The length of the output key in bits, represented as a 4-byte
|
||||
* string in big-endian order.
|
||||
*
|
||||
* Caller fills in K(i-1) in @step, and receives the result K(i)
|
||||
* in the same buffer.
|
||||
*/
|
||||
static int
|
||||
krb5_cmac_Ki(struct crypto_shash *tfm, const struct xdr_netobj *constant,
|
||||
u32 outlen, u32 count, struct xdr_netobj *step)
|
||||
{
|
||||
__be32 k = cpu_to_be32(outlen * 8);
|
||||
SHASH_DESC_ON_STACK(desc, tfm);
|
||||
__be32 i = cpu_to_be32(count);
|
||||
u8 zero = 0;
|
||||
int ret;
|
||||
|
||||
desc->tfm = tfm;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
ret = crypto_shash_update(desc, step->data, step->len);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, (u8 *)&i, sizeof(i));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, constant->data, constant->len);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, &zero, sizeof(zero));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, (u8 *)&k, sizeof(k));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_final(desc, step->data);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
out_err:
|
||||
shash_desc_zero(desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* krb5_kdf_feedback_cmac - Derive a subkey for a Camellia/CMAC-based enctype
|
||||
* @gk5e: Kerberos 5 enctype parameters
|
||||
* @inkey: base protocol key
|
||||
* @outkey: OUT: derived key
|
||||
* @constant: subkey usage label
|
||||
* @gfp_mask: memory allocation control flags
|
||||
*
|
||||
* RFC 6803 Section 3:
|
||||
*
|
||||
* "We use a key derivation function from the family specified in
|
||||
* [SP800-108], Section 5.2, 'KDF in Feedback Mode'."
|
||||
*
|
||||
* n = ceiling(k / 128)
|
||||
* K(0) = zeros
|
||||
* K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k)
|
||||
* DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n))
|
||||
* KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant))
|
||||
*
|
||||
* Caller sets @outkey->len to the desired length of the derived key (k).
|
||||
*
|
||||
* On success, returns 0 and fills in @outkey. A negative errno value
|
||||
* is returned on failure.
|
||||
*/
|
||||
int
|
||||
krb5_kdf_feedback_cmac(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
const struct xdr_netobj *constant,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct xdr_netobj step = { .data = NULL };
|
||||
struct xdr_netobj DR = { .data = NULL };
|
||||
unsigned int blocksize, offset;
|
||||
struct crypto_shash *tfm;
|
||||
int n, count, ret;
|
||||
|
||||
/*
|
||||
* This implementation assumes the CMAC used for an enctype's
|
||||
* key derivation is the same as the CMAC used for its
|
||||
* checksumming. This happens to be true for enctypes that
|
||||
* are currently supported by this implementation.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(gk5e->cksum_name, 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
ret = PTR_ERR(tfm);
|
||||
goto out;
|
||||
}
|
||||
ret = crypto_shash_setkey(tfm, inkey->data, inkey->len);
|
||||
if (ret)
|
||||
goto out_free_tfm;
|
||||
|
||||
blocksize = crypto_shash_digestsize(tfm);
|
||||
n = (outkey->len + blocksize - 1) / blocksize;
|
||||
|
||||
/* K(0) is all zeroes */
|
||||
ret = -ENOMEM;
|
||||
step.len = blocksize;
|
||||
step.data = kzalloc(step.len, gfp_mask);
|
||||
if (!step.data)
|
||||
goto out_free_tfm;
|
||||
|
||||
DR.len = blocksize * n;
|
||||
DR.data = kmalloc(DR.len, gfp_mask);
|
||||
if (!DR.data)
|
||||
goto out_free_tfm;
|
||||
|
||||
/* XXX: Does not handle partial-block key sizes */
|
||||
for (offset = 0, count = 1; count <= n; count++) {
|
||||
ret = krb5_cmac_Ki(tfm, constant, outkey->len, count, &step);
|
||||
if (ret)
|
||||
goto out_free_tfm;
|
||||
|
||||
memcpy(DR.data + offset, step.data, blocksize);
|
||||
offset += blocksize;
|
||||
}
|
||||
|
||||
/* k-truncate and random-to-key */
|
||||
memcpy(outkey->data, DR.data, outkey->len);
|
||||
ret = 0;
|
||||
|
||||
out_free_tfm:
|
||||
crypto_free_shash(tfm);
|
||||
out:
|
||||
kfree_sensitive(step.data);
|
||||
kfree_sensitive(DR.data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* K1 = HMAC-SHA(key, 0x00000001 | label | 0x00 | k)
|
||||
*
|
||||
* key: The source of entropy from which subsequent keys are derived.
|
||||
*
|
||||
* label: An octet string describing the intended usage of the
|
||||
* derived key.
|
||||
*
|
||||
* k: Length in bits of the key to be outputted, expressed in
|
||||
* big-endian binary representation in 4 bytes.
|
||||
*/
|
||||
static int
|
||||
krb5_hmac_K1(struct crypto_shash *tfm, const struct xdr_netobj *label,
|
||||
u32 outlen, struct xdr_netobj *K1)
|
||||
{
|
||||
__be32 k = cpu_to_be32(outlen * 8);
|
||||
SHASH_DESC_ON_STACK(desc, tfm);
|
||||
__be32 one = cpu_to_be32(1);
|
||||
u8 zero = 0;
|
||||
int ret;
|
||||
|
||||
desc->tfm = tfm;
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, (u8 *)&one, sizeof(one));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, label->data, label->len);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, &zero, sizeof(zero));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_update(desc, (u8 *)&k, sizeof(k));
|
||||
if (ret)
|
||||
goto out_err;
|
||||
ret = crypto_shash_final(desc, K1->data);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
out_err:
|
||||
shash_desc_zero(desc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* krb5_kdf_hmac_sha2 - Derive a subkey for an AES/SHA2-based enctype
|
||||
* @gk5e: Kerberos 5 enctype policy parameters
|
||||
* @inkey: base protocol key
|
||||
* @outkey: OUT: derived key
|
||||
* @label: subkey usage label
|
||||
* @gfp_mask: memory allocation control flags
|
||||
*
|
||||
* RFC 8009 Section 3:
|
||||
*
|
||||
* "We use a key derivation function from Section 5.1 of [SP800-108],
|
||||
* which uses the HMAC algorithm as the PRF."
|
||||
*
|
||||
* function KDF-HMAC-SHA2(key, label, [context,] k):
|
||||
* k-truncate(K1)
|
||||
*
|
||||
* Caller sets @outkey->len to the desired length of the derived key.
|
||||
*
|
||||
* On success, returns 0 and fills in @outkey. A negative errno value
|
||||
* is returned on failure.
|
||||
*/
|
||||
int
|
||||
krb5_kdf_hmac_sha2(const struct gss_krb5_enctype *gk5e,
|
||||
const struct xdr_netobj *inkey,
|
||||
struct xdr_netobj *outkey,
|
||||
const struct xdr_netobj *label,
|
||||
gfp_t gfp_mask)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
struct xdr_netobj K1 = {
|
||||
.data = NULL,
|
||||
};
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* This implementation assumes the HMAC used for an enctype's
|
||||
* key derivation is the same as the HMAC used for its
|
||||
* checksumming. This happens to be true for enctypes that
|
||||
* are currently supported by this implementation.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(gk5e->cksum_name, 0, 0);
|
||||
if (IS_ERR(tfm)) {
|
||||
ret = PTR_ERR(tfm);
|
||||
goto out;
|
||||
}
|
||||
ret = crypto_shash_setkey(tfm, inkey->data, inkey->len);
|
||||
if (ret)
|
||||
goto out_free_tfm;
|
||||
|
||||
K1.len = crypto_shash_digestsize(tfm);
|
||||
K1.data = kmalloc(K1.len, gfp_mask);
|
||||
if (!K1.data) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_tfm;
|
||||
}
|
||||
|
||||
ret = krb5_hmac_K1(tfm, label, outkey->len, &K1);
|
||||
if (ret)
|
||||
goto out_free_tfm;
|
||||
|
||||
/* k-truncate and random-to-key */
|
||||
memcpy(outkey->data, K1.data, outkey->len);
|
||||
|
||||
out_free_tfm:
|
||||
kfree_sensitive(K1.data);
|
||||
crypto_free_shash(tfm);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
@@ -9,8 +9,6 @@
|
||||
* J. Bruce Fields <bfields@umich.edu>
|
||||
*/
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
@@ -19,7 +17,6 @@
|
||||
#include <linux/sunrpc/auth.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <kunit/visibility.h>
|
||||
|
||||
#include "auth_gss_internal.h"
|
||||
#include "gss_krb5_internal.h"
|
||||
@@ -30,201 +27,24 @@
|
||||
|
||||
static struct gss_api_mech gss_kerberos_mech;
|
||||
|
||||
static const struct gss_krb5_enctype supported_gss_krb5_enctypes[] = {
|
||||
#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1)
|
||||
/*
|
||||
* AES-128 with SHA-1 (RFC 3962)
|
||||
*/
|
||||
{
|
||||
.etype = ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
.ctype = CKSUMTYPE_HMAC_SHA1_96_AES128,
|
||||
.name = "aes128-cts",
|
||||
.encrypt_name = "cts(cbc(aes))",
|
||||
.aux_cipher = "cbc(aes)",
|
||||
.cksum_name = "hmac(sha1)",
|
||||
.derive_key = krb5_derive_key_v2,
|
||||
.encrypt = gss_krb5_aes_encrypt,
|
||||
.decrypt = gss_krb5_aes_decrypt,
|
||||
|
||||
.get_mic = gss_krb5_get_mic_v2,
|
||||
.verify_mic = gss_krb5_verify_mic_v2,
|
||||
.wrap = gss_krb5_wrap_v2,
|
||||
.unwrap = gss_krb5_unwrap_v2,
|
||||
|
||||
.signalg = -1,
|
||||
.sealalg = -1,
|
||||
.keybytes = 16,
|
||||
.keylength = BITS2OCTETS(128),
|
||||
.Kc_length = BITS2OCTETS(128),
|
||||
.Ke_length = BITS2OCTETS(128),
|
||||
.Ki_length = BITS2OCTETS(128),
|
||||
.cksumlength = BITS2OCTETS(96),
|
||||
.keyed_cksum = 1,
|
||||
},
|
||||
/*
|
||||
* AES-256 with SHA-1 (RFC 3962)
|
||||
*/
|
||||
{
|
||||
.etype = ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
.ctype = CKSUMTYPE_HMAC_SHA1_96_AES256,
|
||||
.name = "aes256-cts",
|
||||
.encrypt_name = "cts(cbc(aes))",
|
||||
.aux_cipher = "cbc(aes)",
|
||||
.cksum_name = "hmac(sha1)",
|
||||
.derive_key = krb5_derive_key_v2,
|
||||
.encrypt = gss_krb5_aes_encrypt,
|
||||
.decrypt = gss_krb5_aes_decrypt,
|
||||
|
||||
.get_mic = gss_krb5_get_mic_v2,
|
||||
.verify_mic = gss_krb5_verify_mic_v2,
|
||||
.wrap = gss_krb5_wrap_v2,
|
||||
.unwrap = gss_krb5_unwrap_v2,
|
||||
|
||||
.signalg = -1,
|
||||
.sealalg = -1,
|
||||
.keybytes = 32,
|
||||
.keylength = BITS2OCTETS(256),
|
||||
.Kc_length = BITS2OCTETS(256),
|
||||
.Ke_length = BITS2OCTETS(256),
|
||||
.Ki_length = BITS2OCTETS(256),
|
||||
.cksumlength = BITS2OCTETS(96),
|
||||
.keyed_cksum = 1,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA)
|
||||
/*
|
||||
* Camellia-128 with CMAC (RFC 6803)
|
||||
*/
|
||||
{
|
||||
.etype = ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
.ctype = CKSUMTYPE_CMAC_CAMELLIA128,
|
||||
.name = "camellia128-cts-cmac",
|
||||
.encrypt_name = "cts(cbc(camellia))",
|
||||
.aux_cipher = "cbc(camellia)",
|
||||
.cksum_name = "cmac(camellia)",
|
||||
.cksumlength = BITS2OCTETS(128),
|
||||
.keyed_cksum = 1,
|
||||
.keylength = BITS2OCTETS(128),
|
||||
.Kc_length = BITS2OCTETS(128),
|
||||
.Ke_length = BITS2OCTETS(128),
|
||||
.Ki_length = BITS2OCTETS(128),
|
||||
|
||||
.derive_key = krb5_kdf_feedback_cmac,
|
||||
.encrypt = gss_krb5_aes_encrypt,
|
||||
.decrypt = gss_krb5_aes_decrypt,
|
||||
|
||||
.get_mic = gss_krb5_get_mic_v2,
|
||||
.verify_mic = gss_krb5_verify_mic_v2,
|
||||
.wrap = gss_krb5_wrap_v2,
|
||||
.unwrap = gss_krb5_unwrap_v2,
|
||||
},
|
||||
/*
|
||||
* Camellia-256 with CMAC (RFC 6803)
|
||||
*/
|
||||
{
|
||||
.etype = ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
.ctype = CKSUMTYPE_CMAC_CAMELLIA256,
|
||||
.name = "camellia256-cts-cmac",
|
||||
.encrypt_name = "cts(cbc(camellia))",
|
||||
.aux_cipher = "cbc(camellia)",
|
||||
.cksum_name = "cmac(camellia)",
|
||||
.cksumlength = BITS2OCTETS(128),
|
||||
.keyed_cksum = 1,
|
||||
.keylength = BITS2OCTETS(256),
|
||||
.Kc_length = BITS2OCTETS(256),
|
||||
.Ke_length = BITS2OCTETS(256),
|
||||
.Ki_length = BITS2OCTETS(256),
|
||||
|
||||
.derive_key = krb5_kdf_feedback_cmac,
|
||||
.encrypt = gss_krb5_aes_encrypt,
|
||||
.decrypt = gss_krb5_aes_decrypt,
|
||||
|
||||
.get_mic = gss_krb5_get_mic_v2,
|
||||
.verify_mic = gss_krb5_verify_mic_v2,
|
||||
.wrap = gss_krb5_wrap_v2,
|
||||
.unwrap = gss_krb5_unwrap_v2,
|
||||
},
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2)
|
||||
/*
|
||||
* AES-128 with SHA-256 (RFC 8009)
|
||||
*/
|
||||
{
|
||||
.etype = ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
.ctype = CKSUMTYPE_HMAC_SHA256_128_AES128,
|
||||
.name = "aes128-cts-hmac-sha256-128",
|
||||
.encrypt_name = "cts(cbc(aes))",
|
||||
.aux_cipher = "cbc(aes)",
|
||||
.cksum_name = "hmac(sha256)",
|
||||
.cksumlength = BITS2OCTETS(128),
|
||||
.keyed_cksum = 1,
|
||||
.keylength = BITS2OCTETS(128),
|
||||
.Kc_length = BITS2OCTETS(128),
|
||||
.Ke_length = BITS2OCTETS(128),
|
||||
.Ki_length = BITS2OCTETS(128),
|
||||
|
||||
.derive_key = krb5_kdf_hmac_sha2,
|
||||
.encrypt = krb5_etm_encrypt,
|
||||
.decrypt = krb5_etm_decrypt,
|
||||
|
||||
.get_mic = gss_krb5_get_mic_v2,
|
||||
.verify_mic = gss_krb5_verify_mic_v2,
|
||||
.wrap = gss_krb5_wrap_v2,
|
||||
.unwrap = gss_krb5_unwrap_v2,
|
||||
},
|
||||
/*
|
||||
* AES-256 with SHA-384 (RFC 8009)
|
||||
*/
|
||||
{
|
||||
.etype = ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
.ctype = CKSUMTYPE_HMAC_SHA384_192_AES256,
|
||||
.name = "aes256-cts-hmac-sha384-192",
|
||||
.encrypt_name = "cts(cbc(aes))",
|
||||
.aux_cipher = "cbc(aes)",
|
||||
.cksum_name = "hmac(sha384)",
|
||||
.cksumlength = BITS2OCTETS(192),
|
||||
.keyed_cksum = 1,
|
||||
.keylength = BITS2OCTETS(256),
|
||||
.Kc_length = BITS2OCTETS(192),
|
||||
.Ke_length = BITS2OCTETS(256),
|
||||
.Ki_length = BITS2OCTETS(192),
|
||||
|
||||
.derive_key = krb5_kdf_hmac_sha2,
|
||||
.encrypt = krb5_etm_encrypt,
|
||||
.decrypt = krb5_etm_decrypt,
|
||||
|
||||
.get_mic = gss_krb5_get_mic_v2,
|
||||
.verify_mic = gss_krb5_verify_mic_v2,
|
||||
.wrap = gss_krb5_wrap_v2,
|
||||
.unwrap = gss_krb5_unwrap_v2,
|
||||
},
|
||||
#endif
|
||||
/*
|
||||
* Candidate enctypes in order of most preferred to least.
|
||||
* Each is probed against crypto/krb5 at module init; only
|
||||
* enctypes that crypto/krb5 supports are advertised.
|
||||
*/
|
||||
static const u32 gss_krb5_enctypes[] = {
|
||||
KRB5_ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
KRB5_ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
KRB5_ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
KRB5_ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
KRB5_ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
};
|
||||
|
||||
/*
|
||||
* The list of advertised enctypes is specified in order of most
|
||||
* preferred to least.
|
||||
*/
|
||||
static char gss_krb5_enctype_priority_list[64];
|
||||
|
||||
static void gss_krb5_prepare_enctype_priority_list(void)
|
||||
{
|
||||
static const u32 gss_krb5_enctypes[] = {
|
||||
#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA2)
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA384_192,
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA256_128,
|
||||
#endif
|
||||
#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_CAMELLIA)
|
||||
ENCTYPE_CAMELLIA256_CTS_CMAC,
|
||||
ENCTYPE_CAMELLIA128_CTS_CMAC,
|
||||
#endif
|
||||
#if defined(CONFIG_RPCSEC_GSS_KRB5_ENCTYPES_AES_SHA1)
|
||||
ENCTYPE_AES256_CTS_HMAC_SHA1_96,
|
||||
ENCTYPE_AES128_CTS_HMAC_SHA1_96,
|
||||
#endif
|
||||
};
|
||||
size_t total, i;
|
||||
char buf[16];
|
||||
char *sep;
|
||||
@@ -233,6 +53,8 @@ static void gss_krb5_prepare_enctype_priority_list(void)
|
||||
sep = "";
|
||||
gss_krb5_enctype_priority_list[0] = '\0';
|
||||
for (total = 0, i = 0; i < ARRAY_SIZE(gss_krb5_enctypes); i++) {
|
||||
if (!crypto_krb5_find_enctype(gss_krb5_enctypes[i]))
|
||||
continue;
|
||||
n = sprintf(buf, "%s%u", sep, gss_krb5_enctypes[i]);
|
||||
if (n < 0)
|
||||
break;
|
||||
@@ -244,151 +66,56 @@ static void gss_krb5_prepare_enctype_priority_list(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gss_krb5_lookup_enctype - Retrieve profile information for a given enctype
|
||||
* @etype: ENCTYPE value
|
||||
*
|
||||
* Returns a pointer to a gss_krb5_enctype structure, or NULL if no
|
||||
* matching etype is found.
|
||||
*/
|
||||
VISIBLE_IF_KUNIT
|
||||
const struct gss_krb5_enctype *gss_krb5_lookup_enctype(u32 etype)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(supported_gss_krb5_enctypes); i++)
|
||||
if (supported_gss_krb5_enctypes[i].etype == etype)
|
||||
return &supported_gss_krb5_enctypes[i];
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_KUNIT(gss_krb5_lookup_enctype);
|
||||
|
||||
static struct crypto_sync_skcipher *
|
||||
gss_krb5_alloc_cipher_v2(const char *cname, const struct xdr_netobj *key)
|
||||
{
|
||||
struct crypto_sync_skcipher *tfm;
|
||||
|
||||
tfm = crypto_alloc_sync_skcipher(cname, 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return NULL;
|
||||
if (crypto_sync_skcipher_setkey(tfm, key->data, key->len)) {
|
||||
crypto_free_sync_skcipher(tfm);
|
||||
return NULL;
|
||||
}
|
||||
return tfm;
|
||||
}
|
||||
|
||||
static struct crypto_ahash *
|
||||
gss_krb5_alloc_hash_v2(struct krb5_ctx *kctx, const struct xdr_netobj *key)
|
||||
{
|
||||
struct crypto_ahash *tfm;
|
||||
|
||||
tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
return NULL;
|
||||
if (crypto_ahash_setkey(tfm, key->data, key->len)) {
|
||||
crypto_free_ahash(tfm);
|
||||
return NULL;
|
||||
}
|
||||
return tfm;
|
||||
}
|
||||
|
||||
static int
|
||||
gss_krb5_import_ctx_v2(struct krb5_ctx *ctx, gfp_t gfp_mask)
|
||||
{
|
||||
struct xdr_netobj keyin = {
|
||||
.len = ctx->gk5e->keylength,
|
||||
struct krb5_buffer TK = {
|
||||
.len = ctx->krb5e->key_len,
|
||||
.data = ctx->Ksess,
|
||||
};
|
||||
struct xdr_netobj keyout;
|
||||
int ret = -EINVAL;
|
||||
int ret;
|
||||
|
||||
keyout.data = kmalloc(GSS_KRB5_MAX_KEYLEN, gfp_mask);
|
||||
if (!keyout.data)
|
||||
return -ENOMEM;
|
||||
|
||||
/* initiator seal encryption */
|
||||
keyout.len = ctx->gk5e->Ke_length;
|
||||
if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SEAL,
|
||||
KEY_USAGE_SEED_ENCRYPTION, gfp_mask))
|
||||
goto out;
|
||||
ctx->initiator_enc = gss_krb5_alloc_cipher_v2(ctx->gk5e->encrypt_name,
|
||||
&keyout);
|
||||
if (ctx->initiator_enc == NULL)
|
||||
goto out;
|
||||
if (ctx->gk5e->aux_cipher) {
|
||||
ctx->initiator_enc_aux =
|
||||
gss_krb5_alloc_cipher_v2(ctx->gk5e->aux_cipher,
|
||||
&keyout);
|
||||
if (ctx->initiator_enc_aux == NULL)
|
||||
goto out_free;
|
||||
ctx->initiator_enc_aead =
|
||||
crypto_krb5_prepare_encryption(ctx->krb5e, &TK,
|
||||
KG_USAGE_INITIATOR_SEAL,
|
||||
gfp_mask);
|
||||
if (IS_ERR(ctx->initiator_enc_aead)) {
|
||||
ret = PTR_ERR(ctx->initiator_enc_aead);
|
||||
goto out_free;
|
||||
}
|
||||
ctx->acceptor_enc_aead =
|
||||
crypto_krb5_prepare_encryption(ctx->krb5e, &TK,
|
||||
KG_USAGE_ACCEPTOR_SEAL,
|
||||
gfp_mask);
|
||||
if (IS_ERR(ctx->acceptor_enc_aead)) {
|
||||
ret = PTR_ERR(ctx->acceptor_enc_aead);
|
||||
goto out_free;
|
||||
}
|
||||
ctx->initiator_sign_shash =
|
||||
crypto_krb5_prepare_checksum(ctx->krb5e, &TK,
|
||||
KG_USAGE_INITIATOR_SIGN,
|
||||
gfp_mask);
|
||||
if (IS_ERR(ctx->initiator_sign_shash)) {
|
||||
ret = PTR_ERR(ctx->initiator_sign_shash);
|
||||
goto out_free;
|
||||
}
|
||||
ctx->acceptor_sign_shash =
|
||||
crypto_krb5_prepare_checksum(ctx->krb5e, &TK,
|
||||
KG_USAGE_ACCEPTOR_SIGN,
|
||||
gfp_mask);
|
||||
if (IS_ERR(ctx->acceptor_sign_shash)) {
|
||||
ret = PTR_ERR(ctx->acceptor_sign_shash);
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* acceptor seal encryption */
|
||||
if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SEAL,
|
||||
KEY_USAGE_SEED_ENCRYPTION, gfp_mask))
|
||||
goto out_free;
|
||||
ctx->acceptor_enc = gss_krb5_alloc_cipher_v2(ctx->gk5e->encrypt_name,
|
||||
&keyout);
|
||||
if (ctx->acceptor_enc == NULL)
|
||||
goto out_free;
|
||||
if (ctx->gk5e->aux_cipher) {
|
||||
ctx->acceptor_enc_aux =
|
||||
gss_krb5_alloc_cipher_v2(ctx->gk5e->aux_cipher,
|
||||
&keyout);
|
||||
if (ctx->acceptor_enc_aux == NULL)
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
/* initiator sign checksum */
|
||||
keyout.len = ctx->gk5e->Kc_length;
|
||||
if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SIGN,
|
||||
KEY_USAGE_SEED_CHECKSUM, gfp_mask))
|
||||
goto out_free;
|
||||
ctx->initiator_sign = gss_krb5_alloc_hash_v2(ctx, &keyout);
|
||||
if (ctx->initiator_sign == NULL)
|
||||
goto out_free;
|
||||
|
||||
/* acceptor sign checksum */
|
||||
if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SIGN,
|
||||
KEY_USAGE_SEED_CHECKSUM, gfp_mask))
|
||||
goto out_free;
|
||||
ctx->acceptor_sign = gss_krb5_alloc_hash_v2(ctx, &keyout);
|
||||
if (ctx->acceptor_sign == NULL)
|
||||
goto out_free;
|
||||
|
||||
/* initiator seal integrity */
|
||||
keyout.len = ctx->gk5e->Ki_length;
|
||||
if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_INITIATOR_SEAL,
|
||||
KEY_USAGE_SEED_INTEGRITY, gfp_mask))
|
||||
goto out_free;
|
||||
ctx->initiator_integ = gss_krb5_alloc_hash_v2(ctx, &keyout);
|
||||
if (ctx->initiator_integ == NULL)
|
||||
goto out_free;
|
||||
|
||||
/* acceptor seal integrity */
|
||||
if (krb5_derive_key(ctx, &keyin, &keyout, KG_USAGE_ACCEPTOR_SEAL,
|
||||
KEY_USAGE_SEED_INTEGRITY, gfp_mask))
|
||||
goto out_free;
|
||||
ctx->acceptor_integ = gss_krb5_alloc_hash_v2(ctx, &keyout);
|
||||
if (ctx->acceptor_integ == NULL)
|
||||
goto out_free;
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
kfree_sensitive(keyout.data);
|
||||
return ret;
|
||||
return 0;
|
||||
|
||||
out_free:
|
||||
crypto_free_ahash(ctx->acceptor_integ);
|
||||
crypto_free_ahash(ctx->initiator_integ);
|
||||
crypto_free_ahash(ctx->acceptor_sign);
|
||||
crypto_free_ahash(ctx->initiator_sign);
|
||||
crypto_free_sync_skcipher(ctx->acceptor_enc_aux);
|
||||
crypto_free_sync_skcipher(ctx->acceptor_enc);
|
||||
crypto_free_sync_skcipher(ctx->initiator_enc_aux);
|
||||
crypto_free_sync_skcipher(ctx->initiator_enc);
|
||||
goto out;
|
||||
crypto_free_shash(ctx->acceptor_sign_shash);
|
||||
crypto_free_shash(ctx->initiator_sign_shash);
|
||||
crypto_free_aead(ctx->acceptor_enc_aead);
|
||||
crypto_free_aead(ctx->initiator_enc_aead);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -414,25 +141,17 @@ gss_import_v2_context(const void *p, const void *end, struct krb5_ctx *ctx,
|
||||
if (IS_ERR(p))
|
||||
goto out_err;
|
||||
atomic64_set(&ctx->seq_send64, seq_send64);
|
||||
/* set seq_send for use by "older" enctypes */
|
||||
atomic_set(&ctx->seq_send, seq_send64);
|
||||
if (seq_send64 != atomic_read(&ctx->seq_send)) {
|
||||
dprintk("%s: seq_send64 %llx, seq_send %x overflow?\n", __func__,
|
||||
seq_send64, atomic_read(&ctx->seq_send));
|
||||
p = ERR_PTR(-EINVAL);
|
||||
goto out_err;
|
||||
}
|
||||
p = simple_get_bytes(p, end, &ctx->enctype, sizeof(ctx->enctype));
|
||||
if (IS_ERR(p))
|
||||
goto out_err;
|
||||
ctx->gk5e = gss_krb5_lookup_enctype(ctx->enctype);
|
||||
if (ctx->gk5e == NULL) {
|
||||
ctx->krb5e = crypto_krb5_find_enctype(ctx->enctype);
|
||||
if (!ctx->krb5e) {
|
||||
dprintk("gss_kerberos_mech: unsupported krb5 enctype %u\n",
|
||||
ctx->enctype);
|
||||
p = ERR_PTR(-EINVAL);
|
||||
goto out_err;
|
||||
}
|
||||
keylen = ctx->gk5e->keylength;
|
||||
keylen = ctx->krb5e->key_len;
|
||||
|
||||
p = simple_get_bytes(p, end, ctx->Ksess, keylen);
|
||||
if (IS_ERR(p))
|
||||
@@ -495,20 +214,38 @@ gss_krb5_delete_sec_context(void *internal_ctx)
|
||||
{
|
||||
struct krb5_ctx *kctx = internal_ctx;
|
||||
|
||||
crypto_free_sync_skcipher(kctx->seq);
|
||||
crypto_free_sync_skcipher(kctx->enc);
|
||||
crypto_free_sync_skcipher(kctx->acceptor_enc);
|
||||
crypto_free_sync_skcipher(kctx->initiator_enc);
|
||||
crypto_free_sync_skcipher(kctx->acceptor_enc_aux);
|
||||
crypto_free_sync_skcipher(kctx->initiator_enc_aux);
|
||||
crypto_free_ahash(kctx->acceptor_sign);
|
||||
crypto_free_ahash(kctx->initiator_sign);
|
||||
crypto_free_ahash(kctx->acceptor_integ);
|
||||
crypto_free_ahash(kctx->initiator_integ);
|
||||
crypto_free_shash(kctx->acceptor_sign_shash);
|
||||
crypto_free_shash(kctx->initiator_sign_shash);
|
||||
crypto_free_aead(kctx->acceptor_enc_aead);
|
||||
crypto_free_aead(kctx->initiator_enc_aead);
|
||||
kfree(kctx->mech_used.data);
|
||||
kfree(kctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* gss_krb5_errno_to_status - Map a negative errno to a GSS major status
|
||||
* @err: negative errno value, or zero
|
||||
*
|
||||
* Returns:
|
||||
* %GSS_S_COMPLETE if @err is zero
|
||||
* %GSS_S_BAD_SIG if @err is -EBADMSG (integrity check failure)
|
||||
* %GSS_S_DEFECTIVE_TOKEN if @err is -EPROTO (malformed token)
|
||||
* %GSS_S_FAILURE for all other negative values
|
||||
*/
|
||||
u32 gss_krb5_errno_to_status(int err)
|
||||
{
|
||||
switch (err) {
|
||||
case 0:
|
||||
return GSS_S_COMPLETE;
|
||||
case -EBADMSG:
|
||||
return GSS_S_BAD_SIG;
|
||||
case -EPROTO:
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
default:
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gss_krb5_get_mic - get_mic for the Kerberos GSS mechanism
|
||||
* @gctx: GSS context
|
||||
@@ -525,7 +262,7 @@ static u32 gss_krb5_get_mic(struct gss_ctx *gctx, struct xdr_buf *text,
|
||||
{
|
||||
struct krb5_ctx *kctx = gctx->internal_ctx_id;
|
||||
|
||||
return kctx->gk5e->get_mic(kctx, text, token);
|
||||
return gss_krb5_get_mic_v2(kctx, text, token);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +284,7 @@ static u32 gss_krb5_verify_mic(struct gss_ctx *gctx,
|
||||
{
|
||||
struct krb5_ctx *kctx = gctx->internal_ctx_id;
|
||||
|
||||
return kctx->gk5e->verify_mic(kctx, message_buffer, read_token);
|
||||
return gss_krb5_verify_mic_v2(kctx, message_buffer, read_token);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -567,7 +304,7 @@ static u32 gss_krb5_wrap(struct gss_ctx *gctx, int offset,
|
||||
{
|
||||
struct krb5_ctx *kctx = gctx->internal_ctx_id;
|
||||
|
||||
return kctx->gk5e->wrap(kctx, offset, buf, pages);
|
||||
return gss_krb5_wrap_v2(kctx, offset, buf, pages);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -589,7 +326,7 @@ static u32 gss_krb5_unwrap(struct gss_ctx *gctx, int offset,
|
||||
{
|
||||
struct krb5_ctx *kctx = gctx->internal_ctx_id;
|
||||
|
||||
return kctx->gk5e->unwrap(kctx, offset, len, buf,
|
||||
return gss_krb5_unwrap_v2(kctx, offset, len, buf,
|
||||
&gctx->slack, &gctx->align);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,9 +61,9 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "gss_krb5_internal.h"
|
||||
|
||||
@@ -78,10 +78,10 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
void *krb5_hdr;
|
||||
u8 *p, flags = 0x00;
|
||||
|
||||
if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
|
||||
flags |= 0x01;
|
||||
if (!ctx->initiate)
|
||||
flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
|
||||
if (ctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
|
||||
flags |= 0x04;
|
||||
flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
|
||||
|
||||
/* Per rfc 4121, sec 4.2.6.1, there is no header,
|
||||
* just start the token.
|
||||
@@ -97,7 +97,7 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token)
|
||||
*ptr++ = 0xffff;
|
||||
*ptr = 0xffff;
|
||||
|
||||
token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength;
|
||||
token->len = GSS_KRB5_TOK_HDR_LEN + ctx->krb5e->cksum_len;
|
||||
return krb5_hdr;
|
||||
}
|
||||
|
||||
@@ -105,14 +105,17 @@ u32
|
||||
gss_krb5_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
struct xdr_netobj *token)
|
||||
{
|
||||
struct crypto_ahash *tfm = ctx->initiate ?
|
||||
ctx->initiator_sign : ctx->acceptor_sign;
|
||||
struct xdr_netobj cksumobj = {
|
||||
.len = ctx->gk5e->cksumlength,
|
||||
};
|
||||
const struct krb5_enctype *krb5 = ctx->krb5e;
|
||||
struct crypto_shash *shash = ctx->initiate ?
|
||||
ctx->initiator_sign_shash : ctx->acceptor_sign_shash;
|
||||
unsigned int cksum_len = krb5->cksum_len;
|
||||
struct scatterlist sg_head[XDR_BUF_TO_SG_NENTS];
|
||||
struct scatterlist *sg_overflow;
|
||||
__be64 seq_send_be64;
|
||||
void *krb5_hdr;
|
||||
time64_t now;
|
||||
ssize_t ret;
|
||||
int nsg;
|
||||
|
||||
dprintk("RPC: %s\n", __func__);
|
||||
|
||||
@@ -123,9 +126,25 @@ gss_krb5_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text,
|
||||
seq_send_be64 = cpu_to_be64(atomic64_fetch_inc(&ctx->seq_send64));
|
||||
memcpy(krb5_hdr + 8, (char *) &seq_send_be64, 8);
|
||||
|
||||
cksumobj.data = krb5_hdr + GSS_KRB5_TOK_HDR_LEN;
|
||||
if (gss_krb5_checksum(tfm, krb5_hdr, GSS_KRB5_TOK_HDR_LEN,
|
||||
text, 0, &cksumobj))
|
||||
/*
|
||||
* The checksum is written directly into the token buffer.
|
||||
* This is safe: crypto_krb5_get_mic uses shash (software
|
||||
* hash), so the scatterlist is never DMA-mapped.
|
||||
*/
|
||||
nsg = gss_krb5_mic_build_sg(text,
|
||||
krb5_hdr + GSS_KRB5_TOK_HDR_LEN,
|
||||
cksum_len, krb5_hdr,
|
||||
sg_head, &sg_overflow);
|
||||
if (nsg < 0)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
ret = crypto_krb5_get_mic(krb5, shash, NULL, sg_head, nsg,
|
||||
cksum_len + text->len +
|
||||
GSS_KRB5_TOK_HDR_LEN,
|
||||
cksum_len,
|
||||
text->len + GSS_KRB5_TOK_HDR_LEN);
|
||||
kfree(sg_overflow);
|
||||
if (ret < 0)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
now = ktime_get_real_seconds();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -60,6 +60,8 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "gss_krb5_internal.h"
|
||||
|
||||
@@ -71,18 +73,19 @@ u32
|
||||
gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
|
||||
struct xdr_netobj *read_token)
|
||||
{
|
||||
struct crypto_ahash *tfm = ctx->initiate ?
|
||||
ctx->acceptor_sign : ctx->initiator_sign;
|
||||
char cksumdata[GSS_KRB5_MAX_CKSUM_LEN];
|
||||
struct xdr_netobj cksumobj = {
|
||||
.len = ctx->gk5e->cksumlength,
|
||||
.data = cksumdata,
|
||||
};
|
||||
const struct krb5_enctype *krb5 = ctx->krb5e;
|
||||
struct crypto_shash *shash = ctx->initiate ?
|
||||
ctx->acceptor_sign_shash : ctx->initiator_sign_shash;
|
||||
unsigned int cksum_len = krb5->cksum_len;
|
||||
struct scatterlist sg_head[XDR_BUF_TO_SG_NENTS];
|
||||
struct scatterlist *sg_overflow;
|
||||
size_t mic_offset, mic_len;
|
||||
u8 *ptr = read_token->data;
|
||||
__be16 be16_ptr;
|
||||
time64_t now;
|
||||
u8 flags;
|
||||
int i;
|
||||
int nsg, i;
|
||||
int ret;
|
||||
|
||||
dprintk("RPC: %s\n", __func__);
|
||||
|
||||
@@ -104,13 +107,20 @@ gss_krb5_verify_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *message_buffer,
|
||||
if (ptr[i] != 0xff)
|
||||
return GSS_S_DEFECTIVE_TOKEN;
|
||||
|
||||
if (gss_krb5_checksum(tfm, ptr, GSS_KRB5_TOK_HDR_LEN,
|
||||
message_buffer, 0, &cksumobj))
|
||||
nsg = gss_krb5_mic_build_sg(message_buffer,
|
||||
ptr + GSS_KRB5_TOK_HDR_LEN,
|
||||
cksum_len, ptr,
|
||||
sg_head, &sg_overflow);
|
||||
if (nsg < 0)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
if (memcmp(cksumobj.data, ptr + GSS_KRB5_TOK_HDR_LEN,
|
||||
ctx->gk5e->cksumlength))
|
||||
return GSS_S_BAD_SIG;
|
||||
mic_offset = 0;
|
||||
mic_len = cksum_len + message_buffer->len + GSS_KRB5_TOK_HDR_LEN;
|
||||
ret = crypto_krb5_verify_mic(krb5, shash, NULL, sg_head, nsg,
|
||||
&mic_offset, &mic_len);
|
||||
kfree(sg_overflow);
|
||||
if (ret)
|
||||
return gss_krb5_errno_to_status(ret);
|
||||
|
||||
/* it got through unscathed. Make sure the context is unexpired */
|
||||
now = ktime_get_real_seconds();
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
* SUCH DAMAGES.
|
||||
*/
|
||||
|
||||
#include <crypto/skcipher.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/sunrpc/gss_krb5.h>
|
||||
@@ -112,9 +111,9 @@ gss_krb5_wrap_v2(struct krb5_ctx *kctx, int offset,
|
||||
*ptr++ = (unsigned char) ((KG2_TOK_WRAP>>8) & 0xff);
|
||||
*ptr++ = (unsigned char) (KG2_TOK_WRAP & 0xff);
|
||||
|
||||
if ((kctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0)
|
||||
if (!kctx->initiate)
|
||||
flags |= KG2_TOKEN_FLAG_SENTBYACCEPTOR;
|
||||
if ((kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY) != 0)
|
||||
if (kctx->flags & KRB5_CTX_FLAG_ACCEPTOR_SUBKEY)
|
||||
flags |= KG2_TOKEN_FLAG_ACCEPTORSUBKEY;
|
||||
/* We always do confidentiality in wrap tokens */
|
||||
flags |= KG2_TOKEN_FLAG_SEALED;
|
||||
@@ -130,7 +129,7 @@ gss_krb5_wrap_v2(struct krb5_ctx *kctx, int offset,
|
||||
be64ptr = (__be64 *)be16ptr;
|
||||
*be64ptr = cpu_to_be64(atomic64_fetch_inc(&kctx->seq_send64));
|
||||
|
||||
err = (*kctx->gk5e->encrypt)(kctx, offset, buf, pages);
|
||||
err = gss_krb5_aead_encrypt(kctx, offset, buf, pages);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -184,10 +183,10 @@ gss_krb5_unwrap_v2(struct krb5_ctx *kctx, int offset, int len,
|
||||
if (rrc != 0)
|
||||
rotate_left(offset + 16, buf, rrc);
|
||||
|
||||
err = (*kctx->gk5e->decrypt)(kctx, offset, len, buf,
|
||||
&headskip, &tailskip);
|
||||
err = gss_krb5_aead_decrypt(kctx, offset, len, buf,
|
||||
&headskip, &tailskip);
|
||||
if (err)
|
||||
return GSS_S_FAILURE;
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Retrieve the decrypted gss token header and verify
|
||||
|
||||
@@ -206,7 +206,7 @@ static struct cache_head *rsi_alloc(void)
|
||||
|
||||
static int rsi_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall_timeout(cd, h);
|
||||
return sunrpc_cache_upcall_warn(cd, h);
|
||||
}
|
||||
|
||||
static void rsi_request(struct cache_detail *cd,
|
||||
|
||||
@@ -33,9 +33,11 @@
|
||||
#include <linux/sunrpc/cache.h>
|
||||
#include <linux/sunrpc/stats.h>
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <trace/events/sunrpc.h>
|
||||
|
||||
#include "netns.h"
|
||||
#include "netlink.h"
|
||||
#include "fail.h"
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_CACHE
|
||||
@@ -1195,12 +1197,12 @@ static bool cache_listeners_exist(struct cache_detail *detail)
|
||||
}
|
||||
|
||||
/*
|
||||
* register an upcall request to user-space and queue it up for read() by the
|
||||
* upcall daemon.
|
||||
* register an upcall request to user-space and queue it up to be fetched by
|
||||
* the upcall daemon.
|
||||
*
|
||||
* Each request is at most one page long.
|
||||
*/
|
||||
static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
static int cache_do_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
{
|
||||
char *buf;
|
||||
struct cache_request *crq;
|
||||
@@ -1233,6 +1235,8 @@ static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
/* Lost a race, no longer PENDING, so don't enqueue */
|
||||
ret = -EAGAIN;
|
||||
spin_unlock(&detail->queue_lock);
|
||||
if (ret != -EAGAIN && detail->cache_notify)
|
||||
detail->cache_notify(detail, h);
|
||||
wake_up(&detail->queue_wait);
|
||||
if (ret == -EAGAIN) {
|
||||
kfree(buf);
|
||||
@@ -1241,25 +1245,25 @@ static int cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sunrpc_cache_pipe_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
int sunrpc_cache_upcall(struct cache_detail *detail, struct cache_head *h)
|
||||
{
|
||||
if (test_and_set_bit(CACHE_PENDING, &h->flags))
|
||||
return 0;
|
||||
return cache_pipe_upcall(detail, h);
|
||||
return cache_do_upcall(detail, h);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall);
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_upcall);
|
||||
|
||||
int sunrpc_cache_pipe_upcall_timeout(struct cache_detail *detail,
|
||||
struct cache_head *h)
|
||||
int sunrpc_cache_upcall_warn(struct cache_detail *detail,
|
||||
struct cache_head *h)
|
||||
{
|
||||
if (!cache_listeners_exist(detail)) {
|
||||
warn_no_listener(detail);
|
||||
trace_cache_entry_no_listener(detail, h);
|
||||
return -EINVAL;
|
||||
}
|
||||
return sunrpc_cache_pipe_upcall(detail, h);
|
||||
return sunrpc_cache_upcall(detail, h);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_pipe_upcall_timeout);
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_upcall_warn);
|
||||
|
||||
/*
|
||||
* parse a message from user-space and pass it
|
||||
@@ -1900,3 +1904,106 @@ void sunrpc_cache_unhash(struct cache_detail *cd, struct cache_head *h)
|
||||
spin_unlock(&cd->hash_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_unhash);
|
||||
|
||||
/**
|
||||
* sunrpc_cache_requests_count - count pending upcall requests
|
||||
* @cd: cache_detail to query
|
||||
*
|
||||
* Returns the number of requests on the cache's request list that
|
||||
* still have CACHE_PENDING set.
|
||||
*/
|
||||
int sunrpc_cache_requests_count(struct cache_detail *cd)
|
||||
{
|
||||
struct cache_request *crq;
|
||||
int cnt = 0;
|
||||
|
||||
spin_lock(&cd->queue_lock);
|
||||
list_for_each_entry(crq, &cd->requests, list) {
|
||||
if (test_bit(CACHE_PENDING, &crq->item->flags))
|
||||
cnt++;
|
||||
}
|
||||
spin_unlock(&cd->queue_lock);
|
||||
return cnt;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_requests_count);
|
||||
|
||||
/**
|
||||
* sunrpc_cache_requests_snapshot - snapshot pending upcall requests
|
||||
* @cd: cache_detail to query
|
||||
* @items: array to fill with cache_head pointers (caller-allocated)
|
||||
* @seqnos: array to fill with sequence numbers (caller-allocated)
|
||||
* @max: size of the arrays
|
||||
* @min_seqno: only include entries with seqno > min_seqno (0 for all)
|
||||
*
|
||||
* Only entries with CACHE_PENDING set are included. Takes a reference
|
||||
* on each cache_head via cache_get(). Caller must call cache_put()
|
||||
* on each returned item when done.
|
||||
*
|
||||
* Returns the number of entries filled.
|
||||
*/
|
||||
int sunrpc_cache_requests_snapshot(struct cache_detail *cd,
|
||||
struct cache_head **items,
|
||||
u64 *seqnos, int max,
|
||||
u64 min_seqno)
|
||||
{
|
||||
struct cache_request *crq;
|
||||
int i = 0;
|
||||
|
||||
spin_lock(&cd->queue_lock);
|
||||
list_for_each_entry(crq, &cd->requests, list) {
|
||||
if (i >= max)
|
||||
break;
|
||||
if (!test_bit(CACHE_PENDING, &crq->item->flags))
|
||||
continue;
|
||||
if (crq->seqno <= min_seqno)
|
||||
continue;
|
||||
items[i] = cache_get(crq->item);
|
||||
seqnos[i] = crq->seqno;
|
||||
i++;
|
||||
}
|
||||
spin_unlock(&cd->queue_lock);
|
||||
return i;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_requests_snapshot);
|
||||
|
||||
/**
|
||||
* sunrpc_cache_notify - send a netlink notification for a cache event
|
||||
* @cd: cache_detail for the cache
|
||||
* @h: cache_head entry (unused, reserved for future use)
|
||||
* @cache_type: cache type identifier (e.g. SUNRPC_CACHE_TYPE_UNIX_GID)
|
||||
*
|
||||
* Sends a SUNRPC_CMD_CACHE_NOTIFY multicast message on the "exportd"
|
||||
* group if any listeners are present. Returns 0 on success or a
|
||||
* negative errno.
|
||||
*/
|
||||
int sunrpc_cache_notify(struct cache_detail *cd, struct cache_head *h,
|
||||
u32 cache_type)
|
||||
{
|
||||
struct genlmsghdr *hdr;
|
||||
struct sk_buff *msg;
|
||||
|
||||
if (!genl_has_listeners(&sunrpc_nl_family, cd->net,
|
||||
SUNRPC_NLGRP_EXPORTD))
|
||||
return -ENOLINK;
|
||||
|
||||
msg = genlmsg_new(nla_total_size(sizeof(u32)), GFP_KERNEL);
|
||||
if (!msg)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = genlmsg_put(msg, 0, 0, &sunrpc_nl_family, 0,
|
||||
SUNRPC_CMD_CACHE_NOTIFY);
|
||||
if (!hdr) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (nla_put_u32(msg, SUNRPC_A_CACHE_NOTIFY_CACHE_TYPE, cache_type)) {
|
||||
nlmsg_free(msg);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
return genlmsg_multicast_netns(&sunrpc_nl_family, cd->net, msg, 0,
|
||||
SUNRPC_NLGRP_EXPORTD, GFP_KERNEL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sunrpc_cache_notify);
|
||||
|
||||
97
net/sunrpc/netlink.c
Normal file
97
net/sunrpc/netlink.c
Normal file
@@ -0,0 +1,97 @@
|
||||
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/sunrpc_cache.yaml */
|
||||
/* YNL-GEN kernel source */
|
||||
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "netlink.h"
|
||||
|
||||
#include <uapi/linux/sunrpc_netlink.h>
|
||||
|
||||
/* Common nested types */
|
||||
const struct nla_policy sunrpc_ip_map_nl_policy[SUNRPC_A_IP_MAP_EXPIRY + 1] = {
|
||||
[SUNRPC_A_IP_MAP_SEQNO] = { .type = NLA_U64, },
|
||||
[SUNRPC_A_IP_MAP_CLASS] = { .type = NLA_NUL_STRING, },
|
||||
[SUNRPC_A_IP_MAP_ADDR] = { .type = NLA_NUL_STRING, },
|
||||
[SUNRPC_A_IP_MAP_DOMAIN] = { .type = NLA_NUL_STRING, },
|
||||
[SUNRPC_A_IP_MAP_NEGATIVE] = { .type = NLA_FLAG, },
|
||||
[SUNRPC_A_IP_MAP_EXPIRY] = { .type = NLA_U64, },
|
||||
};
|
||||
|
||||
const struct nla_policy sunrpc_unix_gid_nl_policy[SUNRPC_A_UNIX_GID_EXPIRY + 1] = {
|
||||
[SUNRPC_A_UNIX_GID_SEQNO] = { .type = NLA_U64, },
|
||||
[SUNRPC_A_UNIX_GID_UID] = { .type = NLA_U32, },
|
||||
[SUNRPC_A_UNIX_GID_GIDS] = { .type = NLA_U32, },
|
||||
[SUNRPC_A_UNIX_GID_NEGATIVE] = { .type = NLA_FLAG, },
|
||||
[SUNRPC_A_UNIX_GID_EXPIRY] = { .type = NLA_U64, },
|
||||
};
|
||||
|
||||
/* SUNRPC_CMD_IP_MAP_SET_REQS - do */
|
||||
static const struct nla_policy sunrpc_ip_map_set_reqs_nl_policy[SUNRPC_A_IP_MAP_REQS_REQUESTS + 1] = {
|
||||
[SUNRPC_A_IP_MAP_REQS_REQUESTS] = NLA_POLICY_NESTED(sunrpc_ip_map_nl_policy),
|
||||
};
|
||||
|
||||
/* SUNRPC_CMD_UNIX_GID_SET_REQS - do */
|
||||
static const struct nla_policy sunrpc_unix_gid_set_reqs_nl_policy[SUNRPC_A_UNIX_GID_REQS_REQUESTS + 1] = {
|
||||
[SUNRPC_A_UNIX_GID_REQS_REQUESTS] = NLA_POLICY_NESTED(sunrpc_unix_gid_nl_policy),
|
||||
};
|
||||
|
||||
/* SUNRPC_CMD_CACHE_FLUSH - do */
|
||||
static const struct nla_policy sunrpc_cache_flush_nl_policy[SUNRPC_A_CACHE_FLUSH_MASK + 1] = {
|
||||
[SUNRPC_A_CACHE_FLUSH_MASK] = NLA_POLICY_MASK(NLA_U32, 0x3),
|
||||
};
|
||||
|
||||
/* Ops table for sunrpc */
|
||||
static const struct genl_split_ops sunrpc_nl_ops[] = {
|
||||
{
|
||||
.cmd = SUNRPC_CMD_IP_MAP_GET_REQS,
|
||||
.dumpit = sunrpc_nl_ip_map_get_reqs_dumpit,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
|
||||
},
|
||||
{
|
||||
.cmd = SUNRPC_CMD_IP_MAP_SET_REQS,
|
||||
.doit = sunrpc_nl_ip_map_set_reqs_doit,
|
||||
.policy = sunrpc_ip_map_set_reqs_nl_policy,
|
||||
.maxattr = SUNRPC_A_IP_MAP_REQS_REQUESTS,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = SUNRPC_CMD_UNIX_GID_GET_REQS,
|
||||
.dumpit = sunrpc_nl_unix_gid_get_reqs_dumpit,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DUMP,
|
||||
},
|
||||
{
|
||||
.cmd = SUNRPC_CMD_UNIX_GID_SET_REQS,
|
||||
.doit = sunrpc_nl_unix_gid_set_reqs_doit,
|
||||
.policy = sunrpc_unix_gid_set_reqs_nl_policy,
|
||||
.maxattr = SUNRPC_A_UNIX_GID_REQS_REQUESTS,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = SUNRPC_CMD_CACHE_FLUSH,
|
||||
.doit = sunrpc_nl_cache_flush_doit,
|
||||
.policy = sunrpc_cache_flush_nl_policy,
|
||||
.maxattr = SUNRPC_A_CACHE_FLUSH_MASK,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct genl_multicast_group sunrpc_nl_mcgrps[] = {
|
||||
[SUNRPC_NLGRP_NONE] = { "none", },
|
||||
[SUNRPC_NLGRP_EXPORTD] = { "exportd", },
|
||||
};
|
||||
|
||||
struct genl_family sunrpc_nl_family __ro_after_init = {
|
||||
.name = SUNRPC_FAMILY_NAME,
|
||||
.version = SUNRPC_FAMILY_VERSION,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.module = THIS_MODULE,
|
||||
.split_ops = sunrpc_nl_ops,
|
||||
.n_split_ops = ARRAY_SIZE(sunrpc_nl_ops),
|
||||
.mcgrps = sunrpc_nl_mcgrps,
|
||||
.n_mcgrps = ARRAY_SIZE(sunrpc_nl_mcgrps),
|
||||
};
|
||||
35
net/sunrpc/netlink.h
Normal file
35
net/sunrpc/netlink.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/sunrpc_cache.yaml */
|
||||
/* YNL-GEN kernel header */
|
||||
/* To regenerate run: tools/net/ynl/ynl-regen.sh */
|
||||
|
||||
#ifndef _LINUX_SUNRPC_GEN_H
|
||||
#define _LINUX_SUNRPC_GEN_H
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include <uapi/linux/sunrpc_netlink.h>
|
||||
|
||||
/* Common nested types */
|
||||
extern const struct nla_policy sunrpc_ip_map_nl_policy[SUNRPC_A_IP_MAP_EXPIRY + 1];
|
||||
extern const struct nla_policy sunrpc_unix_gid_nl_policy[SUNRPC_A_UNIX_GID_EXPIRY + 1];
|
||||
|
||||
int sunrpc_nl_ip_map_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb);
|
||||
int sunrpc_nl_ip_map_set_reqs_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int sunrpc_nl_unix_gid_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb);
|
||||
int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb,
|
||||
struct genl_info *info);
|
||||
int sunrpc_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
enum {
|
||||
SUNRPC_NLGRP_NONE,
|
||||
SUNRPC_NLGRP_EXPORTD,
|
||||
};
|
||||
|
||||
extern struct genl_family sunrpc_nl_family;
|
||||
|
||||
#endif /* _LINUX_SUNRPC_GEN_H */
|
||||
@@ -23,9 +23,12 @@
|
||||
#include <linux/sunrpc/rpc_pipe_fs.h>
|
||||
#include <linux/sunrpc/xprtsock.h>
|
||||
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "sunrpc.h"
|
||||
#include "sysfs.h"
|
||||
#include "netns.h"
|
||||
#include "netlink.h"
|
||||
|
||||
unsigned int sunrpc_net_id;
|
||||
EXPORT_SYMBOL_GPL(sunrpc_net_id);
|
||||
@@ -108,6 +111,10 @@ init_sunrpc(void)
|
||||
if (err)
|
||||
goto out5;
|
||||
|
||||
err = genl_register_family(&sunrpc_nl_family);
|
||||
if (err)
|
||||
goto out6;
|
||||
|
||||
sunrpc_debugfs_init();
|
||||
#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
|
||||
rpc_register_sysctl();
|
||||
@@ -116,6 +123,8 @@ init_sunrpc(void)
|
||||
init_socket_xprt(); /* clnt sock transport */
|
||||
return 0;
|
||||
|
||||
out6:
|
||||
rpc_sysfs_exit();
|
||||
out5:
|
||||
unregister_rpc_pipefs();
|
||||
out4:
|
||||
@@ -131,6 +140,7 @@ init_sunrpc(void)
|
||||
static void __exit
|
||||
cleanup_sunrpc(void)
|
||||
{
|
||||
genl_unregister_family(&sunrpc_nl_family);
|
||||
rpc_sysfs_exit();
|
||||
rpc_cleanup_clids();
|
||||
xprt_cleanup_ids();
|
||||
|
||||
@@ -1598,6 +1598,12 @@ static void svc_release_rqst(struct svc_rqst *rqstp)
|
||||
|
||||
if (procp && procp->pc_release)
|
||||
procp->pc_release(rqstp);
|
||||
|
||||
/*
|
||||
* A subsequent svc_release_rqst() on this rqstp must not
|
||||
* re-invoke pc_release against released state.
|
||||
*/
|
||||
rqstp->rq_procinfo = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1616,6 +1622,9 @@ void svc_process(struct svc_rqst *rqstp)
|
||||
svc_xprt_deferred_close(rqstp->rq_xprt);
|
||||
#endif
|
||||
|
||||
/* Discard a stale release hook from a previous RPC. */
|
||||
rqstp->rq_procinfo = NULL;
|
||||
|
||||
/*
|
||||
* Setup response xdr_buf.
|
||||
* Initially it has just one page
|
||||
@@ -1672,6 +1681,7 @@ void svc_process_bc(struct rpc_rqst *req, struct svc_rqst *rqstp)
|
||||
int proc_error;
|
||||
|
||||
/* Build the svc_rqst used by the common processing routine */
|
||||
rqstp->rq_procinfo = NULL;
|
||||
rqstp->rq_xid = req->rq_xid;
|
||||
rqstp->rq_prot = req->rq_xprt->prot;
|
||||
rqstp->rq_bc_net = req->rq_xprt->xprt_net;
|
||||
|
||||
@@ -234,7 +234,19 @@ void svc_xprt_received(struct svc_xprt *xprt)
|
||||
svc_xprt_get(xprt);
|
||||
smp_mb__before_atomic();
|
||||
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
svc_xprt_enqueue(xprt);
|
||||
|
||||
/*
|
||||
* Skip the enqueue when no actionable flags are set.
|
||||
* Each producer both sets its flag (XPT_DATA, XPT_CLOSE,
|
||||
* etc.) and calls svc_xprt_enqueue(); if a set_bit races
|
||||
* with this check, the producer's own enqueue observes
|
||||
* !XPT_BUSY and dispatches the transport.
|
||||
*/
|
||||
if (READ_ONCE(xprt->xpt_flags) &
|
||||
(BIT(XPT_CONN) | BIT(XPT_CLOSE) | BIT(XPT_HANDSHAKE) |
|
||||
BIT(XPT_DATA) | BIT(XPT_DEFERRED)))
|
||||
svc_xprt_enqueue(xprt);
|
||||
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_xprt_received);
|
||||
@@ -425,13 +437,35 @@ static bool svc_xprt_reserve_slot(struct svc_rqst *rqstp, struct svc_xprt *xprt)
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* After a caller releases write-space or a request slot,
|
||||
* re-enqueue the transport only when there is pending
|
||||
* work that a thread could act on. The smp_mb() pairs
|
||||
* with the smp_rmb() in svc_xprt_ready() and orders the
|
||||
* preceding counter update before the flags read so a
|
||||
* concurrent set_bit(XPT_DATA) is visible here.
|
||||
*
|
||||
* When the transport is BUSY, the thread holding it will
|
||||
* call svc_xprt_received() upon completion, which checks
|
||||
* for pending work and re-enqueues as needed.
|
||||
*/
|
||||
static void svc_xprt_resource_released(struct svc_xprt *xprt)
|
||||
{
|
||||
unsigned long xpt_flags;
|
||||
|
||||
smp_mb();
|
||||
xpt_flags = READ_ONCE(xprt->xpt_flags);
|
||||
if (xpt_flags & (BIT(XPT_DATA) | BIT(XPT_DEFERRED)) &&
|
||||
!(xpt_flags & BIT(XPT_BUSY)))
|
||||
svc_xprt_enqueue(xprt);
|
||||
}
|
||||
|
||||
static void svc_xprt_release_slot(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_xprt *xprt = rqstp->rq_xprt;
|
||||
if (test_and_clear_bit(RQ_DATA, &rqstp->rq_flags)) {
|
||||
atomic_dec(&xprt->xpt_nr_rqsts);
|
||||
smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */
|
||||
svc_xprt_enqueue(xprt);
|
||||
svc_xprt_resource_released(xprt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -525,10 +559,10 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
|
||||
space += rqstp->rq_res.head[0].iov_len;
|
||||
|
||||
if (xprt && space < rqstp->rq_reserved) {
|
||||
atomic_sub((rqstp->rq_reserved - space), &xprt->xpt_reserved);
|
||||
atomic_sub((rqstp->rq_reserved - space),
|
||||
&xprt->xpt_reserved);
|
||||
rqstp->rq_reserved = space;
|
||||
smp_wmb(); /* See smp_rmb() in svc_xprt_ready() */
|
||||
svc_xprt_enqueue(xprt);
|
||||
svc_xprt_resource_released(xprt);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_reserve);
|
||||
|
||||
@@ -17,11 +17,14 @@
|
||||
#include <net/ipv6.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/user_namespace.h>
|
||||
#include <net/genetlink.h>
|
||||
#include <uapi/linux/sunrpc_netlink.h>
|
||||
#include <trace/events/sunrpc.h>
|
||||
|
||||
#define RPCDBG_FACILITY RPCDBG_AUTH
|
||||
|
||||
#include "netns.h"
|
||||
#include "netlink.h"
|
||||
|
||||
/*
|
||||
* AUTHUNIX and AUTHNULL credentials are both handled here.
|
||||
@@ -152,7 +155,7 @@ static struct cache_head *ip_map_alloc(void)
|
||||
|
||||
static int ip_map_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall(cd, h);
|
||||
return sunrpc_cache_upcall(cd, h);
|
||||
}
|
||||
|
||||
static void ip_map_request(struct cache_detail *cd,
|
||||
@@ -467,7 +470,7 @@ static struct cache_head *unix_gid_alloc(void)
|
||||
|
||||
static int unix_gid_upcall(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_pipe_upcall_timeout(cd, h);
|
||||
return sunrpc_cache_upcall_warn(cd, h);
|
||||
}
|
||||
|
||||
static void unix_gid_request(struct cache_detail *cd,
|
||||
@@ -582,12 +585,278 @@ static int unix_gid_show(struct seq_file *m,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int unix_gid_notify(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_notify(cd, h, SUNRPC_CACHE_TYPE_UNIX_GID);
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_unix_gid_get_reqs_dumpit - dump pending unix_gid requests
|
||||
* @skb: reply buffer
|
||||
* @cb: netlink metadata and command arguments
|
||||
*
|
||||
* Walk the unix_gid cache's pending request list and create a netlink
|
||||
* message with a nested entry for each cache_request, containing the
|
||||
* seqno and uid.
|
||||
*
|
||||
* Uses cb->args[0] as a seqno cursor for dump continuation across
|
||||
* multiple netlink messages.
|
||||
*
|
||||
* Returns the size of the reply or a negative errno.
|
||||
*/
|
||||
int sunrpc_nl_unix_gid_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct sunrpc_net *sn;
|
||||
struct cache_detail *cd;
|
||||
struct cache_head **items;
|
||||
u64 *seqnos;
|
||||
int cnt, i, emitted;
|
||||
void *hdr;
|
||||
int ret;
|
||||
|
||||
sn = net_generic(sock_net(skb->sk), sunrpc_net_id);
|
||||
|
||||
cd = sn->unix_gid_cache;
|
||||
if (!cd)
|
||||
return -ENODEV;
|
||||
|
||||
cnt = sunrpc_cache_requests_count(cd);
|
||||
if (!cnt)
|
||||
return 0;
|
||||
|
||||
items = kcalloc(cnt, sizeof(*items), GFP_KERNEL);
|
||||
seqnos = kcalloc(cnt, sizeof(*seqnos), GFP_KERNEL);
|
||||
if (!items || !seqnos) {
|
||||
ret = -ENOMEM;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
cnt = sunrpc_cache_requests_snapshot(cd, items, seqnos, cnt,
|
||||
cb->args[0]);
|
||||
if (!cnt) {
|
||||
ret = 0;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, &sunrpc_nl_family,
|
||||
NLM_F_MULTI, SUNRPC_CMD_UNIX_GID_GET_REQS);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
emitted = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct unix_gid *ug;
|
||||
struct nlattr *nest;
|
||||
|
||||
ug = container_of(items[i], struct unix_gid, h);
|
||||
|
||||
nest = nla_nest_start(skb,
|
||||
SUNRPC_A_UNIX_GID_REQS_REQUESTS);
|
||||
if (!nest)
|
||||
break;
|
||||
|
||||
if (nla_put_u64_64bit(skb, SUNRPC_A_UNIX_GID_SEQNO,
|
||||
seqnos[i], 0) ||
|
||||
nla_put_u32(skb, SUNRPC_A_UNIX_GID_UID,
|
||||
from_kuid(&init_user_ns, ug->uid))) {
|
||||
nla_nest_cancel(skb, nest);
|
||||
break;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
cb->args[0] = seqnos[i];
|
||||
emitted++;
|
||||
}
|
||||
|
||||
if (!emitted) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
ret = -EMSGSIZE;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
ret = skb->len;
|
||||
out_put:
|
||||
for (i = 0; i < cnt; i++)
|
||||
cache_put(items[i], cd);
|
||||
out_alloc:
|
||||
kfree(seqnos);
|
||||
kfree(items);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_parse_one_unix_gid - parse one unix_gid entry from netlink
|
||||
* @cd: cache_detail for the unix_gid cache
|
||||
* @attr: nested attribute containing unix_gid fields
|
||||
*
|
||||
* Parses one unix_gid entry from a netlink message and updates the
|
||||
* cache. Mirrors the logic in unix_gid_parse().
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
static int sunrpc_nl_parse_one_unix_gid(struct cache_detail *cd,
|
||||
struct nlattr *attr)
|
||||
{
|
||||
struct nlattr *tb[SUNRPC_A_UNIX_GID_EXPIRY + 1];
|
||||
struct unix_gid ug, *ugp;
|
||||
struct timespec64 boot;
|
||||
struct nlattr *gid_attr;
|
||||
int err, rem, gids = 0;
|
||||
kuid_t uid;
|
||||
|
||||
err = nla_parse_nested(tb, SUNRPC_A_UNIX_GID_EXPIRY, attr,
|
||||
sunrpc_unix_gid_nl_policy, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* uid (required) */
|
||||
if (!tb[SUNRPC_A_UNIX_GID_UID])
|
||||
return -EINVAL;
|
||||
uid = make_kuid(current_user_ns(),
|
||||
nla_get_u32(tb[SUNRPC_A_UNIX_GID_UID]));
|
||||
ug.uid = uid;
|
||||
|
||||
/* expiry (required, wallclock seconds) */
|
||||
if (!tb[SUNRPC_A_UNIX_GID_EXPIRY])
|
||||
return -EINVAL;
|
||||
getboottime64(&boot);
|
||||
ug.h.flags = 0;
|
||||
ug.h.expiry_time = nla_get_u64(tb[SUNRPC_A_UNIX_GID_EXPIRY]) -
|
||||
boot.tv_sec;
|
||||
|
||||
if (tb[SUNRPC_A_UNIX_GID_NEGATIVE]) {
|
||||
ug.gi = groups_alloc(0);
|
||||
if (!ug.gi)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
/* Count gids */
|
||||
nla_for_each_nested_type(gid_attr, SUNRPC_A_UNIX_GID_GIDS,
|
||||
attr, rem)
|
||||
gids++;
|
||||
|
||||
if (gids > 8192)
|
||||
return -EINVAL;
|
||||
|
||||
ug.gi = groups_alloc(gids);
|
||||
if (!ug.gi)
|
||||
return -ENOMEM;
|
||||
|
||||
gids = 0;
|
||||
nla_for_each_nested_type(gid_attr, SUNRPC_A_UNIX_GID_GIDS,
|
||||
attr, rem) {
|
||||
kgid_t kgid;
|
||||
|
||||
kgid = make_kgid(current_user_ns(),
|
||||
nla_get_u32(gid_attr));
|
||||
if (!gid_valid(kgid)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ug.gi->gid[gids++] = kgid;
|
||||
}
|
||||
groups_sort(ug.gi);
|
||||
}
|
||||
|
||||
ugp = unix_gid_lookup(cd, uid);
|
||||
if (ugp) {
|
||||
struct cache_head *ch;
|
||||
|
||||
ch = sunrpc_cache_update(cd, &ug.h, &ugp->h,
|
||||
unix_gid_hash(uid));
|
||||
if (!ch) {
|
||||
err = -ENOMEM;
|
||||
} else {
|
||||
err = 0;
|
||||
cache_put(ch, cd);
|
||||
}
|
||||
} else {
|
||||
err = -ENOMEM;
|
||||
}
|
||||
out:
|
||||
if (ug.gi)
|
||||
put_group_info(ug.gi);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_unix_gid_set_reqs_doit - respond to unix_gid requests
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Parse one or more unix_gid cache responses from userspace and
|
||||
* update the unix_gid cache accordingly.
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
int sunrpc_nl_unix_gid_set_reqs_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct sunrpc_net *sn;
|
||||
struct cache_detail *cd;
|
||||
const struct nlattr *attr;
|
||||
int rem, ret = 0;
|
||||
|
||||
sn = net_generic(genl_info_net(info), sunrpc_net_id);
|
||||
|
||||
cd = sn->unix_gid_cache;
|
||||
if (!cd)
|
||||
return -ENODEV;
|
||||
|
||||
nlmsg_for_each_attr_type(attr, SUNRPC_A_UNIX_GID_REQS_REQUESTS,
|
||||
info->nlhdr, GENL_HDRLEN, rem) {
|
||||
ret = sunrpc_nl_parse_one_unix_gid(cd,
|
||||
(struct nlattr *)attr);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_cache_flush_doit - flush sunrpc caches via netlink
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Flush the ip_map and/or unix_gid caches. If SUNRPC_A_CACHE_FLUSH_MASK
|
||||
* is provided, only flush the caches indicated by the bitmask (bit 1 =
|
||||
* ip_map, bit 2 = unix_gid). If omitted, flush both.
|
||||
*
|
||||
* Return 0 on success or a negative errno.
|
||||
*/
|
||||
int sunrpc_nl_cache_flush_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct sunrpc_net *sn;
|
||||
u32 mask = ~0U;
|
||||
|
||||
sn = net_generic(genl_info_net(info), sunrpc_net_id);
|
||||
|
||||
if (info->attrs[SUNRPC_A_CACHE_FLUSH_MASK])
|
||||
mask = nla_get_u32(info->attrs[SUNRPC_A_CACHE_FLUSH_MASK]);
|
||||
|
||||
if ((mask & SUNRPC_CACHE_TYPE_IP_MAP) &&
|
||||
sn->ip_map_cache)
|
||||
cache_purge(sn->ip_map_cache);
|
||||
|
||||
if ((mask & SUNRPC_CACHE_TYPE_UNIX_GID) &&
|
||||
sn->unix_gid_cache)
|
||||
cache_purge(sn->unix_gid_cache);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cache_detail unix_gid_cache_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.hash_size = GID_HASHMAX,
|
||||
.name = "auth.unix.gid",
|
||||
.cache_put = unix_gid_put,
|
||||
.cache_upcall = unix_gid_upcall,
|
||||
.cache_notify = unix_gid_notify,
|
||||
.cache_request = unix_gid_request,
|
||||
.cache_parse = unix_gid_parse,
|
||||
.cache_show = unix_gid_show,
|
||||
@@ -1017,12 +1286,255 @@ struct auth_ops svcauth_unix = {
|
||||
.set_client = svcauth_unix_set_client,
|
||||
};
|
||||
|
||||
static int ip_map_notify(struct cache_detail *cd, struct cache_head *h)
|
||||
{
|
||||
return sunrpc_cache_notify(cd, h, SUNRPC_CACHE_TYPE_IP_MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_ip_map_get_reqs_dumpit - dump pending ip_map requests
|
||||
* @skb: reply buffer
|
||||
* @cb: netlink metadata and command arguments
|
||||
*
|
||||
* Walk the ip_map cache's pending request list and create a netlink
|
||||
* message with a nested entry for each cache_request, containing the
|
||||
* seqno, class and addr.
|
||||
*
|
||||
* Uses cb->args[0] as a seqno cursor for dump continuation across
|
||||
* multiple netlink messages.
|
||||
*
|
||||
* Returns the size of the reply or a negative errno.
|
||||
*/
|
||||
int sunrpc_nl_ip_map_get_reqs_dumpit(struct sk_buff *skb,
|
||||
struct netlink_callback *cb)
|
||||
{
|
||||
struct sunrpc_net *sn;
|
||||
struct cache_detail *cd;
|
||||
struct cache_head **items;
|
||||
u64 *seqnos;
|
||||
int cnt, i, emitted;
|
||||
void *hdr;
|
||||
int ret;
|
||||
|
||||
sn = net_generic(sock_net(skb->sk), sunrpc_net_id);
|
||||
|
||||
cd = sn->ip_map_cache;
|
||||
if (!cd)
|
||||
return -ENODEV;
|
||||
|
||||
cnt = sunrpc_cache_requests_count(cd);
|
||||
if (!cnt)
|
||||
return 0;
|
||||
|
||||
items = kcalloc(cnt, sizeof(*items), GFP_KERNEL);
|
||||
seqnos = kcalloc(cnt, sizeof(*seqnos), GFP_KERNEL);
|
||||
if (!items || !seqnos) {
|
||||
ret = -ENOMEM;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
cnt = sunrpc_cache_requests_snapshot(cd, items, seqnos, cnt,
|
||||
cb->args[0]);
|
||||
if (!cnt) {
|
||||
ret = 0;
|
||||
goto out_alloc;
|
||||
}
|
||||
|
||||
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
|
||||
cb->nlh->nlmsg_seq, &sunrpc_nl_family,
|
||||
NLM_F_MULTI, SUNRPC_CMD_IP_MAP_GET_REQS);
|
||||
if (!hdr) {
|
||||
ret = -ENOBUFS;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
emitted = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
struct ip_map *im;
|
||||
struct nlattr *nest;
|
||||
char text_addr[40];
|
||||
|
||||
im = container_of(items[i], struct ip_map, h);
|
||||
|
||||
if (ipv6_addr_v4mapped(&im->m_addr))
|
||||
snprintf(text_addr, 20, "%pI4",
|
||||
&im->m_addr.s6_addr32[3]);
|
||||
else
|
||||
snprintf(text_addr, 40, "%pI6", &im->m_addr);
|
||||
|
||||
nest = nla_nest_start(skb, SUNRPC_A_IP_MAP_REQS_REQUESTS);
|
||||
if (!nest)
|
||||
break;
|
||||
|
||||
if (nla_put_u64_64bit(skb, SUNRPC_A_IP_MAP_SEQNO,
|
||||
seqnos[i], 0) ||
|
||||
nla_put_string(skb, SUNRPC_A_IP_MAP_CLASS,
|
||||
im->m_class) ||
|
||||
nla_put_string(skb, SUNRPC_A_IP_MAP_ADDR, text_addr)) {
|
||||
nla_nest_cancel(skb, nest);
|
||||
break;
|
||||
}
|
||||
|
||||
nla_nest_end(skb, nest);
|
||||
cb->args[0] = seqnos[i];
|
||||
emitted++;
|
||||
}
|
||||
|
||||
if (!emitted) {
|
||||
genlmsg_cancel(skb, hdr);
|
||||
ret = -EMSGSIZE;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
ret = skb->len;
|
||||
out_put:
|
||||
for (i = 0; i < cnt; i++)
|
||||
cache_put(items[i], cd);
|
||||
out_alloc:
|
||||
kfree(seqnos);
|
||||
kfree(items);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_parse_one_ip_map - parse one ip_map entry from netlink
|
||||
* @cd: cache_detail for the ip_map cache
|
||||
* @attr: nested attribute containing ip_map fields
|
||||
*
|
||||
* Parses one ip_map entry from a netlink message and updates the
|
||||
* cache. Mirrors the logic in ip_map_parse().
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
static int sunrpc_nl_parse_one_ip_map(struct cache_detail *cd,
|
||||
struct nlattr *attr)
|
||||
{
|
||||
struct nlattr *tb[SUNRPC_A_IP_MAP_EXPIRY + 1];
|
||||
union {
|
||||
struct sockaddr sa;
|
||||
struct sockaddr_in s4;
|
||||
struct sockaddr_in6 s6;
|
||||
} address;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct ip_map *ipmp;
|
||||
struct auth_domain *dom = NULL;
|
||||
struct unix_domain *udom = NULL;
|
||||
struct timespec64 boot;
|
||||
time64_t expiry;
|
||||
char class[8];
|
||||
int err;
|
||||
int len;
|
||||
|
||||
err = nla_parse_nested(tb, SUNRPC_A_IP_MAP_EXPIRY, attr,
|
||||
sunrpc_ip_map_nl_policy, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* class (required) */
|
||||
if (!tb[SUNRPC_A_IP_MAP_CLASS])
|
||||
return -EINVAL;
|
||||
len = nla_len(tb[SUNRPC_A_IP_MAP_CLASS]);
|
||||
if (len <= 0 || len > sizeof(class))
|
||||
return -EINVAL;
|
||||
nla_strscpy(class, tb[SUNRPC_A_IP_MAP_CLASS], sizeof(class));
|
||||
|
||||
/* addr (required) */
|
||||
if (!tb[SUNRPC_A_IP_MAP_ADDR])
|
||||
return -EINVAL;
|
||||
if (rpc_pton(cd->net, nla_data(tb[SUNRPC_A_IP_MAP_ADDR]),
|
||||
nla_len(tb[SUNRPC_A_IP_MAP_ADDR]) - 1,
|
||||
&address.sa, sizeof(address)) == 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (address.sa.sa_family) {
|
||||
case AF_INET:
|
||||
sin6.sin6_family = AF_INET6;
|
||||
ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr,
|
||||
&sin6.sin6_addr);
|
||||
break;
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
case AF_INET6:
|
||||
memcpy(&sin6, &address.s6, sizeof(sin6));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* expiry (required, wallclock seconds) */
|
||||
if (!tb[SUNRPC_A_IP_MAP_EXPIRY])
|
||||
return -EINVAL;
|
||||
getboottime64(&boot);
|
||||
expiry = nla_get_u64(tb[SUNRPC_A_IP_MAP_EXPIRY]) - boot.tv_sec;
|
||||
|
||||
/* domain name or negative */
|
||||
if (tb[SUNRPC_A_IP_MAP_NEGATIVE]) {
|
||||
udom = NULL;
|
||||
} else if (tb[SUNRPC_A_IP_MAP_DOMAIN]) {
|
||||
dom = unix_domain_find(nla_data(tb[SUNRPC_A_IP_MAP_DOMAIN]));
|
||||
if (!dom)
|
||||
return -ENOENT;
|
||||
udom = container_of(dom, struct unix_domain, h);
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ipmp = __ip_map_lookup(cd, class, &sin6.sin6_addr);
|
||||
if (ipmp)
|
||||
err = __ip_map_update(cd, ipmp, udom, expiry);
|
||||
else
|
||||
err = -ENOMEM;
|
||||
|
||||
if (dom)
|
||||
auth_domain_put(dom);
|
||||
|
||||
cache_flush();
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* sunrpc_nl_ip_map_set_reqs_doit - respond to ip_map requests
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Parse one or more ip_map cache responses from userspace and
|
||||
* update the ip_map cache accordingly.
|
||||
*
|
||||
* Returns 0 on success or a negative errno.
|
||||
*/
|
||||
int sunrpc_nl_ip_map_set_reqs_doit(struct sk_buff *skb,
|
||||
struct genl_info *info)
|
||||
{
|
||||
struct sunrpc_net *sn;
|
||||
struct cache_detail *cd;
|
||||
const struct nlattr *attr;
|
||||
int rem, ret = 0;
|
||||
|
||||
sn = net_generic(genl_info_net(info), sunrpc_net_id);
|
||||
|
||||
cd = sn->ip_map_cache;
|
||||
if (!cd)
|
||||
return -ENODEV;
|
||||
|
||||
nlmsg_for_each_attr_type(attr, SUNRPC_A_IP_MAP_REQS_REQUESTS,
|
||||
info->nlhdr, GENL_HDRLEN, rem) {
|
||||
ret = sunrpc_nl_parse_one_ip_map(cd,
|
||||
(struct nlattr *)attr);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct cache_detail ip_map_cache_template = {
|
||||
.owner = THIS_MODULE,
|
||||
.hash_size = IP_HASHMAX,
|
||||
.name = "auth.unix.ip",
|
||||
.cache_put = ip_map_put,
|
||||
.cache_upcall = ip_map_upcall,
|
||||
.cache_notify = ip_map_notify,
|
||||
.cache_request = ip_map_request,
|
||||
.cache_parse = ip_map_parse,
|
||||
.cache_show = ip_map_show,
|
||||
|
||||
@@ -471,6 +471,7 @@ static void svc_tcp_handshake_done(void *data, int status, key_serial_t peerid)
|
||||
}
|
||||
clear_bit(XPT_HANDSHAKE, &xprt->xpt_flags);
|
||||
complete_all(&svsk->sk_handshake_done);
|
||||
svc_xprt_put(xprt);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -494,9 +495,13 @@ static void svc_tcp_handshake(struct svc_xprt *xprt)
|
||||
clear_bit(XPT_TLS_SESSION, &xprt->xpt_flags);
|
||||
init_completion(&svsk->sk_handshake_done);
|
||||
|
||||
/* Pin the transport across the asynchronous handshake callback. */
|
||||
svc_xprt_get(xprt);
|
||||
|
||||
ret = tls_server_hello_x509(&args, GFP_KERNEL);
|
||||
if (ret) {
|
||||
trace_svc_tls_not_started(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
goto out_failed;
|
||||
}
|
||||
|
||||
@@ -505,8 +510,13 @@ static void svc_tcp_handshake(struct svc_xprt *xprt)
|
||||
if (ret <= 0) {
|
||||
if (tls_handshake_cancel(sk)) {
|
||||
trace_svc_tls_timed_out(xprt);
|
||||
svc_xprt_put(xprt);
|
||||
goto out_close;
|
||||
}
|
||||
/* Cancellation lost to handshake_complete(): the
|
||||
* callback is in flight and should finish quickly.
|
||||
*/
|
||||
wait_for_completion(&svsk->sk_handshake_done);
|
||||
}
|
||||
|
||||
if (!test_bit(XPT_TLS_SESSION, &xprt->xpt_flags)) {
|
||||
@@ -732,7 +742,7 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
|
||||
.msg_flags = MSG_SPLICE_PAGES,
|
||||
.msg_controllen = sizeof(buffer),
|
||||
};
|
||||
unsigned int count;
|
||||
int count;
|
||||
int err;
|
||||
|
||||
svc_udp_release_ctxt(xprt, rqstp->rq_xprt_ctxt);
|
||||
@@ -746,6 +756,10 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
|
||||
goto out_notconn;
|
||||
|
||||
count = xdr_buf_to_bvec(svsk->sk_bvec, SUNRPC_MAX_UDP_SENDPAGES, xdr);
|
||||
if (count < 0) {
|
||||
err = count;
|
||||
goto out_trace;
|
||||
}
|
||||
|
||||
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
|
||||
count, rqstp->rq_res.len);
|
||||
@@ -757,6 +771,7 @@ static int svc_udp_sendto(struct svc_rqst *rqstp)
|
||||
err = sock_sendmsg(svsk->sk_sock, &msg);
|
||||
}
|
||||
|
||||
out_trace:
|
||||
trace_svcsock_udp_send(xprt, err);
|
||||
|
||||
mutex_unlock(&xprt->xpt_mutex);
|
||||
@@ -1237,7 +1252,7 @@ static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp,
|
||||
struct msghdr msg = {
|
||||
.msg_flags = MSG_SPLICE_PAGES,
|
||||
};
|
||||
unsigned int count;
|
||||
int count;
|
||||
void *buf;
|
||||
int ret;
|
||||
|
||||
@@ -1253,10 +1268,15 @@ static int svc_tcp_sendmsg(struct svc_sock *svsk, struct svc_rqst *rqstp,
|
||||
|
||||
count = xdr_buf_to_bvec(svsk->sk_bvec + 1, rqstp->rq_maxpages,
|
||||
&rqstp->rq_res);
|
||||
if (count < 0) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
iov_iter_bvec(&msg.msg_iter, ITER_SOURCE, svsk->sk_bvec,
|
||||
1 + count, sizeof(marker) + rqstp->rq_res.len);
|
||||
ret = sock_sendmsg(svsk->sk_sock, &msg);
|
||||
out:
|
||||
page_frag_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
289
net/sunrpc/xdr.c
289
net/sunrpc/xdr.c
@@ -139,19 +139,22 @@ xdr_free_bvec(struct xdr_buf *buf)
|
||||
/**
|
||||
* xdr_buf_to_bvec - Copy components of an xdr_buf into a bio_vec array
|
||||
* @bvec: bio_vec array to populate
|
||||
* @bvec_size: element count of @bio_vec
|
||||
* @bvec_size: element count of @bvec
|
||||
* @xdr: xdr_buf to be copied
|
||||
*
|
||||
* Returns the number of entries consumed in @bvec.
|
||||
* Returns the number of entries consumed in @bvec on success, or
|
||||
* -ESERVERFAULT when @xdr does not fit within @bvec_size entries.
|
||||
*/
|
||||
unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
|
||||
const struct xdr_buf *xdr)
|
||||
int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
|
||||
const struct xdr_buf *xdr)
|
||||
{
|
||||
const struct kvec *head = xdr->head;
|
||||
const struct kvec *tail = xdr->tail;
|
||||
unsigned int count = 0;
|
||||
|
||||
if (head->iov_len) {
|
||||
if (unlikely(count >= bvec_size))
|
||||
goto bvec_overflow;
|
||||
bvec_set_virt(bvec++, head->iov_base, head->iov_len);
|
||||
++count;
|
||||
}
|
||||
@@ -165,28 +168,229 @@ unsigned int xdr_buf_to_bvec(struct bio_vec *bvec, unsigned int bvec_size,
|
||||
while (remaining > 0) {
|
||||
len = min_t(unsigned int, remaining,
|
||||
PAGE_SIZE - offset);
|
||||
if (unlikely(count >= bvec_size))
|
||||
goto bvec_overflow;
|
||||
bvec_set_page(bvec++, *pages++, len, offset);
|
||||
remaining -= len;
|
||||
offset = 0;
|
||||
if (unlikely(++count > bvec_size))
|
||||
goto bvec_overflow;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
if (tail->iov_len) {
|
||||
bvec_set_virt(bvec, tail->iov_base, tail->iov_len);
|
||||
if (unlikely(++count > bvec_size))
|
||||
if (unlikely(count >= bvec_size))
|
||||
goto bvec_overflow;
|
||||
bvec_set_virt(bvec, tail->iov_base, tail->iov_len);
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
||||
bvec_overflow:
|
||||
pr_warn_once("%s: bio_vec array overflow\n", __func__);
|
||||
return count - 1;
|
||||
return -ESERVERFAULT;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_buf_to_bvec);
|
||||
|
||||
/**
|
||||
* xdr_buf_to_sg - Populate a scatterlist from an xdr_buf range
|
||||
* @buf: xdr_buf to map
|
||||
* @offset: starting byte offset within @buf
|
||||
* @len: number of bytes to cover
|
||||
* @sg: scatterlist array initialized with sg_init_table()
|
||||
* @nsg: number of entries available in @sg
|
||||
*
|
||||
* @sg is traversed with sg_next(), so callers may pass a list
|
||||
* assembled with sg_chain().
|
||||
*
|
||||
* Return: on success, the number of scatterlist entries used; the
|
||||
* last used entry is marked with sg_mark_end(). On failure, a
|
||||
* negative errno.
|
||||
*/
|
||||
int xdr_buf_to_sg(const struct xdr_buf *buf, unsigned int offset,
|
||||
unsigned int len, struct scatterlist *sg, unsigned int nsg)
|
||||
{
|
||||
unsigned int page_len, thislen, page_offset;
|
||||
struct scatterlist *cur = sg, *prev = NULL;
|
||||
int nents = 0;
|
||||
int i;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if (offset >= buf->head[0].iov_len) {
|
||||
offset -= buf->head[0].iov_len;
|
||||
} else {
|
||||
thislen = min_t(unsigned int,
|
||||
buf->head[0].iov_len - offset, len);
|
||||
if (nents >= nsg)
|
||||
return -ENOSPC;
|
||||
sg_set_buf(cur, buf->head[0].iov_base + offset,
|
||||
thislen);
|
||||
prev = cur;
|
||||
cur = sg_next(cur);
|
||||
nents++;
|
||||
len -= thislen;
|
||||
offset = 0;
|
||||
}
|
||||
if (len == 0)
|
||||
goto done;
|
||||
|
||||
if (offset >= buf->page_len) {
|
||||
offset -= buf->page_len;
|
||||
} else {
|
||||
page_len = min(buf->page_len - offset, len);
|
||||
len -= page_len;
|
||||
page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
|
||||
i = (offset + buf->page_base) >> PAGE_SHIFT;
|
||||
thislen = PAGE_SIZE - page_offset;
|
||||
do {
|
||||
if (thislen > page_len)
|
||||
thislen = page_len;
|
||||
if (nents >= nsg)
|
||||
return -ENOSPC;
|
||||
sg_set_page(cur, buf->pages[i],
|
||||
thislen, page_offset);
|
||||
prev = cur;
|
||||
cur = sg_next(cur);
|
||||
nents++;
|
||||
page_len -= thislen;
|
||||
i++;
|
||||
page_offset = 0;
|
||||
thislen = PAGE_SIZE;
|
||||
} while (page_len != 0);
|
||||
offset = 0;
|
||||
}
|
||||
if (len == 0)
|
||||
goto done;
|
||||
|
||||
if (offset < buf->tail[0].iov_len) {
|
||||
thislen = min_t(unsigned int,
|
||||
buf->tail[0].iov_len - offset, len);
|
||||
if (nents >= nsg)
|
||||
return -ENOSPC;
|
||||
sg_set_buf(cur, buf->tail[0].iov_base + offset,
|
||||
thislen);
|
||||
prev = cur;
|
||||
nents++;
|
||||
len -= thislen;
|
||||
}
|
||||
if (len != 0)
|
||||
return -EINVAL;
|
||||
|
||||
done:
|
||||
if (prev)
|
||||
sg_mark_end(prev);
|
||||
return nents;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_buf_to_sg);
|
||||
|
||||
/*
|
||||
* Count the scatterlist entries needed to cover [offset, offset + len)
|
||||
* within @buf. Mirrors the walk in xdr_buf_to_sg() so the caller can
|
||||
* size an allocation that matches the requested sub-range rather than
|
||||
* the full xdr_buf.
|
||||
*/
|
||||
static unsigned int xdr_buf_sg_nents(const struct xdr_buf *buf,
|
||||
unsigned int offset, unsigned int len)
|
||||
{
|
||||
unsigned int nsg = 0, thislen, page_offset;
|
||||
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if (offset < buf->head[0].iov_len) {
|
||||
thislen = min_t(unsigned int,
|
||||
buf->head[0].iov_len - offset, len);
|
||||
nsg++;
|
||||
len -= thislen;
|
||||
offset = 0;
|
||||
} else {
|
||||
offset -= buf->head[0].iov_len;
|
||||
}
|
||||
if (len == 0)
|
||||
return nsg;
|
||||
|
||||
if (offset < buf->page_len) {
|
||||
thislen = min(buf->page_len - offset, len);
|
||||
page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
|
||||
nsg += DIV_ROUND_UP(page_offset + thislen, PAGE_SIZE);
|
||||
len -= thislen;
|
||||
offset = 0;
|
||||
} else {
|
||||
offset -= buf->page_len;
|
||||
}
|
||||
if (len == 0)
|
||||
return nsg;
|
||||
|
||||
if (offset < buf->tail[0].iov_len)
|
||||
nsg++;
|
||||
return nsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* xdr_buf_to_sg_alloc - Populate a scatterlist for an xdr_buf range
|
||||
* @buf: xdr_buf to map
|
||||
* @offset: starting byte offset within @buf
|
||||
* @len: number of bytes to cover
|
||||
* @sg_head: caller-provided scatterlist array (typically stack-allocated)
|
||||
* @sg_head_nents: number of entries in @sg_head
|
||||
* @sg_overflow: OUT: chained extension, or NULL when @sg_head sufficed
|
||||
* @gfp: memory allocation flags for overflow
|
||||
*
|
||||
* Populates @sg_head directly when the xdr_buf fits. When more
|
||||
* entries are needed, an overflow scatterlist is allocated and
|
||||
* chained from @sg_head so that the result is traversable with
|
||||
* sg_next().
|
||||
*
|
||||
* Return: on success, the number of populated scatterlist entries
|
||||
* (counting only data entries, not chain entries). @sg_head is
|
||||
* the head of the resulting list. Caller must kfree @sg_overflow
|
||||
* when done. On failure, a negative errno.
|
||||
*/
|
||||
int xdr_buf_to_sg_alloc(const struct xdr_buf *buf, unsigned int offset,
|
||||
unsigned int len, struct scatterlist *sg_head,
|
||||
unsigned int sg_head_nents,
|
||||
struct scatterlist **sg_overflow, gfp_t gfp)
|
||||
{
|
||||
unsigned int nsg;
|
||||
int ret;
|
||||
|
||||
*sg_overflow = NULL;
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
nsg = xdr_buf_sg_nents(buf, offset, len);
|
||||
if (nsg == 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (nsg <= sg_head_nents) {
|
||||
sg_init_table(sg_head, nsg);
|
||||
} else {
|
||||
/* +1 replaces the slot sg_chain() consumes as the link. */
|
||||
unsigned int overflow_nents = nsg - sg_head_nents + 1;
|
||||
struct scatterlist *overflow;
|
||||
|
||||
overflow = kmalloc_array(overflow_nents, sizeof(*overflow),
|
||||
gfp);
|
||||
if (!overflow)
|
||||
return -ENOMEM;
|
||||
|
||||
sg_init_table(sg_head, sg_head_nents);
|
||||
sg_init_table(overflow, overflow_nents);
|
||||
sg_chain(sg_head, sg_head_nents, overflow);
|
||||
*sg_overflow = overflow;
|
||||
}
|
||||
|
||||
ret = xdr_buf_to_sg(buf, offset, len, sg_head, nsg);
|
||||
if (ret < 0) {
|
||||
kfree(*sg_overflow);
|
||||
*sg_overflow = NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_buf_to_sg_alloc);
|
||||
|
||||
/**
|
||||
* xdr_inline_pages - Prepare receive buffer for a large reply
|
||||
* @xdr: xdr_buf into which reply will be placed
|
||||
@@ -2149,73 +2353,6 @@ int xdr_encode_array2(const struct xdr_buf *buf, unsigned int base,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_encode_array2);
|
||||
|
||||
int xdr_process_buf(const struct xdr_buf *buf, unsigned int offset,
|
||||
unsigned int len,
|
||||
int (*actor)(struct scatterlist *, void *), void *data)
|
||||
{
|
||||
int i, ret = 0;
|
||||
unsigned int page_len, thislen, page_offset;
|
||||
struct scatterlist sg[1];
|
||||
|
||||
sg_init_table(sg, 1);
|
||||
|
||||
if (offset >= buf->head[0].iov_len) {
|
||||
offset -= buf->head[0].iov_len;
|
||||
} else {
|
||||
thislen = buf->head[0].iov_len - offset;
|
||||
if (thislen > len)
|
||||
thislen = len;
|
||||
sg_set_buf(sg, buf->head[0].iov_base + offset, thislen);
|
||||
ret = actor(sg, data);
|
||||
if (ret)
|
||||
goto out;
|
||||
offset = 0;
|
||||
len -= thislen;
|
||||
}
|
||||
if (len == 0)
|
||||
goto out;
|
||||
|
||||
if (offset >= buf->page_len) {
|
||||
offset -= buf->page_len;
|
||||
} else {
|
||||
page_len = buf->page_len - offset;
|
||||
if (page_len > len)
|
||||
page_len = len;
|
||||
len -= page_len;
|
||||
page_offset = (offset + buf->page_base) & (PAGE_SIZE - 1);
|
||||
i = (offset + buf->page_base) >> PAGE_SHIFT;
|
||||
thislen = PAGE_SIZE - page_offset;
|
||||
do {
|
||||
if (thislen > page_len)
|
||||
thislen = page_len;
|
||||
sg_set_page(sg, buf->pages[i], thislen, page_offset);
|
||||
ret = actor(sg, data);
|
||||
if (ret)
|
||||
goto out;
|
||||
page_len -= thislen;
|
||||
i++;
|
||||
page_offset = 0;
|
||||
thislen = PAGE_SIZE;
|
||||
} while (page_len != 0);
|
||||
offset = 0;
|
||||
}
|
||||
if (len == 0)
|
||||
goto out;
|
||||
if (offset < buf->tail[0].iov_len) {
|
||||
thislen = buf->tail[0].iov_len - offset;
|
||||
if (thislen > len)
|
||||
thislen = len;
|
||||
sg_set_buf(sg, buf->tail[0].iov_base + offset, thislen);
|
||||
ret = actor(sg, data);
|
||||
len -= thislen;
|
||||
}
|
||||
if (len != 0)
|
||||
ret = -EINVAL;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_process_buf);
|
||||
|
||||
/**
|
||||
* xdr_stream_decode_string_dup - Decode and duplicate variable length string
|
||||
* @xdr: pointer to xdr_stream
|
||||
|
||||
@@ -264,38 +264,22 @@ static int svc_rdma_proc_init(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct workqueue_struct *svcrdma_wq;
|
||||
|
||||
void svc_rdma_cleanup(void)
|
||||
{
|
||||
svc_unreg_xprt_class(&svc_rdma_class);
|
||||
svc_rdma_proc_cleanup();
|
||||
if (svcrdma_wq) {
|
||||
struct workqueue_struct *wq = svcrdma_wq;
|
||||
|
||||
svcrdma_wq = NULL;
|
||||
destroy_workqueue(wq);
|
||||
}
|
||||
|
||||
dprintk("SVCRDMA Module Removed, deregister RPC RDMA transport\n");
|
||||
}
|
||||
|
||||
int svc_rdma_init(void)
|
||||
{
|
||||
struct workqueue_struct *wq;
|
||||
int rc;
|
||||
|
||||
wq = alloc_workqueue("svcrdma", WQ_UNBOUND, 0);
|
||||
if (!wq)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = svc_rdma_proc_init();
|
||||
if (rc) {
|
||||
destroy_workqueue(wq);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
svcrdma_wq = wq;
|
||||
svc_reg_xprt_class(&svc_rdma_class);
|
||||
|
||||
dprintk("SVCRDMA Module Init, register RPC RDMA transport\n");
|
||||
|
||||
@@ -242,6 +242,10 @@ void svc_rdma_recv_ctxt_put(struct svcxprt_rdma *rdma,
|
||||
* Ensure that the recv_ctxt is released whether or not a Reply
|
||||
* was sent. For example, the client could close the connection,
|
||||
* or svc_process could drop an RPC, before the Reply is sent.
|
||||
*
|
||||
* Also drain any send_ctxts queued for deferred release so that
|
||||
* DMA unmap and page release run in nfsd thread context between
|
||||
* RPCs rather than on the Send completion path.
|
||||
*/
|
||||
void svc_rdma_release_ctxt(struct svc_xprt *xprt, void *vctxt)
|
||||
{
|
||||
@@ -251,6 +255,8 @@ void svc_rdma_release_ctxt(struct svc_xprt *xprt, void *vctxt)
|
||||
|
||||
if (ctxt)
|
||||
svc_rdma_recv_ctxt_put(rdma, ctxt);
|
||||
|
||||
svc_rdma_send_ctxts_drain(rdma);
|
||||
}
|
||||
|
||||
static bool svc_rdma_refresh_recvs(struct svcxprt_rdma *rdma,
|
||||
@@ -377,13 +383,16 @@ static void svc_rdma_wc_receive(struct ib_cq *cq, struct ib_wc *wc)
|
||||
trace_svcrdma_wc_recv_err(wc, &ctxt->rc_cid);
|
||||
dropped:
|
||||
svc_rdma_recv_ctxt_put(rdma, ctxt);
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_rdma_flush_recv_queues - Drain pending Receive work
|
||||
* @rdma: svcxprt_rdma being shut down
|
||||
*
|
||||
* Caller must guarantee that @rdma's Send and Recv Completion
|
||||
* Queues are empty (e.g., via ib_drain_qp()), so that no completion
|
||||
* handlers can still produce work on the queues being drained.
|
||||
*/
|
||||
void svc_rdma_flush_recv_queues(struct svcxprt_rdma *rdma)
|
||||
{
|
||||
@@ -1001,7 +1010,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp)
|
||||
if (ret == -EINVAL)
|
||||
svc_rdma_send_error(rdma_xprt, ctxt, ret);
|
||||
svc_rdma_recv_ctxt_put(rdma_xprt, ctxt);
|
||||
svc_xprt_deferred_close(xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma_xprt);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -236,19 +236,10 @@ svc_rdma_write_info_alloc(struct svcxprt_rdma *rdma,
|
||||
return info;
|
||||
}
|
||||
|
||||
static void svc_rdma_write_info_free_async(struct work_struct *work)
|
||||
{
|
||||
struct svc_rdma_write_info *info;
|
||||
|
||||
info = container_of(work, struct svc_rdma_write_info, wi_work);
|
||||
svc_rdma_cc_release(info->wi_rdma, &info->wi_cc, DMA_TO_DEVICE);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
static void svc_rdma_write_info_free(struct svc_rdma_write_info *info)
|
||||
{
|
||||
INIT_WORK(&info->wi_work, svc_rdma_write_info_free_async);
|
||||
queue_work(svcrdma_wq, &info->wi_work);
|
||||
svc_rdma_cc_release(info->wi_rdma, &info->wi_cc, DMA_TO_DEVICE);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -313,7 +304,7 @@ static void svc_rdma_reply_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
trace_svcrdma_wc_reply_err(wc, &cc->cc_cid);
|
||||
}
|
||||
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -345,7 +336,7 @@ static void svc_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
* some of the outgoing RPC message. Signal the loss
|
||||
* to the client by closing the connection.
|
||||
*/
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -390,7 +381,7 @@ static void svc_rdma_wc_read_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
*/
|
||||
svc_rdma_cc_release(rdma, cc, DMA_FROM_DEVICE);
|
||||
svc_rdma_recv_ctxt_put(rdma, ctxt);
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -754,216 +745,6 @@ int svc_rdma_prepare_reply_chunk(struct svcxprt_rdma *rdma,
|
||||
return xdr->len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cap contiguous RDMA Read sink allocations at order-4.
|
||||
* Higher orders risk allocation failure under
|
||||
* __GFP_NORETRY, which would negate the benefit of the
|
||||
* contiguous fast path.
|
||||
*/
|
||||
#define SVC_RDMA_CONTIG_MAX_ORDER 4
|
||||
|
||||
/**
|
||||
* svc_rdma_alloc_read_pages - Allocate physically contiguous pages
|
||||
* @nr_pages: number of pages needed
|
||||
* @order: on success, set to the allocation order
|
||||
*
|
||||
* Attempts a higher-order allocation, falling back to smaller orders.
|
||||
* The returned pages are split immediately so each sub-page has its
|
||||
* own refcount and can be freed independently.
|
||||
*
|
||||
* Returns a pointer to the first page on success, or NULL if even
|
||||
* order-1 allocation fails.
|
||||
*/
|
||||
static struct page *
|
||||
svc_rdma_alloc_read_pages(unsigned int nr_pages, unsigned int *order)
|
||||
{
|
||||
unsigned int o;
|
||||
struct page *page;
|
||||
|
||||
o = min(get_order(nr_pages << PAGE_SHIFT),
|
||||
SVC_RDMA_CONTIG_MAX_ORDER);
|
||||
|
||||
while (o >= 1) {
|
||||
page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN,
|
||||
o);
|
||||
if (page) {
|
||||
split_page(page, o);
|
||||
*order = o;
|
||||
return page;
|
||||
}
|
||||
o--;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* svc_rdma_fill_contig_bvec - Replace rq_pages with a contiguous allocation
|
||||
* @rqstp: RPC transaction context
|
||||
* @head: context for ongoing I/O
|
||||
* @bv: bvec entry to fill
|
||||
* @pages_left: number of data pages remaining in the segment
|
||||
* @len_left: bytes remaining in the segment
|
||||
*
|
||||
* On success, fills @bv with a bvec spanning the contiguous range and
|
||||
* advances rc_curpage/rc_page_count. Returns the byte length covered,
|
||||
* or zero if the allocation failed or would overrun rq_maxpages.
|
||||
*/
|
||||
static unsigned int
|
||||
svc_rdma_fill_contig_bvec(struct svc_rqst *rqstp,
|
||||
struct svc_rdma_recv_ctxt *head,
|
||||
struct bio_vec *bv, unsigned int pages_left,
|
||||
unsigned int len_left)
|
||||
{
|
||||
unsigned int order, npages, chunk_pages, chunk_len, i;
|
||||
struct page *page;
|
||||
|
||||
page = svc_rdma_alloc_read_pages(pages_left, &order);
|
||||
if (!page)
|
||||
return 0;
|
||||
npages = 1 << order;
|
||||
|
||||
if (head->rc_curpage + npages > rqstp->rq_maxpages) {
|
||||
for (i = 0; i < npages; i++)
|
||||
__free_page(page + i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace rq_pages[] entries with pages from the contiguous
|
||||
* allocation. If npages exceeds chunk_pages, the extra pages
|
||||
* stay in rq_pages[] for later reuse or normal rqst teardown.
|
||||
*/
|
||||
for (i = 0; i < npages; i++) {
|
||||
svc_rqst_page_release(rqstp,
|
||||
rqstp->rq_pages[head->rc_curpage + i]);
|
||||
rqstp->rq_pages[head->rc_curpage + i] = page + i;
|
||||
}
|
||||
|
||||
chunk_pages = min(npages, pages_left);
|
||||
chunk_len = min_t(unsigned int, chunk_pages << PAGE_SHIFT, len_left);
|
||||
bvec_set_page(bv, page, chunk_len, 0);
|
||||
head->rc_page_count += chunk_pages;
|
||||
head->rc_curpage += chunk_pages;
|
||||
return chunk_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* svc_rdma_fill_page_bvec - Add a single rq_page to the bvec array
|
||||
* @head: context for ongoing I/O
|
||||
* @ctxt: R/W context whose bvec array is being filled
|
||||
* @cur: page to add
|
||||
* @bvec_idx: pointer to current bvec index, not advanced on merge
|
||||
* @len_left: bytes remaining in the segment
|
||||
*
|
||||
* If @cur is physically contiguous with the preceding bvec, it is
|
||||
* merged by extending that bvec's length. Otherwise a new bvec
|
||||
* entry is created. Returns the byte length covered.
|
||||
*/
|
||||
static unsigned int
|
||||
svc_rdma_fill_page_bvec(struct svc_rdma_recv_ctxt *head,
|
||||
struct svc_rdma_rw_ctxt *ctxt, struct page *cur,
|
||||
unsigned int *bvec_idx, unsigned int len_left)
|
||||
{
|
||||
unsigned int chunk_len = min_t(unsigned int, PAGE_SIZE, len_left);
|
||||
|
||||
head->rc_page_count++;
|
||||
head->rc_curpage++;
|
||||
|
||||
if (*bvec_idx > 0) {
|
||||
struct bio_vec *prev = &ctxt->rw_bvec[*bvec_idx - 1];
|
||||
|
||||
if (page_to_phys(prev->bv_page) + prev->bv_offset +
|
||||
prev->bv_len == page_to_phys(cur)) {
|
||||
prev->bv_len += chunk_len;
|
||||
return chunk_len;
|
||||
}
|
||||
}
|
||||
|
||||
bvec_set_page(&ctxt->rw_bvec[*bvec_idx], cur, chunk_len, 0);
|
||||
(*bvec_idx)++;
|
||||
return chunk_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_rdma_build_read_segment_contig - Build RDMA Read WR with contiguous pages
|
||||
* @rqstp: RPC transaction context
|
||||
* @head: context for ongoing I/O
|
||||
* @segment: co-ordinates of remote memory to be read
|
||||
*
|
||||
* Greedily allocates higher-order pages to cover the segment,
|
||||
* building one bvec per contiguous chunk. Each allocation is
|
||||
* split so sub-pages have independent refcounts. When a
|
||||
* higher-order allocation fails, remaining pages are covered
|
||||
* individually, merging adjacent pages into the preceding bvec
|
||||
* when they are physically contiguous. The split sub-pages
|
||||
* replace entries in rq_pages[] so downstream cleanup is
|
||||
* unchanged.
|
||||
*
|
||||
* Returns:
|
||||
* %0: the Read WR was constructed successfully
|
||||
* %-ENOMEM: allocation failed
|
||||
* %-EIO: a DMA mapping error occurred
|
||||
*/
|
||||
static int svc_rdma_build_read_segment_contig(struct svc_rqst *rqstp,
|
||||
struct svc_rdma_recv_ctxt *head,
|
||||
const struct svc_rdma_segment *segment)
|
||||
{
|
||||
struct svcxprt_rdma *rdma = svc_rdma_rqst_rdma(rqstp);
|
||||
struct svc_rdma_chunk_ctxt *cc = &head->rc_cc;
|
||||
unsigned int nr_data_pages, bvec_idx;
|
||||
struct svc_rdma_rw_ctxt *ctxt;
|
||||
unsigned int len_left;
|
||||
int ret;
|
||||
|
||||
nr_data_pages = PAGE_ALIGN(segment->rs_length) >> PAGE_SHIFT;
|
||||
if (head->rc_curpage + nr_data_pages > rqstp->rq_maxpages)
|
||||
return -ENOMEM;
|
||||
|
||||
ctxt = svc_rdma_get_rw_ctxt(rdma, nr_data_pages);
|
||||
if (!ctxt)
|
||||
return -ENOMEM;
|
||||
|
||||
bvec_idx = 0;
|
||||
len_left = segment->rs_length;
|
||||
while (len_left) {
|
||||
unsigned int pages_left = PAGE_ALIGN(len_left) >> PAGE_SHIFT;
|
||||
unsigned int chunk_len = 0;
|
||||
|
||||
if (pages_left >= 2)
|
||||
chunk_len = svc_rdma_fill_contig_bvec(rqstp, head,
|
||||
&ctxt->rw_bvec[bvec_idx],
|
||||
pages_left, len_left);
|
||||
if (chunk_len) {
|
||||
bvec_idx++;
|
||||
} else {
|
||||
struct page *cur =
|
||||
rqstp->rq_pages[head->rc_curpage];
|
||||
chunk_len = svc_rdma_fill_page_bvec(head, ctxt, cur,
|
||||
&bvec_idx,
|
||||
len_left);
|
||||
}
|
||||
|
||||
len_left -= chunk_len;
|
||||
}
|
||||
|
||||
ctxt->rw_nents = bvec_idx;
|
||||
|
||||
head->rc_pageoff = offset_in_page(segment->rs_length);
|
||||
if (head->rc_pageoff)
|
||||
head->rc_curpage--;
|
||||
|
||||
ret = svc_rdma_rw_ctx_init(rdma, ctxt, segment->rs_offset,
|
||||
segment->rs_handle, segment->rs_length,
|
||||
DMA_FROM_DEVICE);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
percpu_counter_inc(&svcrdma_stat_read);
|
||||
|
||||
list_add(&ctxt->rw_list, &cc->cc_rwctxts);
|
||||
cc->cc_sqecount += ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_rdma_build_read_segment - Build RDMA Read WQEs to pull one RDMA segment
|
||||
* @rqstp: RPC transaction context
|
||||
@@ -990,14 +771,6 @@ static int svc_rdma_build_read_segment(struct svc_rqst *rqstp,
|
||||
if (check_add_overflow(head->rc_pageoff, len, &total))
|
||||
return -EINVAL;
|
||||
nr_bvec = PAGE_ALIGN(total) >> PAGE_SHIFT;
|
||||
|
||||
if (head->rc_pageoff == 0 && nr_bvec >= 2) {
|
||||
ret = svc_rdma_build_read_segment_contig(rqstp, head,
|
||||
segment);
|
||||
if (ret != -ENOMEM)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctxt = svc_rdma_get_rw_ctxt(rdma, nr_bvec);
|
||||
if (!ctxt)
|
||||
return -ENOMEM;
|
||||
@@ -1343,11 +1116,6 @@ static void svc_rdma_clear_rqst_pages(struct svc_rqst *rqstp,
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
/*
|
||||
* Move only pages containing RPC data into rc_pages[]. Pages
|
||||
* from a contiguous allocation that were not used for the
|
||||
* payload remain in rq_pages[] for subsequent reuse.
|
||||
*/
|
||||
for (i = 0; i < head->rc_page_count; i++) {
|
||||
head->rc_pages[i] = rqstp->rq_pages[i];
|
||||
rqstp->rq_pages[i] = NULL;
|
||||
|
||||
@@ -79,21 +79,21 @@
|
||||
* The ownership of all of the Reply's pages are transferred into that
|
||||
* ctxt, the Send WR is posted, and sendto returns.
|
||||
*
|
||||
* The svc_rdma_send_ctxt is presented when the Send WR completes. The
|
||||
* Send completion handler finally releases the Reply's pages.
|
||||
*
|
||||
* This mechanism also assumes that completions on the transport's Send
|
||||
* Completion Queue do not run in parallel. Otherwise a Write completion
|
||||
* and Send completion running at the same time could release pages that
|
||||
* are still DMA-mapped.
|
||||
* The svc_rdma_send_ctxt is presented when the Send WR completes.
|
||||
* The Send completion handler queues the send_ctxt onto the
|
||||
* per-transport sc_send_release_list (a lock-free llist). The
|
||||
* nfsd thread drains sc_send_release_list in xpo_release_ctxt
|
||||
* between RPCs, DMA-unmapping SGEs, releasing chunk I/O
|
||||
* resources and pages, and returning send_ctxts to the free
|
||||
* list in a batch.
|
||||
*
|
||||
* Error Handling
|
||||
*
|
||||
* - If the Send WR is posted successfully, it will either complete
|
||||
* successfully, or get flushed. Either way, the Send completion
|
||||
* handler releases the Reply's pages.
|
||||
* - If the Send WR cannot be not posted, the forward path releases
|
||||
* the Reply's pages.
|
||||
* handler queues the send_ctxt for deferred release.
|
||||
* - If the Send WR cannot be posted, the forward path releases the
|
||||
* Reply's pages.
|
||||
*
|
||||
* This handles the case, without the use of page reference counting,
|
||||
* where two different Write segments send portions of the same page.
|
||||
@@ -226,14 +226,25 @@ struct svc_rdma_send_ctxt *svc_rdma_send_ctxt_get(struct svcxprt_rdma *rdma)
|
||||
return ctxt;
|
||||
|
||||
out_empty:
|
||||
svc_rdma_send_ctxts_drain(rdma);
|
||||
|
||||
spin_lock(&rdma->sc_send_lock);
|
||||
node = llist_del_first(&rdma->sc_send_ctxts);
|
||||
spin_unlock(&rdma->sc_send_lock);
|
||||
if (node) {
|
||||
ctxt = llist_entry(node, struct svc_rdma_send_ctxt, sc_node);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctxt = svc_rdma_send_ctxt_alloc(rdma);
|
||||
if (!ctxt)
|
||||
return NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static void svc_rdma_send_ctxt_release(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt)
|
||||
/* Release chunk I/O resources and DMA-unmap SGEs. */
|
||||
static void svc_rdma_send_ctxt_unmap(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt)
|
||||
{
|
||||
struct ib_device *device = rdma->sc_cm_id->device;
|
||||
unsigned int i;
|
||||
@@ -241,9 +252,6 @@ static void svc_rdma_send_ctxt_release(struct svcxprt_rdma *rdma,
|
||||
svc_rdma_write_chunk_release(rdma, ctxt);
|
||||
svc_rdma_reply_chunk_release(rdma, ctxt);
|
||||
|
||||
if (ctxt->sc_page_count)
|
||||
release_pages(ctxt->sc_pages, ctxt->sc_page_count);
|
||||
|
||||
/* The first SGE contains the transport header, which
|
||||
* remains mapped until @ctxt is destroyed.
|
||||
*/
|
||||
@@ -256,30 +264,56 @@ static void svc_rdma_send_ctxt_release(struct svcxprt_rdma *rdma,
|
||||
ctxt->sc_sges[i].length,
|
||||
DMA_TO_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Unmap, release pages, and return send_ctxt to the free list. */
|
||||
static void svc_rdma_send_ctxt_release(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt)
|
||||
{
|
||||
svc_rdma_send_ctxt_unmap(rdma, ctxt);
|
||||
|
||||
if (ctxt->sc_page_count)
|
||||
release_pages(ctxt->sc_pages, ctxt->sc_page_count);
|
||||
|
||||
llist_add(&ctxt->sc_node, &rdma->sc_send_ctxts);
|
||||
}
|
||||
|
||||
static void svc_rdma_send_ctxt_put_async(struct work_struct *work)
|
||||
/**
|
||||
* svc_rdma_send_ctxts_drain - Release completed send_ctxts
|
||||
* @rdma: controlling svcxprt_rdma
|
||||
*/
|
||||
void svc_rdma_send_ctxts_drain(struct svcxprt_rdma *rdma)
|
||||
{
|
||||
struct svc_rdma_send_ctxt *ctxt;
|
||||
struct svc_rdma_send_ctxt *ctxt, *next;
|
||||
struct llist_node *node;
|
||||
|
||||
ctxt = container_of(work, struct svc_rdma_send_ctxt, sc_work);
|
||||
svc_rdma_send_ctxt_release(ctxt->sc_rdma, ctxt);
|
||||
node = llist_del_all(&rdma->sc_send_release_list);
|
||||
llist_for_each_entry_safe(ctxt, next, node, sc_node)
|
||||
svc_rdma_send_ctxt_release(rdma, ctxt);
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_rdma_send_ctxt_put - Return send_ctxt to free list
|
||||
* svc_rdma_send_ctxt_put - Queue send_ctxt for deferred release
|
||||
* @rdma: controlling svcxprt_rdma
|
||||
* @ctxt: object to return to the free list
|
||||
* @ctxt: send_ctxt to queue for deferred release
|
||||
*
|
||||
* Pages left in sc_pages are DMA unmapped and released.
|
||||
* Queues @ctxt onto sc_send_release_list. DMA unmap and
|
||||
* page release run later in svc_rdma_send_ctxts_drain(),
|
||||
* typically from xpo_release_ctxt.
|
||||
*
|
||||
* On the empty-to-non-empty transition, set XPT_DATA and
|
||||
* enqueue the transport. Without this self-trigger, a Send
|
||||
* completion arriving after the last xpo_release_ctxt on an
|
||||
* idle connection would leave the send_ctxt's DMA mappings
|
||||
* and reply pages pinned until another drain occurred.
|
||||
*/
|
||||
void svc_rdma_send_ctxt_put(struct svcxprt_rdma *rdma,
|
||||
struct svc_rdma_send_ctxt *ctxt)
|
||||
{
|
||||
INIT_WORK(&ctxt->sc_work, svc_rdma_send_ctxt_put_async);
|
||||
queue_work(svcrdma_wq, &ctxt->sc_work);
|
||||
if (llist_add(&ctxt->sc_node, &rdma->sc_send_release_list)) {
|
||||
set_bit(XPT_DATA, &rdma->sc_xprt.xpt_flags);
|
||||
svc_xprt_enqueue(&rdma->sc_xprt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -367,6 +401,15 @@ int svc_rdma_sq_wait(struct svcxprt_rdma *rdma,
|
||||
atomic_inc(&rdma->sc_sq_ticket_tail);
|
||||
wake_up(&rdma->sc_sq_ticket_wait);
|
||||
trace_svcrdma_sq_retry(rdma, cid);
|
||||
|
||||
/*
|
||||
* While this thread sat on sc_send_wait or sc_sq_ticket_wait,
|
||||
* Send completions that tried to enqueue this transport for a
|
||||
* release-list drain were rejected: svc_rdma_has_wspace returns
|
||||
* 0 while either waitqueue is active, and svc_xprt_ready
|
||||
* rejects the enqueue. Drain the release list now.
|
||||
*/
|
||||
svc_rdma_send_ctxts_drain(rdma);
|
||||
return 0;
|
||||
|
||||
out_close:
|
||||
@@ -395,7 +438,7 @@ int svc_rdma_post_send_err(struct svcxprt_rdma *rdma,
|
||||
int sqecount, int ret)
|
||||
{
|
||||
trace_svcrdma_sq_post_err(rdma, cid, ret);
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
|
||||
/* If even one WR was posted, a Send completion will
|
||||
* return the reserved SQ slots.
|
||||
@@ -437,7 +480,7 @@ static void svc_rdma_wc_send(struct ib_cq *cq, struct ib_wc *wc)
|
||||
else
|
||||
trace_svcrdma_wc_send_flush(wc, &ctxt->sc_cid);
|
||||
svc_rdma_send_ctxt_put(rdma, ctxt);
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1158,7 +1201,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
||||
svc_rdma_send_ctxt_put(rdma, sctxt);
|
||||
drop_connection:
|
||||
trace_svcrdma_send_err(rqstp, ret);
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,10 +98,27 @@ struct svc_xprt_class svc_rdma_class = {
|
||||
.xcl_ident = XPRT_TRANSPORT_RDMA,
|
||||
};
|
||||
|
||||
/**
|
||||
* svc_rdma_xprt_deferred_close - Close an RDMA transport (deferred)
|
||||
* @rdma: transport to close
|
||||
*/
|
||||
void svc_rdma_xprt_deferred_close(struct svcxprt_rdma *rdma)
|
||||
{
|
||||
svc_xprt_deferred_close(&rdma->sc_xprt);
|
||||
|
||||
/* Release parked sc_sq_ticket_wait and sc_send_wait waiters.
|
||||
* Once XPT_CLOSE is observed each returns -ENOTCONN.
|
||||
*/
|
||||
wake_up_all(&rdma->sc_sq_ticket_wait);
|
||||
wake_up_all(&rdma->sc_send_wait);
|
||||
}
|
||||
|
||||
/* QP event handler */
|
||||
static void qp_event_handler(struct ib_event *event, void *context)
|
||||
{
|
||||
struct svc_xprt *xprt = context;
|
||||
struct svcxprt_rdma *rdma =
|
||||
container_of(xprt, struct svcxprt_rdma, sc_xprt);
|
||||
|
||||
trace_svcrdma_qp_error(event, (struct sockaddr *)&xprt->xpt_remote);
|
||||
switch (event->event) {
|
||||
@@ -119,7 +136,7 @@ static void qp_event_handler(struct ib_event *event, void *context)
|
||||
case IB_EVENT_QP_ACCESS_ERR:
|
||||
case IB_EVENT_DEVICE_FATAL:
|
||||
default:
|
||||
svc_xprt_deferred_close(xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -178,6 +195,7 @@ static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv,
|
||||
init_llist_head(&cma_xprt->sc_send_ctxts);
|
||||
init_llist_head(&cma_xprt->sc_recv_ctxts);
|
||||
init_llist_head(&cma_xprt->sc_rw_ctxts);
|
||||
init_llist_head(&cma_xprt->sc_send_release_list);
|
||||
init_waitqueue_head(&cma_xprt->sc_send_wait);
|
||||
init_waitqueue_head(&cma_xprt->sc_sq_ticket_wait);
|
||||
|
||||
@@ -340,7 +358,7 @@ static int svc_rdma_cma_handler(struct rdma_cm_id *cma_id,
|
||||
svc_xprt_enqueue(xprt);
|
||||
break;
|
||||
case RDMA_CM_EVENT_DISCONNECTED:
|
||||
svc_xprt_deferred_close(xprt);
|
||||
svc_rdma_xprt_deferred_close(rdma);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -597,6 +615,15 @@ static void svc_rdma_detach(struct svc_xprt *xprt)
|
||||
container_of(xprt, struct svcxprt_rdma, sc_xprt);
|
||||
|
||||
rdma_disconnect(rdma->sc_cm_id);
|
||||
|
||||
/*
|
||||
* Most close paths go through svc_rdma_xprt_deferred_close(),
|
||||
* which wakes the SQ waitqueues. svc_xprt_close() reaches
|
||||
* detach without that helper, so wake any threads parked in
|
||||
* svc_rdma_sq_wait() here as well.
|
||||
*/
|
||||
wake_up_all(&rdma->sc_sq_ticket_wait);
|
||||
wake_up_all(&rdma->sc_send_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -614,7 +641,7 @@ static void svc_rdma_free(struct svc_xprt *xprt)
|
||||
/* This blocks until the Completion Queues are empty */
|
||||
if (rdma->sc_qp && !IS_ERR(rdma->sc_qp))
|
||||
ib_drain_qp(rdma->sc_qp);
|
||||
flush_workqueue(svcrdma_wq);
|
||||
svc_rdma_send_ctxts_drain(rdma);
|
||||
|
||||
svc_rdma_flush_recv_queues(rdma);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user