NFSv4.x: Allow callers of nfs_remove_bad_delegation() to specify a stateid
authorTrond Myklebust <trond.myklebust@primarydata.com>
Thu, 22 Sep 2016 17:38:58 +0000 (13:38 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 27 Sep 2016 18:33:37 +0000 (14:33 -0400)
Allow the callers of nfs_remove_bad_delegation() to specify the stateid
that needs to be marked as bad.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Tested-by: Oleg Drokin <green@linuxhacker.ru>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/flexfilelayout/flexfilelayout.c
fs/nfs/nfs4proc.c

index b9c65421ed812c04fad08d18290449634a7d85fb..e5212e5c73d2b22c27394fad175f9f18e2658cb2 100644 (file)
@@ -652,23 +652,39 @@ static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *cl
        rcu_read_unlock();
 }
 
-static void nfs_revoke_delegation(struct inode *inode)
+static void nfs_mark_delegation_revoked(struct nfs_server *server,
+               struct nfs_delegation *delegation)
+{
+       set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
+       nfs_mark_return_delegation(server, delegation);
+}
+
+static bool nfs_revoke_delegation(struct inode *inode,
+               const nfs4_stateid *stateid)
 {
        struct nfs_delegation *delegation;
+       bool ret = false;
+
        rcu_read_lock();
        delegation = rcu_dereference(NFS_I(inode)->delegation);
-       if (delegation != NULL) {
-               set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
-               nfs_mark_return_delegation(NFS_SERVER(inode), delegation);
-       }
+       if (delegation == NULL)
+               goto out;
+       if (stateid && !nfs4_stateid_match(stateid, &delegation->stateid))
+               goto out;
+       nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
+       ret = true;
+out:
        rcu_read_unlock();
+       return ret;
 }
 
-void nfs_remove_bad_delegation(struct inode *inode)
+void nfs_remove_bad_delegation(struct inode *inode,
+               const nfs4_stateid *stateid)
 {
        struct nfs_delegation *delegation;
 
-       nfs_revoke_delegation(inode);
+       if (!nfs_revoke_delegation(inode, stateid))
+               return;
        delegation = nfs_inode_detach_delegation(inode);
        if (delegation) {
                nfs_inode_find_state_and_recover(inode, &delegation->stateid);
index 64724d252a7973074fcff861a31164c9df7415f9..d40827af591304548b943f0002671e2d1a53fa6d 100644 (file)
@@ -47,7 +47,7 @@ void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags);
 void nfs_expire_unreferenced_delegations(struct nfs_client *clp);
 int nfs_client_return_marked_delegations(struct nfs_client *clp);
 int nfs_delegations_present(struct nfs_client *clp);
-void nfs_remove_bad_delegation(struct inode *inode);
+void nfs_remove_bad_delegation(struct inode *inode, const nfs4_stateid *stateid);
 
 void nfs_delegation_mark_reclaim(struct nfs_client *clp);
 void nfs_delegation_reap_unclaimed(struct nfs_client *clp);
index 51b51369704c56c00732b10ff0c31edfd0d9c19e..98ace127bf861e723647019a0c8ad856f5ee0391 100644 (file)
@@ -1080,7 +1080,7 @@ static int ff_layout_async_handle_error_v4(struct rpc_task *task,
        case -NFS4ERR_BAD_STATEID:
                if (state == NULL)
                        break;
-               nfs_remove_bad_delegation(state->inode);
+               nfs_remove_bad_delegation(state->inode, NULL);
        case -NFS4ERR_OPENMODE:
                if (state == NULL)
                        break;
index 04baee4327b2287319e52f621d2dbd0bfc0f4eb7..4cc86001220a393bbb80902dabf7a79ee008dafa 100644 (file)
@@ -2385,9 +2385,10 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
        return ret;
 }
 
-static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
+static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state,
+               const nfs4_stateid *stateid)
 {
-       nfs_remove_bad_delegation(state->inode);
+       nfs_remove_bad_delegation(state->inode, stateid);
        write_seqlock(&state->seqlock);
        nfs4_stateid_copy(&state->stateid, &state->open_stateid);
        write_sequnlock(&state->seqlock);
@@ -2397,7 +2398,7 @@ static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
 static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
 {
        if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
-               nfs_finish_clear_delegation_stateid(state);
+               nfs_finish_clear_delegation_stateid(state, NULL);
 }
 
 static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
@@ -2443,19 +2444,20 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
                rcu_read_unlock();
                return;
        }
+
+       nfs4_stateid_copy(&stateid, &delegation->stateid);
        if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
                rcu_read_unlock();
-               nfs_finish_clear_delegation_stateid(state);
+               nfs_finish_clear_delegation_stateid(state, &stateid);
                return;
        }
 
-       nfs4_stateid_copy(&stateid, &delegation->stateid);
        cred = get_rpccred(delegation->cred);
        rcu_read_unlock();
        status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
        trace_nfs4_test_delegation_stateid(state, NULL, status);
        if (status != NFS_OK)
-               nfs_finish_clear_delegation_stateid(state);
+               nfs_finish_clear_delegation_stateid(state, &stateid);
 
        put_rpccred(cred);
 }