NFSv4.1: Ensure we call FREE_STATEID if needed on close/delegreturn/locku
authorTrond Myklebust <trond.myklebust@primarydata.com>
Thu, 22 Sep 2016 17:39:05 +0000 (13:39 -0400)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Tue, 27 Sep 2016 18:34:27 +0000 (14:34 -0400)
If a server returns NFS4ERR_ADMIN_REVOKED, NFS4ERR_DELEG_REVOKED
or NFS4ERR_EXPIRED on a call to close, open_downgrade, delegreturn, or
locku, we should call FREE_STATEID before attempting to recover.

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/nfs4proc.c

index 1741e6454684db73021124cd2d17f7206b083052..ee1fd4c5e646da7e5d5bbe1c9200c86bce3197f8 100644 (file)
@@ -328,6 +328,33 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
        kunmap_atomic(start);
 }
 
+static void nfs4_test_and_free_stateid(struct nfs_server *server,
+               nfs4_stateid *stateid,
+               struct rpc_cred *cred)
+{
+       const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
+
+       ops->test_and_free_expired(server, stateid, cred);
+}
+
+static void __nfs4_free_revoked_stateid(struct nfs_server *server,
+               nfs4_stateid *stateid,
+               struct rpc_cred *cred)
+{
+       stateid->type = NFS4_REVOKED_STATEID_TYPE;
+       nfs4_test_and_free_stateid(server, stateid, cred);
+}
+
+static void nfs4_free_revoked_stateid(struct nfs_server *server,
+               const nfs4_stateid *stateid,
+               struct rpc_cred *cred)
+{
+       nfs4_stateid tmp;
+
+       nfs4_stateid_copy(&tmp, stateid);
+       __nfs4_free_revoked_stateid(server, &tmp, cred);
+}
+
 static long nfs4_update_delay(long *timeout)
 {
        long ret;
@@ -2985,9 +3012,12 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                        break;
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
+               case -NFS4ERR_EXPIRED:
+                       nfs4_free_revoked_stateid(server,
+                                       &calldata->arg.stateid,
+                                       task->tk_msg.rpc_cred);
                case -NFS4ERR_OLD_STATEID:
                case -NFS4ERR_BAD_STATEID:
-               case -NFS4ERR_EXPIRED:
                        if (!nfs4_stateid_match(&calldata->arg.stateid,
                                                &state->open_stateid)) {
                                rpc_restart_call_prepare(task);
@@ -5479,10 +5509,13 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
                renew_lease(data->res.server, data->timestamp);
        case -NFS4ERR_ADMIN_REVOKED:
        case -NFS4ERR_DELEG_REVOKED:
+       case -NFS4ERR_EXPIRED:
+               nfs4_free_revoked_stateid(data->res.server,
+                               data->args.stateid,
+                               task->tk_msg.rpc_cred);
        case -NFS4ERR_BAD_STATEID:
        case -NFS4ERR_OLD_STATEID:
        case -NFS4ERR_STALE_STATEID:
-       case -NFS4ERR_EXPIRED:
                task->tk_status = 0;
                if (data->roc)
                        pnfs_roc_set_barrier(data->inode, data->roc_barrier);
@@ -5726,10 +5759,14 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                        if (nfs4_update_lock_stateid(calldata->lsp,
                                        &calldata->res.stateid))
                                break;
+               case -NFS4ERR_ADMIN_REVOKED:
+               case -NFS4ERR_EXPIRED:
+                       nfs4_free_revoked_stateid(calldata->server,
+                                       &calldata->arg.stateid,
+                                       task->tk_msg.rpc_cred);
                case -NFS4ERR_BAD_STATEID:
                case -NFS4ERR_OLD_STATEID:
                case -NFS4ERR_STALE_STATEID:
-               case -NFS4ERR_EXPIRED:
                        if (!nfs4_stateid_match(&calldata->arg.stateid,
                                                &calldata->lsp->ls_stateid))
                                rpc_restart_call_prepare(task);