Commit 1b435b10324fe9937f254bb00718f78d5e50837a

Authored by aliguori
1 parent 474ad834

Make bottom halves more robust

Bottom halves are supposed to not complete until the next iteration of the main
loop.  This is very important to ensure that guests can not cause stack
overflows in the block driver code.  Right now, if you attempt to schedule a
bottom half within a bottom half callback, you will enter an infinite loop.

This patch uses the same logic that we use for the IOHandler loop to make the
bottom half processing robust in list manipulation while in a callback.

This patch also introduces idle scheduling for bottom halves.  qemu_bh_poll()
returns an indication of whether any bottom halves were successfully executed.
qemu_aio_wait() uses this to immediately return if a bottom half was executed
instead of waiting for a completion notification.

qemu_bh_schedule_idle() works around this by not reporting the callback has
run in the qemu_bh_poll loop.  qemu_aio_wait() probably needs some refactoring
but that would require a larger code audit.  idle scheduling seems like a good
compromise.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>




git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5572 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 2 changed files with 38 additions and 23 deletions
qemu-common.h
... ... @@ -70,6 +70,7 @@ typedef void QEMUBHFunc(void *opaque);
70 70  
71 71 QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque);
72 72 void qemu_bh_schedule(QEMUBH *bh);
  73 +void qemu_bh_schedule_idle(QEMUBH *bh);
73 74 void qemu_bh_cancel(QEMUBH *bh);
74 75 void qemu_bh_delete(QEMUBH *bh);
75 76 int qemu_bh_poll(void);
... ...
... ... @@ -7578,6 +7578,8 @@ struct QEMUBH {
7578 7578 QEMUBHFunc *cb;
7579 7579 void *opaque;
7580 7580 int scheduled;
  7581 + int idle;
  7582 + int deleted;
7581 7583 QEMUBH *next;
7582 7584 };
7583 7585  
... ... @@ -7591,37 +7593,56 @@ QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
7591 7593 return NULL;
7592 7594 bh->cb = cb;
7593 7595 bh->opaque = opaque;
  7596 + bh->next = first_bh;
  7597 + first_bh = bh;
7594 7598 return bh;
7595 7599 }
7596 7600  
7597 7601 int qemu_bh_poll(void)
7598 7602 {
7599   - QEMUBH *bh, **pbh;
  7603 + QEMUBH *bh, **bhp;
7600 7604 int ret;
7601 7605  
7602 7606 ret = 0;
7603   - for(;;) {
7604   - pbh = &first_bh;
7605   - bh = *pbh;
7606   - if (!bh)
7607   - break;
7608   - ret = 1;
7609   - *pbh = bh->next;
7610   - bh->scheduled = 0;
7611   - bh->cb(bh->opaque);
  7607 + for (bh = first_bh; bh; bh = bh->next) {
  7608 + if (!bh->deleted && bh->scheduled) {
  7609 + bh->scheduled = 0;
  7610 + if (!bh->idle)
  7611 + ret = 1;
  7612 + bh->idle = 0;
  7613 + bh->cb(bh->opaque);
  7614 + }
7612 7615 }
  7616 +
  7617 + /* remove deleted bhs */
  7618 + bhp = &first_bh;
  7619 + while (*bhp) {
  7620 + bh = *bhp;
  7621 + if (bh->deleted) {
  7622 + *bhp = bh->next;
  7623 + qemu_free(bh);
  7624 + } else
  7625 + bhp = &bh->next;
  7626 + }
  7627 +
7613 7628 return ret;
7614 7629 }
7615 7630  
  7631 +void qemu_bh_schedule_idle(QEMUBH *bh)
  7632 +{
  7633 + if (bh->scheduled)
  7634 + return;
  7635 + bh->scheduled = 1;
  7636 + bh->idle = 1;
  7637 +}
  7638 +
7616 7639 void qemu_bh_schedule(QEMUBH *bh)
7617 7640 {
7618 7641 CPUState *env = cpu_single_env;
7619 7642 if (bh->scheduled)
7620 7643 return;
7621 7644 bh->scheduled = 1;
7622   - bh->next = first_bh;
7623   - first_bh = bh;
7624   -
  7645 + bh->idle = 0;
7625 7646 /* stop the currently executing CPU to execute the BH ASAP */
7626 7647 if (env) {
7627 7648 cpu_interrupt(env, CPU_INTERRUPT_EXIT);
... ... @@ -7630,20 +7651,13 @@ void qemu_bh_schedule(QEMUBH *bh)
7630 7651  
7631 7652 void qemu_bh_cancel(QEMUBH *bh)
7632 7653 {
7633   - QEMUBH **pbh;
7634   - if (bh->scheduled) {
7635   - pbh = &first_bh;
7636   - while (*pbh != bh)
7637   - pbh = &(*pbh)->next;
7638   - *pbh = bh->next;
7639   - bh->scheduled = 0;
7640   - }
  7654 + bh->scheduled = 0;
7641 7655 }
7642 7656  
7643 7657 void qemu_bh_delete(QEMUBH *bh)
7644 7658 {
7645   - qemu_bh_cancel(bh);
7646   - qemu_free(bh);
  7659 + bh->scheduled = 0;
  7660 + bh->deleted = 1;
7647 7661 }
7648 7662  
7649 7663 /***********************************************************/
... ...