mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2024-12-29 17:22:07 +00:00
NFSD 6.11 Release Notes
This is a light release containing optimizations, code clean-ups, and minor bug fixes. This development cycle focused on work outside of upstream kernel development: 1. Continuing to build upstream CI for NFSD based on kdevops 2. Continuing to focus on the quality of NFSD in LTS kernels 3. Participation in IETF nfsv4 WG discussions about NFSv4 ACLs, directory delegation, and NFSv4.2 COPY offload Notable features in v6.11 that were not pulled through the NFSD tree include NFS server-side support for the new pNFS NVMe layout type [RFC9561]. Functional testing for pNFS block layouts like this one has been introduced to our kdevops CI harness. Work on improving the resolution of file attribute time stamps in local filesystems is also ongoing tree-wide. As always I am grateful to NFSD contributors, reviewers, testers, and bug reporters who participated during this cycle. -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEKLLlsBKG3yQ88j7+M2qzM29mf5cFAmaVM0cACgkQM2qzM29m f5fzOQ//c5CXIF3zCLIUofm5eZSP2zIszmHR75rVTEnf0Ehm2BJRF6VZiTvWXRpz bOuswxfV1Bds+TofbPIP8jqDcMp8NIXemdb6+QMwh4FDY4M8t1v6TRYt35L6Ulrq bSV81aRS622ofQ35sRzwxpGX6rB6YbB+5L4EKuxdEqRKSB8rCxQcjPy2qypcWlRC hEAGDe3IiVxTz4VQBpASRqbH9Udw/XEqIhv5c8aLtPvl8i+yWyV5m2G5FMRdBj49 u8rCLoPi/mON8TDs2U4pbhcdgfBWWvGS6woFp6qrqM0wzXIPLalWsPGK3DUtuFUg onxsClJXMWUvW4k4hbjiqosduLGY/kMeX62Lx1dCj/gktrJpU0GDNR/XbBhHU+hj UT2CL8AfedC4FQekdyJri/rDgPiTMsf8UE0lgtchHMUXH0ztrjaRxMGiIFMm5vCl dJBMGJfCkKR/+U1YrGRQI0tPL8CJKYI8klOEhLoOsCr/WC9p4nvvAzSg4W9mNK5P ni4+KU4f/bj8U0Ap2bUacTpXj6W8VcwJWeuHahVA1Slo+eqXO401hj4W88dQmm9O ZDR5h+6PI6KoL/KL6I4EyOv+sIEtW3s18cEWbSSu3N/CPuhSGTx8d2J201shJXRN uDdMkvbwv48x20pgD2oTkPrZbJHOL3BK5/WPBg7pwpfkoRrBAhY= =Xd5e -----END PGP SIGNATURE----- Merge tag 'nfsd-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux Pull nfsd updates from Chuck Lever: "This is a light release containing optimizations, code clean-ups, and minor bug fixes. This development cycle focused on work outside of upstream kernel development: - Continuing to build upstream CI for NFSD based on kdevops - Continuing to focus on the quality of NFSD in LTS kernels - Participation in IETF nfsv4 WG discussions about NFSv4 ACLs, directory delegation, and NFSv4.2 COPY offload Notable features for v6.11 that do not come through the NFSD tree include NFS server-side support for the new pNFS NVMe layout type [RFC9561]. Functional testing for pNFS block layouts like this one has been introduced to our kdevops CI harness. Work on improving the resolution of file attribute time stamps in local filesystems is also ongoing tree-wide. As always I am grateful to NFSD contributors, reviewers, testers, and bug reporters who participated during this cycle" * tag 'nfsd-6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux: nfsd: nfsd_file_lease_notifier_call gets a file_lease as an argument gss_krb5: Fix the error handling path for crypto_sync_skcipher_setkey MAINTAINERS: Add a bugzilla link for NFSD nfsd: new netlink ops to get/set server pool_mode sunrpc: refactor pool_mode setting code nfsd: allow passing in array of thread counts via netlink nfsd: make nfsd_svc take an array of thread counts sunrpc: fix up the special handling of sv_nrpools == 1 SUNRPC: Add a trace point in svc_xprt_deferred_close NFSD: Support write delegations in LAYOUTGET lockd: Use *-y instead of *-objs in Makefile NFSD: Fix nfsdcld warning svcrdma: Handle ADDR_CHANGE CM event properly svcrdma: Refactor the creation of listener CMA ID NFSD: remove unused structs 'nfsd3_voidargs' NFSD: harden svcxdr_dupstr() and svcxdr_tmpalloc() against integer overflows
This commit is contained in:
commit
586a7a8542
@ -115,6 +115,15 @@ attribute-sets:
|
||||
type: nest
|
||||
nested-attributes: sock
|
||||
multi-attr: true
|
||||
-
|
||||
name: pool-mode
|
||||
attributes:
|
||||
-
|
||||
name: mode
|
||||
type: string
|
||||
-
|
||||
name: npools
|
||||
type: u32
|
||||
|
||||
operations:
|
||||
list:
|
||||
@ -195,3 +204,21 @@ operations:
|
||||
reply:
|
||||
attributes:
|
||||
- addr
|
||||
-
|
||||
name: pool-mode-set
|
||||
doc: set the current server pool-mode
|
||||
attribute-set: pool-mode
|
||||
flags: [ admin-perm ]
|
||||
do:
|
||||
request:
|
||||
attributes:
|
||||
- mode
|
||||
-
|
||||
name: pool-mode-get
|
||||
doc: get info about server pool-mode
|
||||
attribute-set: pool-mode
|
||||
do:
|
||||
reply:
|
||||
attributes:
|
||||
- mode
|
||||
- npools
|
||||
|
@ -12065,7 +12065,7 @@ R: Dai Ngo <Dai.Ngo@oracle.com>
|
||||
R: Tom Talpey <tom@talpey.com>
|
||||
L: linux-nfs@vger.kernel.org
|
||||
S: Supported
|
||||
W: http://nfs.sourceforge.net/
|
||||
B: https://bugzilla.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/cel/linux.git
|
||||
F: Documentation/filesystems/nfs/
|
||||
F: fs/lockd/
|
||||
|
@ -7,8 +7,7 @@ ccflags-y += -I$(src) # needed for trace events
|
||||
|
||||
obj-$(CONFIG_LOCKD) += lockd.o
|
||||
|
||||
lockd-objs-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
|
||||
lockd-objs-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
|
||||
lockd-objs-$(CONFIG_PROC_FS) += procfs.o
|
||||
lockd-objs := $(lockd-objs-y)
|
||||
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
|
||||
lockd-$(CONFIG_LOCKD_V4) += clnt4xdr.o xdr4.o svc4proc.o
|
||||
lockd-$(CONFIG_PROC_FS) += procfs.o
|
||||
|
@ -162,7 +162,7 @@ config NFSD_V4_SECURITY_LABEL
|
||||
config NFSD_LEGACY_CLIENT_TRACKING
|
||||
bool "Support legacy NFSv4 client tracking methods (DEPRECATED)"
|
||||
depends on NFSD_V4
|
||||
default n
|
||||
default y
|
||||
help
|
||||
The NFSv4 server needs to store a small amount of information on
|
||||
stable storage in order to handle state recovery after reboot. Most
|
||||
|
@ -664,7 +664,7 @@ static int
|
||||
nfsd_file_lease_notifier_call(struct notifier_block *nb, unsigned long arg,
|
||||
void *data)
|
||||
{
|
||||
struct file_lock *fl = data;
|
||||
struct file_lease *fl = data;
|
||||
|
||||
/* Only close files for F_SETLEASE leases */
|
||||
if (fl->c.flc_flags & FL_LEASE)
|
||||
|
@ -40,6 +40,11 @@ static const struct nla_policy nfsd_listener_set_nl_policy[NFSD_A_SERVER_SOCK_AD
|
||||
[NFSD_A_SERVER_SOCK_ADDR] = NLA_POLICY_NESTED(nfsd_sock_nl_policy),
|
||||
};
|
||||
|
||||
/* NFSD_CMD_POOL_MODE_SET - do */
|
||||
static const struct nla_policy nfsd_pool_mode_set_nl_policy[NFSD_A_POOL_MODE_MODE + 1] = {
|
||||
[NFSD_A_POOL_MODE_MODE] = { .type = NLA_NUL_STRING, },
|
||||
};
|
||||
|
||||
/* Ops table for nfsd */
|
||||
static const struct genl_split_ops nfsd_nl_ops[] = {
|
||||
{
|
||||
@ -83,6 +88,18 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
|
||||
.doit = nfsd_nl_listener_get_doit,
|
||||
.flags = GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_POOL_MODE_SET,
|
||||
.doit = nfsd_nl_pool_mode_set_doit,
|
||||
.policy = nfsd_pool_mode_set_nl_policy,
|
||||
.maxattr = NFSD_A_POOL_MODE_MODE,
|
||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||
},
|
||||
{
|
||||
.cmd = NFSD_CMD_POOL_MODE_GET,
|
||||
.doit = nfsd_nl_pool_mode_get_doit,
|
||||
.flags = GENL_CMD_CAP_DO,
|
||||
},
|
||||
};
|
||||
|
||||
struct genl_family nfsd_nl_family __ro_after_init = {
|
||||
|
@ -23,6 +23,8 @@ int nfsd_nl_version_set_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
int nfsd_nl_version_get_doit(struct sk_buff *skb, struct genl_info *info);
|
||||
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);
|
||||
|
||||
extern struct genl_family nfsd_nl_family;
|
||||
|
||||
|
@ -308,8 +308,6 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
|
||||
fh_put(&resp->fh);
|
||||
}
|
||||
|
||||
struct nfsd3_voidargs { int dummy; };
|
||||
|
||||
#define ST 1 /* status*/
|
||||
#define AT 21 /* attributes */
|
||||
#define pAT (1+AT) /* post attributes - conditional */
|
||||
|
@ -221,8 +221,6 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
|
||||
posix_acl_release(resp->acl_default);
|
||||
}
|
||||
|
||||
struct nfsd3_voidargs { int dummy; };
|
||||
|
||||
#define ST 1 /* status*/
|
||||
#define AT 21 /* attributes */
|
||||
#define pAT (1+AT) /* post attributes - conditional */
|
||||
|
@ -2269,7 +2269,7 @@ nfsd4_layoutget(struct svc_rqst *rqstp,
|
||||
const struct nfsd4_layout_ops *ops;
|
||||
struct nfs4_layout_stateid *ls;
|
||||
__be32 nfserr;
|
||||
int accmode = NFSD_MAY_READ_IF_EXEC;
|
||||
int accmode = NFSD_MAY_READ_IF_EXEC | NFSD_MAY_OWNER_OVERRIDE;
|
||||
|
||||
switch (lgp->lg_seg.iomode) {
|
||||
case IOMODE_READ:
|
||||
@ -2359,7 +2359,8 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp,
|
||||
struct nfs4_layout_stateid *ls;
|
||||
__be32 nfserr;
|
||||
|
||||
nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_WRITE);
|
||||
nfserr = fh_verify(rqstp, current_fh, 0,
|
||||
NFSD_MAY_WRITE | NFSD_MAY_OWNER_OVERRIDE);
|
||||
if (nfserr)
|
||||
goto out;
|
||||
|
||||
|
@ -2086,8 +2086,8 @@ nfsd4_client_tracking_init(struct net *net)
|
||||
status = nn->client_tracking_ops->init(net);
|
||||
out:
|
||||
if (status) {
|
||||
printk(KERN_WARNING "NFSD: Unable to initialize client "
|
||||
"recovery tracking! (%d)\n", status);
|
||||
pr_warn("NFSD: Unable to initialize client recovery tracking! (%d)\n", status);
|
||||
pr_warn("NFSD: Is nfsdcld running? If not, enable CONFIG_NFSD_LEGACY_CLIENT_TRACKING.\n");
|
||||
nn->client_tracking_ops = NULL;
|
||||
}
|
||||
return status;
|
||||
|
@ -118,11 +118,11 @@ static int zero_clientid(clientid_t *clid)
|
||||
* operation described in @argp finishes.
|
||||
*/
|
||||
static void *
|
||||
svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
|
||||
svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, size_t len)
|
||||
{
|
||||
struct svcxdr_tmpbuf *tb;
|
||||
|
||||
tb = kmalloc(sizeof(*tb) + len, GFP_KERNEL);
|
||||
tb = kmalloc(struct_size(tb, buf, len), GFP_KERNEL);
|
||||
if (!tb)
|
||||
return NULL;
|
||||
tb->next = argp->to_free;
|
||||
@ -138,9 +138,9 @@ svcxdr_tmpalloc(struct nfsd4_compoundargs *argp, u32 len)
|
||||
* buffer might end on a page boundary.
|
||||
*/
|
||||
static char *
|
||||
svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
|
||||
svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, size_t len)
|
||||
{
|
||||
char *p = svcxdr_tmpalloc(argp, len + 1);
|
||||
char *p = svcxdr_tmpalloc(argp, size_add(len, 1));
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
@ -150,7 +150,7 @@ svcxdr_dupstr(struct nfsd4_compoundargs *argp, void *buf, u32 len)
|
||||
}
|
||||
|
||||
static void *
|
||||
svcxdr_savemem(struct nfsd4_compoundargs *argp, __be32 *p, u32 len)
|
||||
svcxdr_savemem(struct nfsd4_compoundargs *argp, __be32 *p, size_t len)
|
||||
{
|
||||
__be32 *tmp;
|
||||
|
||||
@ -2146,7 +2146,7 @@ nfsd4_decode_clone(struct nfsd4_compoundargs *argp, union nfsd4_op_u *u)
|
||||
*/
|
||||
static __be32
|
||||
nfsd4_vbuf_from_vector(struct nfsd4_compoundargs *argp, struct xdr_buf *xdr,
|
||||
char **bufp, u32 buflen)
|
||||
char **bufp, size_t buflen)
|
||||
{
|
||||
struct page **pages = xdr->pages;
|
||||
struct kvec *head = xdr->head;
|
||||
|
@ -406,7 +406,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
|
||||
return -EINVAL;
|
||||
trace_nfsd_ctl_threads(net, newthreads);
|
||||
mutex_lock(&nfsd_mutex);
|
||||
rv = nfsd_svc(newthreads, net, file->f_cred, NULL);
|
||||
rv = nfsd_svc(1, &newthreads, net, file->f_cred, NULL);
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
@ -481,6 +481,14 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
|
||||
goto out_free;
|
||||
trace_nfsd_ctl_pool_threads(net, i, nthreads[i]);
|
||||
}
|
||||
|
||||
/*
|
||||
* There must always be a thread in pool 0; the admin
|
||||
* can't shut down NFS completely using pool_threads.
|
||||
*/
|
||||
if (nthreads[0] == 0)
|
||||
nthreads[0] = 1;
|
||||
|
||||
rv = nfsd_set_nrthreads(i, nthreads, net);
|
||||
if (rv)
|
||||
goto out_free;
|
||||
@ -1637,7 +1645,7 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
|
||||
*/
|
||||
int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
int nthreads = 0, count = 0, nrpools, ret = -EOPNOTSUPP, rem;
|
||||
int *nthreads, count = 0, nrpools, i, ret = -EOPNOTSUPP, rem;
|
||||
struct net *net = genl_info_net(info);
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
const struct nlattr *attr;
|
||||
@ -1654,15 +1662,22 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
|
||||
mutex_lock(&nfsd_mutex);
|
||||
|
||||
nrpools = nfsd_nrpools(net);
|
||||
if (nrpools && count > nrpools)
|
||||
count = nrpools;
|
||||
|
||||
/* XXX: make this handle non-global pool-modes */
|
||||
if (count > 1)
|
||||
nrpools = max(count, nfsd_nrpools(net));
|
||||
nthreads = kcalloc(nrpools, sizeof(int), GFP_KERNEL);
|
||||
if (!nthreads) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
nlmsg_for_each_attr(attr, info->nlhdr, GENL_HDRLEN, rem) {
|
||||
if (nla_type(attr) == NFSD_A_SERVER_THREADS) {
|
||||
nthreads[i++] = nla_get_u32(attr);
|
||||
if (i >= nrpools)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
nthreads = nla_get_u32(info->attrs[NFSD_A_SERVER_THREADS]);
|
||||
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
|
||||
info->attrs[NFSD_A_SERVER_LEASETIME] ||
|
||||
info->attrs[NFSD_A_SERVER_SCOPE]) {
|
||||
@ -1696,12 +1711,13 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
scope = nla_data(attr);
|
||||
}
|
||||
|
||||
ret = nfsd_svc(nthreads, net, get_current_cred(), scope);
|
||||
|
||||
ret = nfsd_svc(nrpools, nthreads, net, get_current_cred(), scope);
|
||||
if (ret > 0)
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
mutex_unlock(&nfsd_mutex);
|
||||
|
||||
return ret == nthreads ? 0 : ret;
|
||||
kfree(nthreads);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2140,6 +2156,63 @@ int nfsd_nl_listener_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_pool_mode_set_doit - set the number of running threads
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Return 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_pool_mode_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
const struct nlattr *attr;
|
||||
|
||||
if (GENL_REQ_ATTR_CHECK(info, NFSD_A_POOL_MODE_MODE))
|
||||
return -EINVAL;
|
||||
|
||||
attr = info->attrs[NFSD_A_POOL_MODE_MODE];
|
||||
return sunrpc_set_pool_mode(nla_data(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_nl_pool_mode_get_doit - get info about pool_mode
|
||||
* @skb: reply buffer
|
||||
* @info: netlink metadata and command arguments
|
||||
*
|
||||
* Return 0 on success or a negative errno.
|
||||
*/
|
||||
int nfsd_nl_pool_mode_get_doit(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct net *net = genl_info_net(info);
|
||||
char buf[16];
|
||||
void *hdr;
|
||||
int err;
|
||||
|
||||
if (sunrpc_get_pool_mode(buf, ARRAY_SIZE(buf)) >= ARRAY_SIZE(buf))
|
||||
return -ERANGE;
|
||||
|
||||
skb = genlmsg_new(GENLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
err = -EMSGSIZE;
|
||||
hdr = genlmsg_iput(skb, info);
|
||||
if (!hdr)
|
||||
goto err_free_msg;
|
||||
|
||||
err = nla_put_string(skb, NFSD_A_POOL_MODE_MODE, buf) |
|
||||
nla_put_u32(skb, NFSD_A_POOL_MODE_NPOOLS, nfsd_nrpools(net));
|
||||
if (err)
|
||||
goto err_free_msg;
|
||||
|
||||
genlmsg_end(skb, hdr);
|
||||
return genlmsg_reply(skb, info);
|
||||
|
||||
err_free_msg:
|
||||
nlmsg_free(skb);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_net_init - Prepare the nfsd_net portion of a new net namespace
|
||||
* @net: a freshly-created network namespace
|
||||
|
@ -103,7 +103,8 @@ bool nfssvc_encode_voidres(struct svc_rqst *rqstp,
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
int nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scope);
|
||||
int nfsd_svc(int n, int *nservers, struct net *net,
|
||||
const struct cred *cred, const char *scope);
|
||||
int nfsd_dispatch(struct svc_rqst *rqstp);
|
||||
|
||||
int nfsd_nrthreads(struct net *);
|
||||
|
@ -709,6 +709,19 @@ int nfsd_get_nrthreads(int n, int *nthreads, struct net *net)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_set_nrthreads - set the number of running threads in the net's service
|
||||
* @n: number of array members in @nthreads
|
||||
* @nthreads: array of thread counts for each pool
|
||||
* @net: network namespace to operate within
|
||||
*
|
||||
* This function alters the number of running threads for the given network
|
||||
* namespace in each pool. If passed an array longer then the number of pools
|
||||
* the extra pool settings are ignored. If passed an array shorter than the
|
||||
* number of pools, the missing values are interpreted as 0's.
|
||||
*
|
||||
* Returns 0 on success or a negative errno on error.
|
||||
*/
|
||||
int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
|
||||
{
|
||||
int i = 0;
|
||||
@ -716,11 +729,18 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
|
||||
int err = 0;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
|
||||
WARN_ON(!mutex_is_locked(&nfsd_mutex));
|
||||
lockdep_assert_held(&nfsd_mutex);
|
||||
|
||||
if (nn->nfsd_serv == NULL || n <= 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Special case: When n == 1, pass in NULL for the pool, so that the
|
||||
* change is distributed equally among them.
|
||||
*/
|
||||
if (n == 1)
|
||||
return svc_set_num_threads(nn->nfsd_serv, NULL, nthreads[0]);
|
||||
|
||||
if (n > nn->nfsd_serv->sv_nrpools)
|
||||
n = nn->nfsd_serv->sv_nrpools;
|
||||
|
||||
@ -743,31 +763,40 @@ int nfsd_set_nrthreads(int n, int *nthreads, struct net *net)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* There must always be a thread in pool 0; the admin
|
||||
* can't shut down NFS completely using pool_threads.
|
||||
*/
|
||||
if (nthreads[0] == 0)
|
||||
nthreads[0] = 1;
|
||||
|
||||
/* apply the new numbers */
|
||||
for (i = 0; i < n; i++) {
|
||||
err = svc_set_num_threads(nn->nfsd_serv,
|
||||
&nn->nfsd_serv->sv_pools[i],
|
||||
nthreads[i]);
|
||||
if (err)
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Anything undefined in array is considered to be 0 */
|
||||
for (i = n; i < nn->nfsd_serv->sv_nrpools; ++i) {
|
||||
err = svc_set_num_threads(nn->nfsd_serv,
|
||||
&nn->nfsd_serv->sv_pools[i],
|
||||
0);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adjust the number of threads and return the new number of threads.
|
||||
* This is also the function that starts the server if necessary, if
|
||||
* this is the first time nrservs is nonzero.
|
||||
/**
|
||||
* nfsd_svc: start up or shut down the nfsd server
|
||||
* @n: number of array members in @nthreads
|
||||
* @nthreads: array of thread counts for each pool
|
||||
* @net: network namespace to operate within
|
||||
* @cred: credentials to use for xprt creation
|
||||
* @scope: server scope value (defaults to nodename)
|
||||
*
|
||||
* Adjust the number of threads in each pool and return the new
|
||||
* total number of threads in the service.
|
||||
*/
|
||||
int
|
||||
nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scope)
|
||||
nfsd_svc(int n, int *nthreads, struct net *net, const struct cred *cred, const char *scope)
|
||||
{
|
||||
int error;
|
||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||
@ -777,13 +806,6 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scop
|
||||
|
||||
dprintk("nfsd: creating service\n");
|
||||
|
||||
nrservs = max(nrservs, 0);
|
||||
nrservs = min(nrservs, NFSD_MAXSERVS);
|
||||
error = 0;
|
||||
|
||||
if (nrservs == 0 && nn->nfsd_serv == NULL)
|
||||
goto out;
|
||||
|
||||
strscpy(nn->nfsd_name, scope ? scope : utsname()->nodename,
|
||||
sizeof(nn->nfsd_name));
|
||||
|
||||
@ -795,7 +817,7 @@ nfsd_svc(int nrservs, struct net *net, const struct cred *cred, const char *scop
|
||||
error = nfsd_startup_net(net, cred);
|
||||
if (error)
|
||||
goto out_put;
|
||||
error = svc_set_num_threads(serv, NULL, nrservs);
|
||||
error = nfsd_set_nrthreads(n, nthreads, net);
|
||||
if (error)
|
||||
goto out_put;
|
||||
error = serv->sv_nrthreads;
|
||||
|
@ -85,6 +85,7 @@ struct svc_serv {
|
||||
char * sv_name; /* service name */
|
||||
|
||||
unsigned int sv_nrpools; /* number of thread pools */
|
||||
bool sv_is_pooled; /* is this a pooled service? */
|
||||
struct svc_pool * sv_pools; /* array of thread pools */
|
||||
int (*sv_threadfn)(void *data);
|
||||
|
||||
@ -398,6 +399,8 @@ struct svc_procedure {
|
||||
/*
|
||||
* Function prototypes.
|
||||
*/
|
||||
int sunrpc_set_pool_mode(const char *val);
|
||||
int sunrpc_get_pool_mode(char *val, size_t size);
|
||||
int svc_rpcb_setup(struct svc_serv *serv, struct net *net);
|
||||
void svc_rpcb_cleanup(struct svc_serv *serv, struct net *net);
|
||||
int svc_bind(struct svc_serv *serv, struct net *net);
|
||||
|
@ -70,6 +70,14 @@ enum {
|
||||
NFSD_A_SERVER_SOCK_MAX = (__NFSD_A_SERVER_SOCK_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_A_POOL_MODE_MODE = 1,
|
||||
NFSD_A_POOL_MODE_NPOOLS,
|
||||
|
||||
__NFSD_A_POOL_MODE_MAX,
|
||||
NFSD_A_POOL_MODE_MAX = (__NFSD_A_POOL_MODE_MAX - 1)
|
||||
};
|
||||
|
||||
enum {
|
||||
NFSD_CMD_RPC_STATUS_GET = 1,
|
||||
NFSD_CMD_THREADS_SET,
|
||||
@ -78,6 +86,8 @@ enum {
|
||||
NFSD_CMD_VERSION_GET,
|
||||
NFSD_CMD_LISTENER_SET,
|
||||
NFSD_CMD_LISTENER_GET,
|
||||
NFSD_CMD_POOL_MODE_SET,
|
||||
NFSD_CMD_POOL_MODE_GET,
|
||||
|
||||
__NFSD_CMD_MAX,
|
||||
NFSD_CMD_MAX = (__NFSD_CMD_MAX - 1)
|
||||
|
@ -168,7 +168,7 @@ static int krb5_DK(const struct gss_krb5_enctype *gk5e,
|
||||
goto err_return;
|
||||
blocksize = crypto_sync_skcipher_blocksize(cipher);
|
||||
if (crypto_sync_skcipher_setkey(cipher, inkey->data, inkey->len))
|
||||
goto err_return;
|
||||
goto err_free_cipher;
|
||||
|
||||
ret = -ENOMEM;
|
||||
inblockdata = kmalloc(blocksize, gfp_mask);
|
||||
|
111
net/sunrpc/svc.c
111
net/sunrpc/svc.c
@ -72,57 +72,100 @@ static struct svc_pool_map svc_pool_map = {
|
||||
static DEFINE_MUTEX(svc_pool_map_mutex);/* protects svc_pool_map.count only */
|
||||
|
||||
static int
|
||||
param_set_pool_mode(const char *val, const struct kernel_param *kp)
|
||||
__param_set_pool_mode(const char *val, struct svc_pool_map *m)
|
||||
{
|
||||
int *ip = (int *)kp->arg;
|
||||
struct svc_pool_map *m = &svc_pool_map;
|
||||
int err;
|
||||
int err, mode;
|
||||
|
||||
mutex_lock(&svc_pool_map_mutex);
|
||||
|
||||
err = -EBUSY;
|
||||
if (m->count)
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
if (!strncmp(val, "auto", 4))
|
||||
*ip = SVC_POOL_AUTO;
|
||||
mode = SVC_POOL_AUTO;
|
||||
else if (!strncmp(val, "global", 6))
|
||||
*ip = SVC_POOL_GLOBAL;
|
||||
mode = SVC_POOL_GLOBAL;
|
||||
else if (!strncmp(val, "percpu", 6))
|
||||
*ip = SVC_POOL_PERCPU;
|
||||
mode = SVC_POOL_PERCPU;
|
||||
else if (!strncmp(val, "pernode", 7))
|
||||
*ip = SVC_POOL_PERNODE;
|
||||
mode = SVC_POOL_PERNODE;
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (m->count == 0)
|
||||
m->mode = mode;
|
||||
else if (mode != m->mode)
|
||||
err = -EBUSY;
|
||||
out:
|
||||
mutex_unlock(&svc_pool_map_mutex);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
param_get_pool_mode(char *buf, const struct kernel_param *kp)
|
||||
param_set_pool_mode(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
int *ip = (int *)kp->arg;
|
||||
struct svc_pool_map *m = kp->arg;
|
||||
|
||||
switch (*ip)
|
||||
return __param_set_pool_mode(val, m);
|
||||
}
|
||||
|
||||
int sunrpc_set_pool_mode(const char *val)
|
||||
{
|
||||
return __param_set_pool_mode(val, &svc_pool_map);
|
||||
}
|
||||
EXPORT_SYMBOL(sunrpc_set_pool_mode);
|
||||
|
||||
/**
|
||||
* sunrpc_get_pool_mode - get the current pool_mode for the host
|
||||
* @buf: where to write the current pool_mode
|
||||
* @size: size of @buf
|
||||
*
|
||||
* Grab the current pool_mode from the svc_pool_map and write
|
||||
* the resulting string to @buf. Returns the number of characters
|
||||
* written to @buf (a'la snprintf()).
|
||||
*/
|
||||
int
|
||||
sunrpc_get_pool_mode(char *buf, size_t size)
|
||||
{
|
||||
struct svc_pool_map *m = &svc_pool_map;
|
||||
|
||||
switch (m->mode)
|
||||
{
|
||||
case SVC_POOL_AUTO:
|
||||
return sysfs_emit(buf, "auto\n");
|
||||
return snprintf(buf, size, "auto");
|
||||
case SVC_POOL_GLOBAL:
|
||||
return sysfs_emit(buf, "global\n");
|
||||
return snprintf(buf, size, "global");
|
||||
case SVC_POOL_PERCPU:
|
||||
return sysfs_emit(buf, "percpu\n");
|
||||
return snprintf(buf, size, "percpu");
|
||||
case SVC_POOL_PERNODE:
|
||||
return sysfs_emit(buf, "pernode\n");
|
||||
return snprintf(buf, size, "pernode");
|
||||
default:
|
||||
return sysfs_emit(buf, "%d\n", *ip);
|
||||
return snprintf(buf, size, "%d", m->mode);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(sunrpc_get_pool_mode);
|
||||
|
||||
static int
|
||||
param_get_pool_mode(char *buf, const struct kernel_param *kp)
|
||||
{
|
||||
char str[16];
|
||||
int len;
|
||||
|
||||
len = sunrpc_get_pool_mode(str, ARRAY_SIZE(str));
|
||||
|
||||
/* Ensure we have room for newline and NUL */
|
||||
len = min_t(int, len, ARRAY_SIZE(str) - 2);
|
||||
|
||||
/* tack on the newline */
|
||||
str[len] = '\n';
|
||||
str[len + 1] = '\0';
|
||||
|
||||
return sysfs_emit(buf, str);
|
||||
}
|
||||
|
||||
module_param_call(pool_mode, param_set_pool_mode, param_get_pool_mode,
|
||||
&svc_pool_map.mode, 0644);
|
||||
&svc_pool_map, 0644);
|
||||
|
||||
/*
|
||||
* Detect best pool mapping mode heuristically,
|
||||
@ -250,10 +293,8 @@ svc_pool_map_get(void)
|
||||
int npools = -1;
|
||||
|
||||
mutex_lock(&svc_pool_map_mutex);
|
||||
|
||||
if (m->count++) {
|
||||
mutex_unlock(&svc_pool_map_mutex);
|
||||
WARN_ON_ONCE(m->npools <= 1);
|
||||
return m->npools;
|
||||
}
|
||||
|
||||
@ -275,32 +316,21 @@ svc_pool_map_get(void)
|
||||
m->mode = SVC_POOL_GLOBAL;
|
||||
}
|
||||
m->npools = npools;
|
||||
|
||||
if (npools == 1)
|
||||
/* service is unpooled, so doesn't hold a reference */
|
||||
m->count--;
|
||||
|
||||
mutex_unlock(&svc_pool_map_mutex);
|
||||
return npools;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop a reference to the global map of cpus to pools, if
|
||||
* pools were in use, i.e. if npools > 1.
|
||||
* Drop a reference to the global map of cpus to pools.
|
||||
* When the last reference is dropped, the map data is
|
||||
* freed; this allows the sysadmin to change the pool
|
||||
* mode using the pool_mode module option without
|
||||
* rebooting or re-loading sunrpc.ko.
|
||||
* freed; this allows the sysadmin to change the pool.
|
||||
*/
|
||||
static void
|
||||
svc_pool_map_put(int npools)
|
||||
svc_pool_map_put(void)
|
||||
{
|
||||
struct svc_pool_map *m = &svc_pool_map;
|
||||
|
||||
if (npools <= 1)
|
||||
return;
|
||||
mutex_lock(&svc_pool_map_mutex);
|
||||
|
||||
if (!--m->count) {
|
||||
kfree(m->to_pool);
|
||||
m->to_pool = NULL;
|
||||
@ -308,7 +338,6 @@ svc_pool_map_put(int npools)
|
||||
m->pool_to = NULL;
|
||||
m->npools = 0;
|
||||
}
|
||||
|
||||
mutex_unlock(&svc_pool_map_mutex);
|
||||
}
|
||||
|
||||
@ -553,9 +582,10 @@ struct svc_serv *svc_create_pooled(struct svc_program *prog,
|
||||
serv = __svc_create(prog, stats, bufsize, npools, threadfn);
|
||||
if (!serv)
|
||||
goto out_err;
|
||||
serv->sv_is_pooled = true;
|
||||
return serv;
|
||||
out_err:
|
||||
svc_pool_map_put(npools);
|
||||
svc_pool_map_put();
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(svc_create_pooled);
|
||||
@ -585,7 +615,8 @@ svc_destroy(struct svc_serv **servp)
|
||||
|
||||
cache_clean_deferred(serv);
|
||||
|
||||
svc_pool_map_put(serv->sv_nrpools);
|
||||
if (serv->sv_is_pooled)
|
||||
svc_pool_map_put();
|
||||
|
||||
for (i = 0; i < serv->sv_nrpools; i++) {
|
||||
struct svc_pool *pool = &serv->sv_pools[i];
|
||||
|
@ -157,6 +157,7 @@ int svc_print_xprts(char *buf, int maxlen)
|
||||
*/
|
||||
void svc_xprt_deferred_close(struct svc_xprt *xprt)
|
||||
{
|
||||
trace_svc_xprt_close(xprt);
|
||||
if (!test_and_set_bit(XPT_CLOSE, &xprt->xpt_flags))
|
||||
svc_xprt_enqueue(xprt);
|
||||
}
|
||||
|
@ -65,6 +65,8 @@
|
||||
|
||||
static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv,
|
||||
struct net *net, int node);
|
||||
static int svc_rdma_listen_handler(struct rdma_cm_id *cma_id,
|
||||
struct rdma_cm_event *event);
|
||||
static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
|
||||
struct net *net,
|
||||
struct sockaddr *sa, int salen,
|
||||
@ -122,6 +124,41 @@ static void qp_event_handler(struct ib_event *event, void *context)
|
||||
}
|
||||
}
|
||||
|
||||
static struct rdma_cm_id *
|
||||
svc_rdma_create_listen_id(struct net *net, struct sockaddr *sap,
|
||||
void *context)
|
||||
{
|
||||
struct rdma_cm_id *listen_id;
|
||||
int ret;
|
||||
|
||||
listen_id = rdma_create_id(net, svc_rdma_listen_handler, context,
|
||||
RDMA_PS_TCP, IB_QPT_RC);
|
||||
if (IS_ERR(listen_id))
|
||||
return listen_id;
|
||||
|
||||
/* Allow both IPv4 and IPv6 sockets to bind a single port
|
||||
* at the same time.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
ret = rdma_set_afonly(listen_id, 1);
|
||||
if (ret)
|
||||
goto out_destroy;
|
||||
#endif
|
||||
ret = rdma_bind_addr(listen_id, sap);
|
||||
if (ret)
|
||||
goto out_destroy;
|
||||
|
||||
ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
|
||||
if (ret)
|
||||
goto out_destroy;
|
||||
|
||||
return listen_id;
|
||||
|
||||
out_destroy:
|
||||
rdma_destroy_id(listen_id);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
static struct svcxprt_rdma *svc_rdma_create_xprt(struct svc_serv *serv,
|
||||
struct net *net, int node)
|
||||
{
|
||||
@ -247,17 +284,31 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id,
|
||||
*
|
||||
* Return values:
|
||||
* %0: Do not destroy @cma_id
|
||||
* %1: Destroy @cma_id (never returned here)
|
||||
* %1: Destroy @cma_id
|
||||
*
|
||||
* NB: There is never a DEVICE_REMOVAL event for INADDR_ANY listeners.
|
||||
*/
|
||||
static int svc_rdma_listen_handler(struct rdma_cm_id *cma_id,
|
||||
struct rdma_cm_event *event)
|
||||
{
|
||||
struct sockaddr *sap = (struct sockaddr *)&cma_id->route.addr.src_addr;
|
||||
struct svcxprt_rdma *cma_xprt = cma_id->context;
|
||||
struct svc_xprt *cma_rdma = &cma_xprt->sc_xprt;
|
||||
struct rdma_cm_id *listen_id;
|
||||
|
||||
switch (event->event) {
|
||||
case RDMA_CM_EVENT_CONNECT_REQUEST:
|
||||
handle_connect_req(cma_id, &event->param.conn);
|
||||
break;
|
||||
case RDMA_CM_EVENT_ADDR_CHANGE:
|
||||
listen_id = svc_rdma_create_listen_id(cma_rdma->xpt_net,
|
||||
sap, cma_xprt);
|
||||
if (IS_ERR(listen_id)) {
|
||||
pr_err("Listener dead, address change failed for device %s\n",
|
||||
cma_id->device->name);
|
||||
} else
|
||||
cma_xprt->sc_cm_id = listen_id;
|
||||
return 1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -307,7 +358,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
|
||||
{
|
||||
struct rdma_cm_id *listen_id;
|
||||
struct svcxprt_rdma *cma_xprt;
|
||||
int ret;
|
||||
|
||||
if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
|
||||
return ERR_PTR(-EAFNOSUPPORT);
|
||||
@ -317,30 +367,13 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
|
||||
set_bit(XPT_LISTENER, &cma_xprt->sc_xprt.xpt_flags);
|
||||
strcpy(cma_xprt->sc_xprt.xpt_remotebuf, "listener");
|
||||
|
||||
listen_id = rdma_create_id(net, svc_rdma_listen_handler, cma_xprt,
|
||||
RDMA_PS_TCP, IB_QPT_RC);
|
||||
listen_id = svc_rdma_create_listen_id(net, sa, cma_xprt);
|
||||
if (IS_ERR(listen_id)) {
|
||||
ret = PTR_ERR(listen_id);
|
||||
goto err0;
|
||||
kfree(cma_xprt);
|
||||
return (struct svc_xprt *)listen_id;
|
||||
}
|
||||
|
||||
/* Allow both IPv4 and IPv6 sockets to bind a single port
|
||||
* at the same time.
|
||||
*/
|
||||
#if IS_ENABLED(CONFIG_IPV6)
|
||||
ret = rdma_set_afonly(listen_id, 1);
|
||||
if (ret)
|
||||
goto err1;
|
||||
#endif
|
||||
ret = rdma_bind_addr(listen_id, sa);
|
||||
if (ret)
|
||||
goto err1;
|
||||
cma_xprt->sc_cm_id = listen_id;
|
||||
|
||||
ret = rdma_listen(listen_id, RPCRDMA_LISTEN_BACKLOG);
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
/*
|
||||
* We need to use the address from the cm_id in case the
|
||||
* caller specified 0 for the port number.
|
||||
@ -349,12 +382,6 @@ static struct svc_xprt *svc_rdma_create(struct svc_serv *serv,
|
||||
svc_xprt_set_local(&cma_xprt->sc_xprt, sa, salen);
|
||||
|
||||
return &cma_xprt->sc_xprt;
|
||||
|
||||
err1:
|
||||
rdma_destroy_id(listen_id);
|
||||
err0:
|
||||
kfree(cma_xprt);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user