mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
NFSD 6.15 Release Notes
Neil Brown contributed more scalability improvements to NFSD's open file cache, and Jeff Layton contributed a menagerie of repairs to NFSD's NFSv4 callback / backchannel implementation. Mike Snitzer contributed a change to NFS re-export support that disables support for file locking on a re-exported NFSv4 mount. This is because NFSv4 state recovery is currently difficult if not impossible for re-exported NFS mounts. The change aims to prevent data integrity exposures after the re-export server crashes. Work continues on the evolving NFSD netlink administrative API. Many thanks to the contributors, reviewers, testers, and bug reporters who participated during the v6.15 development cycle. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEKLLlsBKG3yQ88j7+M2qzM29mf5cFAmfmpMIACgkQM2qzM29m f5f6DA/+P0YqoRg3Zk/4oWwXZWbfEOMhWFltT+D1PE2QjUfOZpiwUSFQfsfYgXO6 OFu0iDQ4g8BxBeP6Umv61qy7Cv6n4fVzIHqzymXQvymh9JzoQiXlE9/fA8nAHuiH u7kkNPRi7faBz1sMg/WpN9CHctg7STPOhhG/JrZcSFZnh87mU1i4i4bZBNz8tVnK ZWf483OUuSmJY2/bUTkwvr4GbceTKBlLWFFjiRhfAKvJBWvu4myfC0DI5QzxmsgI MJ62do7AFJP1ww2Ih9LLi2kFIt/yyInSVAgyts1CPhlJ4BfPnTSOw/i2+CuF3D/M bZYEAOjH3AqjBZmq58sIQezpD5f9/TOrTSwYwS31zl/THYE413WiW80/MDoWqo0y 9cSNkD3nJlPVLLCfF58vXLoe7wpLoN/ZbTdxoozzUWEFR5A4Jz3XP8F/Cws0cjem uWWAQMItiQpg1+RYJYfu4dg5+iN6dbgYbvzlr7buISwFNXi3Zo99MkJ4wHj9TJbL Tpjth1rWGPwwSOMT6ojKiYMq1oUzx5PuAm9Saq9oIzQAbBySmxHF/LSDz3wEuBoO MK1jzKroEmMk3fJOOAajSDLOdAbL3vfj6H/xi2IHvKnaz9yHCZNu2YGV05BBMprd hWePf69AO5Ky5Q9KuGClEtwvJ9ZR5pb4DO2dqaYu8ximu3O4vPo= =e2E2 -----END PGP SIGNATURE----- Merge tag 'nfsd-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux Pull nfsd updates from Chuck Lever: "Neil Brown contributed more scalability improvements to NFSD's open file cache, and Jeff Layton contributed a menagerie of repairs to NFSD's NFSv4 callback / backchannel implementation. Mike Snitzer contributed a change to NFS re-export support that disables support for file locking on a re-exported NFSv4 mount. This is because NFSv4 state recovery is currently difficult if not impossible for re-exported NFS mounts. The change aims to prevent data integrity exposures after the re-export server crashes. Work continues on the evolving NFSD netlink administrative API. Many thanks to the contributors, reviewers, testers, and bug reporters who participated during the v6.15 development cycle" * tag 'nfsd-6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: (45 commits) NFSD: Add a Kconfig setting to enable delegated timestamps sysctl: Fixes nsm_local_state bounds nfsd: use a long for the count in nfsd4_state_shrinker_count() nfsd: remove obsolete comment from nfs4_alloc_stid nfsd: remove unneeded forward declaration of nfsd4_mark_cb_fault() nfsd: reorganize struct nfs4_delegation for better packing nfsd: handle errors from rpc_call_async() nfsd: move cb_need_restart flag into cb_flags nfsd: replace CB_GETATTR_BUSY with NFSD4_CALLBACK_RUNNING nfsd: eliminate cl_ra_cblist and NFSD4_CLIENT_CB_RECALL_ANY nfsd: prevent callback tasks running concurrently nfsd: disallow file locking and delegations for NFSv4 reexport nfsd: filecache: drop the list_lru lock during lock gc scans nfsd: filecache: don't repeatedly add/remove files on the lru list nfsd: filecache: introduce NFSD_FILE_RECENT nfsd: filecache: use list_lru_walk_node() in nfsd_file_gc() nfsd: filecache: use nfsd_file_dispose_list() in nfsd_file_close_inode_sync() NFSD: Re-organize nfsd_file_gc_worker() nfsd: filecache: remove race handling. fs: nfs: acl: Avoid -Wflex-array-member-not-at-end warning ...
This commit is contained in:
commit
b6dde1e527
@ -26,9 +26,13 @@ Reboot recovery
|
||||
---------------
|
||||
|
||||
The NFS protocol's normal reboot recovery mechanisms don't work for the
|
||||
case when the reexport server reboots. Clients will lose any locks
|
||||
they held before the reboot, and further IO will result in errors.
|
||||
Closing and reopening files should clear the errors.
|
||||
case when the reexport server reboots because the source server has not
|
||||
rebooted, and so it is not in grace. Since the source server is not in
|
||||
grace, it cannot offer any guarantees that the file won't have been
|
||||
changed between the locks getting lost and any attempt to recover them.
|
||||
The same applies to delegations and any associated locks. Clients are
|
||||
not allowed to get file locks or delegations from a reexport server, any
|
||||
attempts will fail with operation not supported.
|
||||
|
||||
Filehandle limits
|
||||
-----------------
|
||||
|
45
Documentation/netlink/specs/lockd.yaml
Normal file
45
Documentation/netlink/specs/lockd.yaml
Normal file
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
|
||||
name: lockd
|
||||
protocol: genetlink
|
||||
uapi-header: linux/lockd_netlink.h
|
||||
|
||||
doc: lockd configuration over generic netlink
|
||||
|
||||
attribute-sets:
|
||||
-
|
||||
name: server
|
||||
attributes:
|
||||
-
|
||||
name: gracetime
|
||||
type: u32
|
||||
-
|
||||
name: tcp-port
|
||||
type: u16
|
||||
-
|
||||
name: udp-port
|
||||
type: u16
|
||||
|
||||
operations:
|
||||
list:
|
||||
-
|
||||
name: server-set
|
||||
doc: set the lockd server parameters
|
||||
attribute-set: server
|
||||
flags: [ admin-perm ]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- gracetime
|
||||
- tcp-port
|
||||
- udp-port
|
||||
-
|
||||
name: server-get
|
||||
doc: get the lockd server parameters
|
||||
attribute-set: server
|
||||
do:
|
||||
reply:
|
||||
attributes:
|
||||
- gracetime
|
||||
- tcp-port
|
||||
- udp-port
|
@ -8,6 +8,6 @@ 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
|
||||
svcshare.o svcproc.o svcsubs.o mon.o trace.o xdr.o netlink.o
|
||||
lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
|
||||
lockd-$(CONFIG_PROC_FS) += procfs.o
|
||||
|
44
fs/lockd/netlink.c
Normal file
44
fs/lockd/netlink.c
Normal file
@ -0,0 +1,44 @@
|
||||
// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause)
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/lockd.yaml */
|
||||
/* YNL-GEN kernel source */
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include "netlink.h"
|
||||
|
||||
#include <uapi/linux/lockd_netlink.h>
|
||||
|
||||
/* LOCKD_CMD_SERVER_SET - do */
|
||||
static const struct nla_policy lockd_server_set_nl_policy[LOCKD_A_SERVER_UDP_PORT + 1] = {
|
||||
[LOCKD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
|
||||
[LOCKD_A_SERVER_TCP_PORT] = { .type = NLA_U16, },
|
||||
[LOCKD_A_SERVER_UDP_PORT] = { .type = NLA_U16, },
|
||||
};
|
||||
|
||||
/* Ops table for lockd */
|
||||
static const struct genl_split_ops lockd_nl_ops[] = {
|
||||
{
|
||||
.cmd = LOCKD_CMD_SERVER_SET,
|
||||
.doit = lockd_nl_server_set_doit,
|
||||
.policy = lockd_server_set_nl_policy,
|
||||
.maxattr = LOCKD_A_SERVER_UDP_PORT,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = LOCKD_CMD_SERVER_GET,
|
||||
.doit = lockd_nl_server_get_doit,
|
||||
.flags = GENL_CMD_CAP_DO,
|
||||
},
|
||||
};
|
||||
|
||||
struct genl_family lockd_nl_family __ro_after_init = {
|
||||
.name = LOCKD_FAMILY_NAME,
|
||||
.version = LOCKD_FAMILY_VERSION,
|
||||
.netnsok = true,
|
||||
.parallel_ops = true,
|
||||
.module = THIS_MODULE,
|
||||
.split_ops = lockd_nl_ops,
|
||||
.n_split_ops = ARRAY_SIZE(lockd_nl_ops),
|
||||
};
|
19
fs/lockd/netlink.h
Normal file
19
fs/lockd/netlink.h
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/lockd.yaml */
|
||||
/* YNL-GEN kernel header */
|
||||
|
||||
#ifndef _LINUX_LOCKD_GEN_H
|
||||
#define _LINUX_LOCKD_GEN_H
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#include <uapi/linux/lockd_netlink.h>
|
||||
|
||||
int lockd_nl_server_set_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int lockd_nl_server_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
|
||||
extern struct genl_family lockd_nl_family;
|
||||
|
||||
#endif /* _LINUX_LOCKD_GEN_H */
|
@ -10,6 +10,9 @@ struct lockd_net {
|
||||
unsigned int nlmsvc_users;
|
||||
unsigned long next_gc;
|
||||
unsigned long nrhosts;
|
||||
u32 gracetime;
|
||||
u16 tcp_port;
|
||||
u16 udp_port;
|
||||
|
||||
struct delayed_work grace_period_end;
|
||||
struct lock_manager lockd_manager;
|
||||
|
123
fs/lockd/svc.c
123
fs/lockd/svc.c
@ -41,6 +41,7 @@
|
||||
|
||||
#include "netns.h"
|
||||
#include "procfs.h"
|
||||
#include "netlink.h"
|
||||
|
||||
#define NLMDBG_FACILITY NLMDBG_SVC
|
||||
#define LOCKD_BUFSIZE (1024 + NLMSVC_XDRSIZE)
|
||||
@ -83,8 +84,14 @@ static const int nlm_port_min = 0, nlm_port_max = 65535;
|
||||
static struct ctl_table_header * nlm_sysctl_table;
|
||||
#endif
|
||||
|
||||
static unsigned long get_lockd_grace_period(void)
|
||||
static unsigned long get_lockd_grace_period(struct net *net)
|
||||
{
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
|
||||
/* Return the net-ns specific grace period, if there is one */
|
||||
if (ln->gracetime)
|
||||
return ln->gracetime * HZ;
|
||||
|
||||
/* Note: nlm_timeout should always be nonzero */
|
||||
if (nlm_grace_period)
|
||||
return roundup(nlm_grace_period, nlm_timeout) * HZ;
|
||||
@ -103,7 +110,7 @@ static void grace_ender(struct work_struct *grace)
|
||||
|
||||
static void set_grace_period(struct net *net)
|
||||
{
|
||||
unsigned long grace_period = get_lockd_grace_period();
|
||||
unsigned long grace_period = get_lockd_grace_period(net);
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
|
||||
locks_start_grace(net, &ln->lockd_manager);
|
||||
@ -166,15 +173,16 @@ static int create_lockd_listener(struct svc_serv *serv, const char *name,
|
||||
static int create_lockd_family(struct svc_serv *serv, struct net *net,
|
||||
const int family, const struct cred *cred)
|
||||
{
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
int err;
|
||||
|
||||
err = create_lockd_listener(serv, "udp", net, family, nlm_udpport,
|
||||
cred);
|
||||
err = create_lockd_listener(serv, "udp", net, family,
|
||||
ln->udp_port ? ln->udp_port : nlm_udpport, cred);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return create_lockd_listener(serv, "tcp", net, family, nlm_tcpport,
|
||||
cred);
|
||||
return create_lockd_listener(serv, "tcp", net, family,
|
||||
ln->tcp_port ? ln->tcp_port : nlm_tcpport, cred);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -459,9 +467,10 @@ static const struct ctl_table nlm_sysctls[] = {
|
||||
{
|
||||
.procname = "nsm_local_state",
|
||||
.data = &nsm_local_state,
|
||||
.maxlen = sizeof(int),
|
||||
.maxlen = sizeof(nsm_local_state),
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
.proc_handler = proc_douintvec,
|
||||
.extra1 = SYSCTL_ZERO,
|
||||
},
|
||||
};
|
||||
|
||||
@ -588,6 +597,10 @@ static int __init init_nlm(void)
|
||||
if (err)
|
||||
goto err_pernet;
|
||||
|
||||
err = genl_register_family(&lockd_nl_family);
|
||||
if (err)
|
||||
goto err_netlink;
|
||||
|
||||
err = lockd_create_procfs();
|
||||
if (err)
|
||||
goto err_procfs;
|
||||
@ -595,6 +608,8 @@ static int __init init_nlm(void)
|
||||
return 0;
|
||||
|
||||
err_procfs:
|
||||
genl_unregister_family(&lockd_nl_family);
|
||||
err_netlink:
|
||||
unregister_pernet_subsys(&lockd_net_ops);
|
||||
err_pernet:
|
||||
#ifdef CONFIG_SYSCTL
|
||||
@ -608,6 +623,7 @@ static void __exit exit_nlm(void)
|
||||
{
|
||||
/* FIXME: delete all NLM clients */
|
||||
nlm_shutdown_hosts();
|
||||
genl_unregister_family(&lockd_nl_family);
|
||||
lockd_remove_procfs();
|
||||
unregister_pernet_subsys(&lockd_net_ops);
|
||||
#ifdef CONFIG_SYSCTL
|
||||
@ -710,3 +726,94 @@ static struct svc_program nlmsvc_program = {
|
||||
.pg_init_request = svc_generic_init_request,
|
||||
.pg_rpcbind_set = svc_generic_rpcbind_set,
|
||||
};
|
||||
|
||||
/**
|
||||
* lockd_nl_server_set_doit - set the lockd server parameters via netlink
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* This updates the per-net values. When updating the values in the init_net
|
||||
* namespace, also update the "legacy" global values.
|
||||
*
|
||||
* Return 0 on success or a negative errno.
|
||||
*/
|
||||
int lockd_nl_server_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net *net = genl_info_net(info);
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
const struct nlattr *attr;
|
||||
|
||||
if (GENL_REQ_ATTR_CHECK(info, LOCKD_A_SERVER_GRACETIME))
|
||||
return -EINVAL;
|
||||
|
||||
if (info->attrs[LOCKD_A_SERVER_GRACETIME] ||
|
||||
info->attrs[LOCKD_A_SERVER_TCP_PORT] ||
|
||||
info->attrs[LOCKD_A_SERVER_UDP_PORT]) {
|
||||
attr = info->attrs[LOCKD_A_SERVER_GRACETIME];
|
||||
if (attr) {
|
||||
u32 gracetime = nla_get_u32(attr);
|
||||
|
||||
if (gracetime > nlm_grace_period_max)
|
||||
return -EINVAL;
|
||||
|
||||
ln->gracetime = gracetime;
|
||||
|
||||
if (net == &init_net)
|
||||
nlm_grace_period = gracetime;
|
||||
}
|
||||
|
||||
attr = info->attrs[LOCKD_A_SERVER_TCP_PORT];
|
||||
if (attr) {
|
||||
ln->tcp_port = nla_get_u16(attr);
|
||||
if (net == &init_net)
|
||||
nlm_tcpport = ln->tcp_port;
|
||||
}
|
||||
|
||||
attr = info->attrs[LOCKD_A_SERVER_UDP_PORT];
|
||||
if (attr) {
|
||||
ln->udp_port = nla_get_u16(attr);
|
||||
if (net == &init_net)
|
||||
nlm_udpport = ln->udp_port;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* lockd_nl_server_get_doit - get lockd server parameters via netlink
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Return 0 on success or a negative errno.
|
||||
*/
|
||||
int lockd_nl_server_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net *net = genl_info_net(info);
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
hdr = genlmsg_iput(skb, info);
|
||||
if (!hdr) {
|
||||
err = -EMSGSIZE;
|
||||
goto err_free_msg;
|
||||
}
|
||||
|
||||
err = nla_put_u32(skb, LOCKD_A_SERVER_GRACETIME, ln->gracetime) ||
|
||||
nla_put_u16(skb, LOCKD_A_SERVER_TCP_PORT, ln->tcp_port) ||
|
||||
nla_put_u16(skb, LOCKD_A_SERVER_UDP_PORT, ln->udp_port);
|
||||
if (err)
|
||||
goto err_free_msg;
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
|
||||
return genlmsg_reply(skb, info);
|
||||
err_free_msg:
|
||||
nlmsg_free(skb);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -154,5 +154,6 @@ const struct export_operations nfs_export_ops = {
|
||||
EXPORT_OP_CLOSE_BEFORE_UNLINK |
|
||||
EXPORT_OP_REMOTE_FS |
|
||||
EXPORT_OP_NOATOMIC_ATTR |
|
||||
EXPORT_OP_FLUSH_ON_CLOSE,
|
||||
EXPORT_OP_FLUSH_ON_CLOSE |
|
||||
EXPORT_OP_NOLOCKS,
|
||||
};
|
||||
|
@ -42,7 +42,7 @@ struct nfsacl_encode_desc {
|
||||
};
|
||||
|
||||
struct nfsacl_simple_acl {
|
||||
struct posix_acl acl;
|
||||
struct posix_acl_hdr acl;
|
||||
struct posix_acl_entry ace[4];
|
||||
};
|
||||
|
||||
@ -112,7 +112,8 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
|
||||
xdr_encode_word(buf, base, entries))
|
||||
return -EINVAL;
|
||||
if (encode_entries && acl && acl->a_count == 3) {
|
||||
struct posix_acl *acl2 = &aclbuf.acl;
|
||||
struct posix_acl *acl2 =
|
||||
container_of(&aclbuf.acl, struct posix_acl, hdr);
|
||||
|
||||
/* Avoid the use of posix_acl_alloc(). nfsacl_encode() is
|
||||
* invoked in contexts where a memory allocation failure is
|
||||
@ -177,7 +178,8 @@ bool nfs_stream_encode_acl(struct xdr_stream *xdr, struct inode *inode,
|
||||
return false;
|
||||
|
||||
if (encode_entries && acl && acl->a_count == 3) {
|
||||
struct posix_acl *acl2 = &aclbuf.acl;
|
||||
struct posix_acl *acl2 =
|
||||
container_of(&aclbuf.acl, struct posix_acl, hdr);
|
||||
|
||||
/* Avoid the use of posix_acl_alloc(). nfsacl_encode() is
|
||||
* invoked in contexts where a memory allocation failure is
|
||||
|
@ -172,6 +172,16 @@ config NFSD_LEGACY_CLIENT_TRACKING
|
||||
recoverydir, or spawn a process directly using a usermodehelper
|
||||
upcall.
|
||||
|
||||
These legacy client tracking methods have proven to be probelmatic
|
||||
These legacy client tracking methods have proven to be problematic
|
||||
and will be removed in the future. Say Y here if you need support
|
||||
for them in the interim.
|
||||
|
||||
config NFSD_V4_DELEG_TIMESTAMPS
|
||||
bool "Support delegated timestamps"
|
||||
depends on NFSD_V4
|
||||
default n
|
||||
help
|
||||
NFSD implements delegated timestamps according to
|
||||
draft-ietf-nfsv4-delstid-08 "Extending the Opening of Files". This
|
||||
is currently an experimental feature and is therefore left disabled
|
||||
by default.
|
||||
|
@ -319,15 +319,14 @@ nfsd_file_check_writeback(struct nfsd_file *nf)
|
||||
mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK);
|
||||
}
|
||||
|
||||
|
||||
static bool nfsd_file_lru_add(struct nfsd_file *nf)
|
||||
static void nfsd_file_lru_add(struct nfsd_file *nf)
|
||||
{
|
||||
set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
|
||||
if (list_lru_add_obj(&nfsd_file_lru, &nf->nf_lru)) {
|
||||
refcount_inc(&nf->nf_ref);
|
||||
if (list_lru_add_obj(&nfsd_file_lru, &nf->nf_lru))
|
||||
trace_nfsd_file_lru_add(nf);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
else
|
||||
WARN_ON(1);
|
||||
nfsd_file_schedule_laundrette();
|
||||
}
|
||||
|
||||
static bool nfsd_file_lru_remove(struct nfsd_file *nf)
|
||||
@ -363,30 +362,10 @@ nfsd_file_put(struct nfsd_file *nf)
|
||||
|
||||
if (test_bit(NFSD_FILE_GC, &nf->nf_flags) &&
|
||||
test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
|
||||
/*
|
||||
* If this is the last reference (nf_ref == 1), then try to
|
||||
* transfer it to the LRU.
|
||||
*/
|
||||
if (refcount_dec_not_one(&nf->nf_ref))
|
||||
return;
|
||||
|
||||
/* Try to add it to the LRU. If that fails, decrement. */
|
||||
if (nfsd_file_lru_add(nf)) {
|
||||
/* If it's still hashed, we're done */
|
||||
if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
|
||||
nfsd_file_schedule_laundrette();
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We're racing with unhashing, so try to remove it from
|
||||
* the LRU. If removal fails, then someone else already
|
||||
* has our reference.
|
||||
*/
|
||||
if (!nfsd_file_lru_remove(nf))
|
||||
return;
|
||||
}
|
||||
set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
|
||||
set_bit(NFSD_FILE_RECENT, &nf->nf_flags);
|
||||
}
|
||||
|
||||
if (refcount_dec_and_test(&nf->nf_ref))
|
||||
nfsd_file_free(nf);
|
||||
}
|
||||
@ -530,13 +509,12 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
|
||||
}
|
||||
|
||||
/*
|
||||
* Put the reference held on behalf of the LRU. If it wasn't the last
|
||||
* one, then just remove it from the LRU and ignore it.
|
||||
* Put the reference held on behalf of the LRU if it is the last
|
||||
* reference, else rotate.
|
||||
*/
|
||||
if (!refcount_dec_and_test(&nf->nf_ref)) {
|
||||
if (!refcount_dec_if_one(&nf->nf_ref)) {
|
||||
trace_nfsd_file_gc_in_use(nf);
|
||||
list_lru_isolate(lru, &nf->nf_lru);
|
||||
return LRU_REMOVED;
|
||||
return LRU_ROTATE;
|
||||
}
|
||||
|
||||
/* Refcount went to zero. Unhash it and queue it to the dispose list */
|
||||
@ -548,14 +526,54 @@ nfsd_file_lru_cb(struct list_head *item, struct list_lru_one *lru,
|
||||
return LRU_REMOVED;
|
||||
}
|
||||
|
||||
static enum lru_status
|
||||
nfsd_file_gc_cb(struct list_head *item, struct list_lru_one *lru,
|
||||
void *arg)
|
||||
{
|
||||
struct nfsd_file *nf = list_entry(item, struct nfsd_file, nf_lru);
|
||||
|
||||
if (test_and_clear_bit(NFSD_FILE_RECENT, &nf->nf_flags)) {
|
||||
/*
|
||||
* "REFERENCED" really means "should be at the end of the
|
||||
* LRU. As we are putting it there we can clear the flag.
|
||||
*/
|
||||
clear_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
|
||||
trace_nfsd_file_gc_aged(nf);
|
||||
return LRU_ROTATE;
|
||||
}
|
||||
return nfsd_file_lru_cb(item, lru, arg);
|
||||
}
|
||||
|
||||
/* If the shrinker runs between calls to list_lru_walk_node() in
|
||||
* nfsd_file_gc(), the "remaining" count will be wrong. This could
|
||||
* result in premature freeing of some files. This may not matter much
|
||||
* but is easy to fix with this spinlock which temporarily disables
|
||||
* the shrinker.
|
||||
*/
|
||||
static DEFINE_SPINLOCK(nfsd_gc_lock);
|
||||
static void
|
||||
nfsd_file_gc(void)
|
||||
{
|
||||
unsigned long ret = 0;
|
||||
LIST_HEAD(dispose);
|
||||
unsigned long ret;
|
||||
int nid;
|
||||
|
||||
ret = list_lru_walk(&nfsd_file_lru, nfsd_file_lru_cb,
|
||||
&dispose, list_lru_count(&nfsd_file_lru));
|
||||
spin_lock(&nfsd_gc_lock);
|
||||
for_each_node_state(nid, N_NORMAL_MEMORY) {
|
||||
unsigned long remaining = list_lru_count_node(&nfsd_file_lru, nid);
|
||||
|
||||
while (remaining > 0) {
|
||||
unsigned long nr = min(remaining, NFSD_FILE_GC_BATCH);
|
||||
|
||||
remaining -= nr;
|
||||
ret += list_lru_walk_node(&nfsd_file_lru, nid, nfsd_file_gc_cb,
|
||||
&dispose, &nr);
|
||||
if (nr)
|
||||
/* walk aborted early */
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
spin_unlock(&nfsd_gc_lock);
|
||||
trace_nfsd_file_gc_removed(ret, list_lru_count(&nfsd_file_lru));
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
}
|
||||
@ -563,9 +581,9 @@ nfsd_file_gc(void)
|
||||
static void
|
||||
nfsd_file_gc_worker(struct work_struct *work)
|
||||
{
|
||||
nfsd_file_gc();
|
||||
if (list_lru_count(&nfsd_file_lru))
|
||||
nfsd_file_schedule_laundrette();
|
||||
nfsd_file_gc();
|
||||
nfsd_file_schedule_laundrette();
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
@ -580,8 +598,12 @@ nfsd_file_lru_scan(struct shrinker *s, struct shrink_control *sc)
|
||||
LIST_HEAD(dispose);
|
||||
unsigned long ret;
|
||||
|
||||
if (!spin_trylock(&nfsd_gc_lock))
|
||||
return SHRINK_STOP;
|
||||
|
||||
ret = list_lru_shrink_walk(&nfsd_file_lru, sc,
|
||||
nfsd_file_lru_cb, &dispose);
|
||||
spin_unlock(&nfsd_gc_lock);
|
||||
trace_nfsd_file_shrinker_removed(ret, list_lru_count(&nfsd_file_lru));
|
||||
nfsd_file_dispose_list_delayed(&dispose);
|
||||
return ret;
|
||||
@ -686,17 +708,12 @@ nfsd_file_close_inode(struct inode *inode)
|
||||
void
|
||||
nfsd_file_close_inode_sync(struct inode *inode)
|
||||
{
|
||||
struct nfsd_file *nf;
|
||||
LIST_HEAD(dispose);
|
||||
|
||||
trace_nfsd_file_close(inode);
|
||||
|
||||
nfsd_file_queue_for_close(inode, &dispose);
|
||||
while (!list_empty(&dispose)) {
|
||||
nf = list_first_entry(&dispose, struct nfsd_file, nf_gc);
|
||||
list_del_init(&nf->nf_gc);
|
||||
nfsd_file_free(nf);
|
||||
}
|
||||
nfsd_file_dispose_list(&dispose);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1058,16 +1075,8 @@ retry:
|
||||
nf = nfsd_file_lookup_locked(net, current_cred(), inode, need, want_gc);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (nf) {
|
||||
/*
|
||||
* If the nf is on the LRU then it holds an extra reference
|
||||
* that must be put if it's removed. It had better not be
|
||||
* the last one however, since we should hold another.
|
||||
*/
|
||||
if (nfsd_file_lru_remove(nf))
|
||||
refcount_dec(&nf->nf_ref);
|
||||
if (nf)
|
||||
goto wait_for_construction;
|
||||
}
|
||||
|
||||
new = nfsd_file_alloc(net, inode, need, want_gc);
|
||||
if (!new) {
|
||||
@ -1161,6 +1170,9 @@ open_file:
|
||||
*/
|
||||
if (status != nfs_ok || inode->i_nlink == 0)
|
||||
nfsd_file_unhash(nf);
|
||||
else if (want_gc)
|
||||
nfsd_file_lru_add(nf);
|
||||
|
||||
clear_and_wake_up_bit(NFSD_FILE_PENDING, &nf->nf_flags);
|
||||
if (status == nfs_ok)
|
||||
goto out;
|
||||
|
@ -3,6 +3,12 @@
|
||||
|
||||
#include <linux/fsnotify_backend.h>
|
||||
|
||||
/*
|
||||
* Limit the time that the list_lru_one lock is held during
|
||||
* an LRU scan.
|
||||
*/
|
||||
#define NFSD_FILE_GC_BATCH (16UL)
|
||||
|
||||
/*
|
||||
* This is the fsnotify_mark container that nfsd attaches to the files that it
|
||||
* is holding open. Note that we have a separate refcount here aside from the
|
||||
@ -38,6 +44,7 @@ struct nfsd_file {
|
||||
#define NFSD_FILE_PENDING (1)
|
||||
#define NFSD_FILE_REFERENCED (2)
|
||||
#define NFSD_FILE_GC (3)
|
||||
#define NFSD_FILE_RECENT (4)
|
||||
unsigned long nf_flags;
|
||||
refcount_t nf_ref;
|
||||
unsigned char nf_may;
|
||||
|
@ -46,8 +46,6 @@
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
static void nfsd4_mark_cb_fault(struct nfs4_client *clp);
|
||||
|
||||
#define NFSPROC4_CB_NULL 0
|
||||
#define NFSPROC4_CB_COMPOUND 1
|
||||
|
||||
@ -101,15 +99,15 @@ static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||
|
||||
if (bitmap[0] & FATTR4_WORD0_CHANGE)
|
||||
if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_change) < 0)
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
if (bitmap[0] & FATTR4_WORD0_SIZE)
|
||||
if (xdr_stream_decode_u64(xdr, &fattr->ncf_cb_fsize) < 0)
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
if (bitmap[2] & FATTR4_WORD2_TIME_DELEG_ACCESS) {
|
||||
fattr4_time_deleg_access access;
|
||||
|
||||
if (!xdrgen_decode_fattr4_time_deleg_access(xdr, &access))
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
fattr->ncf_cb_atime.tv_sec = access.seconds;
|
||||
fattr->ncf_cb_atime.tv_nsec = access.nseconds;
|
||||
|
||||
@ -118,7 +116,7 @@ static int decode_cb_fattr4(struct xdr_stream *xdr, uint32_t *bitmap,
|
||||
fattr4_time_deleg_modify modify;
|
||||
|
||||
if (!xdrgen_decode_fattr4_time_deleg_modify(xdr, &modify))
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
fattr->ncf_cb_mtime.tv_sec = modify.seconds;
|
||||
fattr->ncf_cb_mtime.tv_nsec = modify.nseconds;
|
||||
|
||||
@ -682,15 +680,15 @@ static int nfs4_xdr_dec_cb_getattr(struct rpc_rqst *rqstp,
|
||||
if (unlikely(status || cb->cb_status))
|
||||
return status;
|
||||
if (xdr_stream_decode_uint32_array(xdr, bitmap, 3) < 0)
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
if (xdr_stream_decode_u32(xdr, &attrlen) < 0)
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
maxlen = sizeof(ncf->ncf_cb_change) + sizeof(ncf->ncf_cb_fsize);
|
||||
if (bitmap[2] != 0)
|
||||
maxlen += (sizeof(ncf->ncf_cb_mtime.tv_sec) +
|
||||
sizeof(ncf->ncf_cb_mtime.tv_nsec)) * 2;
|
||||
if (attrlen > maxlen)
|
||||
return -NFSERR_BAD_XDR;
|
||||
return -EIO;
|
||||
status = decode_cb_fattr4(xdr, bitmap, ncf);
|
||||
return status;
|
||||
}
|
||||
@ -1064,6 +1062,17 @@ static bool nfsd4_queue_cb(struct nfsd4_callback *cb)
|
||||
return queue_work(clp->cl_callback_wq, &cb->cb_work);
|
||||
}
|
||||
|
||||
static void nfsd4_requeue_cb(struct rpc_task *task, struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
|
||||
if (!test_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags)) {
|
||||
trace_nfsd_cb_restart(clp, cb);
|
||||
task->tk_status = 0;
|
||||
set_bit(NFSD4_CALLBACK_REQUEUE, &cb->cb_flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfsd41_cb_inflight_begin(struct nfs4_client *clp)
|
||||
{
|
||||
atomic_inc(&clp->cl_cb_inflight);
|
||||
@ -1301,6 +1310,11 @@ static void nfsd41_destroy_cb(struct nfsd4_callback *cb)
|
||||
|
||||
trace_nfsd_cb_destroy(clp, cb);
|
||||
nfsd41_cb_release_slot(cb);
|
||||
if (test_bit(NFSD4_CALLBACK_WAKE, &cb->cb_flags))
|
||||
clear_and_wake_up_bit(NFSD4_CALLBACK_RUNNING, &cb->cb_flags);
|
||||
else
|
||||
clear_bit(NFSD4_CALLBACK_RUNNING, &cb->cb_flags);
|
||||
|
||||
if (cb->cb_ops && cb->cb_ops->release)
|
||||
cb->cb_ops->release(cb);
|
||||
nfsd41_cb_inflight_end(clp);
|
||||
@ -1328,30 +1342,14 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
|
||||
rpc_call_start(task);
|
||||
}
|
||||
|
||||
/* Returns true if CB_COMPOUND processing should continue */
|
||||
static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
struct nfsd4_session *session = clp->cl_cb_session;
|
||||
bool ret = true;
|
||||
|
||||
if (!clp->cl_minorversion) {
|
||||
/*
|
||||
* If the backchannel connection was shut down while this
|
||||
* task was queued, we need to resubmit it after setting up
|
||||
* a new backchannel connection.
|
||||
*
|
||||
* Note that if we lost our callback connection permanently
|
||||
* the submission code will error out, so we don't need to
|
||||
* handle that case here.
|
||||
*/
|
||||
if (RPC_SIGNALLED(task))
|
||||
goto need_restart;
|
||||
|
||||
return true;
|
||||
}
|
||||
struct nfsd4_session *session = cb->cb_clp->cl_cb_session;
|
||||
bool ret = false;
|
||||
|
||||
if (cb->cb_held_slot < 0)
|
||||
goto need_restart;
|
||||
goto requeue;
|
||||
|
||||
/* This is the operation status code for CB_SEQUENCE */
|
||||
trace_nfsd_cb_seq_status(task, cb);
|
||||
@ -1365,11 +1363,16 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
|
||||
* (sequence ID, cached reply) MUST NOT change.
|
||||
*/
|
||||
++session->se_cb_seq_nr[cb->cb_held_slot];
|
||||
ret = true;
|
||||
break;
|
||||
case -ESERVERFAULT:
|
||||
++session->se_cb_seq_nr[cb->cb_held_slot];
|
||||
/*
|
||||
* Call succeeded, but the session, slot index, or slot
|
||||
* sequence number in the response do not match the same
|
||||
* in the server's call. The sequence information is thus
|
||||
* untrustworthy.
|
||||
*/
|
||||
nfsd4_mark_cb_fault(cb->cb_clp);
|
||||
ret = false;
|
||||
break;
|
||||
case 1:
|
||||
/*
|
||||
@ -1381,43 +1384,42 @@ static bool nfsd4_cb_sequence_done(struct rpc_task *task, struct nfsd4_callback
|
||||
fallthrough;
|
||||
case -NFS4ERR_BADSESSION:
|
||||
nfsd4_mark_cb_fault(cb->cb_clp);
|
||||
ret = false;
|
||||
goto need_restart;
|
||||
goto requeue;
|
||||
case -NFS4ERR_DELAY:
|
||||
cb->cb_seq_status = 1;
|
||||
if (!rpc_restart_call(task))
|
||||
goto out;
|
||||
|
||||
if (RPC_SIGNALLED(task) || !rpc_restart_call(task))
|
||||
goto requeue;
|
||||
rpc_delay(task, 2 * HZ);
|
||||
return false;
|
||||
case -NFS4ERR_BADSLOT:
|
||||
goto retry_nowait;
|
||||
case -NFS4ERR_SEQ_MISORDERED:
|
||||
if (session->se_cb_seq_nr[cb->cb_held_slot] != 1) {
|
||||
session->se_cb_seq_nr[cb->cb_held_slot] = 1;
|
||||
goto retry_nowait;
|
||||
}
|
||||
break;
|
||||
case -NFS4ERR_BADSLOT:
|
||||
/*
|
||||
* A SEQ_MISORDERED or BADSLOT error means that the client and
|
||||
* server are out of sync as to the backchannel parameters. Mark
|
||||
* the backchannel faulty and restart the RPC, but leak the slot
|
||||
* so that it's no longer used.
|
||||
*/
|
||||
nfsd4_mark_cb_fault(cb->cb_clp);
|
||||
cb->cb_held_slot = -1;
|
||||
goto retry_nowait;
|
||||
default:
|
||||
nfsd4_mark_cb_fault(cb->cb_clp);
|
||||
}
|
||||
trace_nfsd_cb_free_slot(task, cb);
|
||||
nfsd41_cb_release_slot(cb);
|
||||
|
||||
if (RPC_SIGNALLED(task))
|
||||
goto need_restart;
|
||||
out:
|
||||
return ret;
|
||||
retry_nowait:
|
||||
if (rpc_restart_call_prepare(task))
|
||||
ret = false;
|
||||
goto out;
|
||||
need_restart:
|
||||
if (!test_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags)) {
|
||||
trace_nfsd_cb_restart(clp, cb);
|
||||
task->tk_status = 0;
|
||||
cb->cb_need_restart = true;
|
||||
/*
|
||||
* RPC_SIGNALLED() means that the rpc_client is being torn down and
|
||||
* (possibly) recreated. Requeue the call in that case.
|
||||
*/
|
||||
if (!RPC_SIGNALLED(task)) {
|
||||
if (rpc_restart_call_prepare(task))
|
||||
return false;
|
||||
}
|
||||
requeue:
|
||||
nfsd41_cb_release_slot(cb);
|
||||
nfsd4_requeue_cb(task, cb);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1428,8 +1430,21 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
|
||||
|
||||
trace_nfsd_cb_rpc_done(clp);
|
||||
|
||||
if (!nfsd4_cb_sequence_done(task, cb))
|
||||
if (!clp->cl_minorversion) {
|
||||
/*
|
||||
* If the backchannel connection was shut down while this
|
||||
* task was queued, we need to resubmit it after setting up
|
||||
* a new backchannel connection.
|
||||
*
|
||||
* Note that if we lost our callback connection permanently
|
||||
* the submission code will error out, so we don't need to
|
||||
* handle that case here.
|
||||
*/
|
||||
if (RPC_SIGNALLED(task))
|
||||
nfsd4_requeue_cb(task, cb);
|
||||
} else if (!nfsd4_cb_sequence_done(task, cb)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb->cb_status) {
|
||||
WARN_ONCE(task->tk_status,
|
||||
@ -1462,7 +1477,7 @@ static void nfsd4_cb_release(void *calldata)
|
||||
|
||||
trace_nfsd_cb_rpc_release(cb->cb_clp);
|
||||
|
||||
if (cb->cb_need_restart)
|
||||
if (test_bit(NFSD4_CALLBACK_REQUEUE, &cb->cb_flags))
|
||||
nfsd4_queue_cb(cb);
|
||||
else
|
||||
nfsd41_destroy_cb(cb);
|
||||
@ -1575,7 +1590,7 @@ nfsd4_run_cb_work(struct work_struct *work)
|
||||
container_of(work, struct nfsd4_callback, cb_work);
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
struct rpc_clnt *clnt;
|
||||
int flags;
|
||||
int flags, ret;
|
||||
|
||||
trace_nfsd_cb_start(clp);
|
||||
|
||||
@ -1601,16 +1616,19 @@ nfsd4_run_cb_work(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
if (cb->cb_need_restart) {
|
||||
cb->cb_need_restart = false;
|
||||
} else {
|
||||
if (!test_and_clear_bit(NFSD4_CALLBACK_REQUEUE, &cb->cb_flags)) {
|
||||
if (cb->cb_ops && cb->cb_ops->prepare)
|
||||
cb->cb_ops->prepare(cb);
|
||||
}
|
||||
|
||||
cb->cb_msg.rpc_cred = clp->cl_cb_cred;
|
||||
flags = clp->cl_minorversion ? RPC_TASK_NOCONNECT : RPC_TASK_SOFTCONN;
|
||||
rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | flags,
|
||||
cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb);
|
||||
ret = rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | flags,
|
||||
cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb);
|
||||
if (ret != 0) {
|
||||
set_bit(NFSD4_CALLBACK_REQUEUE, &cb->cb_flags);
|
||||
nfsd4_queue_cb(cb);
|
||||
}
|
||||
}
|
||||
|
||||
void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
||||
@ -1620,10 +1638,10 @@ void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
||||
cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op];
|
||||
cb->cb_msg.rpc_argp = cb;
|
||||
cb->cb_msg.rpc_resp = cb;
|
||||
cb->cb_flags = 0;
|
||||
cb->cb_ops = ops;
|
||||
INIT_WORK(&cb->cb_work, nfsd4_run_cb_work);
|
||||
cb->cb_status = 0;
|
||||
cb->cb_need_restart = false;
|
||||
cb->cb_held_slot = -1;
|
||||
}
|
||||
|
||||
|
@ -344,9 +344,10 @@ nfsd4_recall_file_layout(struct nfs4_layout_stateid *ls)
|
||||
atomic_inc(&ls->ls_stid.sc_file->fi_lo_recalls);
|
||||
trace_nfsd_layout_recall(&ls->ls_stid.sc_stateid);
|
||||
|
||||
refcount_inc(&ls->ls_stid.sc_count);
|
||||
nfsd4_run_cb(&ls->ls_recall);
|
||||
|
||||
if (!test_and_set_bit(NFSD4_CALLBACK_RUNNING, &ls->ls_recall.cb_flags)) {
|
||||
refcount_inc(&ls->ls_stid.sc_count);
|
||||
nfsd4_run_cb(&ls->ls_recall);
|
||||
}
|
||||
out_unlock:
|
||||
spin_unlock(&ls->ls_lock);
|
||||
}
|
||||
|
@ -1847,7 +1847,7 @@ static void nfsd4_send_cb_offload(struct nfsd4_copy *copy)
|
||||
NFSPROC4_CLNT_CB_OFFLOAD);
|
||||
trace_nfsd_cb_offload(copy->cp_clp, &cbo->co_res.cb_stateid,
|
||||
&cbo->co_fh, copy->cp_count, copy->nfserr);
|
||||
nfsd4_run_cb(&cbo->co_cb);
|
||||
nfsd4_try_run_cb(&cbo->co_cb);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -946,15 +946,6 @@ struct nfs4_stid *nfs4_alloc_stid(struct nfs4_client *cl, struct kmem_cache *sla
|
||||
spin_lock_init(&stid->sc_lock);
|
||||
INIT_LIST_HEAD(&stid->sc_cp_list);
|
||||
|
||||
/*
|
||||
* It shouldn't be a problem to reuse an opaque stateid value.
|
||||
* I don't think it is for 4.1. But with 4.0 I worry that, for
|
||||
* example, a stray write retransmission could be accepted by
|
||||
* the server when it should have been rejected. Therefore,
|
||||
* adopt a trick from the sctp code to attempt to maximize the
|
||||
* amount of time until an id is reused, by ensuring they always
|
||||
* "increase" (mod INT_MAX):
|
||||
*/
|
||||
return stid;
|
||||
out_free:
|
||||
kmem_cache_free(slab, stid);
|
||||
@ -1050,6 +1041,12 @@ static struct nfs4_ol_stateid * nfs4_alloc_open_stateid(struct nfs4_client *clp)
|
||||
return openlockstateid(stid);
|
||||
}
|
||||
|
||||
/*
|
||||
* As the sc_free callback of deleg, this may be called by nfs4_put_stid
|
||||
* in nfsd_break_one_deleg.
|
||||
* Considering nfsd_break_one_deleg is called with the flc->flc_lock held,
|
||||
* this function mustn't ever sleep.
|
||||
*/
|
||||
static void nfs4_free_deleg(struct nfs4_stid *stid)
|
||||
{
|
||||
struct nfs4_delegation *dp = delegstateid(stid);
|
||||
@ -1378,7 +1375,8 @@ static void revoke_delegation(struct nfs4_delegation *dp)
|
||||
struct nfs4_client *clp = dp->dl_stid.sc_client;
|
||||
|
||||
WARN_ON(!list_empty(&dp->dl_recall_lru));
|
||||
WARN_ON_ONCE(!(dp->dl_stid.sc_status &
|
||||
WARN_ON_ONCE(dp->dl_stid.sc_client->cl_minorversion > 0 &&
|
||||
!(dp->dl_stid.sc_status &
|
||||
(SC_STATUS_REVOKED | SC_STATUS_ADMIN_REVOKED)));
|
||||
|
||||
trace_nfsd_stid_revoke(&dp->dl_stid);
|
||||
@ -3168,7 +3166,6 @@ nfsd4_cb_recall_any_release(struct nfsd4_callback *cb)
|
||||
{
|
||||
struct nfs4_client *clp = cb->cb_clp;
|
||||
|
||||
clear_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
|
||||
drop_client(clp);
|
||||
}
|
||||
|
||||
@ -3199,7 +3196,6 @@ nfsd4_cb_getattr_release(struct nfsd4_callback *cb)
|
||||
struct nfs4_delegation *dp =
|
||||
container_of(ncf, struct nfs4_delegation, dl_cb_fattr);
|
||||
|
||||
clear_and_wake_up_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags);
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
}
|
||||
|
||||
@ -3220,11 +3216,15 @@ static void nfs4_cb_getattr(struct nfs4_cb_fattr *ncf)
|
||||
struct nfs4_delegation *dp =
|
||||
container_of(ncf, struct nfs4_delegation, dl_cb_fattr);
|
||||
|
||||
if (test_and_set_bit(CB_GETATTR_BUSY, &ncf->ncf_cb_flags))
|
||||
if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &ncf->ncf_getattr.cb_flags))
|
||||
return;
|
||||
|
||||
/* set to proper status when nfsd4_cb_getattr_done runs */
|
||||
ncf->ncf_cb_status = NFS4ERR_IO;
|
||||
|
||||
/* ensure that wake_bit is done when RUNNING is cleared */
|
||||
set_bit(NFSD4_CALLBACK_WAKE, &ncf->ncf_getattr.cb_flags);
|
||||
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
nfsd4_run_cb(&ncf->ncf_getattr);
|
||||
}
|
||||
@ -4815,8 +4815,8 @@ out:
|
||||
static unsigned long
|
||||
nfsd4_state_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
|
||||
{
|
||||
int count;
|
||||
struct nfsd_net *nn = shrink->private_data;
|
||||
long count;
|
||||
|
||||
count = atomic_read(&nn->nfsd_courtesy_clients);
|
||||
if (!count)
|
||||
@ -5414,6 +5414,11 @@ static const struct nfsd4_callback_ops nfsd4_cb_recall_ops = {
|
||||
|
||||
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
|
||||
{
|
||||
bool queued;
|
||||
|
||||
if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &dp->dl_recall.cb_flags))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We're assuming the state code never drops its reference
|
||||
* without first removing the lease. Since we're in this lease
|
||||
@ -5422,7 +5427,10 @@ static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
|
||||
* we know it's safe to take a reference.
|
||||
*/
|
||||
refcount_inc(&dp->dl_stid.sc_count);
|
||||
WARN_ON_ONCE(!nfsd4_run_cb(&dp->dl_recall));
|
||||
queued = nfsd4_run_cb(&dp->dl_recall);
|
||||
WARN_ON_ONCE(!queued);
|
||||
if (!queued)
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
}
|
||||
|
||||
/* Called from break_lease() with flc_lock held. */
|
||||
@ -5948,11 +5956,23 @@ nfsd4_verify_setuid_write(struct nfsd4_open *open, struct nfsd_file *nf)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_DELEG_TIMESTAMPS
|
||||
static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open)
|
||||
{
|
||||
return open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
|
||||
}
|
||||
#else /* CONFIG_NFSD_V4_DELEG_TIMESTAMPS */
|
||||
static bool nfsd4_want_deleg_timestamps(const struct nfsd4_open *open)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif /* CONFIG NFSD_V4_DELEG_TIMESTAMPS */
|
||||
|
||||
static struct nfs4_delegation *
|
||||
nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
|
||||
struct svc_fh *parent)
|
||||
{
|
||||
bool deleg_ts = open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
|
||||
bool deleg_ts = nfsd4_want_deleg_timestamps(open);
|
||||
struct nfs4_client *clp = stp->st_stid.sc_client;
|
||||
struct nfs4_file *fp = stp->st_stid.sc_file;
|
||||
struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
|
||||
@ -5999,6 +6019,15 @@ nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
|
||||
if (!nf)
|
||||
return ERR_PTR(-EAGAIN);
|
||||
|
||||
/*
|
||||
* File delegations and associated locks cannot be recovered if the
|
||||
* export is from an NFS proxy server.
|
||||
*/
|
||||
if (exportfs_cannot_lock(nf->nf_file->f_path.mnt->mnt_sb->s_export_op)) {
|
||||
nfsd_file_put(nf);
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
|
||||
spin_lock(&state_lock);
|
||||
spin_lock(&fp->fi_lock);
|
||||
if (nfs4_delegation_exists(clp, fp))
|
||||
@ -6151,8 +6180,8 @@ static void
|
||||
nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
|
||||
struct svc_fh *currentfh)
|
||||
{
|
||||
bool deleg_ts = open->op_deleg_want & OPEN4_SHARE_ACCESS_WANT_DELEG_TIMESTAMPS;
|
||||
struct nfs4_openowner *oo = openowner(stp->st_stateowner);
|
||||
bool deleg_ts = nfsd4_want_deleg_timestamps(open);
|
||||
struct nfs4_client *clp = stp->st_stid.sc_client;
|
||||
struct svc_fh *parent = NULL;
|
||||
struct nfs4_delegation *dp;
|
||||
@ -6855,38 +6884,34 @@ deleg_reaper(struct nfsd_net *nn)
|
||||
{
|
||||
struct list_head *pos, *next;
|
||||
struct nfs4_client *clp;
|
||||
LIST_HEAD(cblist);
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_safe(pos, next, &nn->client_lru) {
|
||||
clp = list_entry(pos, struct nfs4_client, cl_lru);
|
||||
if (clp->cl_state != NFSD4_ACTIVE ||
|
||||
list_empty(&clp->cl_delegations) ||
|
||||
atomic_read(&clp->cl_delegs_in_recall) ||
|
||||
test_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags) ||
|
||||
(ktime_get_boottime_seconds() -
|
||||
clp->cl_ra_time < 5)) {
|
||||
|
||||
if (clp->cl_state != NFSD4_ACTIVE)
|
||||
continue;
|
||||
if (list_empty(&clp->cl_delegations))
|
||||
continue;
|
||||
if (atomic_read(&clp->cl_delegs_in_recall))
|
||||
continue;
|
||||
if (test_and_set_bit(NFSD4_CALLBACK_RUNNING, &clp->cl_ra->ra_cb.cb_flags))
|
||||
continue;
|
||||
if (ktime_get_boottime_seconds() - clp->cl_ra_time < 5)
|
||||
continue;
|
||||
if (clp->cl_cb_state != NFSD4_CB_UP)
|
||||
continue;
|
||||
}
|
||||
list_add(&clp->cl_ra_cblist, &cblist);
|
||||
|
||||
/* release in nfsd4_cb_recall_any_release */
|
||||
kref_get(&clp->cl_nfsdfs.cl_ref);
|
||||
set_bit(NFSD4_CLIENT_CB_RECALL_ANY, &clp->cl_flags);
|
||||
clp->cl_ra_time = ktime_get_boottime_seconds();
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
while (!list_empty(&cblist)) {
|
||||
clp = list_first_entry(&cblist, struct nfs4_client,
|
||||
cl_ra_cblist);
|
||||
list_del_init(&clp->cl_ra_cblist);
|
||||
clp->cl_ra->ra_keep = 0;
|
||||
clp->cl_ra->ra_bmval[0] = BIT(RCA4_TYPE_MASK_RDATA_DLG) |
|
||||
BIT(RCA4_TYPE_MASK_WDATA_DLG);
|
||||
trace_nfsd_cb_recall_any(clp->cl_ra);
|
||||
nfsd4_run_cb(&clp->cl_ra->ra_cb);
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -7051,7 +7076,7 @@ nfsd4_lookup_stateid(struct nfsd4_compound_state *cstate,
|
||||
*/
|
||||
statusmask |= SC_STATUS_REVOKED;
|
||||
|
||||
statusmask |= SC_STATUS_ADMIN_REVOKED;
|
||||
statusmask |= SC_STATUS_ADMIN_REVOKED | SC_STATUS_FREEABLE;
|
||||
|
||||
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid) ||
|
||||
CLOSE_STATEID(stateid))
|
||||
@ -7706,9 +7731,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
|
||||
return status;
|
||||
|
||||
status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG,
|
||||
SC_STATUS_REVOKED | SC_STATUS_FREEABLE,
|
||||
&s, nn);
|
||||
status = nfsd4_lookup_stateid(cstate, stateid, SC_TYPE_DELEG, SC_STATUS_REVOKED, &s, nn);
|
||||
if (status)
|
||||
goto out;
|
||||
dp = delegstateid(s);
|
||||
@ -7816,7 +7839,7 @@ nfsd4_lm_notify(struct file_lock *fl)
|
||||
|
||||
if (queue) {
|
||||
trace_nfsd_cb_notify_lock(lo, nbl);
|
||||
nfsd4_run_cb(&nbl->nbl_cb);
|
||||
nfsd4_try_run_cb(&nbl->nbl_cb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -8134,6 +8157,10 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
|
||||
if (status != nfs_ok)
|
||||
return status;
|
||||
if (exportfs_cannot_lock(cstate->current_fh.fh_dentry->d_sb->s_export_op)) {
|
||||
status = nfserr_notsupp;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (lock->lk_is_new) {
|
||||
if (nfsd4_has_session(cstate))
|
||||
@ -8473,6 +8500,11 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
status = nfserr_lock_range;
|
||||
goto put_stateid;
|
||||
}
|
||||
if (exportfs_cannot_lock(nf->nf_file->f_path.mnt->mnt_sb->s_export_op)) {
|
||||
status = nfserr_notsupp;
|
||||
goto put_file;
|
||||
}
|
||||
|
||||
file_lock = locks_alloc_lock();
|
||||
if (!file_lock) {
|
||||
dprintk("NFSD: %s: unable to allocate lock!\n", __func__);
|
||||
@ -9182,8 +9214,8 @@ nfsd4_deleg_getattr_conflict(struct svc_rqst *rqstp, struct dentry *dentry,
|
||||
nfs4_cb_getattr(&dp->dl_cb_fattr);
|
||||
spin_unlock(&ctx->flc_lock);
|
||||
|
||||
wait_on_bit_timeout(&ncf->ncf_cb_flags, CB_GETATTR_BUSY,
|
||||
TASK_INTERRUPTIBLE, NFSD_CB_GETATTR_TIMEOUT);
|
||||
wait_on_bit_timeout(&ncf->ncf_getattr.cb_flags, NFSD4_CALLBACK_RUNNING,
|
||||
TASK_UNINTERRUPTIBLE, NFSD_CB_GETATTR_TIMEOUT);
|
||||
if (ncf->ncf_cb_status) {
|
||||
/* Recall delegation only if client didn't respond */
|
||||
status = nfserrno(nfsd_open_break_lease(inode, NFSD_MAY_READ));
|
||||
|
@ -1917,6 +1917,7 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
struct svc_serv *serv;
|
||||
LIST_HEAD(permsocks);
|
||||
struct nfsd_net *nn;
|
||||
bool delete = false;
|
||||
int err, rem;
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
@ -1977,34 +1978,28 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
}
|
||||
}
|
||||
|
||||
/* For now, no removing old sockets while server is running */
|
||||
if (serv->sv_nrthreads && !list_empty(&permsocks)) {
|
||||
/*
|
||||
* If there are listener transports remaining on the permsocks list,
|
||||
* it means we were asked to remove a listener.
|
||||
*/
|
||||
if (!list_empty(&permsocks)) {
|
||||
list_splice_init(&permsocks, &serv->sv_permsocks);
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
delete = true;
|
||||
}
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
|
||||
/* Do not remove listeners while there are active threads. */
|
||||
if (serv->sv_nrthreads) {
|
||||
err = -EBUSY;
|
||||
goto out_unlock_mtx;
|
||||
}
|
||||
|
||||
/* Close the remaining sockets on the permsocks list */
|
||||
while (!list_empty(&permsocks)) {
|
||||
xprt = list_first_entry(&permsocks, struct svc_xprt, xpt_list);
|
||||
list_move(&xprt->xpt_list, &serv->sv_permsocks);
|
||||
|
||||
/*
|
||||
* Newly-created sockets are born with the BUSY bit set. Clear
|
||||
* it if there are no threads, since nothing can pick it up
|
||||
* in that case.
|
||||
*/
|
||||
if (!serv->sv_nrthreads)
|
||||
clear_bit(XPT_BUSY, &xprt->xpt_flags);
|
||||
|
||||
set_bit(XPT_CLOSE, &xprt->xpt_flags);
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
svc_xprt_close(xprt);
|
||||
spin_lock_bh(&serv->sv_lock);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&serv->sv_lock);
|
||||
/*
|
||||
* Since we can't delete an arbitrary llist entry, destroy the
|
||||
* remaining listeners and recreate the list.
|
||||
*/
|
||||
if (delete)
|
||||
svc_xprt_destroy_all(serv, net);
|
||||
|
||||
/* walk list of addrs again, open any that still don't exist */
|
||||
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
||||
@ -2031,6 +2026,9 @@ int nfsd_nl_listener_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
xprt = svc_find_listener(serv, xcl_name, net, sa);
|
||||
if (xprt) {
|
||||
if (delete)
|
||||
WARN_ONCE(1, "Transport type=%s already exists\n",
|
||||
xcl_name);
|
||||
svc_xprt_put(xprt);
|
||||
continue;
|
||||
}
|
||||
@ -2204,8 +2202,14 @@ static __net_init int nfsd_net_init(struct net *net)
|
||||
NFSD_STATS_COUNTERS_NUM);
|
||||
if (retval)
|
||||
goto out_repcache_error;
|
||||
|
||||
memset(&nn->nfsd_svcstats, 0, sizeof(nn->nfsd_svcstats));
|
||||
nn->nfsd_svcstats.program = &nfsd_programs[0];
|
||||
if (!nfsd_proc_stat_init(net)) {
|
||||
retval = -ENOMEM;
|
||||
goto out_proc_error;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(nn->nfsd_versions); i++)
|
||||
nn->nfsd_versions[i] = nfsd_support_version(i);
|
||||
for (i = 0; i < sizeof(nn->nfsd4_minorversions); i++)
|
||||
@ -2215,13 +2219,14 @@ static __net_init int nfsd_net_init(struct net *net)
|
||||
nfsd4_init_leases_net(nn);
|
||||
get_random_bytes(&nn->siphash_key, sizeof(nn->siphash_key));
|
||||
seqlock_init(&nn->writeverf_lock);
|
||||
nfsd_proc_stat_init(net);
|
||||
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
||||
spin_lock_init(&nn->local_clients_lock);
|
||||
INIT_LIST_HEAD(&nn->local_clients);
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
out_proc_error:
|
||||
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
|
||||
out_repcache_error:
|
||||
nfsd_idmap_shutdown(net);
|
||||
out_idmap_error:
|
||||
|
@ -67,12 +67,15 @@ typedef struct {
|
||||
struct nfsd4_callback {
|
||||
struct nfs4_client *cb_clp;
|
||||
struct rpc_message cb_msg;
|
||||
#define NFSD4_CALLBACK_RUNNING (0)
|
||||
#define NFSD4_CALLBACK_WAKE (1)
|
||||
#define NFSD4_CALLBACK_REQUEUE (2)
|
||||
unsigned long cb_flags;
|
||||
const struct nfsd4_callback_ops *cb_ops;
|
||||
struct work_struct cb_work;
|
||||
int cb_seq_status;
|
||||
int cb_status;
|
||||
int cb_held_slot;
|
||||
bool cb_need_restart;
|
||||
};
|
||||
|
||||
struct nfsd4_callback_ops {
|
||||
@ -162,15 +165,11 @@ struct nfs4_cb_fattr {
|
||||
struct timespec64 ncf_cb_mtime;
|
||||
struct timespec64 ncf_cb_atime;
|
||||
|
||||
unsigned long ncf_cb_flags;
|
||||
bool ncf_file_modified;
|
||||
u64 ncf_initial_cinfo;
|
||||
u64 ncf_cur_fsize;
|
||||
};
|
||||
|
||||
/* bits for ncf_cb_flags */
|
||||
#define CB_GETATTR_BUSY 0
|
||||
|
||||
/*
|
||||
* Represents a delegation stateid. The nfs4_client holds references to these
|
||||
* and they are put when it is being destroyed or when the delegation is
|
||||
@ -198,8 +197,8 @@ struct nfs4_delegation {
|
||||
struct list_head dl_perclnt;
|
||||
struct list_head dl_recall_lru; /* delegation recalled */
|
||||
struct nfs4_clnt_odstate *dl_clnt_odstate;
|
||||
u32 dl_type;
|
||||
time64_t dl_time;
|
||||
u32 dl_type;
|
||||
/* For recall: */
|
||||
int dl_retries;
|
||||
struct nfsd4_callback dl_recall;
|
||||
@ -452,7 +451,6 @@ struct nfs4_client {
|
||||
#define NFSD4_CLIENT_UPCALL_LOCK (5) /* upcall serialization */
|
||||
#define NFSD4_CLIENT_CB_FLAG_MASK (1 << NFSD4_CLIENT_CB_UPDATE | \
|
||||
1 << NFSD4_CLIENT_CB_KILL)
|
||||
#define NFSD4_CLIENT_CB_RECALL_ANY (6)
|
||||
unsigned long cl_flags;
|
||||
|
||||
struct workqueue_struct *cl_callback_wq;
|
||||
@ -498,7 +496,6 @@ struct nfs4_client {
|
||||
|
||||
struct nfsd4_cb_recall_any *cl_ra;
|
||||
time64_t cl_ra_time;
|
||||
struct list_head cl_ra_cblist;
|
||||
};
|
||||
|
||||
/* struct nfs4_client_reset
|
||||
@ -780,6 +777,13 @@ extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *
|
||||
extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp,
|
||||
const struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op);
|
||||
extern bool nfsd4_run_cb(struct nfsd4_callback *cb);
|
||||
|
||||
static inline void nfsd4_try_run_cb(struct nfsd4_callback *cb)
|
||||
{
|
||||
if (!test_and_set_bit(NFSD4_CALLBACK_RUNNING, &cb->cb_flags))
|
||||
WARN_ON_ONCE(!nfsd4_run_cb(cb));
|
||||
}
|
||||
|
||||
extern void nfsd4_shutdown_callback(struct nfs4_client *);
|
||||
extern void nfsd4_shutdown_copy(struct nfs4_client *clp);
|
||||
void nfsd4_async_copy_reaper(struct nfsd_net *nn);
|
||||
|
@ -73,11 +73,11 @@ static int nfsd_show(struct seq_file *seq, void *v)
|
||||
|
||||
DEFINE_PROC_SHOW_ATTRIBUTE(nfsd);
|
||||
|
||||
void nfsd_proc_stat_init(struct net *net)
|
||||
struct proc_dir_entry *nfsd_proc_stat_init(struct net *net)
|
||||
{
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
|
||||
return svc_proc_register(net, &nn->nfsd_svcstats, &nfsd_proc_ops);
|
||||
}
|
||||
|
||||
void nfsd_proc_stat_shutdown(struct net *net)
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include <uapi/linux/nfsd/stats.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
|
||||
void nfsd_proc_stat_init(struct net *net);
|
||||
struct proc_dir_entry *nfsd_proc_stat_init(struct net *net);
|
||||
void nfsd_proc_stat_shutdown(struct net *net);
|
||||
|
||||
static inline void nfsd_stats_rc_hits_inc(struct nfsd_net *nn)
|
||||
|
@ -803,6 +803,14 @@ DEFINE_EVENT(nfsd_cs_slot_class, nfsd_##name, \
|
||||
DEFINE_CS_SLOT_EVENT(slot_seqid_conf);
|
||||
DEFINE_CS_SLOT_EVENT(slot_seqid_unconf);
|
||||
|
||||
#define show_nfs_slot_flags(val) \
|
||||
__print_flags(val, "|", \
|
||||
{ NFSD4_SLOT_INUSE, "INUSE" }, \
|
||||
{ NFSD4_SLOT_CACHETHIS, "CACHETHIS" }, \
|
||||
{ NFSD4_SLOT_INITIALIZED, "INITIALIZED" }, \
|
||||
{ NFSD4_SLOT_CACHED, "CACHED" }, \
|
||||
{ NFSD4_SLOT_REUSED, "REUSED" })
|
||||
|
||||
TRACE_EVENT(nfsd_slot_seqid_sequence,
|
||||
TP_PROTO(
|
||||
const struct nfs4_client *clp,
|
||||
@ -813,10 +821,11 @@ TRACE_EVENT(nfsd_slot_seqid_sequence,
|
||||
TP_STRUCT__entry(
|
||||
__field(u32, seqid)
|
||||
__field(u32, slot_seqid)
|
||||
__field(u32, slot_index)
|
||||
__field(unsigned long, slot_flags)
|
||||
__field(u32, cl_boot)
|
||||
__field(u32, cl_id)
|
||||
__sockaddr(addr, clp->cl_cb_conn.cb_addrlen)
|
||||
__field(bool, in_use)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__entry->cl_boot = clp->cl_clientid.cl_boot;
|
||||
@ -825,11 +834,13 @@ TRACE_EVENT(nfsd_slot_seqid_sequence,
|
||||
clp->cl_cb_conn.cb_addrlen);
|
||||
__entry->seqid = seq->seqid;
|
||||
__entry->slot_seqid = slot->sl_seqid;
|
||||
__entry->slot_index = seq->slotid;
|
||||
__entry->slot_flags = slot->sl_flags;
|
||||
),
|
||||
TP_printk("addr=%pISpc client %08x:%08x seqid=%u slot_seqid=%u (%sin use)",
|
||||
TP_printk("addr=%pISpc client %08x:%08x idx=%u seqid=%u slot_seqid=%u flags=%s",
|
||||
__get_sockaddr(addr), __entry->cl_boot, __entry->cl_id,
|
||||
__entry->seqid, __entry->slot_seqid,
|
||||
__entry->in_use ? "" : "not "
|
||||
__entry->slot_index, __entry->seqid, __entry->slot_seqid,
|
||||
show_nfs_slot_flags(__entry->slot_flags)
|
||||
)
|
||||
);
|
||||
|
||||
@ -1039,6 +1050,7 @@ DEFINE_CLID_EVENT(confirmed_r);
|
||||
{ 1 << NFSD_FILE_HASHED, "HASHED" }, \
|
||||
{ 1 << NFSD_FILE_PENDING, "PENDING" }, \
|
||||
{ 1 << NFSD_FILE_REFERENCED, "REFERENCED" }, \
|
||||
{ 1 << NFSD_FILE_RECENT, "RECENT" }, \
|
||||
{ 1 << NFSD_FILE_GC, "GC" })
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_file_class,
|
||||
@ -1317,6 +1329,7 @@ DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_lru_del_disposed);
|
||||
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_in_use);
|
||||
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_writeback);
|
||||
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_referenced);
|
||||
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_aged);
|
||||
DEFINE_NFSD_FILE_GC_EVENT(nfsd_file_gc_disposed);
|
||||
|
||||
DECLARE_EVENT_CLASS(nfsd_file_lruwalk_class,
|
||||
@ -1346,6 +1359,7 @@ DEFINE_EVENT(nfsd_file_lruwalk_class, name, \
|
||||
TP_ARGS(removed, remaining))
|
||||
|
||||
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_removed);
|
||||
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_gc_recent);
|
||||
DEFINE_NFSD_FILE_LRUWALK_EVENT(nfsd_file_shrinker_removed);
|
||||
|
||||
TRACE_EVENT(nfsd_file_close,
|
||||
@ -1602,7 +1616,7 @@ DECLARE_EVENT_CLASS(nfsd_cb_lifetime_class,
|
||||
__entry->cl_id = clp->cl_clientid.cl_id;
|
||||
__entry->cb = cb;
|
||||
__entry->opcode = cb->cb_ops ? cb->cb_ops->opcode : _CB_NULL;
|
||||
__entry->need_restart = cb->cb_need_restart;
|
||||
__entry->need_restart = test_bit(NFSD4_CALLBACK_REQUEUE, &cb->cb_flags);
|
||||
__assign_sockaddr(addr, &clp->cl_cb_conn.cb_addr,
|
||||
clp->cl_cb_conn.cb_addrlen)
|
||||
),
|
||||
|
106
fs/nfsd/vfs.c
106
fs/nfsd/vfs.c
@ -71,7 +71,6 @@ nfserrno (int errno)
|
||||
{ nfserr_acces, -EACCES },
|
||||
{ nfserr_exist, -EEXIST },
|
||||
{ nfserr_xdev, -EXDEV },
|
||||
{ nfserr_mlink, -EMLINK },
|
||||
{ nfserr_nodev, -ENODEV },
|
||||
{ nfserr_notdir, -ENOTDIR },
|
||||
{ nfserr_isdir, -EISDIR },
|
||||
@ -1687,9 +1686,17 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a hardlink
|
||||
* N.B. After this call _both_ ffhp and tfhp need an fh_put
|
||||
/**
|
||||
* nfsd_link - create a link
|
||||
* @rqstp: RPC transaction context
|
||||
* @ffhp: the file handle of the directory where the new link is to be created
|
||||
* @name: the filename of the new link
|
||||
* @len: the length of @name in octets
|
||||
* @tfhp: the file handle of an existing file object
|
||||
*
|
||||
* After this call _both_ ffhp and tfhp need an fh_put.
|
||||
*
|
||||
* Returns a generic NFS status code in network byte-order.
|
||||
*/
|
||||
__be32
|
||||
nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
||||
@ -1697,6 +1704,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
||||
{
|
||||
struct dentry *ddir, *dnew, *dold;
|
||||
struct inode *dirp;
|
||||
int type;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
|
||||
@ -1716,11 +1724,11 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
||||
if (isdotent(name, len))
|
||||
goto out;
|
||||
|
||||
err = nfs_ok;
|
||||
type = d_inode(tfhp->fh_dentry)->i_mode & S_IFMT;
|
||||
host_err = fh_want_write(tfhp);
|
||||
if (host_err) {
|
||||
err = nfserrno(host_err);
|
||||
if (host_err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ddir = ffhp->fh_dentry;
|
||||
dirp = d_inode(ddir);
|
||||
@ -1728,7 +1736,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
||||
|
||||
dnew = lookup_one_len(name, ddir, len);
|
||||
if (IS_ERR(dnew)) {
|
||||
err = nfserrno(PTR_ERR(dnew));
|
||||
host_err = PTR_ERR(dnew);
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
@ -1744,17 +1752,26 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
|
||||
fh_fill_post_attrs(ffhp);
|
||||
inode_unlock(dirp);
|
||||
if (!host_err) {
|
||||
err = nfserrno(commit_metadata(ffhp));
|
||||
if (!err)
|
||||
err = nfserrno(commit_metadata(tfhp));
|
||||
} else {
|
||||
err = nfserrno(host_err);
|
||||
host_err = commit_metadata(ffhp);
|
||||
if (!host_err)
|
||||
host_err = commit_metadata(tfhp);
|
||||
}
|
||||
|
||||
dput(dnew);
|
||||
out_drop_write:
|
||||
fh_drop_write(tfhp);
|
||||
if (host_err == -EBUSY) {
|
||||
/*
|
||||
* See RFC 8881 Section 18.9.4 para 1-2: NFSv4 LINK
|
||||
* wants a status unique to the object type.
|
||||
*/
|
||||
if (type != S_IFDIR)
|
||||
err = nfserr_file_open;
|
||||
else
|
||||
err = nfserr_acces;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
return err != nfs_ok ? err : nfserrno(host_err);
|
||||
|
||||
out_dput:
|
||||
dput(dnew);
|
||||
@ -1783,9 +1800,19 @@ nfsd_has_cached_files(struct dentry *dentry)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rename a file
|
||||
* N.B. After this call _both_ ffhp and tfhp need an fh_put
|
||||
/**
|
||||
* nfsd_rename - rename a directory entry
|
||||
* @rqstp: RPC transaction context
|
||||
* @ffhp: the file handle of parent directory containing the entry to be renamed
|
||||
* @fname: the filename of directory entry to be renamed
|
||||
* @flen: the length of @fname in octets
|
||||
* @tfhp: the file handle of parent directory to contain the renamed entry
|
||||
* @tname: the filename of the new entry
|
||||
* @tlen: the length of @tlen in octets
|
||||
*
|
||||
* After this call _both_ ffhp and tfhp need an fh_put.
|
||||
*
|
||||
* Returns a generic NFS status code in network byte-order.
|
||||
*/
|
||||
__be32
|
||||
nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
||||
@ -1793,6 +1820,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
|
||||
{
|
||||
struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap;
|
||||
struct inode *fdir, *tdir;
|
||||
int type = S_IFDIR;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
bool close_cached = false;
|
||||
@ -1850,11 +1878,14 @@ retry:
|
||||
host_err = -EINVAL;
|
||||
if (odentry == trap)
|
||||
goto out_dput_old;
|
||||
type = d_inode(odentry)->i_mode & S_IFMT;
|
||||
|
||||
ndentry = lookup_one_len(tname, tdentry, tlen);
|
||||
host_err = PTR_ERR(ndentry);
|
||||
if (IS_ERR(ndentry))
|
||||
goto out_dput_old;
|
||||
if (d_inode(ndentry))
|
||||
type = d_inode(ndentry)->i_mode & S_IFMT;
|
||||
host_err = -ENOTEMPTY;
|
||||
if (ndentry == trap)
|
||||
goto out_dput_new;
|
||||
@ -1892,7 +1923,18 @@ retry:
|
||||
out_dput_old:
|
||||
dput(odentry);
|
||||
out_nfserr:
|
||||
err = nfserrno(host_err);
|
||||
if (host_err == -EBUSY) {
|
||||
/*
|
||||
* See RFC 8881 Section 18.26.4 para 1-3: NFSv4 RENAME
|
||||
* wants a status unique to the object type.
|
||||
*/
|
||||
if (type != S_IFDIR)
|
||||
err = nfserr_file_open;
|
||||
else
|
||||
err = nfserr_acces;
|
||||
} else {
|
||||
err = nfserrno(host_err);
|
||||
}
|
||||
|
||||
if (!close_cached) {
|
||||
fh_fill_post_attrs(ffhp);
|
||||
@ -1919,9 +1961,17 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unlink a file or directory
|
||||
* N.B. After this call fhp needs an fh_put
|
||||
/**
|
||||
* nfsd_unlink - remove a directory entry
|
||||
* @rqstp: RPC transaction context
|
||||
* @fhp: the file handle of the parent directory to be modified
|
||||
* @type: enforced file type of the object to be removed
|
||||
* @fname: the name of directory entry to be removed
|
||||
* @flen: length of @fname in octets
|
||||
*
|
||||
* After this call fhp needs an fh_put.
|
||||
*
|
||||
* Returns a generic NFS status code in network byte-order.
|
||||
*/
|
||||
__be32
|
||||
nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
|
||||
@ -1995,15 +2045,17 @@ out_drop_write:
|
||||
fh_drop_write(fhp);
|
||||
out_nfserr:
|
||||
if (host_err == -EBUSY) {
|
||||
/* name is mounted-on. There is no perfect
|
||||
* error status.
|
||||
/*
|
||||
* See RFC 8881 Section 18.25.4 para 4: NFSv4 REMOVE
|
||||
* wants a status unique to the object type.
|
||||
*/
|
||||
err = nfserr_file_open;
|
||||
} else {
|
||||
err = nfserrno(host_err);
|
||||
if (type != S_IFDIR)
|
||||
err = nfserr_file_open;
|
||||
else
|
||||
err = nfserr_acces;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
return err != nfs_ok ? err : nfserrno(host_err);
|
||||
out_unlock:
|
||||
inode_unlock(dirp);
|
||||
goto out_drop_write;
|
||||
|
@ -279,10 +279,22 @@ struct export_operations {
|
||||
atomic attribute updates
|
||||
*/
|
||||
#define EXPORT_OP_FLUSH_ON_CLOSE (0x20) /* fs flushes file data on close */
|
||||
#define EXPORT_OP_ASYNC_LOCK (0x40) /* fs can do async lock request */
|
||||
#define EXPORT_OP_NOLOCKS (0x40) /* no file locking support */
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
/**
|
||||
* exportfs_cannot_lock() - check if export implements file locking
|
||||
* @export_ops: the nfs export operations to check
|
||||
*
|
||||
* Returns true if the export does not support file locking.
|
||||
*/
|
||||
static inline bool
|
||||
exportfs_cannot_lock(const struct export_operations *export_ops)
|
||||
{
|
||||
return export_ops->flags & EXPORT_OP_NOLOCKS;
|
||||
}
|
||||
|
||||
extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
|
||||
int *max_len, struct inode *parent,
|
||||
int flags);
|
||||
|
@ -27,11 +27,16 @@ struct posix_acl_entry {
|
||||
};
|
||||
|
||||
struct posix_acl {
|
||||
refcount_t a_refcount;
|
||||
unsigned int a_count;
|
||||
struct rcu_head a_rcu;
|
||||
/* New members MUST be added within the struct_group() macro below. */
|
||||
struct_group_tagged(posix_acl_hdr, hdr,
|
||||
refcount_t a_refcount;
|
||||
unsigned int a_count;
|
||||
struct rcu_head a_rcu;
|
||||
);
|
||||
struct posix_acl_entry a_entries[] __counted_by(a_count);
|
||||
};
|
||||
static_assert(offsetof(struct posix_acl, a_entries) == sizeof(struct posix_acl_hdr),
|
||||
"struct member likely outside of struct_group_tagged()");
|
||||
|
||||
#define FOREACH_ACL_ENTRY(pa, acl, pe) \
|
||||
for(pa=(acl)->a_entries, pe=pa+(acl)->a_count; pa<pe; pa++)
|
||||
|
29
include/uapi/linux/lockd_netlink.h
Normal file
29
include/uapi/linux/lockd_netlink.h
Normal file
@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
|
||||
/* Do not edit directly, auto-generated from: */
|
||||
/* Documentation/netlink/specs/lockd.yaml */
|
||||
/* YNL-GEN uapi header */
|
||||
|
||||
#ifndef _UAPI_LINUX_LOCKD_NETLINK_H
|
||||
#define _UAPI_LINUX_LOCKD_NETLINK_H
|
||||
|
||||
#define LOCKD_FAMILY_NAME "lockd"
|
||||
#define LOCKD_FAMILY_VERSION 1
|
||||
|
||||
enum {
|
||||
LOCKD_A_SERVER_GRACETIME = 1,
|
||||
LOCKD_A_SERVER_TCP_PORT,
|
||||
LOCKD_A_SERVER_UDP_PORT,
|
||||
|
||||
__LOCKD_A_SERVER_MAX,
|
||||
LOCKD_A_SERVER_MAX = (__LOCKD_A_SERVER_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
LOCKD_CMD_SERVER_SET = 1,
|
||||
LOCKD_CMD_SERVER_GET,
|
||||
|
||||
__LOCKD_CMD_MAX,
|
||||
LOCKD_CMD_MAX = (__LOCKD_CMD_MAX - 1)
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_LOCKD_NETLINK_H */
|
@ -138,60 +138,6 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* krb5_decrypt - simple decryption of an RPCSEC GSS payload
|
||||
* @tfm: initialized cipher transform
|
||||
* @iv: pointer to an IV
|
||||
* @in: ciphertext to decrypt
|
||||
* @out: OUT: plaintext
|
||||
* @length: length of input and output buffers, in bytes
|
||||
*
|
||||
* @iv may be NULL to force the use of an all-zero IV.
|
||||
* The buffer containing the IV must be as large as the
|
||||
* cipher's ivsize.
|
||||
*
|
||||
* Return values:
|
||||
* %0: @in successfully decrypted into @out
|
||||
* negative errno: @in not decrypted
|
||||
*/
|
||||
u32
|
||||
krb5_decrypt(
|
||||
struct crypto_sync_skcipher *tfm,
|
||||
void * iv,
|
||||
void * in,
|
||||
void * out,
|
||||
int length)
|
||||
{
|
||||
u32 ret = -EINVAL;
|
||||
struct scatterlist sg[1];
|
||||
u8 local_iv[GSS_KRB5_MAX_BLOCKSIZE] = {0};
|
||||
SYNC_SKCIPHER_REQUEST_ON_STACK(req, tfm);
|
||||
|
||||
if (length % crypto_sync_skcipher_blocksize(tfm) != 0)
|
||||
goto out;
|
||||
|
||||
if (crypto_sync_skcipher_ivsize(tfm) > GSS_KRB5_MAX_BLOCKSIZE) {
|
||||
dprintk("RPC: gss_k5decrypt: tfm iv size too large %d\n",
|
||||
crypto_sync_skcipher_ivsize(tfm));
|
||||
goto out;
|
||||
}
|
||||
if (iv)
|
||||
memcpy(local_iv, iv, crypto_sync_skcipher_ivsize(tfm));
|
||||
|
||||
memcpy(out, in, length);
|
||||
sg_init_one(sg, out, length);
|
||||
|
||||
skcipher_request_set_sync_tfm(req, tfm);
|
||||
skcipher_request_set_callback(req, 0, NULL, NULL);
|
||||
skcipher_request_set_crypt(req, sg, sg, length, local_iv);
|
||||
|
||||
ret = crypto_skcipher_decrypt(req);
|
||||
skcipher_request_zero(req);
|
||||
out:
|
||||
dprintk("RPC: gss_k5decrypt returns %d\n",ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
checksummer(struct scatterlist *sg, void *data)
|
||||
{
|
||||
@ -202,96 +148,6 @@ checksummer(struct scatterlist *sg, void *data)
|
||||
return crypto_ahash_update(req);
|
||||
}
|
||||
|
||||
/*
|
||||
* checksum the plaintext data and hdrlen bytes of the token header
|
||||
* The checksum is performed over the first 8 bytes of the
|
||||
* gss token header and then over the data body
|
||||
*/
|
||||
u32
|
||||
make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
|
||||
struct xdr_buf *body, int body_offset, u8 *cksumkey,
|
||||
unsigned int usage, struct xdr_netobj *cksumout)
|
||||
{
|
||||
struct crypto_ahash *tfm;
|
||||
struct ahash_request *req;
|
||||
struct scatterlist sg[1];
|
||||
int err = -1;
|
||||
u8 *checksumdata;
|
||||
unsigned int checksumlen;
|
||||
|
||||
if (cksumout->len < kctx->gk5e->cksumlength) {
|
||||
dprintk("%s: checksum buffer length, %u, too small for %s\n",
|
||||
__func__, cksumout->len, kctx->gk5e->name);
|
||||
return GSS_S_FAILURE;
|
||||
}
|
||||
|
||||
checksumdata = kmalloc(GSS_KRB5_MAX_CKSUM_LEN, GFP_KERNEL);
|
||||
if (checksumdata == NULL)
|
||||
return GSS_S_FAILURE;
|
||||
|
||||
tfm = crypto_alloc_ahash(kctx->gk5e->cksum_name, 0, CRYPTO_ALG_ASYNC);
|
||||
if (IS_ERR(tfm))
|
||||
goto out_free_cksum;
|
||||
|
||||
req = ahash_request_alloc(tfm, GFP_KERNEL);
|
||||
if (!req)
|
||||
goto out_free_ahash;
|
||||
|
||||
ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_SLEEP, NULL, NULL);
|
||||
|
||||
checksumlen = crypto_ahash_digestsize(tfm);
|
||||
|
||||
if (cksumkey != NULL) {
|
||||
err = crypto_ahash_setkey(tfm, cksumkey,
|
||||
kctx->gk5e->keylength);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = crypto_ahash_init(req);
|
||||
if (err)
|
||||
goto out;
|
||||
sg_init_one(sg, header, hdrlen);
|
||||
ahash_request_set_crypt(req, sg, NULL, hdrlen);
|
||||
err = crypto_ahash_update(req);
|
||||
if (err)
|
||||
goto out;
|
||||
err = xdr_process_buf(body, body_offset, body->len - body_offset,
|
||||
checksummer, req);
|
||||
if (err)
|
||||
goto out;
|
||||
ahash_request_set_crypt(req, NULL, checksumdata, 0);
|
||||
err = crypto_ahash_final(req);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
switch (kctx->gk5e->ctype) {
|
||||
case CKSUMTYPE_RSA_MD5:
|
||||
err = krb5_encrypt(kctx->seq, NULL, checksumdata,
|
||||
checksumdata, checksumlen);
|
||||
if (err)
|
||||
goto out;
|
||||
memcpy(cksumout->data,
|
||||
checksumdata + checksumlen - kctx->gk5e->cksumlength,
|
||||
kctx->gk5e->cksumlength);
|
||||
break;
|
||||
case CKSUMTYPE_HMAC_SHA1_DES3:
|
||||
memcpy(cksumout->data, checksumdata, kctx->gk5e->cksumlength);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
break;
|
||||
}
|
||||
cksumout->len = kctx->gk5e->cksumlength;
|
||||
out:
|
||||
ahash_request_free(req);
|
||||
out_free_ahash:
|
||||
crypto_free_ahash(tfm);
|
||||
out_free_cksum:
|
||||
kfree(checksumdata);
|
||||
return err ? GSS_S_FAILURE : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* gss_krb5_checksum - Compute the MAC for a GSS Wrap or MIC token
|
||||
* @tfm: an initialized hash transform
|
||||
|
@ -155,10 +155,6 @@ static inline int krb5_derive_key(struct krb5_ctx *kctx,
|
||||
|
||||
void krb5_make_confounder(u8 *p, int conflen);
|
||||
|
||||
u32 make_checksum(struct krb5_ctx *kctx, char *header, int hdrlen,
|
||||
struct xdr_buf *body, int body_offset, u8 *cksumkey,
|
||||
unsigned int usage, struct xdr_netobj *cksumout);
|
||||
|
||||
u32 gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
|
||||
const struct xdr_buf *body, int body_offset,
|
||||
struct xdr_netobj *cksumout);
|
||||
@ -166,9 +162,6 @@ u32 gss_krb5_checksum(struct crypto_ahash *tfm, char *header, int hdrlen,
|
||||
u32 krb5_encrypt(struct crypto_sync_skcipher *key, void *iv, void *in,
|
||||
void *out, int length);
|
||||
|
||||
u32 krb5_decrypt(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);
|
||||
|
||||
|
@ -1536,9 +1536,13 @@ static ssize_t write_flush(struct file *file, const char __user *buf,
|
||||
* or by one second if it has already reached the current time.
|
||||
* Newly added cache entries will always have ->last_refresh greater
|
||||
* that ->flush_time, so they don't get flushed prematurely.
|
||||
*
|
||||
* If someone frequently calls the flush interface, we should
|
||||
* immediately clean the corresponding cache_detail instead of
|
||||
* continuously accumulating nextcheck.
|
||||
*/
|
||||
|
||||
if (cd->flush_time >= now)
|
||||
if (cd->flush_time >= now && cd->flush_time < (now + 5))
|
||||
now = cd->flush_time + 1;
|
||||
|
||||
cd->flush_time = now;
|
||||
|
@ -621,7 +621,8 @@ static void __svc_rdma_free(struct work_struct *work)
|
||||
/* Destroy the CM ID */
|
||||
rdma_destroy_id(rdma->sc_cm_id);
|
||||
|
||||
rpcrdma_rn_unregister(device, &rdma->sc_rn);
|
||||
if (!test_bit(XPT_LISTENER, &rdma->sc_xprt.xpt_flags))
|
||||
rpcrdma_rn_unregister(device, &rdma->sc_rn);
|
||||
kfree(rdma);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user