Commit 213189ab65d83ecd9072f27c80a15dcb91b6bdbf

Authored by Markus Armbruster
Committed by Anthony Liguori
1 parent 3e28c9ad

Fix VM state change handlers running out of order

When a VM state change handler changes VM state, other VM state change
handlers can see the state transitions out of order.

bmdma_map(), scsi_disk_init() and virtio_blk_init() install VM state
change handlers to restart DMA.  These handlers can vm_stop() by
running into a write error on a drive with werror=stop.  This throws
the VM state change handler callback into disarray.  Here's an example
case I observed:

0. The virtual IDE drive goes south.  All future writes return errors.

1. Something encounters a write error, and duly stops the VM with
   vm_stop().

2. vm_stop() calls vm_state_notify(0).

3. vm_state_notify() runs the callbacks in list vm_change_state_head.
   It contains ide_dma_restart_cb() installed by bmdma_map().  It also
   contains audio_vm_change_state_handler() installed by audio_init().

4. audio_vm_change_state_handler() stops audio stuff.

5. User continues VM with monitor command "c".  This runs vm_start().

6. vm_start() calls vm_state_notify(1).

7. vm_state_notify() runs the callbacks in vm_change_state_head.

8. ide_dma_restart_cb() happens to come first.  It does its work, runs
   into a write error, and duly stops the VM with vm_stop().

9. vm_stop() runs vm_state_notify(0).

10. vm_state_notify() runs the callbacks in vm_change_state_head.

11. audio_vm_change_state_handler() stops audio stuff.  Which isn't
   running.

12. vm_stop() finishes, ide_dma_restart_cb() finishes, step 7's
   vm_state_notify() resumes running handlers.

13. audio_vm_change_state_handler() starts audio stuff.  Oopsie.

Fix this by moving the actual write from each VM state change handler
into a new bottom half (suggested by Gleb Natapov).

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
hw/ide.c
@@ -501,6 +501,7 @@ typedef struct BMDMAState { @@ -501,6 +501,7 @@ typedef struct BMDMAState {
501 QEMUIOVector qiov; 501 QEMUIOVector qiov;
502 int64_t sector_num; 502 int64_t sector_num;
503 uint32_t nsector; 503 uint32_t nsector;
  504 + QEMUBH *bh;
504 } BMDMAState; 505 } BMDMAState;
505 506
506 typedef struct PCIIDEState { 507 typedef struct PCIIDEState {
@@ -1109,11 +1110,13 @@ static void ide_sector_write(IDEState *s) @@ -1109,11 +1110,13 @@ static void ide_sector_write(IDEState *s)
1109 } 1110 }
1110 } 1111 }
1111 1112
1112 -static void ide_dma_restart_cb(void *opaque, int running, int reason) 1113 +static void ide_dma_restart_bh(void *opaque)
1113 { 1114 {
1114 BMDMAState *bm = opaque; 1115 BMDMAState *bm = opaque;
1115 - if (!running)  
1116 - return; 1116 +
  1117 + qemu_bh_delete(bm->bh);
  1118 + bm->bh = NULL;
  1119 +
1117 if (bm->status & BM_STATUS_DMA_RETRY) { 1120 if (bm->status & BM_STATUS_DMA_RETRY) {
1118 bm->status &= ~BM_STATUS_DMA_RETRY; 1121 bm->status &= ~BM_STATUS_DMA_RETRY;
1119 ide_dma_restart(bm->ide_if); 1122 ide_dma_restart(bm->ide_if);
@@ -1123,6 +1126,19 @@ static void ide_dma_restart_cb(void *opaque, int running, int reason) @@ -1123,6 +1126,19 @@ static void ide_dma_restart_cb(void *opaque, int running, int reason)
1123 } 1126 }
1124 } 1127 }
1125 1128
  1129 +static void ide_dma_restart_cb(void *opaque, int running, int reason)
  1130 +{
  1131 + BMDMAState *bm = opaque;
  1132 +
  1133 + if (!running)
  1134 + return;
  1135 +
  1136 + if (!bm->bh) {
  1137 + bm->bh = qemu_bh_new(ide_dma_restart_bh, bm);
  1138 + qemu_bh_schedule(bm->bh);
  1139 + }
  1140 +}
  1141 +
