From: Philipp Reisner Date: Thu, 21 Apr 2011 09:36:49 +0000 (+0200) Subject: drbd: Considering that the two_primaries config flag can change X-Git-Url: http://drtracing.org/?a=commitdiff_plain;h=302bdeae49842cbd2faec8203f49b1c4ef20294d;p=deliverable%2Flinux.git drbd: Considering that the two_primaries config flag can change Now since it is possible to change the two_primaries config flag while the connection is up, make sure we treat a peer_req in a consistent way if the config flag changes while the peer_req is under IO. Signed-off-by: Philipp Reisner Signed-off-by: Lars Ellenberg --- diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 83e6cadbe7aa..3833d56b8de8 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -661,6 +661,9 @@ enum { /* The peer wants a write ACK for this (wire proto C) */ __EE_SEND_WRITE_ACK, + + /* Is set when net_conf had two_primaries set while creating this peer_req */ + __EE_IN_INTERVAL_TREE, }; #define EE_CALL_AL_COMPLETE_IO (1<<__EE_CALL_AL_COMPLETE_IO) #define EE_MAY_SET_IN_SYNC (1<<__EE_MAY_SET_IN_SYNC) @@ -669,6 +672,7 @@ enum { #define EE_HAS_DIGEST (1<<__EE_HAS_DIGEST) #define EE_RESTART_REQUESTS (1<<__EE_RESTART_REQUESTS) #define EE_SEND_WRITE_ACK (1<<__EE_SEND_WRITE_ACK) +#define EE_IN_INTERVAL_TREE (1<<__EE_IN_INTERVAL_TREE) /* flag bits per mdev */ enum { diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 397f97701988..4665ad79b4ae 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -1752,7 +1752,7 @@ static int e_end_block(struct drbd_work *w, int cancel) } /* we delete from the conflict detection hash _after_ we sent out the * P_WRITE_ACK / P_NEG_ACK, to get the sequence number right. */ - if (mdev->tconn->net_conf->two_primaries) { + if (peer_req->flags & EE_IN_INTERVAL_TREE) { spin_lock_irq(&mdev->tconn->req_lock); D_ASSERT(!drbd_interval_empty(&peer_req->i)); drbd_remove_epoch_entry_interval(mdev, peer_req); @@ -1811,14 +1811,19 @@ static u32 seq_max(u32 a, u32 b) static bool need_peer_seq(struct drbd_conf *mdev) { struct drbd_tconn *tconn = mdev->tconn; + int tp; /* * We only need to keep track of the last packet_seq number of our peer * if we are in dual-primary mode and we have the discard flag set; see * handle_write_conflicts(). */ - return tconn->net_conf->two_primaries && - test_bit(DISCARD_CONCURRENT, &tconn->flags); + + rcu_read_lock(); + tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries; + rcu_read_unlock(); + + return tp && test_bit(DISCARD_CONCURRENT, &tconn->flags); } static void update_peer_seq(struct drbd_conf *mdev, unsigned int peer_seq) @@ -2049,7 +2054,7 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi) u32 peer_seq = be32_to_cpu(p->seq_num); int rw = WRITE; u32 dp_flags; - int err; + int err, tp; mdev = vnr_to_mdev(tconn, pi->vnr); if (!mdev) @@ -2094,7 +2099,11 @@ static int receive_Data(struct drbd_tconn *tconn, struct packet_info *pi) atomic_inc(&peer_req->epoch->active); spin_unlock(&mdev->epoch_lock); - if (mdev->tconn->net_conf->two_primaries) { + rcu_read_lock(); + tp = rcu_dereference(mdev->tconn->net_conf)->two_primaries; + rcu_read_unlock(); + if (tp) { + peer_req->flags |= EE_IN_INTERVAL_TREE; err = wait_for_and_update_peer_seq(mdev, peer_seq); if (err) goto out_interrupted;