]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - fs/nfs/nfs4proc.c
nfs41: drain session cleanup
[mv-sheeva.git] / fs / nfs / nfs4proc.c
index 741a562177fc3f587dcd1e1019f3cfe53c367de8..a0f73e99ff3d5e7a689af6f224efcc597695a2f4 100644 (file)
@@ -270,11 +270,18 @@ static int nfs4_handle_exception(const struct nfs_server *server, int errorcode,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR: %d Reset session\n", __func__,
                                errorcode);
-                       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
                        exception->retry = 1;
-                       /* FALLTHROUGH */
+                       break;
 #endif /* !defined(CONFIG_NFS_V4_1) */
                case -NFS4ERR_FILE_OPEN:
+                       if (exception->timeout > HZ) {
+                               /* We have retried a decent amount, time to
+                                * fail
+                                */
+                               ret = -EBUSY;
+                               break;
+                       }
                case -NFS4ERR_GRACE:
                case -NFS4ERR_DELAY:
                        ret = nfs4_delay(server->client, &exception->timeout);
@@ -329,7 +336,6 @@ nfs4_free_slot(struct nfs4_slot_table *tbl, u8 free_slotid)
                else
                        tbl->highest_used_slotid = -1;
        }
-       rpc_wake_up_next(&tbl->slot_tbl_waitq);
        spin_unlock(&tbl->slot_tbl_lock);
        dprintk("%s: free_slotid %u highest_used_slotid %d\n", __func__,
                free_slotid, tbl->highest_used_slotid);
@@ -346,14 +352,25 @@ void nfs41_sequence_free_slot(const struct nfs_client *clp,
        }
        tbl = &clp->cl_session->fc_slot_table;
        if (res->sr_slotid == NFS4_MAX_SLOT_TABLE) {
-               dprintk("%s: No slot\n", __func__);
                /* just wake up the next guy waiting since
                 * we may have not consumed a slot after all */
+               dprintk("%s: No slot\n", __func__);
+       } else {
+               nfs4_free_slot(tbl, res->sr_slotid);
+               res->sr_slotid = NFS4_MAX_SLOT_TABLE;
+       }
+
+       /* Signal state manager thread if session is drained */
+       if (test_bit(NFS4CLNT_SESSION_DRAINING, &clp->cl_state)) {
+               spin_lock(&tbl->slot_tbl_lock);
+               if (tbl->highest_used_slotid == -1) {
+                       dprintk("%s COMPLETE: Session Drained\n", __func__);
+                       complete(&clp->cl_session->complete);
+               }
+               spin_unlock(&tbl->slot_tbl_lock);
+       } else {
                rpc_wake_up_next(&tbl->slot_tbl_waitq);
-               return;
        }
