aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-02-15 05:14:44 -0500
committerPhilipp Reisner <philipp.reisner@linbit.com>2011-10-14 10:47:32 -0400
commitdf24aa45f4df43e8881c0f80d6a4e2653df7af05 (patch)
tree3601bf824ef8f63adafec861fabfae42acde9791 /drivers/block
parent047cd4a682b09a7bc5dd5610262405bb085f8b19 (diff)
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')
-rw-r--r--drivers/block/drbd/drbd_nl.c28
-rw-r--r--drivers/block/drbd/drbd_state.c62
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:
1572static int drbd_nl_disconnect(struct drbd_conf *mdev, struct drbd_nl_cfg_req *nlp, 1572static 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
1369static 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, &params);
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
1399static enum drbd_state_rv
1400conn_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
1417abort:
1418 mutex_unlock(&tconn->cstate_mutex);
1419 spin_lock_irq(&tconn->req_lock);
1420
1421 return rv;
1422}
1423
1369enum drbd_state_rv 1424enum 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);