[Devel] [PATCH RHEL7 COMMIT] ploop: fix busyloop on secondary discard bio
Konstantin Khorenko
khorenko at virtuozzo.com
Fri May 22 07:45:45 PDT 2015
The commit is pushed to "branch-rh7-3.10.0-123.1.2-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-123.1.2.vz7.5.5
------>
commit f3a874d5028d4ab3e010087866c47972092af9ad
Author: Andrey Smetanin <asmetanin at virtuozzo.com>
Date: Fri May 22 18:45:45 2015 +0400
ploop: fix busyloop on secondary discard bio
After diff-ploop-add-a-separate-queue-for-discard-bio-s, ploop_thread()
skips processing previously queued discard bio-s if any discard bio is
already under processing (fbd->fbd_dbl is not empty).
ploop_wait() must take care about such a case, otherwise a busyloop may
happen: ploop_thread() believes that it has to go to sleep because all
incoming queues are empty excepting plo->bio_discard_list which cannot be
processed by now and calls ploop_wait(); the latter returns immediately
because plo->bio_discard_list is not empty and hence needs for processing.
The patch also fixes a trivial bug in discard bio accounting:
ploop_bio_queue() is called for all bio-s including discard bio-s and
it decrements bio_qlen unconditionally. This is incorrect: it has to
decrement either bio_qlen or discard_bio_qlen dependently on the type of bio.
https://jira.sw.ru/browse/PSBM-30451
https://bugzilla.openvz.org/show_bug.cgi?id=3124
Signed-off-by: Maxim Patlasov <MPatlasov at parallels.com>
Acked-by: Andrew Vagin <avagin at parallels.com>
---
drivers/block/ploop/dev.c | 8 ++++++--
drivers/block/ploop/freeblks.c | 12 ++++++++----
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/drivers/block/ploop/dev.c b/drivers/block/ploop/dev.c
index 5baffbb..95b335c 100644
--- a/drivers/block/ploop/dev.c
+++ b/drivers/block/ploop/dev.c
@@ -551,7 +551,10 @@ ploop_bio_queue(struct ploop_device * plo, struct bio * bio,
__TRACE("A %p %u\n", preq, preq->req_cluster);
- plo->bio_qlen--;
+ if (unlikely(bio->bi_rw & REQ_DISCARD))
+ plo->bio_discard_qlen--;
+ else
+ plo->bio_qlen--;
ploop_entry_add(plo, preq);
if (bio->bi_size && !(bio->bi_rw & REQ_DISCARD))
@@ -2575,7 +2578,8 @@ static void ploop_wait(struct ploop_device * plo, int once, struct blk_plug *plu
!plo->active_reqs))
break;
} else if (plo->bio_head ||
- !bio_list_empty(&plo->bio_discard_list)) {
+ (!bio_list_empty(&plo->bio_discard_list) &&
+ !ploop_discard_is_inprogress(plo->fbd))) {
/* ready_queue and entry_queue are empty, but
* bio list not. Obviously, we'd like to process
* bio_list instead of sleeping */
diff --git a/drivers/block/ploop/freeblks.c b/drivers/block/ploop/freeblks.c
index cf48d3a..89108c7 100644
--- a/drivers/block/ploop/freeblks.c
+++ b/drivers/block/ploop/freeblks.c
@@ -696,20 +696,24 @@ int ploop_fb_get_free_block(struct ploop_freeblks_desc *fbd,
static void fbd_complete_bio(struct ploop_freeblks_desc *fbd, int err)
{
+ struct ploop_device *plo = fbd->plo;
unsigned int nr_completed = 0;
while (fbd->fbd_dbl.head) {
struct bio * bio = fbd->fbd_dbl.head;
fbd->fbd_dbl.head = bio->bi_next;
bio->bi_next = NULL;
- BIO_ENDIO(fbd->plo->queue, bio, err);
+ BIO_ENDIO(plo->queue, bio, err);
nr_completed++;
}
fbd->fbd_dbl.tail = NULL;
- spin_lock_irq(&fbd->plo->lock);
- fbd->plo->bio_total -= nr_completed;
- spin_unlock_irq(&fbd->plo->lock);
+ spin_lock_irq(&plo->lock);
+ plo->bio_total -= nr_completed;
+ if (!bio_list_empty(&plo->bio_discard_list) &&
+ waitqueue_active(&plo->waitq))
+ wake_up_interruptible(&plo->waitq);
+ spin_unlock_irq(&plo->lock);
}
void ploop_fb_reinit(struct ploop_freeblks_desc *fbd, int err)
More information about the Devel
mailing list