diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-02-15 05:14:44 -0500 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2011-10-14 10:47:32 -0400 |
commit | df24aa45f4df43e8881c0f80d6a4e2653df7af05 (patch) | |
tree | 3601bf824ef8f63adafec861fabfae42acde9791 /drivers/block | |
parent | 047cd4a682b09a7bc5dd5610262405bb085f8b19 (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.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); |