-       nfs4_free_slot(tbl, res->sr_slotid);
-       res->sr_slotid = NFS4_MAX_SLOT_TABLE;
 }
 
 static void nfs41_sequence_done(struct nfs_client *clp,
@@ -377,10 +394,10 @@ static void nfs41_sequence_done(struct nfs_client *clp,
        if (res->sr_slotid == NFS4_MAX_SLOT_TABLE)
                goto out;
 
-       tbl = &clp->cl_session->fc_slot_table;
-       slot = tbl->slots + res->sr_slotid;
-
+       /* Check the SEQUENCE operation status */
        if (res->sr_status == 0) {
+               tbl = &clp->cl_session->fc_slot_table;
+               slot = tbl->slots + res->sr_slotid;
                /* Update the slot's sequence and clientid lease timer */
                ++slot->seq_nr;
                timestamp = res->sr_renewal_time;
@@ -429,24 +446,6 @@ out:
        return ret_id;
 }
 
-static int nfs4_recover_session(struct nfs4_session *session)
-{
-       struct nfs_client *clp = session->clp;
-       unsigned int loop;
-       int ret;
-
-       for (loop = NFS4_MAX_LOOP_ON_RECOVER; loop != 0; loop--) {
-               ret = nfs4_wait_clnt_recover(clp);
-               if (ret != 0)
-                       break;
-               if (!test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state))
-                       break;
-               nfs4_schedule_state_manager(clp);
-               ret = -EIO;
-       }
-       return ret;
-}
-
 static int nfs41_setup_sequence(struct nfs4_session *session,
                                struct nfs4_sequence_args *args,
                                struct nfs4_sequence_res *res,
@@ -455,7 +454,6 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
 {
        struct nfs4_slot *slot;
        struct nfs4_slot_table *tbl;
-       int status = 0;
        u8 slotid;
 
        dprintk("--> %s\n", __func__);
@@ -468,21 +466,16 @@ static int nfs41_setup_sequence(struct nfs4_session *session,
        tbl = &session->fc_slot_table;
 
        spin_lock(&tbl->slot_tbl_lock);
-       if (test_bit(NFS4CLNT_SESSION_SETUP, &session->clp->cl_state)) {
-               if (tbl->highest_used_slotid != -1) {
-                       rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
-                       spin_unlock(&tbl->slot_tbl_lock);
-                       dprintk("<-- %s: Session reset: draining\n", __func__);
-                       return -EAGAIN;
-               }
-
-               /* The slot table is empty; start the reset thread */
-               dprintk("%s Session Reset\n", __func__);
+       if (test_bit(NFS4CLNT_SESSION_RESET, &session->clp->cl_state)) {
+               /*
+                * The state manager will wait until the slot table is empty.
+                * Schedule the reset thread
+                */
+               dprintk("%s Schedule Session Reset\n", __func__);
+               rpc_sleep_on(&tbl->slot_tbl_waitq, task, NULL);
+               nfs4_schedule_state_manager(session->clp);
                spin_unlock(&tbl->slot_tbl_lock);
-               status = nfs4_recover_session(session);
-               if (status)
-                       return status;
-               spin_lock(&tbl->slot_tbl_lock);
+               return -EAGAIN;
        }
 
        slotid = nfs4_find_slot(tbl, task);
@@ -527,7 +520,7 @@ int nfs4_setup_sequence(struct nfs_client *clp,
                goto out;
        ret = nfs41_setup_sequence(clp->cl_session, args, res, cache_reply,
                                   task);
-       if (ret != -EAGAIN) {
+       if (ret && ret != -EAGAIN) {
                /* terminate rpc task */
                task->tk_status = ret;
                task->tk_action = NULL;
@@ -637,6 +630,19 @@ static void nfs4_sequence_done(const struct nfs_server *server,
 #endif /* CONFIG_NFS_V4_1 */
 }
 
+void nfs4_restart_rpc(struct rpc_task *task, const struct nfs_client *clp,
+                     struct nfs4_sequence_res *res)
+{
+#ifdef CONFIG_NFS_V4_1
+       if (nfs4_has_session(clp)) {
+               nfs41_sequence_free_slot(clp, res);
+               rpc_restart_call_prepare(task);
+               return;
+       }
+#endif /* CONFIG_NFS_V4_1 */
+       rpc_restart_call(task);
+}
+
 /* no restart, therefore free slot here */
 static void nfs4_sequence_done_free_slot(const struct nfs_server *server,
                                         struct nfs4_sequence_res *res,
@@ -1488,7 +1494,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
        return ret;
 }
 
-static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
+static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state)
 {
        struct nfs_server *server = NFS_SERVER(state->inode);
        struct nfs4_exception exception = { };
@@ -1496,10 +1502,16 @@ static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4
 
        do {
                err = _nfs4_open_expired(ctx, state);
-               if (err != -NFS4ERR_DELAY)
-                       break;
-               nfs4_handle_exception(server, err, &exception);
+               switch (err) {
+               default:
+                       goto out;
+               case -NFS4ERR_GRACE:
+               case -NFS4ERR_DELAY:
+                       nfs4_handle_exception(server, err, &exception);
+                       err = 0;
+               }
        } while (exception.retry);
+out:
        return err;
 }
 
@@ -1737,7 +1749,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                                break;
                default:
                        if (nfs4_async_handle_error(task, server, state) == -EAGAIN) {
-                               nfs4_restart_rpc(task, server->nfs_client);
+                               nfs4_restart_rpc(task, server->nfs_client,
+                                                &calldata->res.seq_res);
                                return;
                        }
        }
@@ -1981,7 +1994,7 @@ out_drop:
        return 0;
 }
 
-void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
+static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync)
 {
        if (ctx->state == NULL)
                return;
@@ -2975,13 +2988,16 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_read_data *data)
        nfs4_sequence_done(server, &data->res.seq_res, task->tk_status);
 
        if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) {
-               nfs4_restart_rpc(task, server->nfs_client);
+               nfs4_restart_rpc(task, server->nfs_client, &data->res.seq_res);
                return -EAGAIN;
        }
 
        nfs_invalidate_atime(data->inode);
        if (task->tk_status > 0)
                renew_lease(server, data->timestamp);
+       else if (task->tk_status < 0)
+               nfs4_sequence_free_slot(server->nfs_client, &data->res.seq_res);
+
        return 0;
 }
 
@@ -3000,7 +3016,8 @@ static int nfs4_write_done(struct rpc_task *task, struct nfs_write_data *data)
                           task->tk_status);
 
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) {
-               nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
+               nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client,
+                                &data->res.seq_res);
                return -EAGAIN;
        }
        if (task->tk_status >= 0) {
@@ -3028,7 +3045,8 @@ static int nfs4_commit_done(struct rpc_task *task, struct nfs_write_data *data)
        nfs4_sequence_done(NFS_SERVER(inode), &data->res.seq_res,
                           task->tk_status);
        if (nfs4_async_handle_error(task, NFS_SERVER(inode), NULL) == -EAGAIN) {
-               nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client);
+               nfs4_restart_rpc(task, NFS_SERVER(inode)->nfs_client,
+                                &data->res.seq_res);
                return -EAGAIN;
        }
        nfs4_sequence_free_slot(NFS_SERVER(inode)->nfs_client,
@@ -3350,7 +3368,7 @@ _nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
                case -NFS4ERR_SEQ_MISORDERED:
                        dprintk("%s ERROR %d, Reset session\n", __func__,
                                task->tk_status);
-                       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
+                       set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
                        task->tk_status = 0;
                        return -EAGAIN;
 #endif /* CONFIG_NFS_V4_1 */
@@ -3742,7 +3760,8 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
                default:
                        if (nfs4_async_handle_error(task, calldata->server, NULL) == -EAGAIN)
                                nfs4_restart_rpc(task,
-                                               calldata->server->nfs_client);
+                                                calldata->server->nfs_client,
+                                                &calldata->res.seq_res);
        }
        nfs4_sequence_free_slot(calldata->server->nfs_client,
                                &calldata->res.seq_res);
