aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_state.c
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2011-03-25 09:31:11 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 10:44:57 -0500
commit88ef594ed7367a76e53f4a33b3d866f4dfb1d4ff (patch)
tree1d70714d2d69887899d150bac5c48f80028b986c /drivers/block/drbd/drbd_state.c
parentbd0c824a9db54bfbf5a26a5bb9b604d65c25b904 (diff)
drbd: Fixed logging of old connection state
During a disconnect the oc variable in _conn_request_state() could become outdated. Determin the common old state after sleeping. While at it, I implemented that for all parts of the state Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_state.c')
-rw-r--r--drivers/block/drbd/drbd_state.c117
1 files changed, 87 insertions, 30 deletions
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c
index 85cfbeadd513..2a170bf7cc29 100644
--- a/drivers/block/drbd/drbd_state.c
+++ b/drivers/block/drbd/drbd_state.c
@@ -1377,42 +1377,100 @@ static void print_conn_state_change(struct drbd_tconn *tconn, enum drbd_conns oc
1377 conn_info(tconn, "%s\n", pb); 1377 conn_info(tconn, "%s\n", pb);
1378} 1378}
1379 1379
1380struct _is_valid_itr_params { 1380enum sp_state {
1381 enum drbd_conns oc; 1381 OC_UNINITIALIZED,
1382 enum { 1382 OC_CONSISTENT,
1383 OC_UNINITIALIZED, 1383 OC_INCONSISTENT,
1384 OC_CONSISTENT, 1384} oc_state;
1385 OC_INCONSISTENT, 1385
1386 } oc_state; 1386static void common_state_part(enum sp_state *sps, int *sp, int nsp)
1387}; 1387{
1388 switch (*sps) {
1389 case OC_UNINITIALIZED:
1390 *sp = nsp;
1391 *sps = OC_CONSISTENT;
1392 break;
1393 case OC_CONSISTENT:
1394 if (*sp != nsp)
1395 *sps = OC_INCONSISTENT;
1396 break;
1397 case OC_INCONSISTENT:
1398 break;
1399 }
1400}
1401
1402void conn_old_common_state(struct drbd_tconn *tconn, union drbd_state *pcs, union drbd_state *pmask)
1403{
1404 union drbd_state css = {}; /* common state state */
1405 union drbd_state os, cs = {}; /* old_state, common_state */
1406 union drbd_state mask = {};
1407 enum sp_state sps; /* state part state */
1408 int sp; /* state part */
1409 struct drbd_conf *mdev;
1410 int vnr;
1411
1412 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1413 os = mdev->state;
1414
1415 sps = css.role;
1416 sp = cs.role;
1417 common_state_part(&sps, &sp, os.role);
1418 css.role = sps;
1419 cs.role = sp;
1420
1421 sps = css.peer;
1422 sp = cs.peer;
1423 common_state_part(&sps, &sp, os.peer);
1424 css.peer = sps;
1425 cs.peer = sp;
1426
1427 sps = css.conn;
1428 sp = cs.conn;
1429 common_state_part(&sps, &sp, os.conn);
1430 css.conn = sps;
1431 cs.conn = sp;
1432
1433 sps = css.disk;
1434 sp = cs.disk;
1435 common_state_part(&sps, &sp, os.disk);
1436 css.disk = sps;
1437 cs.disk = sp;
1438
1439 sps = css.pdsk;
1440 sp = cs.pdsk;
1441 common_state_part(&sps, &sp, os.pdsk);
1442 css.pdsk = sps;
1443 cs.pdsk = sp;
1444 }
1445
1446 if (css.role == OC_CONSISTENT)
1447 mask.role = R_MASK;
1448 if (css.peer == OC_CONSISTENT)
1449 mask.peer = R_MASK;
1450 if (css.conn == OC_CONSISTENT)
1451 mask.conn = C_MASK;
1452 if (css.disk == OC_CONSISTENT)
1453 mask.disk = D_MASK;
1454 if (css.pdsk == OC_CONSISTENT)
1455 mask.pdsk = D_MASK;
1456
1457 *pcs = cs;
1458 *pmask = mask;
1459}
1388 1460
1389static enum drbd_state_rv 1461static enum drbd_state_rv
1390conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val, 1462conn_is_valid_transition(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val,
1391 enum chg_state_flags flags, struct _is_valid_itr_params *params) 1463 enum chg_state_flags flags)
1392{ 1464{
1393 enum drbd_state_rv rv = SS_SUCCESS; 1465 enum drbd_state_rv rv = SS_SUCCESS;
1394 union drbd_state ns, os; 1466 union drbd_state ns, os;
1395 struct drbd_conf *mdev; 1467 struct drbd_conf *mdev;
1396 int vnr; 1468 int vnr;
1397 1469
1398 params->oc_state = OC_UNINITIALIZED;
1399 idr_for_each_entry(&tconn->volumes, mdev, vnr) { 1470 idr_for_each_entry(&tconn->volumes, mdev, vnr) {
1400 os = mdev->state; 1471 os = mdev->state;
1401 ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL); 1472 ns = sanitize_state(mdev, apply_mask_val(os, mask, val), NULL);
1402 1473
1403 switch (params->oc_state) {
1404 case OC_UNINITIALIZED:
1405 params->oc = os.conn;
1406 params->oc_state = OC_CONSISTENT;
1407 break;
1408 case OC_CONSISTENT:
1409 if (params->oc != os.conn)
1410 params->oc_state = OC_INCONSISTENT;
1411 break;
1412 case OC_INCONSISTENT:
1413 break;
1414 }
1415
1416 if (ns.i == os.i) 1474 if (ns.i == os.i)
1417 continue; 1475 continue;
1418 1476
@@ -1471,7 +1529,6 @@ conn_set_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
1471static enum drbd_state_rv 1529static enum drbd_state_rv
1472_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val) 1530_conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state val)
1473{ 1531{
1474 struct _is_valid_itr_params params;
1475 enum drbd_state_rv rv; 1532 enum drbd_state_rv rv;
1476 1533
1477 if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags)) 1534 if (test_and_clear_bit(CONN_WD_ST_CHG_OKAY, &tconn->flags))
@@ -1484,7 +1541,7 @@ _conn_rq_cond(struct drbd_tconn *tconn, union drbd_state mask, union drbd_state
1484 rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR; 1541 rv = tconn->cstate != C_WF_REPORT_PARAMS ? SS_CW_NO_NEED : SS_UNKNOWN_ERROR;
1485 1542
1486 if (rv == SS_UNKNOWN_ERROR) 1543 if (rv == SS_UNKNOWN_ERROR)
1487 rv = conn_is_valid_transition(tconn, mask, val, CS_NO_CSTATE_CHG, &params); 1544 rv = conn_is_valid_transition(tconn, mask, val, CS_NO_CSTATE_CHG);
1488 1545
1489 if (rv == SS_SUCCESS) 1546 if (rv == SS_SUCCESS)
1490 rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */ 1547 rv = SS_UNKNOWN_ERROR; /* cont waiting, otherwise fail. */
@@ -1524,16 +1581,15 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
1524 enum chg_state_flags flags) 1581 enum chg_state_flags flags)
1525{ 1582{
1526 enum drbd_state_rv rv = SS_SUCCESS; 1583 enum drbd_state_rv rv = SS_SUCCESS;
1527 struct _is_valid_itr_params params;
1528 struct after_conn_state_chg_work *acscw; 1584 struct after_conn_state_chg_work *acscw;
1529 enum drbd_conns oc = tconn->cstate; 1585 enum drbd_conns oc = tconn->cstate;
1530 union drbd_state ms; 1586 union drbd_state ms, os_val, os_mask;
1531 1587
1532 rv = is_valid_conn_transition(oc, val.conn); 1588 rv = is_valid_conn_transition(oc, val.conn);
1533 if (rv < SS_SUCCESS) 1589 if (rv < SS_SUCCESS)
1534 goto abort; 1590 goto abort;
1535 1591
1536 rv = conn_is_valid_transition(tconn, mask, val, flags, &params); 1592 rv = conn_is_valid_transition(tconn, mask, val, flags);
1537 if (rv < SS_SUCCESS) 1593 if (rv < SS_SUCCESS)
1538 goto abort; 1594 goto abort;
1539 1595
@@ -1544,8 +1600,9 @@ _conn_request_state(struct drbd_tconn *tconn, union drbd_state mask, union drbd_
1544 goto abort; 1600 goto abort;
1545 } 1601 }
1546 1602
1547 if (params.oc_state == OC_CONSISTENT) { 1603 conn_old_common_state(tconn, &os_val, &os_mask);
1548 oc = params.oc; 1604 if (os_mask.conn == C_MASK) {
1605 oc = os_val.conn;
1549 print_conn_state_change(tconn, oc, val.conn); 1606 print_conn_state_change(tconn, oc, val.conn);
1550 flags |= CS_NO_CSTATE_CHG; 1607 flags |= CS_NO_CSTATE_CHG;
1551 } 1608 }