lockd: NLM grace period shouldn't block NFSv4 opens
NLM locks don't conflict with NFSv4 share reservations, so we're not going to learn anything new by watiting for them. They do conflict with NFSv4 locks and with delegations. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
Родитель
4bc6603778
Коммит
c87fb4a378
|
@ -591,6 +591,7 @@ static int lockd_init_net(struct net *net)
|
||||||
|
|
||||||
INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
|
INIT_DELAYED_WORK(&ln->grace_period_end, grace_ender);
|
||||||
INIT_LIST_HEAD(&ln->lockd_manager.list);
|
INIT_LIST_HEAD(&ln->lockd_manager.list);
|
||||||
|
ln->lockd_manager.block_opens = false;
|
||||||
spin_lock_init(&ln->nsm_clnt_lock);
|
spin_lock_init(&ln->nsm_clnt_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,14 +63,33 @@ EXPORT_SYMBOL_GPL(locks_end_grace);
|
||||||
* lock reclaims.
|
* lock reclaims.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
locks_in_grace(struct net *net)
|
__state_in_grace(struct net *net, bool open)
|
||||||
{
|
{
|
||||||
struct list_head *grace_list = net_generic(net, grace_net_id);
|
struct list_head *grace_list = net_generic(net, grace_net_id);
|
||||||
|
struct lock_manager *lm;
|
||||||
|
|
||||||
return !list_empty(grace_list);
|
if (!open)
|
||||||
|
return !list_empty(grace_list);
|
||||||
|
|
||||||
|
list_for_each_entry(lm, grace_list, list) {
|
||||||
|
if (lm->block_opens)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int locks_in_grace(struct net *net)
|
||||||
|
{
|
||||||
|
return __state_in_grace(net, 0);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(locks_in_grace);
|
EXPORT_SYMBOL_GPL(locks_in_grace);
|
||||||
|
|
||||||
|
int opens_in_grace(struct net *net)
|
||||||
|
{
|
||||||
|
return __state_in_grace(net, 1);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(opens_in_grace);
|
||||||
|
|
||||||
static int __net_init
|
static int __net_init
|
||||||
grace_init_net(struct net *net)
|
grace_init_net(struct net *net)
|
||||||
{
|
{
|
||||||
|
|
|
@ -415,10 +415,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(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
if (opens_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
|
||||||
goto out;
|
goto out;
|
||||||
status = nfserr_no_grace;
|
status = nfserr_no_grace;
|
||||||
if (!locks_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
if (!opens_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
switch (open->op_claim_type) {
|
switch (open->op_claim_type) {
|
||||||
|
@ -827,7 +827,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||||
{
|
{
|
||||||
__be32 status;
|
__be32 status;
|
||||||
|
|
||||||
if (locks_in_grace(SVC_NET(rqstp)))
|
if (opens_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);
|
||||||
|
@ -846,7 +846,7 @@ 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(SVC_NET(rqstp)) &&
|
if (opens_in_grace(SVC_NET(rqstp)) &&
|
||||||
!(cstate->save_fh.fh_export->ex_flags & 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,
|
||||||
|
|
|
@ -4065,7 +4065,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
|
||||||
case NFS4_OPEN_CLAIM_FH:
|
case NFS4_OPEN_CLAIM_FH:
|
||||||
/*
|
/*
|
||||||
* Let's not give out any delegations till everyone's
|
* Let's not give out any delegations till everyone's
|
||||||
* had the chance to reclaim theirs....
|
* had the chance to reclaim theirs, *and* until
|
||||||
|
* NLM locks have all been reclaimed:
|
||||||
*/
|
*/
|
||||||
if (locks_in_grace(clp->net))
|
if (locks_in_grace(clp->net))
|
||||||
goto out_no_deleg;
|
goto out_no_deleg;
|
||||||
|
@ -4440,7 +4441,7 @@ check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid,
|
||||||
{
|
{
|
||||||
if (ONE_STATEID(stateid) && (flags & RD_STATE))
|
if (ONE_STATEID(stateid) && (flags & RD_STATE))
|
||||||
return nfs_ok;
|
return nfs_ok;
|
||||||
else if (locks_in_grace(net)) {
|
else if (opens_in_grace(net)) {
|
||||||
/* Answer in remaining cases depends on existence of
|
/* Answer in remaining cases depends on existence of
|
||||||
* conflicting state; so we must wait out the grace period. */
|
* conflicting state; so we must wait out the grace period. */
|
||||||
return nfserr_grace;
|
return nfserr_grace;
|
||||||
|
@ -4459,7 +4460,7 @@ check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid,
|
||||||
static inline int
|
static inline int
|
||||||
grace_disallows_io(struct net *net, struct inode *inode)
|
grace_disallows_io(struct net *net, struct inode *inode)
|
||||||
{
|
{
|
||||||
return locks_in_grace(net) && mandatory_lock(inode);
|
return opens_in_grace(net) && mandatory_lock(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true iff a is later than b: */
|
/* Returns true iff a is later than b: */
|
||||||
|
@ -6578,6 +6579,7 @@ nfs4_state_start_net(struct net *net)
|
||||||
return ret;
|
return ret;
|
||||||
nn->boot_time = get_seconds();
|
nn->boot_time = get_seconds();
|
||||||
nn->grace_ended = false;
|
nn->grace_ended = false;
|
||||||
|
nn->nfsd4_manager.block_opens = true;
|
||||||
locks_start_grace(net, &nn->nfsd4_manager);
|
locks_start_grace(net, &nn->nfsd4_manager);
|
||||||
nfsd4_client_tracking_init(net);
|
nfsd4_client_tracking_init(net);
|
||||||
printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
|
printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
|
||||||
|
|
|
@ -942,12 +942,18 @@ struct lock_manager_operations {
|
||||||
|
|
||||||
struct lock_manager {
|
struct lock_manager {
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
/*
|
||||||
|
* NFSv4 and up also want opens blocked during the grace period;
|
||||||
|
* NLM doesn't care:
|
||||||
|
*/
|
||||||
|
bool block_opens;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct net;
|
struct net;
|
||||||
void locks_start_grace(struct net *, struct lock_manager *);
|
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(struct net *);
|
int locks_in_grace(struct net *);
|
||||||
|
int opens_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>
|
||||||
|
|
Загрузка…
Ссылка в новой задаче