Commit 1b228c98 authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Jens Axboe

drbd: fix regression: protocol A sometimes synchronous, C sometimes double-latency

Regression introduced with 8.4.5
 drbd: application writes may set-in-sync in protocol != C

Overwriting the same block (LBA) while a former version is still
"in-flight" to the peer (to be exact: we did not receive the
P_BARRIER_ACK for its epoch yet) would wait for the full epoch of that
former version to be acknowledged by the peer.

In synchronous and quasi-synchronous protocols C and B,
this may double the latency on overwrites.

With protocol A, which is supposed to be asynchronous and only wait for
local completion, it is even worse: it would make overwrites
quasi-synchronous, they would be hit by the full RTT, which protocol A
was specifically meant to avoid, and possibly the additional time it
takes to drain the buffers first.

Particularly bad for databases, or anything else that
does frequent updates to the same blocks (various file system meta data).

No impact if >= rtt passes between updates to the same block.
Signed-off-by: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent bca1cbae
...@@ -977,16 +977,20 @@ static void complete_conflicting_writes(struct drbd_request *req) ...@@ -977,16 +977,20 @@ static void complete_conflicting_writes(struct drbd_request *req)
sector_t sector = req->i.sector; sector_t sector = req->i.sector;
int size = req->i.size; int size = req->i.size;
i = drbd_find_overlap(&device->write_requests, sector, size);
if (!i)
return;
for (;;) { for (;;) {
prepare_to_wait(&device->misc_wait, &wait, TASK_UNINTERRUPTIBLE); drbd_for_each_overlap(i, &device->write_requests, sector, size) {
i = drbd_find_overlap(&device->write_requests, sector, size); /* Ignore, if already completed to upper layers. */
if (!i) if (i->completed)
continue;
/* Handle the first found overlap. After the schedule
* we have to restart the tree walk. */
break; break;
}
if (!i) /* if any */
break;
/* Indicate to wake up device->misc_wait on progress. */ /* Indicate to wake up device->misc_wait on progress. */
prepare_to_wait(&device->misc_wait, &wait, TASK_UNINTERRUPTIBLE);
i->waiting = true; i->waiting = true;
spin_unlock_irq(&device->resource->req_lock); spin_unlock_irq(&device->resource->req_lock);
schedule(); schedule();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment