Commit 08843b79 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'nfsd-next' of git://linux-nfs.org/~bfields/linux

Pull nfsd changes from J. Bruce Fields:
 "This has been an unusually quiet cycle--mostly bugfixes and cleanup.
  The one large piece is Stanislav's work to containerize the server's
  grace period--but that in itself is just one more step in a
  not-yet-complete project to allow fully containerized nfs service.

  There are a number of outstanding delegation, container, v4 state, and
  gss patches that aren't quite ready yet; 3.7 may be wilder."

* 'nfsd-next' of git://linux-nfs.org/~bfields/linux: (35 commits)
  NFSd: make boot_time variable per network namespace
  NFSd: make grace end flag per network namespace
  Lockd: move grace period management from lockd() to per-net functions
  LockD: pass actual network namespace to grace period management functions
  LockD: manage grace list per network namespace
  SUNRPC: service request network namespace helper introduced
  NFSd: make nfsd4_manager allocated per network namespace context.
  LockD: make lockd manager allocated per network namespace
  LockD: manage grace period per network namespace
  Lockd: add more debug to host shutdown functions
  Lockd: host complaining function introduced
  LockD: manage used host count per networks namespace
  LockD: manage garbage collection timeout per networks namespace
  LockD: make garbage collector network namespace aware.
  LockD: mark host per network namespace on garbage collect
  nfsd4: fix missing fault_inject.h include
  locks: move lease-specific code out of locks_delete_lock
  locks: prevent side-effects of locks_release_private before file_lock is initialized
  NFSd: set nfsd_serv to NULL after service destruction
  NFSd: introduce nfsd_destroy() helper
  ...
parents cc8362b1 2c142baa
...@@ -4,8 +4,10 @@ ...@@ -4,8 +4,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/lockd/bind.h> #include <linux/lockd/bind.h>
#include <net/net_namespace.h>
#include "netns.h"
static LIST_HEAD(grace_list);
static DEFINE_SPINLOCK(grace_lock); static DEFINE_SPINLOCK(grace_lock);
/** /**
...@@ -19,10 +21,12 @@ static DEFINE_SPINLOCK(grace_lock); ...@@ -19,10 +21,12 @@ static DEFINE_SPINLOCK(grace_lock);
* *
* This function is called to start a grace period. * This function is called to start a grace period.
*/ */
void locks_start_grace(struct lock_manager *lm) void locks_start_grace(struct net *net, struct lock_manager *lm)
{ {
struct lockd_net *ln = net_generic(net, lockd_net_id);
spin_lock(&grace_lock); spin_lock(&grace_lock);
list_add(&lm->list, &grace_list); list_add(&lm->list, &ln->grace_list);
spin_unlock(&grace_lock); spin_unlock(&grace_lock);
} }
EXPORT_SYMBOL_GPL(locks_start_grace); EXPORT_SYMBOL_GPL(locks_start_grace);
...@@ -52,8 +56,10 @@ EXPORT_SYMBOL_GPL(locks_end_grace); ...@@ -52,8 +56,10 @@ EXPORT_SYMBOL_GPL(locks_end_grace);
* to answer ordinary lock requests, and when they should accept only * to answer ordinary lock requests, and when they should accept only
* lock reclaims. * lock reclaims.
*/ */
int locks_in_grace(void) int locks_in_grace(struct net *net)
{ {
return !list_empty(&grace_list); struct lockd_net *ln = net_generic(net, lockd_net_id);
return !list_empty(&ln->grace_list);
} }
EXPORT_SYMBOL_GPL(locks_in_grace); EXPORT_SYMBOL_GPL(locks_in_grace);
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <net/ipv6.h> #include <net/ipv6.h>
#include "netns.h"
#define NLMDBG_FACILITY NLMDBG_HOSTCACHE #define NLMDBG_FACILITY NLMDBG_HOSTCACHE
#define NLM_HOST_NRHASH 32 #define NLM_HOST_NRHASH 32
#define NLM_HOST_REBIND (60 * HZ) #define NLM_HOST_REBIND (60 * HZ)
...@@ -41,11 +43,10 @@ static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH]; ...@@ -41,11 +43,10 @@ static struct hlist_head nlm_client_hosts[NLM_HOST_NRHASH];
hlist_for_each_entry_safe((host), (pos), (next), \ hlist_for_each_entry_safe((host), (pos), (next), \
(chain), h_hash) (chain), h_hash)
static unsigned long next_gc;
static unsigned long nrhosts; static unsigned long nrhosts;
static DEFINE_MUTEX(nlm_host_mutex); static DEFINE_MUTEX(nlm_host_mutex);
static void nlm_gc_hosts(void); static void nlm_gc_hosts(struct net *net);
struct nlm_lookup_host_info { struct nlm_lookup_host_info {
const int server; /* search for server|client */ const int server; /* search for server|client */
...@@ -172,6 +173,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni, ...@@ -172,6 +173,7 @@ static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
static void nlm_destroy_host_locked(struct nlm_host *host) static void nlm_destroy_host_locked(struct nlm_host *host)
{ {
struct rpc_clnt *clnt; struct rpc_clnt *clnt;
struct lockd_net *ln = net_generic(host->net, lockd_net_id);
dprintk("lockd: destroy host %s\n", host->h_name); dprintk("lockd: destroy host %s\n", host->h_name);
...@@ -188,6 +190,7 @@ static void nlm_destroy_host_locked(struct nlm_host *host) ...@@ -188,6 +190,7 @@ static void nlm_destroy_host_locked(struct nlm_host *host)
rpc_shutdown_client(clnt); rpc_shutdown_client(clnt);
kfree(host); kfree(host);
ln->nrhosts--;
nrhosts--; nrhosts--;
} }
...@@ -228,6 +231,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, ...@@ -228,6 +231,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
struct hlist_node *pos; struct hlist_node *pos;
struct nlm_host *host; struct nlm_host *host;
struct nsm_handle *nsm = NULL; struct nsm_handle *nsm = NULL;
struct lockd_net *ln = net_generic(net, lockd_net_id);
dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__, dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
(hostname ? hostname : "<none>"), version, (hostname ? hostname : "<none>"), version,
...@@ -262,6 +266,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap, ...@@ -262,6 +266,7 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
goto out; goto out;
hlist_add_head(&host->h_hash, chain); hlist_add_head(&host->h_hash, chain);
ln->nrhosts++;
nrhosts++; nrhosts++;
dprintk("lockd: %s created host %s (%s)\n", __func__, dprintk("lockd: %s created host %s (%s)\n", __func__,
...@@ -326,7 +331,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, ...@@ -326,7 +331,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
struct nsm_handle *nsm = NULL; struct nsm_handle *nsm = NULL;
struct sockaddr *src_sap = svc_daddr(rqstp); struct sockaddr *src_sap = svc_daddr(rqstp);
size_t src_len = rqstp->rq_daddrlen; size_t src_len = rqstp->rq_daddrlen;
struct net *net = rqstp->rq_xprt->xpt_net; struct net *net = SVC_NET(rqstp);
struct nlm_lookup_host_info ni = { struct nlm_lookup_host_info ni = {
.server = 1, .server = 1,
.sap = svc_addr(rqstp), .sap = svc_addr(rqstp),
...@@ -337,6 +342,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, ...@@ -337,6 +342,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
.hostname_len = hostname_len, .hostname_len = hostname_len,
.net = net, .net = net,
}; };
struct lockd_net *ln = net_generic(net, lockd_net_id);
dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__, dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
(int)hostname_len, hostname, rqstp->rq_vers, (int)hostname_len, hostname, rqstp->rq_vers,
...@@ -344,8 +350,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, ...@@ -344,8 +350,8 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
mutex_lock(&nlm_host_mutex); mutex_lock(&nlm_host_mutex);
if (time_after_eq(jiffies, next_gc)) if (time_after_eq(jiffies, ln->next_gc))
nlm_gc_hosts(); nlm_gc_hosts(net);
chain = &nlm_server_hosts[nlm_hash_address(ni.sap)]; chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
hlist_for_each_entry(host, pos, chain, h_hash) { hlist_for_each_entry(host, pos, chain, h_hash) {
...@@ -382,6 +388,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp, ...@@ -382,6 +388,7 @@ struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
memcpy(nlm_srcaddr(host), src_sap, src_len); memcpy(nlm_srcaddr(host), src_sap, src_len);
host->h_srcaddrlen = src_len; host->h_srcaddrlen = src_len;
hlist_add_head(&host->h_hash, chain); hlist_add_head(&host->h_hash, chain);
ln->nrhosts++;
nrhosts++; nrhosts++;
dprintk("lockd: %s created host %s (%s)\n", dprintk("lockd: %s created host %s (%s)\n",
...@@ -565,6 +572,35 @@ void nlm_host_rebooted(const struct nlm_reboot *info) ...@@ -565,6 +572,35 @@ void nlm_host_rebooted(const struct nlm_reboot *info)
nsm_release(nsm); nsm_release(nsm);
} }
static void nlm_complain_hosts(struct net *net)
{
struct hlist_head *chain;
struct hlist_node *pos;
struct nlm_host *host;
if (net) {
struct lockd_net *ln = net_generic(net, lockd_net_id);
if (ln->nrhosts == 0)
return;
printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net);
dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net);
} else {
if (nrhosts == 0)
return;
printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
dprintk("lockd: %lu hosts left:\n", nrhosts);
}
for_each_host(host, pos, chain, nlm_server_hosts) {
if (net && host->net != net)
continue;
dprintk(" %s (cnt %d use %d exp %ld net %p)\n",
host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires, host->net);
}
}
void void
nlm_shutdown_hosts_net(struct net *net) nlm_shutdown_hosts_net(struct net *net)
{ {
...@@ -572,11 +608,10 @@ nlm_shutdown_hosts_net(struct net *net) ...@@ -572,11 +608,10 @@ nlm_shutdown_hosts_net(struct net *net)
struct hlist_node *pos; struct hlist_node *pos;
struct nlm_host *host; struct nlm_host *host;
dprintk("lockd: shutting down host module\n");
mutex_lock(&nlm_host_mutex); mutex_lock(&nlm_host_mutex);
/* First, make all hosts eligible for gc */ /* First, make all hosts eligible for gc */
dprintk("lockd: nuking all hosts...\n"); dprintk("lockd: nuking all hosts in net %p...\n", net);
for_each_host(host, pos, chain, nlm_server_hosts) { for_each_host(host, pos, chain, nlm_server_hosts) {
if (net && host->net != net) if (net && host->net != net)
continue; continue;
...@@ -588,8 +623,10 @@ nlm_shutdown_hosts_net(struct net *net) ...@@ -588,8 +623,10 @@ nlm_shutdown_hosts_net(struct net *net)
} }
/* Then, perform a garbage collection pass */ /* Then, perform a garbage collection pass */
nlm_gc_hosts(); nlm_gc_hosts(net);
mutex_unlock(&nlm_host_mutex); mutex_unlock(&nlm_host_mutex);
nlm_complain_hosts(net);
} }
/* /*
...@@ -599,22 +636,8 @@ nlm_shutdown_hosts_net(struct net *net) ...@@ -599,22 +636,8 @@ nlm_shutdown_hosts_net(struct net *net)
void void
nlm_shutdown_hosts(void) nlm_shutdown_hosts(void)
{ {
struct hlist_head *chain; dprintk("lockd: shutting down host module\n");
struct hlist_node *pos;
struct nlm_host *host;
nlm_shutdown_hosts_net(NULL); nlm_shutdown_hosts_net(NULL);
/* complain if any hosts are left */
if (nrhosts != 0) {
printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
dprintk("lockd: %lu hosts left:\n", nrhosts);
for_each_host(host, pos, chain, nlm_server_hosts) {
dprintk(" %s (cnt %d use %d exp %ld net %p)\n",
host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires, host->net);
}
}
} }
/* /*
...@@ -623,30 +646,39 @@ nlm_shutdown_hosts(void) ...@@ -623,30 +646,39 @@ nlm_shutdown_hosts(void)
* mark & sweep for resources held by remote clients. * mark & sweep for resources held by remote clients.
*/ */
static void static void
nlm_gc_hosts(void) nlm_gc_hosts(struct net *net)
{ {
struct hlist_head *chain; struct hlist_head *chain;
struct hlist_node *pos, *next; struct hlist_node *pos, *next;
struct nlm_host *host; struct nlm_host *host;
dprintk("lockd: host garbage collection\n"); dprintk("lockd: host garbage collection for net %p\n", net);
for_each_host(host, pos, chain, nlm_server_hosts) for_each_host(host, pos, chain, nlm_server_hosts) {
if (net && host->net != net)
continue;
host->h_inuse = 0; host->h_inuse = 0;
}
/* Mark all hosts that hold locks, blocks or shares */ /* Mark all hosts that hold locks, blocks or shares */
nlmsvc_mark_resources(); nlmsvc_mark_resources(net);
for_each_host_safe(host, pos, next, chain, nlm_server_hosts) { for_each_host_safe(host, pos, next, chain, nlm_server_hosts) {
if (net && host->net != net)
continue;
if (atomic_read(&host->h_count) || host->h_inuse if (atomic_read(&host->h_count) || host->h_inuse
|| time_before(jiffies, host->h_expires)) { || time_before(jiffies, host->h_expires)) {
dprintk("nlm_gc_hosts skipping %s " dprintk("nlm_gc_hosts skipping %s "
"(cnt %d use %d exp %ld)\n", "(cnt %d use %d exp %ld net %p)\n",
host->h_name, atomic_read(&host->h_count), host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires); host->h_inuse, host->h_expires, host->net);
continue; continue;
} }
nlm_destroy_host_locked(host); nlm_destroy_host_locked(host);
} }
next_gc = jiffies + NLM_HOST_COLLECT; if (net) {
struct lockd_net *ln = net_generic(net, lockd_net_id);
ln->next_gc = jiffies + NLM_HOST_COLLECT;
}
} }
#ifndef __LOCKD_NETNS_H__ #ifndef __LOCKD_NETNS_H__
#define __LOCKD_NETNS_H__ #define __LOCKD_NETNS_H__
#include <linux/fs.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
struct lockd_net { struct lockd_net {
unsigned int nlmsvc_users; unsigned int nlmsvc_users;
unsigned long next_gc;
unsigned long nrhosts;
struct delayed_work grace_period_end;
struct lock_manager lockd_manager;
struct list_head grace_list;
}; };
extern int lockd_net_id; extern int lockd_net_id;
......
...@@ -87,32 +87,36 @@ static unsigned long get_lockd_grace_period(void) ...@@ -87,32 +87,36 @@ static unsigned long get_lockd_grace_period(void)
return nlm_timeout * 5 * HZ; return nlm_timeout * 5 * HZ;
} }
static struct lock_manager lockd_manager = { static void grace_ender(struct work_struct *grace)
};
static void grace_ender(struct work_struct *not_used)
{ {
locks_end_grace(&lockd_manager); struct delayed_work *dwork = container_of(grace, struct delayed_work,
} work);
struct lockd_net *ln = container_of(dwork, struct lockd_net,
grace_period_end);
static DECLARE_DELAYED_WORK(grace_period_end, grace_ender); locks_end_grace(&ln->lockd_manager);
}
static void set_grace_period(void) static void set_grace_period(struct net *net)
{ {
unsigned long grace_period = get_lockd_grace_period(); unsigned long grace_period = get_lockd_grace_period();
struct lockd_net *ln = net_generic(net, lockd_net_id);
locks_start_grace(&lockd_manager); locks_start_grace(net, &ln->lockd_manager);
cancel_delayed_work_sync(&grace_period_end); cancel_delayed_work_sync(&ln->grace_period_end);
schedule_delayed_work(&grace_period_end, grace_period); schedule_delayed_work(&ln->grace_period_end, grace_period);
} }
static void restart_grace(void) static void restart_grace(void)
{ {
if (nlmsvc_ops) { if (nlmsvc_ops) {
cancel_delayed_work_sync(&grace_period_end); struct net *net = &init_net;
locks_end_grace(&lockd_manager); struct lockd_net *ln = net_generic(net, lockd_net_id);
cancel_delayed_work_sync(&ln->grace_period_end);
locks_end_grace(&ln->lockd_manager);
nlmsvc_invalidate_all(); nlmsvc_invalidate_all();
set_grace_period(); set_grace_period(net);
} }
} }
...@@ -137,8 +141,6 @@ lockd(void *vrqstp) ...@@ -137,8 +141,6 @@ lockd(void *vrqstp)
nlm_timeout = LOCKD_DFLT_TIMEO; nlm_timeout = LOCKD_DFLT_TIMEO;
nlmsvc_timeout = nlm_timeout * HZ; nlmsvc_timeout = nlm_timeout * HZ;
set_grace_period();
/* /*
* The main request loop. We don't terminate until the last * The main request loop. We don't terminate until the last
* NFS mount or NFS daemon has gone away. * NFS mount or NFS daemon has gone away.
...@@ -184,8 +186,6 @@ lockd(void *vrqstp) ...@@ -184,8 +186,6 @@ lockd(void *vrqstp)
svc_process(rqstp); svc_process(rqstp);
} }
flush_signals(current); flush_signals(current);
cancel_delayed_work_sync(&grace_period_end);
locks_end_grace(&lockd_manager);
if (nlmsvc_ops) if (nlmsvc_ops)
nlmsvc_invalidate_all(); nlmsvc_invalidate_all();
nlm_shutdown_hosts(); nlm_shutdown_hosts();
...@@ -266,6 +266,7 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net) ...@@ -266,6 +266,7 @@ static int lockd_up_net(struct svc_serv *serv, struct net *net)
error = make_socks(serv, net); error = make_socks(serv, net);
if (error < 0) if (error < 0)
goto err_socks; goto err_socks;
set_grace_period(net);
dprintk("lockd_up_net: per-net data created; net=%p\n", net); dprintk("lockd_up_net: per-net data created; net=%p\n", net);
return 0; return 0;
...@@ -283,6 +284,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net) ...@@ -283,6 +284,8 @@ static void lockd_down_net(struct svc_serv *serv, struct net *net)
if (ln->nlmsvc_users) { if (ln->nlmsvc_users) {
if (--ln->nlmsvc_users == 0) { if (--ln->nlmsvc_users == 0) {
nlm_shutdown_hosts_net(net); nlm_shutdown_hosts_net(net);
cancel_delayed_work_sync(&ln->grace_period_end);
locks_end_grace(&ln->lockd_manager);
svc_shutdown_net(serv, net); svc_shutdown_net(serv, net);
dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net); dprintk("lockd_down_net: per-net data destroyed; net=%p\n", net);
} }
...@@ -589,6 +592,10 @@ module_param(nlm_max_connections, uint, 0644); ...@@ -589,6 +592,10 @@ module_param(nlm_max_connections, uint, 0644);
static int lockd_init_net(struct net *net) static int lockd_init_net(struct net *net)
{ {
struct lockd_net *ln = net_generic(net, lockd_net_id);
INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
INIT_LIST_HEAD(&ln->grace_list);
return 0; return 0;
} }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/share.h> #include <linux/lockd/share.h>
#include <linux/sunrpc/svc_xprt.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
...@@ -151,7 +152,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -151,7 +152,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept requests during grace period */ /* Don't accept requests during grace period */
if (locks_in_grace()) { if (locks_in_grace(SVC_NET(rqstp))) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
...@@ -161,7 +162,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -161,7 +162,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Try to cancel request. */ /* Try to cancel request. */
resp->status = nlmsvc_cancel_blocked(file, &argp->lock); resp->status = nlmsvc_cancel_blocked(SVC_NET(rqstp), file, &argp->lock);
dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
nlmsvc_release_host(host); nlmsvc_release_host(host);
...@@ -184,7 +185,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -184,7 +185,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */ /* Don't accept new lock requests during grace period */
if (locks_in_grace()) { if (locks_in_grace(SVC_NET(rqstp))) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
...@@ -194,7 +195,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -194,7 +195,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to remove the lock */ /* Now try to remove the lock */
resp->status = nlmsvc_unlock(file, &argp->lock); resp->status = nlmsvc_unlock(SVC_NET(rqstp), file, &argp->lock);
dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
nlmsvc_release_host(host); nlmsvc_release_host(host);
...@@ -321,7 +322,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -321,7 +322,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */ /* Don't accept new lock requests during grace period */
if (locks_in_grace() && !argp->reclaim) { if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
...@@ -354,7 +355,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -354,7 +355,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept requests during grace period */ /* Don't accept requests during grace period */
if (locks_in_grace()) { if (locks_in_grace(SVC_NET(rqstp))) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h> #include <linux/sunrpc/svc_xprt.h>
#include <linux/lockd/nlm.h> #include <linux/lockd/nlm.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/kthread.h> #include <linux/kthread.h>
...@@ -447,11 +447,11 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -447,11 +447,11 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out; goto out;
} }
if (locks_in_grace() && !reclaim) { if (locks_in_grace(SVC_NET(rqstp)) && !reclaim) {
ret = nlm_lck_denied_grace_period; ret = nlm_lck_denied_grace_period;
goto out; goto out;
} }
if (reclaim && !locks_in_grace()) { if (reclaim && !locks_in_grace(SVC_NET(rqstp))) {
ret = nlm_lck_denied_grace_period; ret = nlm_lck_denied_grace_period;
goto out; goto out;
} }
...@@ -559,7 +559,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -559,7 +559,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out; goto out;
} }
if (locks_in_grace()) { if (locks_in_grace(SVC_NET(rqstp))) {
ret = nlm_lck_denied_grace_period; ret = nlm_lck_denied_grace_period;
goto out; goto out;
} }
...@@ -603,7 +603,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -603,7 +603,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
* must be removed. * must be removed.
*/ */
__be32 __be32
nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) nlmsvc_unlock(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
{ {
int error; int error;
...@@ -615,7 +615,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) ...@@ -615,7 +615,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
(long long)lock->fl.fl_end); (long long)lock->fl.fl_end);
/* First, cancel any lock that might be there */ /* First, cancel any lock that might be there */
nlmsvc_cancel_blocked(file, lock); nlmsvc_cancel_blocked(net, file, lock);
lock->fl.fl_type = F_UNLCK; lock->fl.fl_type = F_UNLCK;
error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL); error = vfs_lock_file(file->f_file, F_SETLK, &lock->fl, NULL);
...@@ -631,7 +631,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock) ...@@ -631,7 +631,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
* The calling procedure must check whether the file can be closed. * The calling procedure must check whether the file can be closed.
*/ */
__be32 __be32
nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) nlmsvc_cancel_blocked(struct net *net, struct nlm_file *file, struct nlm_lock *lock)
{ {
struct nlm_block *block; struct nlm_block *block;
int status = 0; int status = 0;
...@@ -643,7 +643,7 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock) ...@@ -643,7 +643,7 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
(long long)lock->fl.fl_start, (long long)lock->fl.fl_start,
(long long)lock->fl.fl_end); (long long)lock->fl.fl_end);
if (locks_in_grace()) if (locks_in_grace(net))
return nlm_lck_denied_grace_period; return nlm_lck_denied_grace_period;
mutex_lock(&file->f_mutex); mutex_lock(&file->f_mutex);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/time.h> #include <linux/time.h>
#include <linux/lockd/lockd.h> #include <linux/lockd/lockd.h>
#include <linux/lockd/share.h> #include <linux/lockd/share.h>
#include <linux/sunrpc/svc_xprt.h>
#define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMDBG_FACILITY NLMDBG_CLIENT
...@@ -175,13 +176,14 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -175,13 +176,14 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
{ {
struct nlm_host *host; struct nlm_host *host;
struct nlm_file *file; struct nlm_file *file;
struct net *net = SVC_NET(rqstp);
dprintk("lockd: CANCEL called\n"); dprintk("lockd: CANCEL called\n");
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept requests during grace period */ /* Don't accept requests during grace period */
if (locks_in_grace()) { if (locks_in_grace(net)) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
...@@ -191,7 +193,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -191,7 +193,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Try to cancel request. */ /* Try to cancel request. */
resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock)); resp->status = cast_status(nlmsvc_cancel_blocked(net, file, &argp->lock));
dprintk("lockd: CANCEL status %d\n", ntohl(resp->status)); dprintk("lockd: CANCEL status %d\n", ntohl(resp->status));
nlmsvc_release_host(host); nlmsvc_release_host(host);
...@@ -208,13 +210,14 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -208,13 +210,14 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
{ {
struct nlm_host *host; struct nlm_host *host;
struct nlm_file *file; struct nlm_file *file;
struct net *net = SVC_NET(rqstp);
dprintk("lockd: UNLOCK called\n"); dprintk("lockd: UNLOCK called\n");
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */ /* Don't accept new lock requests during grace period */
if (locks_in_grace()) { if (locks_in_grace(net)) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
...@@ -224,7 +227,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -224,7 +227,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success; return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to remove the lock */ /* Now try to remove the lock */
resp->status = cast_status(nlmsvc_unlock(file, &argp->lock)); resp->status = cast_status(nlmsvc_unlock(net, file, &argp->lock));
dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status)); dprintk("lockd: UNLOCK status %d\n", ntohl(resp->status));
nlmsvc_release_host(host); nlmsvc_release_host(host);
...@@ -361,7 +364,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -361,7 +364,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept new lock requests during grace period */ /* Don't accept new lock requests during grace period */
if (locks_in_grace() && !argp->reclaim) { if (locks_in_grace(SVC_NET(rqstp)) && !argp->reclaim) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
...@@ -394,7 +397,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp, ...@@ -394,7 +397,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
resp->cookie = argp->cookie; resp->cookie = argp->cookie;
/* Don't accept requests during grace period */ /* Don't accept requests during grace period */
if (locks_in_grace()) { if (locks_in_grace(SVC_NET(rqstp))) {
resp->status = nlm_lck_denied_grace_period; resp->status = nlm_lck_denied_grace_period;
return rpc_success; return rpc_success;
} }
......
...@@ -309,7 +309,8 @@ nlm_release_file(struct nlm_file *file) ...@@ -309,7 +309,8 @@ nlm_release_file(struct nlm_file *file)
* Helpers function for resource traversal * Helpers function for resource traversal
* *
* nlmsvc_mark_host: * nlmsvc_mark_host:
* used by the garbage collector; simply sets h_inuse. * used by the garbage collector; simply sets h_inuse only for those
* hosts, which passed network check.
* Always returns 0. * Always returns 0.
* *
* nlmsvc_same_host: * nlmsvc_same_host:
...@@ -320,12 +321,15 @@ nlm_release_file(struct nlm_file *file) ...@@ -320,12 +321,15 @@ nlm_release_file(struct nlm_file *file)
* returns 1 iff the host is a client. * returns 1 iff the host is a client.
* Used by nlmsvc_invalidate_all * Used by nlmsvc_invalidate_all
*/ */
static int static int
nlmsvc_mark_host(void *data, struct nlm_host *dummy) nlmsvc_mark_host(void *data, struct nlm_host *hint)
{ {
struct nlm_host *host = data; struct nlm_host *host = data;
host->h_inuse = 1; if ((hint->net == NULL) ||
(host->net == hint->net))
host->h_inuse = 1;
return 0; return 0;
} }
...@@ -358,10 +362,13 @@ nlmsvc_is_client(void *data, struct nlm_host *dummy) ...@@ -358,10 +362,13 @@ nlmsvc_is_client(void *data, struct nlm_host *dummy)
* Mark all hosts that still hold resources * Mark all hosts that still hold resources
*/ */
void void
nlmsvc_mark_resources(void) nlmsvc_mark_resources(struct net *net)
{ {
dprintk("lockd: nlmsvc_mark_resources\n"); struct nlm_host hint;
nlm_traverse_files(NULL, nlmsvc_mark_host, NULL);
dprintk("lockd: nlmsvc_mark_resources for net %p\n", net);
hint.net = net;
nlm_traverse_files(&hint, nlmsvc_mark_host, NULL);
} }
/* /*
......
...@@ -427,18 +427,8 @@ static void lease_break_callback(struct file_lock *fl) ...@@ -427,18 +427,8 @@ static void lease_break_callback(struct file_lock *fl)
kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG); kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
} }
static void lease_release_private_callback(struct file_lock *fl)
{
if (!fl->fl_file)
return;
f_delown(fl->fl_file);
fl->fl_file->f_owner.signum = 0;
}
static const struct lock_manager_operations lease_manager_ops = { static const struct lock_manager_operations lease_manager_ops = {
.lm_break = lease_break_callback, .lm_break = lease_break_callback,
.lm_release_private = lease_release_private_callback,
.lm_change = lease_modify, .lm_change = lease_modify,
}; };
...@@ -580,12 +570,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p) ...@@ -580,12 +570,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p)
fl->fl_next = NULL; fl->fl_next = NULL;
list_del_init(&fl->fl_link); list_del_init(&fl->fl_link);
fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
if (fl->fl_fasync != NULL) {
printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
fl->fl_fasync = NULL;
}
if (fl->fl_nspid) { if (fl->fl_nspid) {
put_pid(fl->fl_nspid); put_pid(fl->fl_nspid);
fl->fl_nspid = NULL; fl->fl_nspid = NULL;
...@@ -1155,8 +1139,18 @@ int lease_modify(struct file_lock **before, int arg) ...@@ -1155,8 +1139,18 @@ int lease_modify(struct file_lock **before, int arg)
return error; return error;
lease_clear_pending(fl, arg); lease_clear_pending(fl, arg);
locks_wake_up_blocks(fl); locks_wake_up_blocks(fl);
if (arg == F_UNLCK) if (arg == F_UNLCK) {
struct file *filp = fl->fl_file;
f_delown(filp);
filp->f_owner.signum = 0;
fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
if (fl->fl_fasync != NULL) {
printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
fl->fl_fasync = NULL;
}
locks_delete_lock(before); locks_delete_lock(before);
}
return 0; return 0;
} }
......
...@@ -863,7 +863,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r ...@@ -863,7 +863,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
.drc_status = 0, .drc_status = 0,
.clp = NULL, .clp = NULL,
.slotid = NFS4_NO_SLOT, .slotid = NFS4_NO_SLOT,
.net = rqstp->rq_xprt->xpt_net, .net = SVC_NET(rqstp),
}; };
unsigned int nops = 0; unsigned int nops = 0;
...@@ -879,7 +879,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r ...@@ -879,7 +879,7 @@ static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
return rpc_garbage_args; return rpc_garbage_args;
if (hdr_arg.minorversion == 0) { if (hdr_arg.minorversion == 0) {
cps.clp = nfs4_find_client_ident(rqstp->rq_xprt->xpt_net, hdr_arg.cb_ident); cps.clp = nfs4_find_client_ident(SVC_NET(rqstp), hdr_arg.cb_ident);
if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp)) if (!cps.clp || !check_gss_callback_principal(cps.clp, rqstp))
return rpc_drop_reply; return rpc_drop_reply;
} }
......
...@@ -398,7 +398,7 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) ...@@ -398,7 +398,7 @@ fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
int migrated, i, err; int migrated, i, err;
/* listsize */ /* listsize */
err = get_int(mesg, &fsloc->locations_count); err = get_uint(mesg, &fsloc->locations_count);
if (err) if (err)
return err; return err;
if (fsloc->locations_count > MAX_FS_LOCATIONS) if (fsloc->locations_count > MAX_FS_LOCATIONS)
...@@ -456,7 +456,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) ...@@ -456,7 +456,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
return -EINVAL; return -EINVAL;
for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) { for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
err = get_int(mesg, &f->pseudoflavor); err = get_uint(mesg, &f->pseudoflavor);
if (err) if (err)
return err; return err;
/* /*
...@@ -465,7 +465,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp) ...@@ -465,7 +465,7 @@ static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
* problem at export time instead of when a client fails * problem at export time instead of when a client fails
* to authenticate. * to authenticate.
*/ */
err = get_int(mesg, &f->flags); err = get_uint(mesg, &f->flags);
if (err) if (err)
return err; return err;
/* Only some flags are allowed to differ between flavors: */ /* Only some flags are allowed to differ between flavors: */
...@@ -929,7 +929,7 @@ struct svc_export * ...@@ -929,7 +929,7 @@ struct svc_export *
rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path) rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
{ {
struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
struct cache_detail *cd = nn->svc_export_cache; struct cache_detail *cd = nn->svc_export_cache;
if (rqstp->rq_client == NULL) if (rqstp->rq_client == NULL)
...@@ -960,7 +960,7 @@ struct svc_export * ...@@ -960,7 +960,7 @@ struct svc_export *
rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv) rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
{ {
struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
struct cache_detail *cd = nn->svc_export_cache; struct cache_detail *cd = nn->svc_export_cache;
if (rqstp->rq_client == NULL) if (rqstp->rq_client == NULL)
......
...@@ -34,6 +34,10 @@ struct nfsd_net { ...@@ -34,6 +34,10 @@ struct nfsd_net {
struct cache_detail *idtoname_cache; struct cache_detail *idtoname_cache;
struct cache_detail *nametoid_cache; struct cache_detail *nametoid_cache;
struct lock_manager nfsd4_manager;
bool grace_ended;
time_t boot_time;
}; };
extern int nfsd_net_id; extern int nfsd_net_id;
......
...@@ -756,7 +756,6 @@ static void do_probe_callback(struct nfs4_client *clp) ...@@ -756,7 +756,6 @@ static void do_probe_callback(struct nfs4_client *clp)
*/ */
void nfsd4_probe_callback(struct nfs4_client *clp) void nfsd4_probe_callback(struct nfs4_client *clp)
{ {
/* XXX: atomicity? Also, should we be using cl_flags? */
clp->cl_cb_state = NFSD4_CB_UNKNOWN; clp->cl_cb_state = NFSD4_CB_UNKNOWN;
set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags);
do_probe_callback(clp); do_probe_callback(clp);
......
...@@ -546,7 +546,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen ...@@ -546,7 +546,7 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
.type = type, .type = type,
}; };
int ret; int ret;
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
if (namelen + 1 > sizeof(key.name)) if (namelen + 1 > sizeof(key.name))
return nfserr_badowner; return nfserr_badowner;
...@@ -571,7 +571,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name) ...@@ -571,7 +571,7 @@ idmap_id_to_name(struct svc_rqst *rqstp, int type, uid_t id, char *name)
.type = type, .type = type,
}; };
int ret; int ret;
struct nfsd_net *nn = net_generic(rqstp->rq_xprt->xpt_net, nfsd_net_id); struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname)); strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item); ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item);
......
...@@ -354,10 +354,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -354,10 +354,10 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
/* Openowner is now set, so sequence id will get bumped. Now we need /* Openowner is now set, so sequence id will get bumped. Now we need
* these checks before we do any creates: */ * these checks before we do any creates: */
status = nfserr_grace; status = nfserr_grace;
if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS) if (locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
goto out; goto out;
status = nfserr_no_grace; status = nfserr_no_grace;
if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) if (!locks_in_grace(SVC_NET(rqstp)) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
goto out; goto out;
switch (open->op_claim_type) { switch (open->op_claim_type) {
...@@ -686,7 +686,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -686,7 +686,8 @@ nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
nfs4_lock_state(); nfs4_lock_state();
/* check stateid */ /* check stateid */
if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid, if ((status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
cstate, &read->rd_stateid,
RD_STATE, &read->rd_filp))) { RD_STATE, &read->rd_filp))) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n"); dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out; goto out;
...@@ -741,7 +742,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -741,7 +742,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
{ {
__be32 status; __be32 status;
if (locks_in_grace()) if (locks_in_grace(SVC_NET(rqstp)))
return nfserr_grace; return nfserr_grace;
status = nfsd_unlink(rqstp, &cstate->current_fh, 0, status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
remove->rm_name, remove->rm_namelen); remove->rm_name, remove->rm_namelen);
...@@ -760,8 +761,8 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -760,8 +761,8 @@ nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (!cstate->save_fh.fh_dentry) if (!cstate->save_fh.fh_dentry)
return status; return status;
if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags if (locks_in_grace(SVC_NET(rqstp)) &&
& NFSEXP_NOSUBTREECHECK)) !(cstate->save_fh.fh_export->ex_flags & NFSEXP_NOSUBTREECHECK))
return nfserr_grace; return nfserr_grace;
status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname, status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
rename->rn_snamelen, &cstate->current_fh, rename->rn_snamelen, &cstate->current_fh,
...@@ -845,7 +846,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -845,7 +846,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) { if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
nfs4_lock_state(); nfs4_lock_state();
status = nfs4_preprocess_stateid_op(cstate, status = nfs4_preprocess_stateid_op(SVC_NET(rqstp), cstate,
&setattr->sa_stateid, WR_STATE, NULL); &setattr->sa_stateid, WR_STATE, NULL);
nfs4_unlock_state(); nfs4_unlock_state();
if (status) { if (status) {
...@@ -890,7 +891,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -890,7 +891,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
return nfserr_inval; return nfserr_inval;
nfs4_lock_state(); nfs4_lock_state();
status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp); status = nfs4_preprocess_stateid_op(SVC_NET(rqstp),
cstate, stateid, WR_STATE, &filp);
if (filp) if (filp)
get_file(filp); get_file(filp);
nfs4_unlock_state(); nfs4_unlock_state();
......
This diff is collapsed.
...@@ -2259,7 +2259,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, ...@@ -2259,7 +2259,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) { if (bmval0 & FATTR4_WORD0_CASE_INSENSITIVE) {
if ((buflen -= 4) < 0) if ((buflen -= 4) < 0)
goto out_resource; goto out_resource;
WRITE32(1); WRITE32(0);
} }
if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) { if (bmval0 & FATTR4_WORD0_CASE_PRESERVING) {
if ((buflen -= 4) < 0) if ((buflen -= 4) < 0)
......
...@@ -673,9 +673,7 @@ static ssize_t __write_ports_addfd(char *buf) ...@@ -673,9 +673,7 @@ static ssize_t __write_ports_addfd(char *buf)
err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT); err = svc_addsock(nfsd_serv, fd, buf, SIMPLE_TRANSACTION_LIMIT);
if (err < 0) { if (err < 0) {
if (nfsd_serv->sv_nrthreads == 1) nfsd_destroy(net);
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
return err; return err;
} }
...@@ -744,9 +742,7 @@ static ssize_t __write_ports_addxprt(char *buf) ...@@ -744,9 +742,7 @@ static ssize_t __write_ports_addxprt(char *buf)
svc_xprt_put(xprt); svc_xprt_put(xprt);
} }
out_err: out_err:
if (nfsd_serv->sv_nrthreads == 1) nfsd_destroy(net);
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
return err; return err;
} }
......
...@@ -72,6 +72,19 @@ int nfsd_nrthreads(void); ...@@ -72,6 +72,19 @@ int nfsd_nrthreads(void);
int nfsd_nrpools(void); int nfsd_nrpools(void);
int nfsd_get_nrthreads(int n, int *); int nfsd_get_nrthreads(int n, int *);
int nfsd_set_nrthreads(int n, int *); int nfsd_set_nrthreads(int n, int *);
int nfsd_pool_stats_open(struct inode *, struct file *);
int nfsd_pool_stats_release(struct inode *, struct file *);
static inline void nfsd_destroy(struct net *net)
{
int destroy = (nfsd_serv->sv_nrthreads == 1);
if (destroy)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
if (destroy)
nfsd_serv = NULL;
}
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) #if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
#ifdef CONFIG_NFSD_V2_ACL #ifdef CONFIG_NFSD_V2_ACL
......
...@@ -254,8 +254,6 @@ static void nfsd_shutdown(void) ...@@ -254,8 +254,6 @@ static void nfsd_shutdown(void)
static void nfsd_last_thread(struct svc_serv *serv, struct net *net) static void nfsd_last_thread(struct svc_serv *serv, struct net *net)
{ {
/* When last nfsd thread exits we need to do some clean-up */
nfsd_serv = NULL;
nfsd_shutdown(); nfsd_shutdown();
svc_rpcb_cleanup(serv, net); svc_rpcb_cleanup(serv, net);
...@@ -332,6 +330,7 @@ static int nfsd_get_default_max_blksize(void) ...@@ -332,6 +330,7 @@ static int nfsd_get_default_max_blksize(void)
int nfsd_create_serv(void) int nfsd_create_serv(void)
{ {
int error; int error;
struct net *net = current->nsproxy->net_ns;
WARN_ON(!mutex_is_locked(&nfsd_mutex)); WARN_ON(!mutex_is_locked(&nfsd_mutex));
if (nfsd_serv) { if (nfsd_serv) {
...@@ -346,7 +345,7 @@ int nfsd_create_serv(void) ...@@ -346,7 +345,7 @@ int nfsd_create_serv(void)
if (nfsd_serv == NULL) if (nfsd_serv == NULL)
return -ENOMEM; return -ENOMEM;
error = svc_bind(nfsd_serv, current->nsproxy->net_ns); error = svc_bind(nfsd_serv, net);
if (error < 0) { if (error < 0) {
svc_destroy(nfsd_serv); svc_destroy(nfsd_serv);
return error; return error;
...@@ -427,11 +426,7 @@ int nfsd_set_nrthreads(int n, int *nthreads) ...@@ -427,11 +426,7 @@ int nfsd_set_nrthreads(int n, int *nthreads)
if (err) if (err)
break; break;
} }
nfsd_destroy(net);
if (nfsd_serv->sv_nrthreads == 1)
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
return err; return err;
} }
...@@ -478,9 +473,7 @@ nfsd_svc(unsigned short port, int nrservs) ...@@ -478,9 +473,7 @@ nfsd_svc(unsigned short port, int nrservs)
if (error < 0 && !nfsd_up_before) if (error < 0 && !nfsd_up_before)
nfsd_shutdown(); nfsd_shutdown();
out_destroy: out_destroy:
if (nfsd_serv->sv_nrthreads == 1) nfsd_destroy(net); /* Release server */
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv); /* Release server */
out: out:
mutex_unlock(&nfsd_mutex); mutex_unlock(&nfsd_mutex);
return error; return error;
...@@ -563,12 +556,13 @@ nfsd(void *vrqstp) ...@@ -563,12 +556,13 @@ nfsd(void *vrqstp)
nfsdstats.th_cnt --; nfsdstats.th_cnt --;
out: out:
if (rqstp->rq_server->sv_nrthreads == 1) rqstp->rq_server = NULL;
svc_shutdown_net(rqstp->rq_server, &init_net);
/* Release the thread */ /* Release the thread */
svc_exit_thread(rqstp); svc_exit_thread(rqstp);
nfsd_destroy(&init_net);
/* Release module */ /* Release module */
mutex_unlock(&nfsd_mutex); mutex_unlock(&nfsd_mutex);
module_put_and_exit(0); module_put_and_exit(0);
...@@ -682,9 +676,7 @@ int nfsd_pool_stats_release(struct inode *inode, struct file *file) ...@@ -682,9 +676,7 @@ int nfsd_pool_stats_release(struct inode *inode, struct file *file)
mutex_lock(&nfsd_mutex); mutex_lock(&nfsd_mutex);
/* this function really, really should have been called svc_put() */ /* this function really, really should have been called svc_put() */
if (nfsd_serv->sv_nrthreads == 1) nfsd_destroy(net);
svc_shutdown_net(nfsd_serv, net);
svc_destroy(nfsd_serv);
mutex_unlock(&nfsd_mutex); mutex_unlock(&nfsd_mutex);
return ret; return ret;
} }
...@@ -450,8 +450,10 @@ static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) ...@@ -450,8 +450,10 @@ static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)
#define WR_STATE 0x00000020 #define WR_STATE 0x00000020
struct nfsd4_compound_state; struct nfsd4_compound_state;
struct nfsd_net;
extern __be32 nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate, extern __be32 nfs4_preprocess_stateid_op(struct net *net,
struct nfsd4_compound_state *cstate,
stateid_t *stateid, int flags, struct file **filp); stateid_t *stateid, int flags, struct file **filp);
extern void nfs4_lock_state(void); extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void); extern void nfs4_unlock_state(void);
...@@ -475,7 +477,6 @@ extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname); ...@@ -475,7 +477,6 @@ extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
extern int nfs4_client_to_reclaim(const char *name); extern int nfs4_client_to_reclaim(const char *name);
extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id); extern int nfs4_has_reclaimed_state(const char *name, bool use_exchange_id);
extern void release_session_client(struct nfsd4_session *); extern void release_session_client(struct nfsd4_session *);
extern __be32 nfs4_validate_stateid(struct nfs4_client *, stateid_t *);
extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *); extern void nfsd4_purge_closed_stateid(struct nfs4_stateowner *);
/* nfs4recover operations */ /* nfs4recover operations */
......
...@@ -757,8 +757,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, ...@@ -757,8 +757,16 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
* If we get here, then the client has already done an "open", * If we get here, then the client has already done an "open",
* and (hopefully) checked permission - so allow OWNER_OVERRIDE * and (hopefully) checked permission - so allow OWNER_OVERRIDE
* in case a chmod has now revoked permission. * in case a chmod has now revoked permission.
*
* Arguably we should also allow the owner override for
* directories, but we never have and it doesn't seem to have
* caused anyone a problem. If we were to change this, note
* also that our filldir callbacks would need a variant of
* lookup_one_len that doesn't check permissions.
*/ */
err = fh_verify(rqstp, fhp, type, may_flags | NFSD_MAY_OWNER_OVERRIDE); if (type == S_IFREG)
may_flags |= NFSD_MAY_OWNER_OVERRIDE;
err = fh_verify(rqstp, fhp, type, may_flags);
if (err) if (err)
goto out; goto out;
......
...@@ -1163,9 +1163,10 @@ struct lock_manager { ...@@ -1163,9 +1163,10 @@ struct lock_manager {
struct list_head list; struct list_head list;
}; };
void locks_start_grace(struct lock_manager *); struct net;
void locks_start_grace(struct net *, struct lock_manager *);
void locks_end_grace(struct lock_manager *); void locks_end_grace(struct lock_manager *);
int locks_in_grace(void); int locks_in_grace(struct net *);
/* that will die - we need it for nfs_lock_info */ /* that will die - we need it for nfs_lock_info */
#include <linux/nfs_fs_i.h> #include <linux/nfs_fs_i.h>
......
...@@ -262,11 +262,11 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref); ...@@ -262,11 +262,11 @@ typedef int (*nlm_host_match_fn_t)(void *cur, struct nlm_host *ref);
__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *, __be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_host *, struct nlm_lock *, int, struct nlm_host *, struct nlm_lock *, int,
struct nlm_cookie *, int); struct nlm_cookie *, int);
__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *); __be32 nlmsvc_unlock(struct net *net, struct nlm_file *, struct nlm_lock *);
__be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *, __be32 nlmsvc_testlock(struct svc_rqst *, struct nlm_file *,
struct nlm_host *, struct nlm_lock *, struct nlm_host *, struct nlm_lock *,
struct nlm_lock *, struct nlm_cookie *); struct nlm_lock *, struct nlm_cookie *);
__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *); __be32 nlmsvc_cancel_blocked(struct net *net, struct nlm_file *, struct nlm_lock *);
unsigned long nlmsvc_retry_blocked(void); unsigned long nlmsvc_retry_blocked(void);
void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *, void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
nlm_host_match_fn_t match); nlm_host_match_fn_t match);
...@@ -279,7 +279,7 @@ void nlmsvc_release_call(struct nlm_rqst *); ...@@ -279,7 +279,7 @@ void nlmsvc_release_call(struct nlm_rqst *);
__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **, __be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
struct nfs_fh *); struct nfs_fh *);
void nlm_release_file(struct nlm_file *); void nlm_release_file(struct nlm_file *);
void nlmsvc_mark_resources(void); void nlmsvc_mark_resources(struct net *);
void nlmsvc_free_host_resources(struct nlm_host *); void nlmsvc_free_host_resources(struct nlm_host *);
void nlmsvc_invalidate_all(void); void nlmsvc_invalidate_all(void);
......
...@@ -217,14 +217,32 @@ extern int qword_get(char **bpp, char *dest, int bufsize); ...@@ -217,14 +217,32 @@ extern int qword_get(char **bpp, char *dest, int bufsize);
static inline int get_int(char **bpp, int *anint) static inline int get_int(char **bpp, int *anint)
{ {
char buf[50]; char buf[50];
char *ep; int len = qword_get(bpp, buf, sizeof(buf));
int rv;
int len = qword_get(bpp, buf, 50); if (len < 0)
if (len < 0) return -EINVAL; return -EINVAL;
if (len ==0) return -ENOENT; if (len == 0)
rv = simple_strtol(buf, &ep, 0); return -ENOENT;
if (*ep) return -EINVAL;
*anint = rv; if (kstrtoint(buf, 0, anint))
return -EINVAL;
return 0;
}
static inline int get_uint(char **bpp, unsigned int *anint)
{
char buf[50];
int len = qword_get(bpp, buf, sizeof(buf));
if (len < 0)
return -EINVAL;
if (len == 0)
return -ENOENT;
if (kstrtouint(buf, 0, anint))
return -EINVAL;
return 0; return 0;
} }
......
...@@ -278,6 +278,8 @@ struct svc_rqst { ...@@ -278,6 +278,8 @@ struct svc_rqst {
struct task_struct *rq_task; /* service thread */ struct task_struct *rq_task; /* service thread */
}; };
#define SVC_NET(svc_rqst) (svc_rqst->rq_xprt->xpt_net)
/* /*
* Rigorous type checking on sockaddr type conversions * Rigorous type checking on sockaddr type conversions
*/ */
......
...@@ -1349,8 +1349,11 @@ static int c_show(struct seq_file *m, void *p) ...@@ -1349,8 +1349,11 @@ static int c_show(struct seq_file *m, void *p)
if (cache_check(cd, cp, NULL)) if (cache_check(cd, cp, NULL))
/* cache_check does a cache_put on failure */ /* cache_check does a cache_put on failure */
seq_printf(m, "# "); seq_printf(m, "# ");
else else {
if (cache_is_expired(cd, cp))
seq_printf(m, "# ");
cache_put(cp, cd); cache_put(cp, cd);
}
return cd->cache_show(m, cd, cp); return cd->cache_show(m, cd, cp);
} }
......
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