lockd: NLM grace period shouldn't block NFSv4 opens
authorJ. Bruce Fields <bfields@redhat.com>
Thu, 6 Aug 2015 16:47:02 +0000 (12:47 -0400)
committerJ. Bruce Fields <bfields@redhat.com>
Thu, 13 Aug 2015 14:22:06 +0000 (10:22 -0400)
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>
fs/lockd/svc.c
fs/nfs_common/grace.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
include/linux/fs.h

index 530914b5c455046dcaaf9712bfa94e5cadfeac0b..d678bcc3cbcb440e90045e578c755f6972079852 100644 (file)
@@ -591,6 +591,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);
        return 0;
 }
index ae6e58ea4de51b832138268f8cbdf9ed5cdefa56..fd8c9a5bcac44c74101d1b2ba4001c8785875254 100644 (file)
@@ -63,14 +63,33 @@ EXPORT_SYMBOL_GPL(locks_end_grace);
  * lock reclaims.
  */
 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 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);
 
+int opens_in_grace(struct net *net)
+{
+       return __state_in_grace(net, 1);
+}
+EXPORT_SYMBOL_GPL(opens_in_grace);
+
 static int __net_init
 grace_init_net(struct net *net)
 {
index e779d7db24b0f984c063e8883ce26880da0c6354..b9681ee0ed19e5dec47681a65bf1d1a365f19af6 100644 (file)
@@ -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
         * these checks before we do any creates: */
        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;
        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;
 
        switch (open->op_claim_type) {
@@ -827,7 +827,7 @@ nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        __be32 status;
 
-       if (locks_in_grace(SVC_NET(rqstp)))
+       if (opens_in_grace(SVC_NET(rqstp)))
                return nfserr_grace;
        status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
                             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)
                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))
                return nfserr_grace;
        status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
index 43903abd6189a4692e2e5de06466fb3dd899b6c5..c0c47a878cc61ffb8a33495b5b002d169f2c6359 100644 (file)
@@ -4065,7 +4065,8 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
                case NFS4_OPEN_CLAIM_FH:
                        /*
                         * 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))
                                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))
                return nfs_ok;
-       else if (locks_in_grace(net)) {
+       else if (opens_in_grace(net)) {
                /* Answer in remaining cases depends on existence of
                 * conflicting state; so we must wait out the grace period. */
                return nfserr_grace;
@@ -4459,7 +4460,7 @@ check_special_stateids(struct net *net, svc_fh *current_fh, stateid_t *stateid,
 static inline int
 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: */
@@ -6578,6 +6579,7 @@ nfs4_state_start_net(struct net *net)
                return ret;
        nn->boot_time = get_seconds();
        nn->grace_ended = false;
+       nn->nfsd4_manager.block_opens = true;
        locks_start_grace(net, &nn->nfsd4_manager);
        nfsd4_client_tracking_init(net);
        printk(KERN_INFO "NFSD: starting %ld-second grace period (net %p)\n",
index cc008c338f5a9bcb66076da96e929d6104697373..9a9d314f7b27f3502f0069968136057f09bea759 100644 (file)
@@ -942,12 +942,18 @@ struct lock_manager_operations {
 
 struct lock_manager {
        struct list_head list;
+       /*
+        * NFSv4 and up also want opens blocked during the grace period;
+        * NLM doesn't care:
+        */
+       bool block_opens;
 };
 
 struct net;
 void locks_start_grace(struct net *, struct lock_manager *);
 void locks_end_grace(struct lock_manager *);
 int locks_in_grace(struct net *);
+int opens_in_grace(struct net *);
 
 /* that will die - we need it for nfs_lock_info */
 #include <linux/nfs_fs_i.h>