diff options
| -rw-r--r-- | drivers/block/drbd/drbd_nl.c | 28 | ||||
| -rw-r--r-- | drivers/block/drbd/drbd_state.c | 62 |
2 files changed, 76 insertions, 14 deletions
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 3d8e63190dcd..d6832f8d49a5 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
| @@ -1572,6 +1572,7 @@ fail: | |||
| 1572 | static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, | 1572 | static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, |
| 1573 | struct drbd_nl_cfg_reply *reply) | 1573 | struct drbd_nl_cfg_reply *reply) |
| 1574 | { | 1574 | { |
| 1575 | struct drbd_tconn *tconn = mdev->tconn; | ||
| 1575 | int retcode; | 1576 | int retcode; |
| 1576 | struct disconnect dc; | 1577 | struct disconnect dc; |
| 1577 | 1578 | ||
| @@ -1582,30 +1583,29 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
| 1582 | } | 1583 | } |
| 1583 | 1584 | ||
| 1584 | if (dc.force) { | 1585 | if (dc.force) { |
| 1585 | spin_lock_irq(&mdev->tconn->req_lock); | 1586 | spin_lock_irq(&tconn->req_lock); |
| 1586 | if (mdev->state.conn >= C_WF_CONNECTION) | 1587 | if (tconn->cstate >= C_WF_CONNECTION) |
| 1587 | _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), CS_HARD, NULL); | 1588 | _conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); |
| 1588 | spin_unlock_irq(&mdev->tconn->req_lock); | 1589 | spin_unlock_irq(&tconn->req_lock); |
| 1589 | goto done; | 1590 | goto done; |
| 1590 | } | 1591 | } |
| 1591 | 1592 | ||
| 1592 | retcode = _drbd_request_state(mdev, NS(conn, C_DISCONNECTING), CS_ORDERED); | 1593 | retcode = conn_request_state(tconn, NS(conn, C_DISCONNECTING), 0); |
| 1593 | 1594 | ||
| 1594 | if (retcode == SS_NOTHING_TO_DO) | 1595 | if (retcode == SS_NOTHING_TO_DO) |
| 1595 | goto done; | 1596 | goto done; |
| 1596 | else if (retcode == SS_ALREADY_STANDALONE) | 1597 | else if (retcode == SS_ALREADY_STANDALONE) |
| 1597 | goto done; | 1598 | goto done; |
| 1598 | else if (retcode == SS_PRIMARY_NOP) { | 1599 | else if (retcode == SS_PRIMARY_NOP) { |
| 1599 | /* Our statche checking code wants to see the peer outdated. */ | 1600 | /* Our state checking code wants to see the peer outdated. */ |
| 1600 | retcode = drbd_request_state(mdev, NS2(conn, C_DISCONNECTING, | 1601 | retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, |
| 1601 | pdsk, D_OUTDATED)); | 1602 | pdsk, D_OUTDATED), CS_VERBOSE); |
| 1602 | } else if (retcode == SS_CW_FAILED_BY_PEER) { | 1603 | } else if (retcode == SS_CW_FAILED_BY_PEER) { |
| 1603 | /* The peer probably wants to see us outdated. */ | 1604 | /* The peer probably wants to see us outdated. */ |
| 1604 | retcode = _drbd_request_state(mdev, NS2(conn, C_DISCONNECTING, | 1605 | retcode = conn_request_state(tconn, NS2(conn, C_DISCONNECTING, |
| 1605 | disk, D_OUTDATED), | 1606 | disk, D_OUTDATED), 0); |
| 1606 | CS_ORDERED); | ||
| 1607 | if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) { | 1607 | if (retcode == SS_IS_DISKLESS || retcode == SS_LOWER_THAN_OUTDATED) { |
| 1608 | drbd_force_state(mdev, NS(conn, C_DISCONNECTING)); | 1608 | conn_request_state(tconn, NS(conn, C_DISCONNECTING), CS_HARD); |
| 1609 | retcode = SS_SUCCESS; | 1609 | retcode = SS_SUCCESS; |
| 1610 | } | 1610 | } |
| 1611 | } | 1611 | } |
| @@ -1613,8 +1613,8 @@ static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nl | |||
| 1613 | if (retcode < SS_SUCCESS) | 1613 | if (retcode < SS_SUCCESS) |
| 1614 | goto fail; | 1614 | goto fail; |
| 1615 | 1615 | ||
| 1616 | if (wait_event_interruptible(mdev->state_wait, | 1616 | if (wait_event_interruptible(tconn->ping_wait, |
| 1617 | mdev->state.conn != C_DISCONNECTING)) { | 1617 | tconn->cstate != C_DISCONNECTING)) { |
| 1618 | /* Do not test for mdev->state.conn == C_STANDALONE, since | 1618 | /* Do not test for mdev->state.conn == C_STANDALONE, since |
| 1619 | someone else might connect us in the mean time! */ | 1619 | someone else might connect us in the mean time! */ |
| 1620 | retcode = ERR_INTR; | 1620 | retcode = ERR_INTR; |
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) | |||
| 1366 | return 0; | 1366 | return 0; |
| 1367 | } | 1367 | } |
| 1368 | 1368 | ||
| 1369 | static enum drbd_state_rv | ||
| 1370 | _conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val) | ||
| 1371 | { | ||
| 1372 | struct _is_valid_itr_params params; | ||
| 1373 | enum drbd_state_rv rv; | ||
| 1374 | |||
| 1375 | if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags)) | ||
| 1376 | return SS_CW_SUCCESS; | ||
| 1377 | |||
| 1378 | if (test_and_clear_bit(CONN_WD_ST_CHG_FAIL, &tconn->flags)) | ||
| 1379 | return SS_CW_FAILED_BY_PEER; | ||
| 1380 | |||
| 1381 | params.flags = CS_NO_CSTATE_CHG; /* ΓΆΓΆ think */ | ||
| 1382 | params.mask = mask; | ||
| 1383 | params.val = val; | ||
| 1384 | |||
| 1385 | spin_lock_irq(&tconn->req_lock); | ||
| 1386 | rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR; | ||
| 1387 | |||
| 1388 | if (rv == SS_UNKNOWN_ERROR) | ||
| 1389 | rv = idr_for_each(&tconn->volumes, _is_valid_itr_fn, ¶ms); | ||
| 1390 | |||
| 1391 | if (rv == 0) /* idr_for_each semantics */ | ||
| 1392 | rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ | ||
| 1393 | |||
| 1394 | spin_unlock_irq(&tconn->req_lock); | ||
| 1395 | |||
| 1396 | return rv; | ||
| 1397 | } | ||
| 1398 | |||
| 1399 | static enum drbd_state_rv | ||
| 1400 | conn_cl_wide(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, | ||
| 1401 | enum chg_state_flags f) | ||
| 1402 | { | ||
| 1403 | enum drbd_state_rv rv; | ||
| 1404 | |||
| 1405 | spin_unlock_irq(&tconn->req_lock); | ||
| 1406 | mutex_lock(&tconn->cstate_mutex); | ||
| 1407 | |||
| 1408 | if (!conn_send_state_req(tconn, mask, val)) { | ||
| 1409 | rv = SS_CW_FAILED_BY_PEER; | ||
| 1410 | /* if (f & CS_VERBOSE) | ||
| 1411 | print_st_err(mdev, os, ns, rv); */ | ||
| 1412 | goto abort; | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | wait_event(tconn->ping_wait, (rv = _conn_rq_cond(tconn, mask, val))); | ||
| 1416 | |||
| 1417 | abort: | ||
| 1418 | mutex_unlock(&tconn->cstate_mutex); | ||
| 1419 | spin_lock_irq(&tconn->req_lock); | ||
| 1420 | |||
| 1421 | return rv; | ||
| 1422 | } | ||
| 1423 | |||
| 1369 | enum drbd_state_rv | 1424 | enum drbd_state_rv |
| 1370 | _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, | 1425 | _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, |
| 1371 | enum chg_state_flags flags) | 1426 | enum chg_state_flags flags) |
| @@ -1393,6 +1448,13 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_ | |||
| 1393 | if (rv < SS_SUCCESS) | 1448 | if (rv < SS_SUCCESS) |
| 1394 | goto abort; | 1449 | goto abort; |
| 1395 | 1450 | ||
| 1451 | if (oc == C_WF_REPORT_PARAMS && val.conn == C_DISCONNECTING && | ||
| 1452 | !(flags & (CS_LOCAL_ONLY | CS_HARD))) { | ||
| 1453 | rv = conn_cl_wide(tconn, mask, val, flags); | ||
| 1454 | if (rv < SS_SUCCESS) | ||
| 1455 | goto abort; | ||
| 1456 | } | ||
| 1457 | |||
| 1396 | if (params.oc_state == OC_CONSISTENT) { | 1458 | if (params.oc_state == OC_CONSISTENT) { |
| 1397 | oc = params.oc; | 1459 | oc = params.oc; |
| 1398 | print_conn_state_change(tconn, oc, val.conn); | 1460 | print_conn_state_change(tconn, oc, val.conn); |
