diff options
author | Philipp Reisner | 2011-04-14 01:24:47 +0200 |
---|---|---|
committer | Philipp Reisner | 2012-11-08 16:45:18 +0100 |
commit | 303d1448a048fb5b099babc5f41d0b1e22238778 (patch) | |
tree | dccb81765e81d3275addf91ff9644bacdda64b60 /drivers/block/drbd/drbd_receiver.c | |
parent | drbd: protect all idr accesses that might sleep with drbd_cfg_rwsem (diff) | |
download | kernel-qcow2-linux-303d1448a048fb5b099babc5f41d0b1e22238778.tar.gz kernel-qcow2-linux-303d1448a048fb5b099babc5f41d0b1e22238778.tar.xz kernel-qcow2-linux-303d1448a048fb5b099babc5f41d0b1e22238778.zip |
drbd: Runtime changeable wire protocol
The wire protocol is no longer a property that is negotiated
between the two peers. It is now expressed with two bits
(DP_SEND_WRITE_ACK and DP_SEND_RECEIVE_ACK) in each data
packet. Therefore the primary node is free to change the
wire protocol at any time without disconnect/reconnect.
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_receiver.c')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 39 |
1 files changed, 19 insertions, 20 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index fd3859407a05..295707ec12bc 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1697,7 +1697,7 @@ static int e_end_block(struct drbd_work *w, int cancel) sector_t sector = peer_req->i.sector; int err = 0, pcmd; - if (mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C) { + if (peer_req->flags & EE_SEND_WRITE_ACK) { if (likely((peer_req->flags & EE_WAS_ERROR) == 0)) { pcmd = (mdev->state.conn >= C_SYNC_SOURCE && mdev->state.conn <= C_PAUSED_SYNC_T && @@ -2074,20 +2074,28 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi) list_add(&peer_req->w.list, &mdev->active_ee); spin_unlock_irq(&mdev->tconn->req_lock); - switch (mdev->tconn->net_conf->wire_protocol) { - case DRBD_PROT_C: + if (mdev->tconn->agreed_pro_version < 100) { + switch (mdev->tconn->net_conf->wire_protocol) { + case DRBD_PROT_C: + dp_flags |= DP_SEND_WRITE_ACK; + break; + case DRBD_PROT_B: + dp_flags |= DP_SEND_RECEIVE_ACK; + break; + } + } + + if (dp_flags & DP_SEND_WRITE_ACK) { + peer_req->flags |= EE_SEND_WRITE_ACK; inc_unacked(mdev); /* corresponding dec_unacked() in e_end_block() * respective _drbd_clear_done_ee */ - break; - case DRBD_PROT_B: + } + + if (dp_flags & DP_SEND_RECEIVE_ACK) { /* I really don't like it that the receiver thread * sends on the msock, but anyways */ drbd_send_ack(mdev, P_RECV_ACK, peer_req); - break; - case DRBD_PROT_A: - /* nothing to do */ - break; } if (mdev->state.pdsk < D_INCONSISTENT) { @@ -2932,7 +2940,7 @@ static int receive_protocol(struct drbd_tconn *tconn, struct packet_info *pi) if (cf & CF_DRY_RUN) set_bit(CONN_DRY_RUN, &tconn->flags); - if (p_proto != tconn->net_conf->wire_protocol) { + if (p_proto != tconn->net_conf->wire_protocol && tconn->agreed_pro_version < 100) { conn_err(tconn, "incompatible communication protocols\n"); goto disconnect; } @@ -4622,23 +4630,18 @@ static int got_BlockAck(struct drbd_tconn *tconn, struct packet_info *pi) } switch (pi->cmd) { case P_RS_WRITE_ACK: - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = WRITE_ACKED_BY_PEER_AND_SIS; break; case P_WRITE_ACK: - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = WRITE_ACKED_BY_PEER; break; case P_RECV_ACK: - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_B); what = RECV_ACKED_BY_PEER; break; case P_DISCARD_WRITE: - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = DISCARD_WRITE; break; case P_RETRY_WRITE: - D_ASSERT(mdev->tconn->net_conf->wire_protocol == DRBD_PROT_C); what = POSTPONE_WRITE; break; default: @@ -4656,8 +4659,6 @@ static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi) struct p_block_ack *p = pi->data; sector_t sector = be64_to_cpu(p->sector); int size = be32_to_cpu(p->blksize); - bool missing_ok = tconn->net_conf->wire_protocol == DRBD_PROT_A || - tconn->net_conf->wire_protocol == DRBD_PROT_B; int err; mdev = vnr_to_mdev(tconn, pi->vnr); @@ -4674,15 +4675,13 @@ static int got_NegAck(struct drbd_tconn *tconn, struct packet_info *pi) err = validate_req_change_req_state(mdev, p->block_id, sector, &mdev->write_requests, __func__, - NEG_ACKED, missing_ok); + NEG_ACKED, true); if (err) { /* Protocol A has no P_WRITE_ACKs, but has P_NEG_ACKs. The master bio might already be completed, therefore the request is no longer in the collision hash. */ /* In Protocol B we might already have got a P_RECV_ACK but then get a P_NEG_ACK afterwards. */ - if (!missing_ok) - return err; drbd_set_out_of_sync(mdev, sector, size); } return 0; |