drbd: Considering that the two_primaries config flag can change
authorPhilipp Reisner <philipp.reisner@linbit.com>
Thu, 21 Apr 2011 09:36:49 +0000 (11:36 +0200)
committerPhilipp Reisner <philipp.reisner@linbit.com>
Thu, 8 Nov 2012 15:49:03 +0000 (16:49 +0100)
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 <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
drivers/block/drbd/drbd_int.h
drivers/block/drbd/drbd_receiver.c

index 83e6cadbe7aa0f03d9e5c72d57083042e921fe8c..3833d56b8de80179ad3adc48abf1bf701142a27d 100644 (file)
@@ -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 {
index 397f97701988cb393090689914b9ed9305b26457..4665ad79b4aeb70b0f443cc0562dbd83727e0505 100644 (file)
@@ -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;