}
struct _is_valid_itr_params {
- enum chg_state_flags flags;
- union drbd_state mask, val;
- union drbd_state ms; /* maximal state, over all mdevs */
enum drbd_conns oc;
enum {
OC_UNINITIALIZED,
} oc_state;
};
-static int _is_valid_itr_fn(int vnr, void *p, void *data)
+static enum drbd_state_rv
+conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+ enum chg_state_flags flags, struct _is_valid_itr_params *params)
{
- struct drbd_conf *mdev = (struct drbd_conf *)p;
- struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data;
- enum chg_state_flags flags = params->flags;
+ enum drbd_state_rv rv = SS_SUCCESS;
union drbd_state ns, os;
- enum drbd_state_rv rv;
+ struct drbd_conf *mdev;
+ int vnr;
- os = mdev->state;
- ns = apply_mask_val(os, params->mask, params->val);
- ns = sanitize_state(mdev, ns, NULL);
- rv = is_valid_state(mdev, ns);
+ params->oc_state = OC_UNINITIALIZED;
+ idr_for_each_entry(&tconn->volumes, mdev, vnr) {
+ os = mdev->state;
+ ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
+
+ switch (params->oc_state) {
+ case OC_UNINITIALIZED:
+ params->oc = os.conn;
+ params->oc_state = OC_CONSISTENT;
+ break;
+ case OC_CONSISTENT:
+ if (params->oc != os.conn)
+ params->oc_state = OC_INCONSISTENT;
+ break;
+ case OC_INCONSISTENT:
+ break;
+ }
- if (rv < SS_SUCCESS) {
- /* If the old state was illegal as well, then let this happen...*/
+ if (ns.i == os.i)
+ continue;
- if (is_valid_state(mdev, os) == rv)
- rv = is_valid_soft_transition(os, ns);
- } else
- rv = is_valid_soft_transition(os, ns);
-
- switch (params->oc_state) {
- case OC_UNINITIALIZED:
- params->oc = os.conn;
- params->oc_state = OC_CONSISTENT;
- break;
- case OC_CONSISTENT:
- if (params->oc != os.conn)
- params->oc_state = OC_INCONSISTENT;
- break;
- case OC_INCONSISTENT:
- break;
+ rv = is_valid_transition(os, ns);
+ if (rv < SS_SUCCESS)
+ break;
+
+ if (!(flags & CS_HARD)) {
+ rv = is_valid_state(mdev, ns);
+ if (rv < SS_SUCCESS) {
+ if (is_valid_state(mdev, os) == rv)
+ rv = is_valid_soft_transition(os, ns);
+ } else
+ rv = is_valid_soft_transition(os, ns);
+ }
+ if (rv < SS_SUCCESS)
+ break;
}
- if (rv < SS_SUCCESS) {
- if (flags & CS_VERBOSE)
- print_st_err(mdev, os, ns, rv);
- return rv;
- } else
- return 0;
+ if (rv < SS_SUCCESS && flags & CS_VERBOSE)
+ print_st_err(mdev, os, ns, rv);
+
+ return rv;
}
-static int _set_state_itr_fn(int vnr, void *p, void *data)
+static union drbd_state
+conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
+ enum chg_state_flags flags)
{
- struct drbd_conf *mdev = (struct drbd_conf *)p;
- struct _is_valid_itr_params *params = (struct _is_valid_itr_params *)data;
- enum chg_state_flags flags = params->flags;
- union drbd_state os, ns, ms = params->ms;
+ union drbd_state ns, os, ms = { };
+ struct drbd_conf *mdev;
enum drbd_state_rv rv;
+ int vnr;
- os = mdev->state;
- ns = apply_mask_val(os, params->mask, params->val);
- ns = sanitize_state(mdev, ns, NULL);
+ if (mask.conn == C_MASK)
+ tconn->cstate = val.conn;
+
+ idr_for_each_entry(&tconn->volumes, mdev, vnr) {
+ os = mdev->state;
+ ns = apply_mask_val(os, mask, val);
+ ns = sanitize_state(mdev, ns, NULL);
- rv = __drbd_set_state(mdev, ns, flags, NULL);
+ rv = __drbd_set_state(mdev, ns, flags, NULL);
+ if (rv < SS_SUCCESS)
+ BUG();
- ms.role = max_role(ns.role, ms.role);
- ms.peer = max_role(ns.peer, ms.peer);
- ms.disk = max_t(enum drbd_role, mdev->state.disk, ms.disk);
- ms.pdsk = max_t(enum drbd_role, mdev->state.pdsk, ms.pdsk);
- params->ms = ms;
+ ms.role = max_role(mdev->state.role, ms.role);
+ ms.peer = max_role(mdev->state.peer, ms.peer);
+ ms.disk = max_t(enum drbd_disk_state, mdev->state.disk, ms.disk);
+ ms.pdsk = max_t(enum drbd_disk_state, mdev->state.pdsk, ms.pdsk);
+ }
- return 0;
+ return ms;
}
static enum drbd_state_rv
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, ¶ms);
+ rv = conn_is_valid_transition(tconn, mask, val, CS_NO_CSTATE_CHG, ¶ms);
- if (rv == 0) /* idr_for_each semantics */
- rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
+ if (rv == SS_SUCCESS)
+ rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
spin_unlock_irq(&tconn->req_lock);
struct _is_valid_itr_params params;
struct after_conn_state_chg_work *acscw;
enum drbd_conns oc = tconn->cstate;
+ union drbd_state ms;
rv = is_valid_conn_transition(oc, val.conn);
if (rv < SS_SUCCESS)
goto abort;
- params.flags = flags;
- params.mask = mask;
- params.val = val;
- params.oc_state = OC_UNINITIALIZED;
-
- if (!(flags & CS_HARD))
- rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, ¶ms);
-
- if (rv == 0) /* idr_for_each semantics */
- rv = SS_SUCCESS;
-
+ rv = conn_is_valid_transition(tconn, mask, val, flags, ¶ms);
if (rv < SS_SUCCESS)
goto abort;
if (params.oc_state == OC_CONSISTENT) {
oc = params.oc;
print_conn_state_change(tconn, oc, val.conn);
- params.flags |= CS_NO_CSTATE_CHG;
+ flags |= CS_NO_CSTATE_CHG;
}
- tconn->cstate = val.conn;
- params.ms.i = 0;
- params.ms.conn = val.conn;
- idr_for_each(&tconn->volumes, _set_state_itr_fn, ¶ms);
+
+ ms = conn_set_state(tconn, mask, val, flags);
+ ms.conn = val.conn;
acscw = kmalloc(sizeof(*acscw), GFP_ATOMIC);
if (acscw) {
acscw->oc = oc;
- acscw->nms = params.ms;
+ acscw->nms = ms;
acscw->flags = flags;
acscw->w.cb = w_after_conn_state_ch;
acscw->w.tconn = tconn;