drbd: Allow to wait for the completion of an epoch entry as well

Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index d9f3f7f..b84a9c9 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -334,13 +334,15 @@
 		goto fail;
 
 	drbd_clear_interval(&e->i);
+	e->i.size = data_size;
+	e->i.sector = sector;
+	e->i.waiting = false;
+
 	e->epoch = NULL;
 	e->mdev = mdev;
 	e->pages = page;
 	atomic_set(&e->pending_bios, 0);
-	e->i.size = data_size;
 	e->flags = 0;
-	e->i.sector = sector;
 	/*
 	 * The block_id is opaque to the receiver.  It is not endianness
 	 * converted, and sent back to the sender unchanged.
@@ -1172,6 +1174,19 @@
 	return err;
 }
 
+static void drbd_remove_epoch_entry_interval(struct drbd_conf *mdev,
+					     struct drbd_epoch_entry *e)
+{
+	struct drbd_interval *i = &e->i;
+
+	drbd_remove_interval(&mdev->write_requests, i);
+	drbd_clear_interval(i);
+
+	/* Wake up any processes waiting for this epoch entry to complete.  */
+	if (i->waiting)
+		wake_up(&mdev->misc_wait);
+}
+
 static int receive_Barrier(struct drbd_conf *mdev, enum drbd_packet cmd,
 			   unsigned int data_size)
 {
@@ -1591,8 +1606,7 @@
 	if (mdev->tconn->net_conf->two_primaries) {
 		spin_lock_irq(&mdev->tconn->req_lock);
 		D_ASSERT(!drbd_interval_empty(&e->i));
-		drbd_remove_interval(&mdev->epoch_entries, &e->i);
-		drbd_clear_interval(&e->i);
+		drbd_remove_epoch_entry_interval(mdev, e);
 		spin_unlock_irq(&mdev->tconn->req_lock);
 	} else
 		D_ASSERT(drbd_interval_empty(&e->i));
@@ -1612,8 +1626,7 @@
 
 	spin_lock_irq(&mdev->tconn->req_lock);
 	D_ASSERT(!drbd_interval_empty(&e->i));
-	drbd_remove_interval(&mdev->epoch_entries, &e->i);
-	drbd_clear_interval(&e->i);
+	drbd_remove_epoch_entry_interval(mdev, e);
 	spin_unlock_irq(&mdev->tconn->req_lock);
 
 	dec_unacked(mdev);
@@ -1860,17 +1873,14 @@
 			}
 
 			if (signal_pending(current)) {
-				drbd_remove_interval(&mdev->epoch_entries, &e->i);
-				drbd_clear_interval(&e->i);
-
+				drbd_remove_epoch_entry_interval(mdev, e);
 				spin_unlock_irq(&mdev->tconn->req_lock);
-
 				finish_wait(&mdev->misc_wait, &wait);
 				goto out_interrupted;
 			}
 
 			/* Indicate to wake up mdev->misc_wait upon completion.  */
-			req2->rq_state |= RQ_COLLISION;
+			i->waiting = true;
 
 			spin_unlock_irq(&mdev->tconn->req_lock);
 			if (first) {
@@ -1922,8 +1932,7 @@
 	dev_err(DEV, "submit failed, triggering re-connect\n");
 	spin_lock_irq(&mdev->tconn->req_lock);
 	list_del(&e->w.list);
-	drbd_remove_interval(&mdev->epoch_entries, &e->i);
-	drbd_clear_interval(&e->i);
+	drbd_remove_epoch_entry_interval(mdev, e);
 	spin_unlock_irq(&mdev->tconn->req_lock);
 	if (e->flags & EE_CALL_AL_COMPLETE_IO)
 		drbd_al_complete_io(mdev, e->i.sector);