summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_state.c
diff options
context:
space:
mode:
authorPhilipp Reisner2011-02-15 11:14:44 +0100
committerPhilipp Reisner2011-10-14 16:47:32 +0200
commitdf24aa45f4df43e8881c0f80d6a4e2653df7af05 (patch)
tree3601bf824ef8f63adafec861fabfae42acde9791 /drivers/block/drbd/drbd_state.c
parentdrbd: implemented receiving of P_CONN_ST_CHG_REQ (diff)
downloadkernel-qcow2-linux-df24aa45f4df43e8881c0f80d6a4e2653df7af05.tar.gz
kernel-qcow2-linux-df24aa45f4df43e8881c0f80d6a4e2653df7af05.tar.xz
kernel-qcow2-linux-df24aa45f4df43e8881c0f80d6a4e2653df7af05.zip
drbd: Implemented connection wide state changes
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>
Diffstat (limited to 'drivers/block/drbd/drbd_state.c')
-rw-r--r--drivers/block/drbd/drbd_state.c62
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 8c49ca8dea3c..d3bf8e39fa56 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -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);