@@ -4049,10 +4068,16 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request
                if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
                        return 0;
                err = _nfs4_do_setlk(state, F_SETLK, request, 0);
-               if (err != -NFS4ERR_DELAY)
-                       break;
-               nfs4_handle_exception(server, err, &exception);
+               switch (err) {
+               default:
+                       goto out;
+               case -NFS4ERR_GRACE:
+               case -NFS4ERR_DELAY:
+                       nfs4_handle_exception(server, err, &exception);
+                       err = 0;
+               }
        } while (exception.retry);
+out:
        return err;
 }
 
@@ -4296,7 +4321,7 @@ int nfs4_proc_fs_locations(struct inode *dir, const struct qstr *name,
  * NFS4ERR_BADSESSION in the sequence operation, and will therefore
  * be in some phase of session reset.
  */
-static int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
+int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
 {
        nfs4_verifier verifier;
        struct nfs41_exchange_id_args args = {
@@ -4389,7 +4414,7 @@ static void nfs4_get_lease_time_done(struct rpc_task *task, void *calldata)
                dprintk("%s Retry: tk_status %d\n", __func__, task->tk_status);
                rpc_delay(task, NFS4_POLL_RETRY_MIN);
                task->tk_status = 0;
-               nfs4_restart_rpc(task, data->clp);
+               rpc_restart_call(task);
                return;
        }
        nfs41_sequence_free_slot(data->clp, &data->res->lr_seq_res);
@@ -4487,6 +4512,7 @@ static int nfs4_reset_slot_tables(struct nfs4_session *session)
                        1);
        if (status)
                return status;
+       init_completion(&session->complete);
 
        status = nfs4_reset_slot_table(&session->bc_slot_table,
                        session->bc_attrs.max_reqs,
@@ -4582,7 +4608,6 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
        if (!session)
                return NULL;
 
-       set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
        /*
         * The create session reply races with the server back
         * channel probe. Mark the client NFS_CS_SESSION_INITING
@@ -4590,6 +4615,7 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
         * nfs_client struct
         */
        clp->cl_cons_state = NFS_CS_SESSION_INITING;
+       init_completion(&session->complete);
 
        tbl = &session->fc_slot_table;
        spin_lock_init(&tbl->slot_tbl_lock);
@@ -4872,7 +4898,7 @@ void nfs41_sequence_call_done(struct rpc_task *task, void *data)
 
                if (_nfs4_async_handle_error(task, NULL, clp, NULL)
                                                                == -EAGAIN) {
-                       nfs4_restart_rpc(task, clp);
+                       nfs4_restart_rpc(task, clp, task->tk_msg.rpc_resp);
                        return;
                }
        }
@@ -4948,7 +4974,7 @@ struct nfs4_state_recovery_ops nfs41_reboot_recovery_ops = {
        .state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
        .recover_open   = nfs4_open_reclaim,
        .recover_lock   = nfs4_lock_reclaim,
-       .establish_clid = nfs4_proc_exchange_id,
+       .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
 #endif /* CONFIG_NFS_V4_1 */
@@ -4968,7 +4994,7 @@ struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = {
        .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
        .recover_open   = nfs4_open_expired,
        .recover_lock   = nfs4_lock_expired,
-       .establish_clid = nfs4_proc_exchange_id,
+       .establish_clid = nfs41_init_clientid,
        .get_clid_cred  = nfs4_get_exchange_id_cred,
 };
 #endif /* CONFIG_NFS_V4_1 */