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>
This commit is contained in:
parent
047cd4a682
commit
df24aa45f4
|
@ -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;
|
||||
|
|
|
@ -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, ¶ms);
|
||||
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue