Loading drivers/block/drbd/drbd_int.h +2 −2 Original line number Diff line number Diff line Loading @@ -1472,8 +1472,8 @@ extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev); extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force); extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev); extern bool conn_try_outdate_peer(struct drbd_tconn *tconn); extern void conn_try_outdate_peer_async(struct drbd_tconn *tconn); extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); /* drbd_worker.c */ Loading drivers/block/drbd/drbd_nl.c +70 −74 Original line number Diff line number Diff line Loading @@ -366,116 +366,122 @@ int conn_khelper(struct drbd_tconn *tconn, char *cmd) return ret; } enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev) static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn) { enum drbd_fencing_p fp = FP_NOT_AVAIL; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) { if (get_ldev_if_state(mdev, D_CONSISTENT)) { fp = max_t(enum drbd_fencing_p, fp, mdev->ldev->dc.fencing); put_ldev(mdev); } } return fp; } bool conn_try_outdate_peer(struct drbd_tconn *tconn) { union drbd_state mask = { }; union drbd_state val = { }; enum drbd_fencing_p fp; char *ex_to_string; int r; enum drbd_disk_state nps; enum drbd_fencing_p fp; D_ASSERT(mdev->state.pdsk == D_UNKNOWN); if (tconn->cstate >= C_WF_REPORT_PARAMS) { conn_err(tconn, "Expected cstate < C_WF_REPORT_PARAMS\n"); return false; } if (get_ldev_if_state(mdev, D_CONSISTENT)) { fp = mdev->ldev->dc.fencing; put_ldev(mdev); } else { dev_warn(DEV, "Not fencing peer, I'm not even Consistent myself.\n"); nps = mdev->state.pdsk; fp = highest_fencing_policy(tconn); switch (fp) { case FP_NOT_AVAIL: conn_warn(tconn, "Not fencing peer, I'm not even Consistent myself.\n"); goto out; case FP_DONT_CARE: return true; default: ; } r = drbd_khelper(mdev, "fence-peer"); r = conn_khelper(tconn, "fence-peer"); switch ((r>>8) & 0xff) { case 3: /* peer is inconsistent */ ex_to_string = "peer is inconsistent or worse"; nps = D_INCONSISTENT; mask.pdsk = D_MASK; val.pdsk = D_INCONSISTENT; break; case 4: /* peer got outdated, or was already outdated */ ex_to_string = "peer was fenced"; nps = D_OUTDATED; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; break; case 5: /* peer was down */ if (mdev->state.disk == D_UP_TO_DATE) { if (conn_highest_disk(tconn) == D_UP_TO_DATE) { /* we will(have) create(d) a new UUID anyways... */ ex_to_string = "peer is unreachable, assumed to be dead"; nps = D_OUTDATED; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; } else { ex_to_string = "peer unreachable, doing nothing since disk != UpToDate"; nps = mdev->state.pdsk; } break; case 6: /* Peer is primary, voluntarily outdate myself. * This is useful when an unconnected R_SECONDARY is asked to * become R_PRIMARY, but finds the other peer being active. */ ex_to_string = "peer is active"; dev_warn(DEV, "Peer is primary, outdating myself.\n"); nps = D_UNKNOWN; _drbd_request_state(mdev, NS(disk, D_OUTDATED), CS_WAIT_COMPLETE); conn_warn(tconn, "Peer is primary, outdating myself.\n"); mask.disk = D_MASK; val.disk = D_OUTDATED; break; case 7: if (fp != FP_STONITH) dev_err(DEV, "fence-peer() = 7 && fencing != Stonith !!!\n"); conn_err(tconn, "fence-peer() = 7 && fencing != Stonith !!!\n"); ex_to_string = "peer was stonithed"; nps = D_OUTDATED; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; break; default: /* The script is broken ... */ nps = D_UNKNOWN; dev_err(DEV, "fence-peer helper broken, returned %d\n", (r>>8)&0xff); return nps; conn_err(tconn, "fence-peer helper broken, returned %d\n", (r>>8)&0xff); return false; /* Eventually leave IO frozen */ } dev_info(DEV, "fence-peer helper returned %d (%s)\n", conn_info(tconn, "fence-peer helper returned %d (%s)\n", (r>>8) & 0xff, ex_to_string); out: if (mdev->state.susp_fen && nps >= D_UNKNOWN) { /* The handler was not successful... unfreeze here, the state engine can not unfreeze... */ _drbd_request_state(mdev, NS(susp_fen, 0), CS_VERBOSE); } return nps; /* Not using conn_request_state(tconn, mask, val, CS_VERBOSE); here, because we might were able to re-establish the connection in the meantime. */ spin_lock_irq(&tconn->req_lock); if (tconn->cstate < C_WF_REPORT_PARAMS) _conn_request_state(tconn, mask, val, CS_VERBOSE); spin_unlock_irq(&tconn->req_lock); return conn_highest_pdsk(tconn) <= D_OUTDATED; } static int _try_outdate_peer_async(void *data) { struct drbd_conf *mdev = (struct drbd_conf *)data; enum drbd_disk_state nps; union drbd_state ns; struct drbd_tconn *tconn = (struct drbd_tconn *)data; nps = drbd_try_outdate_peer(mdev); /* Not using drbd_request_state(mdev, NS(pdsk, nps)); here, because we might were able to re-establish the connection in the meantime. This can only partially be solved in the state's engine is_valid_state() and is_valid_state_transition() functions. nps can be D_INCONSISTENT, D_OUTDATED or D_UNKNOWN. pdsk == D_INCONSISTENT while conn >= C_CONNECTED is valid, therefore we have to have the pre state change check here. */ spin_lock_irq(&mdev->tconn->req_lock); ns = mdev->state; if (ns.conn < C_WF_REPORT_PARAMS) { ns.pdsk = nps; _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); } spin_unlock_irq(&mdev->tconn->req_lock); conn_try_outdate_peer(tconn); return 0; } void drbd_try_outdate_peer_async(struct drbd_conf *mdev) void conn_try_outdate_peer_async(struct drbd_tconn *tconn) { struct task_struct *opa; opa = kthread_run(_try_outdate_peer_async, mdev, "drbd%d_a_helper", mdev_to_minor(mdev)); opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h"); if (IS_ERR(opa)) dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n"); conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n"); } enum drbd_state_rv Loading @@ -486,7 +492,6 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) int try = 0; int forced = 0; union drbd_state mask, val; enum drbd_disk_state nps; if (new_role == R_PRIMARY) request_ping(mdev->tconn); /* Detect a dead peer ASAP */ Loading Loading @@ -519,32 +524,23 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) if (rv == SS_NO_UP_TO_DATE_DISK && mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) { D_ASSERT(mdev->state.pdsk == D_UNKNOWN); nps = drbd_try_outdate_peer(mdev); if (nps == D_OUTDATED || nps == D_INCONSISTENT) { if (conn_try_outdate_peer(mdev->tconn)) { val.disk = D_UP_TO_DATE; mask.disk = D_MASK; } val.pdsk = nps; mask.pdsk = D_MASK; continue; } if (rv == SS_NOTHING_TO_DO) goto out; if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) { nps = drbd_try_outdate_peer(mdev); if (force && nps > D_OUTDATED) { if (!conn_try_outdate_peer(mdev->tconn) && force) { dev_warn(DEV, "Forced into split brain situation!\n"); nps = D_OUTDATED; } mask.pdsk = D_MASK; val.pdsk = nps; val.pdsk = D_OUTDATED; } continue; } if (rv == SS_TWO_PRIMARIES) { Loading drivers/block/drbd/drbd_receiver.c +3 −4 Original line number Diff line number Diff line Loading @@ -4030,9 +4030,11 @@ static void drbd_disconnect(struct drbd_tconn *tconn) drbd_free_sock(tconn); idr_for_each(&tconn->volumes, drbd_disconnected, tconn); conn_info(tconn, "Connection closed\n"); if (conn_highest_role(tconn) == R_PRIMARY && conn_highest_pdsk(tconn) >= D_UNKNOWN) conn_try_outdate_peer_async(tconn); spin_lock_irq(&tconn->req_lock); oc = tconn->cstate; if (oc >= C_UNCONNECTED) Loading Loading @@ -4109,9 +4111,6 @@ static int drbd_disconnected(int vnr, void *p, void *data) put_ldev(mdev); } if (mdev->state.role == R_PRIMARY && fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) drbd_try_outdate_peer_async(mdev); /* serialize with bitmap writeout triggered by the state change, * if any. */ wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); Loading drivers/block/drbd/drbd_state.c +70 −15 Original line number Diff line number Diff line Loading @@ -61,6 +61,73 @@ bool conn_all_vols_unconf(struct drbd_tconn *tconn) return true; } /* Unfortunately the states where not correctly ordered, when they where defined. therefore can not use max_t() here. */ static enum drbd_role max_role(enum drbd_role role1, enum drbd_role role2) { if (role1 == R_PRIMARY || role2 == R_PRIMARY) return R_PRIMARY; if (role1 == R_SECONDARY || role2 == R_SECONDARY) return R_SECONDARY; return R_UNKNOWN; } static enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2) { if (role1 == R_UNKNOWN || role2 == R_UNKNOWN) return R_UNKNOWN; if (role1 == R_SECONDARY || role2 == R_SECONDARY) return R_SECONDARY; return R_PRIMARY; } enum drbd_role conn_highest_role(struct drbd_tconn *tconn) { enum drbd_role role = R_UNKNOWN; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) role = max_role(role, mdev->state.role); return role; } enum drbd_role conn_highest_peer(struct drbd_tconn *tconn) { enum drbd_role peer = R_UNKNOWN; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) peer = max_role(peer, mdev->state.peer); return peer; } enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn) { enum drbd_disk_state ds = D_DISKLESS; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) ds = max_t(enum drbd_disk_state, ds, mdev->state.disk); return ds; } enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn) { enum drbd_disk_state ds = D_DISKLESS; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) ds = max_t(enum drbd_disk_state, ds, mdev->state.pdsk); return ds; } /** * cl_wide_st_chg() - true if the state change is a cluster wide one * @mdev: DRBD device. Loading Loading @@ -329,18 +396,6 @@ static void print_state_change(struct drbd_conf *mdev, union drbd_state os, unio dev_info(DEV, "%s\n", pb); } static bool vol_has_primary_peer(struct drbd_tconn *tconn) { struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) { if (mdev->state.peer == R_PRIMARY) return true; } return false; } /** * is_valid_state() - Returns an SS_ error code if ns is not valid * @mdev: DRBD device. Loading @@ -364,7 +419,7 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) if (!mdev->tconn->net_conf->two_primaries && ns.role == R_PRIMARY) { if (ns.peer == R_PRIMARY) rv = SS_TWO_PRIMARIES; else if (vol_has_primary_peer(mdev->tconn)) else if (conn_highest_peer(mdev->tconn) == R_PRIMARY) rv = SS_O_VOL_PEER_PRI; } put_net_conf(mdev->tconn); Loading Loading @@ -1390,8 +1445,8 @@ static int _set_state_itr_fn(int vnr, void *p, void *data) rv = __drbd_set_state(mdev, ns, flags, NULL); ms.role = max_t(enum drbd_role, mdev->state.role, ms.role); ms.peer = max_t(enum drbd_role, mdev->state.peer, ms.peer); 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; Loading drivers/block/drbd/drbd_state.h +5 −0 Original line number Diff line number Diff line Loading @@ -110,4 +110,9 @@ static inline int drbd_request_state(struct drbd_conf *mdev, return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED); } enum drbd_role conn_highest_role(struct drbd_tconn *tconn); enum drbd_role conn_highest_peer(struct drbd_tconn *tconn); enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn); enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn); #endif Loading
drivers/block/drbd/drbd_int.h +2 −2 Original line number Diff line number Diff line Loading @@ -1472,8 +1472,8 @@ extern void drbd_reconsider_max_bio_size(struct drbd_conf *mdev); extern enum drbd_state_rv drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force); extern enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev); extern void drbd_try_outdate_peer_async(struct drbd_conf *mdev); extern bool conn_try_outdate_peer(struct drbd_tconn *tconn); extern void conn_try_outdate_peer_async(struct drbd_tconn *tconn); extern int drbd_khelper(struct drbd_conf *mdev, char *cmd); /* drbd_worker.c */ Loading
drivers/block/drbd/drbd_nl.c +70 −74 Original line number Diff line number Diff line Loading @@ -366,116 +366,122 @@ int conn_khelper(struct drbd_tconn *tconn, char *cmd) return ret; } enum drbd_disk_state drbd_try_outdate_peer(struct drbd_conf *mdev) static enum drbd_fencing_p highest_fencing_policy(struct drbd_tconn *tconn) { enum drbd_fencing_p fp = FP_NOT_AVAIL; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) { if (get_ldev_if_state(mdev, D_CONSISTENT)) { fp = max_t(enum drbd_fencing_p, fp, mdev->ldev->dc.fencing); put_ldev(mdev); } } return fp; } bool conn_try_outdate_peer(struct drbd_tconn *tconn) { union drbd_state mask = { }; union drbd_state val = { }; enum drbd_fencing_p fp; char *ex_to_string; int r; enum drbd_disk_state nps; enum drbd_fencing_p fp; D_ASSERT(mdev->state.pdsk == D_UNKNOWN); if (tconn->cstate >= C_WF_REPORT_PARAMS) { conn_err(tconn, "Expected cstate < C_WF_REPORT_PARAMS\n"); return false; } if (get_ldev_if_state(mdev, D_CONSISTENT)) { fp = mdev->ldev->dc.fencing; put_ldev(mdev); } else { dev_warn(DEV, "Not fencing peer, I'm not even Consistent myself.\n"); nps = mdev->state.pdsk; fp = highest_fencing_policy(tconn); switch (fp) { case FP_NOT_AVAIL: conn_warn(tconn, "Not fencing peer, I'm not even Consistent myself.\n"); goto out; case FP_DONT_CARE: return true; default: ; } r = drbd_khelper(mdev, "fence-peer"); r = conn_khelper(tconn, "fence-peer"); switch ((r>>8) & 0xff) { case 3: /* peer is inconsistent */ ex_to_string = "peer is inconsistent or worse"; nps = D_INCONSISTENT; mask.pdsk = D_MASK; val.pdsk = D_INCONSISTENT; break; case 4: /* peer got outdated, or was already outdated */ ex_to_string = "peer was fenced"; nps = D_OUTDATED; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; break; case 5: /* peer was down */ if (mdev->state.disk == D_UP_TO_DATE) { if (conn_highest_disk(tconn) == D_UP_TO_DATE) { /* we will(have) create(d) a new UUID anyways... */ ex_to_string = "peer is unreachable, assumed to be dead"; nps = D_OUTDATED; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; } else { ex_to_string = "peer unreachable, doing nothing since disk != UpToDate"; nps = mdev->state.pdsk; } break; case 6: /* Peer is primary, voluntarily outdate myself. * This is useful when an unconnected R_SECONDARY is asked to * become R_PRIMARY, but finds the other peer being active. */ ex_to_string = "peer is active"; dev_warn(DEV, "Peer is primary, outdating myself.\n"); nps = D_UNKNOWN; _drbd_request_state(mdev, NS(disk, D_OUTDATED), CS_WAIT_COMPLETE); conn_warn(tconn, "Peer is primary, outdating myself.\n"); mask.disk = D_MASK; val.disk = D_OUTDATED; break; case 7: if (fp != FP_STONITH) dev_err(DEV, "fence-peer() = 7 && fencing != Stonith !!!\n"); conn_err(tconn, "fence-peer() = 7 && fencing != Stonith !!!\n"); ex_to_string = "peer was stonithed"; nps = D_OUTDATED; mask.pdsk = D_MASK; val.pdsk = D_OUTDATED; break; default: /* The script is broken ... */ nps = D_UNKNOWN; dev_err(DEV, "fence-peer helper broken, returned %d\n", (r>>8)&0xff); return nps; conn_err(tconn, "fence-peer helper broken, returned %d\n", (r>>8)&0xff); return false; /* Eventually leave IO frozen */ } dev_info(DEV, "fence-peer helper returned %d (%s)\n", conn_info(tconn, "fence-peer helper returned %d (%s)\n", (r>>8) & 0xff, ex_to_string); out: if (mdev->state.susp_fen && nps >= D_UNKNOWN) { /* The handler was not successful... unfreeze here, the state engine can not unfreeze... */ _drbd_request_state(mdev, NS(susp_fen, 0), CS_VERBOSE); } return nps; /* Not using conn_request_state(tconn, mask, val, CS_VERBOSE); here, because we might were able to re-establish the connection in the meantime. */ spin_lock_irq(&tconn->req_lock); if (tconn->cstate < C_WF_REPORT_PARAMS) _conn_request_state(tconn, mask, val, CS_VERBOSE); spin_unlock_irq(&tconn->req_lock); return conn_highest_pdsk(tconn) <= D_OUTDATED; } static int _try_outdate_peer_async(void *data) { struct drbd_conf *mdev = (struct drbd_conf *)data; enum drbd_disk_state nps; union drbd_state ns; struct drbd_tconn *tconn = (struct drbd_tconn *)data; nps = drbd_try_outdate_peer(mdev); /* Not using drbd_request_state(mdev, NS(pdsk, nps)); here, because we might were able to re-establish the connection in the meantime. This can only partially be solved in the state's engine is_valid_state() and is_valid_state_transition() functions. nps can be D_INCONSISTENT, D_OUTDATED or D_UNKNOWN. pdsk == D_INCONSISTENT while conn >= C_CONNECTED is valid, therefore we have to have the pre state change check here. */ spin_lock_irq(&mdev->tconn->req_lock); ns = mdev->state; if (ns.conn < C_WF_REPORT_PARAMS) { ns.pdsk = nps; _drbd_set_state(mdev, ns, CS_VERBOSE, NULL); } spin_unlock_irq(&mdev->tconn->req_lock); conn_try_outdate_peer(tconn); return 0; } void drbd_try_outdate_peer_async(struct drbd_conf *mdev) void conn_try_outdate_peer_async(struct drbd_tconn *tconn) { struct task_struct *opa; opa = kthread_run(_try_outdate_peer_async, mdev, "drbd%d_a_helper", mdev_to_minor(mdev)); opa = kthread_run(_try_outdate_peer_async, tconn, "drbd_async_h"); if (IS_ERR(opa)) dev_err(DEV, "out of mem, failed to invoke fence-peer helper\n"); conn_err(tconn, "out of mem, failed to invoke fence-peer helper\n"); } enum drbd_state_rv Loading @@ -486,7 +492,6 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) int try = 0; int forced = 0; union drbd_state mask, val; enum drbd_disk_state nps; if (new_role == R_PRIMARY) request_ping(mdev->tconn); /* Detect a dead peer ASAP */ Loading Loading @@ -519,32 +524,23 @@ drbd_set_role(struct drbd_conf *mdev, enum drbd_role new_role, int force) if (rv == SS_NO_UP_TO_DATE_DISK && mdev->state.disk == D_CONSISTENT && mask.pdsk == 0) { D_ASSERT(mdev->state.pdsk == D_UNKNOWN); nps = drbd_try_outdate_peer(mdev); if (nps == D_OUTDATED || nps == D_INCONSISTENT) { if (conn_try_outdate_peer(mdev->tconn)) { val.disk = D_UP_TO_DATE; mask.disk = D_MASK; } val.pdsk = nps; mask.pdsk = D_MASK; continue; } if (rv == SS_NOTHING_TO_DO) goto out; if (rv == SS_PRIMARY_NOP && mask.pdsk == 0) { nps = drbd_try_outdate_peer(mdev); if (force && nps > D_OUTDATED) { if (!conn_try_outdate_peer(mdev->tconn) && force) { dev_warn(DEV, "Forced into split brain situation!\n"); nps = D_OUTDATED; } mask.pdsk = D_MASK; val.pdsk = nps; val.pdsk = D_OUTDATED; } continue; } if (rv == SS_TWO_PRIMARIES) { Loading
drivers/block/drbd/drbd_receiver.c +3 −4 Original line number Diff line number Diff line Loading @@ -4030,9 +4030,11 @@ static void drbd_disconnect(struct drbd_tconn *tconn) drbd_free_sock(tconn); idr_for_each(&tconn->volumes, drbd_disconnected, tconn); conn_info(tconn, "Connection closed\n"); if (conn_highest_role(tconn) == R_PRIMARY && conn_highest_pdsk(tconn) >= D_UNKNOWN) conn_try_outdate_peer_async(tconn); spin_lock_irq(&tconn->req_lock); oc = tconn->cstate; if (oc >= C_UNCONNECTED) Loading Loading @@ -4109,9 +4111,6 @@ static int drbd_disconnected(int vnr, void *p, void *data) put_ldev(mdev); } if (mdev->state.role == R_PRIMARY && fp >= FP_RESOURCE && mdev->state.pdsk >= D_UNKNOWN) drbd_try_outdate_peer_async(mdev); /* serialize with bitmap writeout triggered by the state change, * if any. */ wait_event(mdev->misc_wait, !test_bit(BITMAP_IO, &mdev->flags)); Loading
drivers/block/drbd/drbd_state.c +70 −15 Original line number Diff line number Diff line Loading @@ -61,6 +61,73 @@ bool conn_all_vols_unconf(struct drbd_tconn *tconn) return true; } /* Unfortunately the states where not correctly ordered, when they where defined. therefore can not use max_t() here. */ static enum drbd_role max_role(enum drbd_role role1, enum drbd_role role2) { if (role1 == R_PRIMARY || role2 == R_PRIMARY) return R_PRIMARY; if (role1 == R_SECONDARY || role2 == R_SECONDARY) return R_SECONDARY; return R_UNKNOWN; } static enum drbd_role min_role(enum drbd_role role1, enum drbd_role role2) { if (role1 == R_UNKNOWN || role2 == R_UNKNOWN) return R_UNKNOWN; if (role1 == R_SECONDARY || role2 == R_SECONDARY) return R_SECONDARY; return R_PRIMARY; } enum drbd_role conn_highest_role(struct drbd_tconn *tconn) { enum drbd_role role = R_UNKNOWN; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) role = max_role(role, mdev->state.role); return role; } enum drbd_role conn_highest_peer(struct drbd_tconn *tconn) { enum drbd_role peer = R_UNKNOWN; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) peer = max_role(peer, mdev->state.peer); return peer; } enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn) { enum drbd_disk_state ds = D_DISKLESS; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) ds = max_t(enum drbd_disk_state, ds, mdev->state.disk); return ds; } enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn) { enum drbd_disk_state ds = D_DISKLESS; struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) ds = max_t(enum drbd_disk_state, ds, mdev->state.pdsk); return ds; } /** * cl_wide_st_chg() - true if the state change is a cluster wide one * @mdev: DRBD device. Loading Loading @@ -329,18 +396,6 @@ static void print_state_change(struct drbd_conf *mdev, union drbd_state os, unio dev_info(DEV, "%s\n", pb); } static bool vol_has_primary_peer(struct drbd_tconn *tconn) { struct drbd_conf *mdev; int vnr; idr_for_each_entry(&tconn->volumes, mdev, vnr) { if (mdev->state.peer == R_PRIMARY) return true; } return false; } /** * is_valid_state() - Returns an SS_ error code if ns is not valid * @mdev: DRBD device. Loading @@ -364,7 +419,7 @@ is_valid_state(struct drbd_conf *mdev, union drbd_state ns) if (!mdev->tconn->net_conf->two_primaries && ns.role == R_PRIMARY) { if (ns.peer == R_PRIMARY) rv = SS_TWO_PRIMARIES; else if (vol_has_primary_peer(mdev->tconn)) else if (conn_highest_peer(mdev->tconn) == R_PRIMARY) rv = SS_O_VOL_PEER_PRI; } put_net_conf(mdev->tconn); Loading Loading @@ -1390,8 +1445,8 @@ static int _set_state_itr_fn(int vnr, void *p, void *data) rv = __drbd_set_state(mdev, ns, flags, NULL); ms.role = max_t(enum drbd_role, mdev->state.role, ms.role); ms.peer = max_t(enum drbd_role, mdev->state.peer, ms.peer); 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; Loading
drivers/block/drbd/drbd_state.h +5 −0 Original line number Diff line number Diff line Loading @@ -110,4 +110,9 @@ static inline int drbd_request_state(struct drbd_conf *mdev, return _drbd_request_state(mdev, mask, val, CS_VERBOSE + CS_ORDERED); } enum drbd_role conn_highest_role(struct drbd_tconn *tconn); enum drbd_role conn_highest_peer(struct drbd_tconn *tconn); enum drbd_disk_state conn_highest_disk(struct drbd_tconn *tconn); enum drbd_disk_state conn_highest_pdsk(struct drbd_tconn *tconn); #endif