struct nfs_open_context *ctx, struct nfs4_label *ilabel,
                            struct nfs4_label *olabel);
 #ifdef CONFIG_NFS_V4_1
+static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
+               struct rpc_cred *cred,
+               struct nfs4_slot *slot,
+               bool is_privileged);
 static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
                struct rpc_cred *);
 static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
 
 #if defined(CONFIG_NFS_V4_1)
 
-static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
+static void nfs41_release_slot(struct nfs4_slot *slot)
 {
        struct nfs4_session *session;
        struct nfs4_slot_table *tbl;
-       struct nfs4_slot *slot = res->sr_slot;
        bool send_new_highest_used_slotid = false;
 
+       if (!slot)
+               return;
        tbl = slot->table;
        session = tbl->session;
 
                send_new_highest_used_slotid = false;
 out_unlock:
        spin_unlock(&tbl->slot_tbl_lock);
-       res->sr_slot = NULL;
        if (send_new_highest_used_slotid)
                nfs41_notify_server(session->clp);
        if (waitqueue_active(&tbl->slot_waitq))
                wake_up_all(&tbl->slot_waitq);
 }
 
+static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
+{
+       nfs41_release_slot(res->sr_slot);
+       res->sr_slot = NULL;
+}
+
 static int nfs41_sequence_process(struct rpc_task *task,
                struct nfs4_sequence_res *res)
 {
        /* Check the SEQUENCE operation status */
        switch (res->sr_status) {
        case 0:
-               /* If previous op on slot was interrupted and we reused
-                * the seq# and got a reply from the cache, then retry
-                */
-               if (task->tk_status == -EREMOTEIO && interrupted) {
-                       ++slot->seq_nr;
-                       goto retry_nowait;
-               }
                /* Update the slot's sequence and clientid lease timer */
                slot->seq_done = 1;
                clp = session->clp;
                 * The slot id we used was probably retired. Try again
                 * using a different slot id.
                 */
+               if (slot->seq_nr < slot->table->target_highest_slotid)
+                       goto session_recover;
                goto retry_nowait;
        case -NFS4ERR_SEQ_MISORDERED:
                /*
                 * Was the last operation on this sequence interrupted?
                 * If so, retry after bumping the sequence number.
                 */
-               if (interrupted) {
-                       ++slot->seq_nr;
-                       goto retry_nowait;
-               }
+               if (interrupted)
+                       goto retry_new_seq;
                /*
                 * Could this slot have been previously retired?
                 * If so, then the server may be expecting seq_nr = 1!
                        slot->seq_nr = 1;
                        goto retry_nowait;
                }
-               break;
+               goto session_recover;
        case -NFS4ERR_SEQ_FALSE_RETRY:
-               ++slot->seq_nr;
-               goto retry_nowait;
+               if (interrupted)
+                       goto retry_new_seq;
+               goto session_recover;
        default:
                /* Just update the slot sequence no. */
                slot->seq_done = 1;
        dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
 out_noaction:
        return ret;
+session_recover:
+       nfs4_schedule_session_recovery(session, res->sr_status);
+       goto retry_nowait;
+retry_new_seq:
+       ++slot->seq_nr;
 retry_nowait:
        if (rpc_restart_call_prepare(task)) {
                nfs41_sequence_free_slot(res);
        .rpc_call_done = nfs41_call_sync_done,
 };
 
+static void
+nfs4_sequence_process_interrupted(struct nfs_client *client,
+               struct nfs4_slot *slot, struct rpc_cred *cred)
+{
+       struct rpc_task *task;
+
+       task = _nfs41_proc_sequence(client, cred, slot, true);
+       if (!IS_ERR(task))
+               rpc_put_task_async(task);
+}
+
 #else  /* !CONFIG_NFS_V4_1 */
 
 static int nfs4_sequence_process(struct rpc_task *task, struct nfs4_sequence_res *res)
 }
 EXPORT_SYMBOL_GPL(nfs4_sequence_done);
 
+static void
+nfs4_sequence_process_interrupted(struct nfs_client *client,
+               struct nfs4_slot *slot, struct rpc_cred *cred)
+{
+       WARN_ON_ONCE(1);
+       slot->interrupted = 0;
+}
+
 #endif /* !CONFIG_NFS_V4_1 */
 
-int nfs4_setup_sequence(const struct nfs_client *client,
+static
+void nfs4_sequence_attach_slot(struct nfs4_sequence_args *args,
+               struct nfs4_sequence_res *res,
+               struct nfs4_slot *slot)
+{
+       if (!slot)
+               return;
+       slot->privileged = args->sa_privileged ? 1 : 0;
+       args->sa_slot = slot;
+
+       res->sr_slot = slot;
+       res->sr_timestamp = jiffies;
+       res->sr_status_flags = 0;
+       res->sr_status = 1;
+
+}
+
+int nfs4_setup_sequence(struct nfs_client *client,
                        struct nfs4_sequence_args *args,
                        struct nfs4_sequence_res *res,
                        struct rpc_task *task)
                task->tk_timeout = 0;
        }
 
-       spin_lock(&tbl->slot_tbl_lock);
-       /* The state manager will wait until the slot table is empty */
-       if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
-               goto out_sleep;
+       for (;;) {
+               spin_lock(&tbl->slot_tbl_lock);
+               /* The state manager will wait until the slot table is empty */
+               if (nfs4_slot_tbl_draining(tbl) && !args->sa_privileged)
+                       goto out_sleep;
+
+               slot = nfs4_alloc_slot(tbl);
+               if (IS_ERR(slot)) {
+                       /* Try again in 1/4 second */
+                       if (slot == ERR_PTR(-ENOMEM))
+                               task->tk_timeout = HZ >> 2;
+                       goto out_sleep;
+               }
+               spin_unlock(&tbl->slot_tbl_lock);
 
-       slot = nfs4_alloc_slot(tbl);
-       if (IS_ERR(slot)) {
-               /* Try again in 1/4 second */
-               if (slot == ERR_PTR(-ENOMEM))
-                       task->tk_timeout = HZ >> 2;
-               goto out_sleep;
+               if (likely(!slot->interrupted))
+                       break;
+               nfs4_sequence_process_interrupted(client,
+                               slot, task->tk_msg.rpc_cred);
        }
-       spin_unlock(&tbl->slot_tbl_lock);
-
-       slot->privileged = args->sa_privileged ? 1 : 0;
-       args->sa_slot = slot;
 
-       res->sr_slot = slot;
-       if (session) {
-               res->sr_timestamp = jiffies;
-               res->sr_status_flags = 0;
-               res->sr_status = 1;
-       }
+       nfs4_sequence_attach_slot(args, res, slot);
 
        trace_nfs4_setup_sequence(session, args);
 out_start:
 
 static struct rpc_task *_nfs41_proc_sequence(struct nfs_client *clp,
                struct rpc_cred *cred,
+               struct nfs4_slot *slot,
                bool is_privileged)
 {
        struct nfs4_sequence_data *calldata;
                .callback_ops = &nfs41_sequence_ops,
                .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
        };
+       struct rpc_task *ret;
 
+       ret = ERR_PTR(-EIO);
        if (!atomic_inc_not_zero(&clp->cl_count))
-               return ERR_PTR(-EIO);
+               goto out_err;
+
+       ret = ERR_PTR(-ENOMEM);
        calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
-       if (calldata == NULL) {
-               nfs_put_client(clp);
-               return ERR_PTR(-ENOMEM);
-       }
+       if (calldata == NULL)
+               goto out_put_clp;
        nfs4_init_sequence(&calldata->args, &calldata->res, 0);
+       nfs4_sequence_attach_slot(&calldata->args, &calldata->res, slot);
        if (is_privileged)
                nfs4_set_sequence_privileged(&calldata->args);
        msg.rpc_argp = &calldata->args;
        calldata->clp = clp;
        task_setup_data.callback_data = calldata;
 
-       return rpc_run_task(&task_setup_data);
+       ret = rpc_run_task(&task_setup_data);
+       if (IS_ERR(ret))
+               goto out_err;
+       return ret;
+out_put_clp:
+       nfs_put_client(clp);
+out_err:
+       nfs41_release_slot(slot);
+       return ret;
 }
 
 static int nfs41_proc_async_sequence(struct nfs_client *clp, struct rpc_cred *cred, unsigned renew_flags)
 
        if ((renew_flags & NFS4_RENEW_TIMEOUT) == 0)
                return -EAGAIN;
-       task = _nfs41_proc_sequence(clp, cred, false);
+       task = _nfs41_proc_sequence(clp, cred, NULL, false);
        if (IS_ERR(task))
                ret = PTR_ERR(task);
        else
        struct rpc_task *task;
        int ret;
 
-       task = _nfs41_proc_sequence(clp, cred, true);
+       task = _nfs41_proc_sequence(clp, cred, NULL, true);
        if (IS_ERR(task)) {
                ret = PTR_ERR(task);
                goto out;