Merge tag 'nfsd-4.4' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "Apologies for coming a little late in the merge window. Fortunately this is another fairly quiet one: Mainly smaller bugfixes and cleanup. We're still finding some bugs from the breakup of the big NFSv4 state lock in 3.17 -- thanks especially to Andrew Elble and Jeff Layton for tracking down some of the remaining races" * tag 'nfsd-4.4' of git://linux-nfs.org/~bfields/linux: svcrpc: document lack of some memory barriers nfsd: fix race with open / open upgrade stateids nfsd: eliminate sending duplicate and repeated delegations nfsd: remove recurring workqueue job to clean DRC SUNRPC: drop stale comment in svc_setup_socket() nfsd: ensure that seqid morphing operations are atomic wrt to copies nfsd: serialize layout stateid morphing operations nfsd: improve client_has_state to check for unused openowners nfsd: fix clid_inuse on mount with security change sunrpc/cache: make cache flushing more reliable. nfsd: move include of state.h from trace.c to trace.h sunrpc: avoid warning in gss_key_timeout lockd: get rid of reference-counted NSM RPC clients SUNRPC: Use MSG_SENDPAGE_NOTLAST when calling sendpage() lockd: create NSM handles per net namespace nfsd: switch unsigned char flags in svc_fh to bools nfsd: move svc_fh->fh_maxsize to just after fh_handle nfsd: drop null test before destroy functions nfsd: serialize state seqid morphing operations
This commit is contained in:
@@ -116,7 +116,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
|
||||
atomic_inc(&nsm->sm_count);
|
||||
else {
|
||||
host = NULL;
|
||||
nsm = nsm_get_handle(ni->sap, ni->salen,
|
||||
nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
|
||||
ni->hostname, ni->hostname_len);
|
||||
if (unlikely(nsm == NULL)) {
|
||||
dprintk("lockd: %s failed; no nsm handle\n",
|
||||
@@ -161,6 +161,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
|
||||
host->h_nsmhandle = nsm;
|
||||
host->h_addrbuf = nsm->sm_addrbuf;
|
||||
host->net = ni->net;
|
||||
strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename));
|
||||
|
||||
out:
|
||||
return host;
|
||||
@@ -534,17 +535,18 @@ static struct nlm_host *next_host_state(struct hlist_head *cache,
|
||||
|
||||
/**
|
||||
* nlm_host_rebooted - Release all resources held by rebooted host
|
||||
* @net: network namespace
|
||||
* @info: pointer to decoded results of NLM_SM_NOTIFY call
|
||||
*
|
||||
* We were notified that the specified host has rebooted. Release
|
||||
* all resources held by that peer.
|
||||
*/
|
||||
void nlm_host_rebooted(const struct nlm_reboot *info)
|
||||
void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
struct nlm_host *host;
|
||||
|
||||
nsm = nsm_reboot_lookup(info);
|
||||
nsm = nsm_reboot_lookup(net, info);
|
||||
if (unlikely(nsm == NULL))
|
||||
return;
|
||||
|
||||
|
125
fs/lockd/mon.c
125
fs/lockd/mon.c
@@ -42,7 +42,7 @@ struct nsm_args {
|
||||
u32 proc;
|
||||
|
||||
char *mon_name;
|
||||
char *nodename;
|
||||
const char *nodename;
|
||||
};
|
||||
|
||||
struct nsm_res {
|
||||
@@ -51,7 +51,6 @@ struct nsm_res {
|
||||
};
|
||||
|
||||
static const struct rpc_program nsm_program;
|
||||
static LIST_HEAD(nsm_handles);
|
||||
static DEFINE_SPINLOCK(nsm_lock);
|
||||
|
||||
/*
|
||||
@@ -87,69 +86,18 @@ static struct rpc_clnt *nsm_create(struct net *net, const char *nodename)
|
||||
return rpc_create(&args);
|
||||
}
|
||||
|
||||
static struct rpc_clnt *nsm_client_set(struct lockd_net *ln,
|
||||
struct rpc_clnt *clnt)
|
||||
{
|
||||
spin_lock(&ln->nsm_clnt_lock);
|
||||
if (ln->nsm_users == 0) {
|
||||
if (clnt == NULL)
|
||||
goto out;
|
||||
ln->nsm_clnt = clnt;
|
||||
}
|
||||
clnt = ln->nsm_clnt;
|
||||
ln->nsm_users++;
|
||||
out:
|
||||
spin_unlock(&ln->nsm_clnt_lock);
|
||||
return clnt;
|
||||
}
|
||||
|
||||
static struct rpc_clnt *nsm_client_get(struct net *net, const char *nodename)
|
||||
{
|
||||
struct rpc_clnt *clnt, *new;
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
|
||||
clnt = nsm_client_set(ln, NULL);
|
||||
if (clnt != NULL)
|
||||
goto out;
|
||||
|
||||
clnt = new = nsm_create(net, nodename);
|
||||
if (IS_ERR(clnt))
|
||||
goto out;
|
||||
|
||||
clnt = nsm_client_set(ln, new);
|
||||
if (clnt != new)
|
||||
rpc_shutdown_client(new);
|
||||
out:
|
||||
return clnt;
|
||||
}
|
||||
|
||||
static void nsm_client_put(struct net *net)
|
||||
{
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
struct rpc_clnt *clnt = NULL;
|
||||
|
||||
spin_lock(&ln->nsm_clnt_lock);
|
||||
ln->nsm_users--;
|
||||
if (ln->nsm_users == 0) {
|
||||
clnt = ln->nsm_clnt;
|
||||
ln->nsm_clnt = NULL;
|
||||
}
|
||||
spin_unlock(&ln->nsm_clnt_lock);
|
||||
if (clnt != NULL)
|
||||
rpc_shutdown_client(clnt);
|
||||
}
|
||||
|
||||
static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
|
||||
struct rpc_clnt *clnt)
|
||||
const struct nlm_host *host)
|
||||
{
|
||||
int status;
|
||||
struct rpc_clnt *clnt;
|
||||
struct nsm_args args = {
|
||||
.priv = &nsm->sm_priv,
|
||||
.prog = NLM_PROGRAM,
|
||||
.vers = 3,
|
||||
.proc = NLMPROC_NSM_NOTIFY,
|
||||
.mon_name = nsm->sm_mon_name,
|
||||
.nodename = clnt->cl_nodename,
|
||||
.nodename = host->nodename,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_argp = &args,
|
||||
@@ -158,6 +106,13 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
|
||||
|
||||
memset(res, 0, sizeof(*res));
|
||||
|
||||
clnt = nsm_create(host->net, host->nodename);
|
||||
if (IS_ERR(clnt)) {
|
||||
dprintk("lockd: failed to create NSM upcall transport, "
|
||||
"status=%ld, net=%p\n", PTR_ERR(clnt), host->net);
|
||||
return PTR_ERR(clnt);
|
||||
}
|
||||
|
||||
msg.rpc_proc = &clnt->cl_procinfo[proc];
|
||||
status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);
|
||||
if (status == -ECONNREFUSED) {
|
||||
@@ -171,6 +126,8 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res,
|
||||
status);
|
||||
else
|
||||
status = 0;
|
||||
|
||||
rpc_shutdown_client(clnt);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -190,32 +147,19 @@ int nsm_monitor(const struct nlm_host *host)
|
||||
struct nsm_handle *nsm = host->h_nsmhandle;
|
||||
struct nsm_res res;
|
||||
int status;
|
||||
struct rpc_clnt *clnt;
|
||||
const char *nodename = NULL;
|
||||
|
||||
dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
|
||||
|
||||
if (nsm->sm_monitored)
|
||||
return 0;
|
||||
|
||||
if (host->h_rpcclnt)
|
||||
nodename = host->h_rpcclnt->cl_nodename;
|
||||
|
||||
/*
|
||||
* Choose whether to record the caller_name or IP address of
|
||||
* this peer in the local rpc.statd's database.
|
||||
*/
|
||||
nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
|
||||
|
||||
clnt = nsm_client_get(host->net, nodename);
|
||||
if (IS_ERR(clnt)) {
|
||||
status = PTR_ERR(clnt);
|
||||
dprintk("lockd: failed to create NSM upcall transport, "
|
||||
"status=%d, net=%p\n", status, host->net);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);
|
||||
status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, host);
|
||||
if (unlikely(res.status != 0))
|
||||
status = -EIO;
|
||||
if (unlikely(status < 0)) {
|
||||
@@ -247,11 +191,9 @@ void nsm_unmonitor(const struct nlm_host *host)
|
||||
|
||||
if (atomic_read(&nsm->sm_count) == 1
|
||||
&& nsm->sm_monitored && !nsm->sm_sticky) {
|
||||
struct lockd_net *ln = net_generic(host->net, lockd_net_id);
|
||||
|
||||
dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
|
||||
|
||||
status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);
|
||||
status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, host);
|
||||
if (res.status != 0)
|
||||
status = -EIO;
|
||||
if (status < 0)
|
||||
@@ -259,38 +201,38 @@ void nsm_unmonitor(const struct nlm_host *host)
|
||||
nsm->sm_name);
|
||||
else
|
||||
nsm->sm_monitored = 0;
|
||||
|
||||
nsm_client_put(host->net);
|
||||
}
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
|
||||
const size_t len)
|
||||
static struct nsm_handle *nsm_lookup_hostname(const struct list_head *nsm_handles,
|
||||
const char *hostname, const size_t len)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
|
||||
list_for_each_entry(nsm, &nsm_handles, sm_link)
|
||||
list_for_each_entry(nsm, nsm_handles, sm_link)
|
||||
if (strlen(nsm->sm_name) == len &&
|
||||
memcmp(nsm->sm_name, hostname, len) == 0)
|
||||
return nsm;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
|
||||
static struct nsm_handle *nsm_lookup_addr(const struct list_head *nsm_handles,
|
||||
const struct sockaddr *sap)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
|
||||
list_for_each_entry(nsm, &nsm_handles, sm_link)
|
||||
list_for_each_entry(nsm, nsm_handles, sm_link)
|
||||
if (rpc_cmp_addr(nsm_addr(nsm), sap))
|
||||
return nsm;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
|
||||
static struct nsm_handle *nsm_lookup_priv(const struct list_head *nsm_handles,
|
||||
const struct nsm_private *priv)
|
||||
{
|
||||
struct nsm_handle *nsm;
|
||||
|
||||
list_for_each_entry(nsm, &nsm_handles, sm_link)
|
||||
list_for_each_entry(nsm, nsm_handles, sm_link)
|
||||
if (memcmp(nsm->sm_priv.data, priv->data,
|
||||
sizeof(priv->data)) == 0)
|
||||
return nsm;
|
||||
@@ -353,6 +295,7 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
|
||||
|
||||
/**
|
||||
* nsm_get_handle - Find or create a cached nsm_handle
|
||||
* @net: network namespace
|
||||
* @sap: pointer to socket address of handle to find
|
||||
* @salen: length of socket address
|
||||
* @hostname: pointer to C string containing hostname to find
|
||||
@@ -365,11 +308,13 @@ static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
|
||||
* @hostname cannot be found in the handle cache. Returns NULL if
|
||||
* an error occurs.
|
||||
*/
|
||||
struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
|
||||
struct nsm_handle *nsm_get_handle(const struct net *net,
|
||||
const struct sockaddr *sap,
|
||||
const size_t salen, const char *hostname,
|
||||
const size_t hostname_len)
|
||||
{
|
||||
struct nsm_handle *cached, *new = NULL;
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
|
||||
if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
|
||||
if (printk_ratelimit()) {
|
||||
@@ -384,9 +329,10 @@ retry:
|
||||
spin_lock(&nsm_lock);
|
||||
|
||||
if (nsm_use_hostnames && hostname != NULL)
|
||||
cached = nsm_lookup_hostname(hostname, hostname_len);
|
||||
cached = nsm_lookup_hostname(&ln->nsm_handles,
|
||||
hostname, hostname_len);
|
||||
else
|
||||
cached = nsm_lookup_addr(sap);
|
||||
cached = nsm_lookup_addr(&ln->nsm_handles, sap);
|
||||
|
||||
if (cached != NULL) {
|
||||
atomic_inc(&cached->sm_count);
|
||||
@@ -400,7 +346,7 @@ retry:
|
||||
}
|
||||
|
||||
if (new != NULL) {
|
||||
list_add(&new->sm_link, &nsm_handles);
|
||||
list_add(&new->sm_link, &ln->nsm_handles);
|
||||
spin_unlock(&nsm_lock);
|
||||
dprintk("lockd: created nsm_handle for %s (%s)\n",
|
||||
new->sm_name, new->sm_addrbuf);
|
||||
@@ -417,19 +363,22 @@ retry:
|
||||
|
||||
/**
|
||||
* nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
|
||||
* @net: network namespace
|
||||
* @info: pointer to NLMPROC_SM_NOTIFY arguments
|
||||
*
|
||||
* Returns a matching nsm_handle if found in the nsm cache. The returned
|
||||
* nsm_handle's reference count is bumped. Otherwise returns NULL if some
|
||||
* error occurred.
|
||||
*/
|
||||
struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
|
||||
struct nsm_handle *nsm_reboot_lookup(const struct net *net,
|
||||
const struct nlm_reboot *info)
|
||||
{
|
||||
struct nsm_handle *cached;
|
||||
struct lockd_net *ln = net_generic(net, lockd_net_id);
|
||||
|
||||
spin_lock(&nsm_lock);
|
||||
|
||||
cached = nsm_lookup_priv(&info->priv);
|
||||
cached = nsm_lookup_priv(&ln->nsm_handles, &info->priv);
|
||||
if (unlikely(cached == NULL)) {
|
||||
spin_unlock(&nsm_lock);
|
||||
dprintk("lockd: never saw rebooted peer '%.*s' before\n",
|
||||
|
@@ -12,9 +12,7 @@ struct lockd_net {
|
||||
struct delayed_work grace_period_end;
|
||||
struct lock_manager lockd_manager;
|
||||
|
||||
spinlock_t nsm_clnt_lock;
|
||||
unsigned int nsm_users;
|
||||
struct rpc_clnt *nsm_clnt;
|
||||
struct list_head nsm_handles;
|
||||
};
|
||||
|
||||
extern int lockd_net_id;
|
||||
|
@@ -592,7 +592,7 @@ static int lockd_init_net(struct net *net)
|
||||
INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
|
||||
INIT_LIST_HEAD(&ln->lockd_manager.list);
|
||||
ln->lockd_manager.block_opens = false;
|
||||
spin_lock_init(&ln->nsm_clnt_lock);
|
||||
INIT_LIST_HEAD(&ln->nsm_handles);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -421,7 +421,7 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
||||
return rpc_system_err;
|
||||
}
|
||||
|
||||
nlm_host_rebooted(argp);
|
||||
nlm_host_rebooted(SVC_NET(rqstp), argp);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
@@ -464,7 +464,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
|
||||
return rpc_system_err;
|
||||
}
|
||||
|
||||
nlm_host_rebooted(argp);
|
||||
nlm_host_rebooted(SVC_NET(rqstp), argp);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user