drbd: Implemented connection wide state changes
authorPhilipp Reisner <philipp.reisner@linbit.com>
Tue, 15 Feb 2011 10:14:44 +0000 (11:14 +0100)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Fri, 14 Oct 2011 14:47:32 +0000 (16:47 +0200)
That is used for graceful disconnect only

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
drivers/block/drbd/drbd_nl.c
drivers/block/drbd/drbd_state.c

index 3d8e63190dcdb9b48122cefda84a68fe9d1602fc..d6832f8d49a5f72197a168a1646e0c6e76f45172 100644 (file)
@@ -1572,6 +1572,7 @@ fail:
 static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp,
                              struct drbd_nl_cfg_reply *reply)
 {
+       struct drbd_tconn *tconn = mdev->tconn;
        int retcode;
        struct disconnect dc;
 
@@ -1582,30 +1583,29 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl
        }
 
        if (dc.force) {
-               spin_lock_irq(&mdev->tconn->req_lock);
-               if (mdev->state.conn >= C_WF_CONNECTION)
-                       _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), CS_HARD, NULL);
-               spin_unlock_irq(&mdev->tconn->req_lock);
+               spin_lock_irq(&tconn->req_lock);
+               if (tconn->cstate >= C_WF_CONNECTION)
+                       _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
+               spin_unlock_irq(&tconn->req_lock);
                goto done;
        }
 
-       retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED);
+       retcode = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0);
 
        if (retcode == SS_NOTHING_TO_DO)
                goto done;
        else if (retcode == SS_ALREADY_STANDALONE)
                goto done;
        else if (retcode == SS_PRIMARY_NOP) {
-               /* Our statche checking code wants to see the peer outdated. */
-               retcode = drbd_request_state(mdev, NS2(conn, C_DISCONNECTING,
-                                                     pdsk, D_OUTDATED));
+               /* Our state checking code wants to see the peer outdated. */
+               retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+                                                       pdsk, D_OUTDATED), CS_VERBOSE);
        } else if (retcode == SS_CW_FAILED_BY_PEER) {
                /* The peer probably wants to see us outdated. */
-               retcode = _drbd_request_state(mdev, NS2(conn, C_DISCONNECTING,
-                                                       disk, D_OUTDATED),
-                                             CS_ORDERED);
+               retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING,
+                                                       disk, D_OUTDATED), 0);
                if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) {
-                       drbd_force_state(mdev, NS(conn, C_DISCONNECTING));
+                       conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD);
                        retcode = SS_SUCCESS;
                }
        }
@@ -1613,8 +1613,8 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl
        if (retcode < SS_SUCCESS)
                goto fail;
 
-       if (wait_event_interruptible(mdev->state_wait,
-                                    mdev->state.conn != C_DISCONNECTING)) {
+       if (wait_event_interruptible(tconn->ping_wait,
+                                    tconn->cstate != C_DISCONNECTING)) {
                /* Do not test for mdev->state.conn == C_STANDALONE, since
                   someone else might connect us in the mean time! */
                retcode = ERR_INTR;
index 8c49ca8dea3c4d7d0fc42077d121c1862960dc24..d3bf8e39fa5675caaf94cd3c446d9d0e03a5c63b 100644 (file)
@@ -1366,6 +1366,61 @@ static int _set_state_itr_fn(int vnr, void *p, void *data)
        return 0;
 }
 
+static enum drbd_state_rv
+_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
+{
+       struct _is_valid_itr_params params;
+       enum drbd_state_rv rv;
+
+       if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags))
+               return SS_CW_SUCCESS;
+
+       if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags))
+               return SS_CW_FAILED_BY_PEER;
+
+       params.flags = CS_NO_CSTATE_CHG; /* ΓΆΓΆ think */
+       params.mask = mask;
+       params.val = val;
+
+       spin_lock_irq(&tconn->req_lock);
+       rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR;
+
+       if (rv == SS_UNKNOWN_ERROR)
+               rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, &params);
+
+       if (rv == 0)  /* idr_for_each semantics */
+               rv = SS_UNKNOWN_ERROR;  /* cont waiting, otherwise fail. */
+
+       spin_unlock_irq(&tconn->req_lock);
+
+       return rv;
+}
+
+static enum drbd_state_rv
+conn_cl_wide(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+            enum chg_state_flags f)
+{
+       enum drbd_state_rv rv;
+
+       spin_unlock_irq(&tconn->req_lock);
+       mutex_lock(&tconn->cstate_mutex);
+
+       if (!conn_send_state_req(tconn, mask, val)) {
+               rv = SS_CW_FAILED_BY_PEER;
+               /* if (f & CS_VERBOSE)
+                  print_st_err(mdev, os, ns, rv); */
+               goto abort;
+       }
+
+       wait_event(tconn->ping_wait, (rv = _conn_rq_cond(tconn, mask, val)));
+
+abort:
+       mutex_unlock(&tconn->cstate_mutex);
+       spin_lock_irq(&tconn->req_lock);
+
+       return rv;
+}
+
 enum drbd_state_rv
 _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
                    enum chg_state_flags flags)
@@ -1393,6 +1448,13 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
        if (rv < SS_SUCCESS)
                goto abort;
 
+       if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING &&
+           !(flags & (CS_LOCAL_ONLY | CS_HARD))) {
+               rv = conn_cl_wide(tconn, mask, val, flags);
+               if (rv < SS_SUCCESS)
+                       goto abort;
+       }
+
        if (params.oc_state == OC_CONSISTENT) {
                oc = params.oc;
                print_conn_state_change(tconn, oc, val.conn);