1126 static void ide_write_dma_cb(void *opaque, int ret) 1142 static void ide_write_dma_cb(void *opaque, int ret)
1127 { 1143 {
1128 BMDMAState *bm = opaque; 1144 BMDMAState *bm = opaque;
hw/scsi-disk.c
@@ -74,6 +74,7 @@ struct SCSIDeviceState @@ -74,6 +74,7 @@ struct SCSIDeviceState
74 scsi_completionfn completion; 74 scsi_completionfn completion;
75 void *opaque; 75 void *opaque;
76 char drive_serial_str[21]; 76 char drive_serial_str[21];
  77 + QEMUBH *bh;
77 }; 78 };
78 79
79 /* Global pool of SCSIRequest structures. */ 80 /* Global pool of SCSIRequest structures. */
@@ -308,12 +309,13 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag) @@ -308,12 +309,13 @@ static int scsi_write_data(SCSIDevice *d, uint32_t tag)
308 return 0; 309 return 0;
309 } 310 }
310 311
311 -static void scsi_dma_restart_cb(void *opaque, int running, int reason) 312 +static void scsi_dma_restart_bh(void *opaque)
312 { 313 {
313 SCSIDeviceState *s = opaque; 314 SCSIDeviceState *s = opaque;
314 SCSIRequest *r = s->requests; 315 SCSIRequest *r = s->requests;
315 - if (!running)  
316 - return; 316 +
  317 + qemu_bh_delete(s->bh);
  318 + s->bh = NULL;
317 319
318 while (r) { 320 while (r) {
319 if (r->status & SCSI_REQ_STATUS_RETRY) { 321 if (r->status & SCSI_REQ_STATUS_RETRY) {
@@ -324,6 +326,19 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason) @@ -324,6 +326,19 @@ static void scsi_dma_restart_cb(void *opaque, int running, int reason)
324 } 326 }
325 } 327 }
326 328
  329 +static void scsi_dma_restart_cb(void *opaque, int running, int reason)
  330 +{
  331 + SCSIDeviceState *s = opaque;
  332 +
  333 + if (!running)
  334 + return;
  335 +
  336 + if (!s->bh) {
  337 + s->bh = qemu_bh_new(scsi_dma_restart_bh, s);
  338 + qemu_bh_schedule(s->bh);
  339 + }
  340 +}
  341 +
327 /* Return a pointer to the data buffer. */ 342 /* Return a pointer to the data buffer. */
328 static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag) 343 static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
329 { 344 {
hw/virtio-blk.c
@@ -26,6 +26,7 @@ typedef struct VirtIOBlock @@ -26,6 +26,7 @@ typedef struct VirtIOBlock
26 VirtQueue *vq; 26 VirtQueue *vq;
27 void *rq; 27 void *rq;
28 char serial_str[BLOCK_SERIAL_STRLEN + 1]; 28 char serial_str[BLOCK_SERIAL_STRLEN + 1];
  29 + QEMUBH *bh;
29 } VirtIOBlock; 30 } VirtIOBlock;
30 31
31 static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) 32 static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
@@ -302,13 +303,13 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq) @@ -302,13 +303,13 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
302 */ 303 */
303 } 304 }
304 305
305 -static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason) 306 +static void virtio_blk_dma_restart_bh(void *opaque)
306 { 307 {
307 VirtIOBlock *s = opaque; 308 VirtIOBlock *s = opaque;
308 VirtIOBlockReq *req = s->rq; 309 VirtIOBlockReq *req = s->rq;
309 310
310 - if (!running)  
311 - return; 311 + qemu_bh_delete(s->bh);
  312 + s->bh = NULL;
312 313
313 s->rq = NULL; 314 s->rq = NULL;
314 315
@@ -318,6 +319,19 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason) @@ -318,6 +319,19 @@ static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
318 } 319 }
319 } 320 }
320 321
  322 +static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
  323 +{
  324 + VirtIOBlock *s = opaque;
  325 +
  326 + if (!running)
  327 + return;
  328 +
  329 + if (!s->bh) {
  330 + s->bh = qemu_bh_new(virtio_blk_dma_restart_bh, s);
  331 + qemu_bh_schedule(s->bh);
  332 + }
  333 +}
  334 +
321 static void virtio_blk_reset(VirtIODevice *vdev) 335 static void virtio_blk_reset(VirtIODevice *vdev)
322 { 336 {
323 /* 337 /*