Commit 586a7a85 authored by Linus Torvalds's avatar Linus Torvalds

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
parents 48f8bfd4 769d2002
......@@ -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);
......
......@@ -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)
{
struct svc_pool_map *m = kp->arg;
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)
{
int *ip = (int *)kp->arg;
struct svc_pool_map *m = &svc_pool_map;
switch (*ip)
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);
}
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment