diff options
48 files changed, 623 insertions, 222 deletions
diff --git a/.travis.yml b/.travis.yml index e0c72210b7..2fd63eceaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -318,8 +318,10 @@ jobs: env: - CONFIG="--enable-tools --target-list=aarch64-softmmu,alpha-softmmu,arm-softmmu,m68k-softmmu,microblaze-softmmu,mips-softmmu,mips64el-softmmu,nios2-softmmu,or1k-softmmu,ppc-softmmu,ppc64-softmmu,s390x-softmmu,sparc-softmmu,x86_64-softmmu,xtensa-softmmu" - TEST_CMD="make check-acceptance" + - CACHE_NAME="${TRAVIS_BRANCH}-linux-gcc-acceptance" after_script: - python3 -c 'import json; r = json.load(open("tests/results/latest/results.json")); [print(t["logfile"]) for t in r["tests"] if t["status"] not in ("PASS", "SKIP")]' | xargs cat + - du -chs $HOME/avocado/data/cache addons: apt: packages: diff --git a/MAINTAINERS b/MAINTAINERS index 0559e84790..642c8e0b6b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -440,6 +440,7 @@ F: hw/9pfs/xen-9p* F: hw/char/xen_console.c F: hw/display/xenfb.c F: hw/net/xen_nic.c +F: hw/usb/xen-usb.c F: hw/block/xen* F: hw/block/dataplane/xen* F: hw/xen/ diff --git a/audio/audio.c b/audio/audio.c index 9ac9a20c41..7a9e680355 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -1491,15 +1491,13 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size) size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size) { - size_t src_size, copy_size; - void *src = hw->pcm_ops->get_buffer_in(hw, &src_size); - copy_size = MIN(size, src_size); + void *src = hw->pcm_ops->get_buffer_in(hw, &size); - memcpy(buf, src, copy_size); - hw->pcm_ops->put_buffer_in(hw, src, copy_size); - return copy_size; -} + memcpy(buf, src, size); + hw->pcm_ops->put_buffer_in(hw, src, size); + return size; +} static int audio_driver_init(AudioState *s, struct audio_driver *drv, bool msg, Audiodev *dev) diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c index bd57082a8d..4cdf19ab67 100644 --- a/audio/dsoundaudio.c +++ b/audio/dsoundaudio.c @@ -279,7 +279,7 @@ static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp, return -1; } - if (*statusp & DSERR_BUFFERLOST) { + if (*statusp & DSBSTATUS_BUFFERLOST) { dsound_restore_out(dsb, s); return -1; } @@ -540,7 +540,12 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size) } req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul); - req_size = MIN(req_size, hw->size_emul - hw->pos_emul); + req_size = MIN(*size, MIN(req_size, hw->size_emul - hw->pos_emul)); + + if (req_size == 0) { + *size = 0; + return NULL; + } err = dsound_lock_in(dscb, &hw->info, hw->pos_emul, req_size, &ret, NULL, &act_size, NULL, false, ds->s); diff --git a/block/backup.c b/block/backup.c index 7430ca5883..a7a7dcaf4c 100644 --- a/block/backup.c +++ b/block/backup.c @@ -126,11 +126,7 @@ static void backup_abort(Job *job) static void backup_clean(Job *job) { BackupBlockJob *s = container_of(job, BackupBlockJob, common.job); - AioContext *aio_context = bdrv_get_aio_context(s->backup_top); - - aio_context_acquire(aio_context); bdrv_backup_top_drop(s->backup_top); - aio_context_release(aio_context); } void backup_do_checkpoint(BlockJob *job, Error **errp) diff --git a/block/block-backend.c b/block/block-backend.c index 8b8f2a80a0..38ae413826 100644 --- a/block/block-backend.c +++ b/block/block-backend.c @@ -1140,16 +1140,22 @@ static int blk_check_byte_request(BlockBackend *blk, int64_t offset, return 0; } +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ static void coroutine_fn blk_wait_while_drained(BlockBackend *blk) { + assert(blk->in_flight > 0); + if (blk->quiesce_counter && !blk->disable_request_queuing) { + blk_dec_in_flight(blk); qemu_co_queue_wait(&blk->queued_requests, NULL); + blk_inc_in_flight(blk); } } -int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, - unsigned int bytes, QEMUIOVector *qiov, - BdrvRequestFlags flags) +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_do_preadv(BlockBackend *blk, int64_t offset, unsigned int bytes, + QEMUIOVector *qiov, BdrvRequestFlags flags) { int ret; BlockDriverState *bs; @@ -1178,10 +1184,24 @@ int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, return ret; } -int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, - unsigned int bytes, - QEMUIOVector *qiov, size_t qiov_offset, - BdrvRequestFlags flags) +int coroutine_fn blk_co_preadv(BlockBackend *blk, int64_t offset, + unsigned int bytes, QEMUIOVector *qiov, + BdrvRequestFlags flags) +{ + int ret; + + blk_inc_in_flight(blk); + ret = blk_do_preadv(blk, offset, bytes, qiov, flags); + blk_dec_in_flight(blk); + + return ret; +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_do_pwritev_part(BlockBackend *blk, int64_t offset, unsigned int bytes, + QEMUIOVector *qiov, size_t qiov_offset, + BdrvRequestFlags flags) { int ret; BlockDriverState *bs; @@ -1214,6 +1234,20 @@ int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, return ret; } +int coroutine_fn blk_co_pwritev_part(BlockBackend *blk, int64_t offset, + unsigned int bytes, + QEMUIOVector *qiov, size_t qiov_offset, + BdrvRequestFlags flags) +{ + int ret; + + blk_inc_in_flight(blk); + ret = blk_do_pwritev_part(blk, offset, bytes, qiov, qiov_offset, flags); + blk_dec_in_flight(blk); + + return ret; +} + int coroutine_fn blk_co_pwritev(BlockBackend *blk, int64_t offset, unsigned int bytes, QEMUIOVector *qiov, BdrvRequestFlags flags) @@ -1234,7 +1268,7 @@ static void blk_read_entry(void *opaque) BlkRwCo *rwco = opaque; QEMUIOVector *qiov = rwco->iobuf; - rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, qiov->size, + rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, qiov->size, qiov, rwco->flags); aio_wait_kick(); } @@ -1244,8 +1278,8 @@ static void blk_write_entry(void *opaque) BlkRwCo *rwco = opaque; QEMUIOVector *qiov = rwco->iobuf; - rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, qiov->size, - qiov, rwco->flags); + rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, qiov->size, + qiov, 0, rwco->flags); aio_wait_kick(); } @@ -1262,6 +1296,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, .ret = NOT_DONE, }; + blk_inc_in_flight(blk); if (qemu_in_coroutine()) { /* Fast-path if already in coroutine context */ co_entry(&rwco); @@ -1270,6 +1305,7 @@ static int blk_prw(BlockBackend *blk, int64_t offset, uint8_t *buf, bdrv_coroutine_enter(blk_bs(blk), co); BDRV_POLL_WHILE(blk_bs(blk), rwco.ret == NOT_DONE); } + blk_dec_in_flight(blk); return rwco.ret; } @@ -1387,14 +1423,8 @@ static void blk_aio_read_entry(void *opaque) BlkRwCo *rwco = &acb->rwco; QEMUIOVector *qiov = rwco->iobuf; - if (rwco->blk->quiesce_counter) { - blk_dec_in_flight(rwco->blk); - blk_wait_while_drained(rwco->blk); - blk_inc_in_flight(rwco->blk); - } - assert(qiov->size == acb->bytes); - rwco->ret = blk_co_preadv(rwco->blk, rwco->offset, acb->bytes, + rwco->ret = blk_do_preadv(rwco->blk, rwco->offset, acb->bytes, qiov, rwco->flags); blk_aio_complete(acb); } @@ -1405,15 +1435,9 @@ static void blk_aio_write_entry(void *opaque) BlkRwCo *rwco = &acb->rwco; QEMUIOVector *qiov = rwco->iobuf; - if (rwco->blk->quiesce_counter) { - blk_dec_in_flight(rwco->blk); - blk_wait_while_drained(rwco->blk); - blk_inc_in_flight(rwco->blk); - } - assert(!qiov || qiov->size == acb->bytes); - rwco->ret = blk_co_pwritev(rwco->blk, rwco->offset, acb->bytes, - qiov, rwco->flags); + rwco->ret = blk_do_pwritev_part(rwco->blk, rwco->offset, acb->bytes, + qiov, 0, rwco->flags); blk_aio_complete(acb); } @@ -1488,38 +1512,6 @@ BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset, blk_aio_write_entry, flags, cb, opaque); } -static void blk_aio_flush_entry(void *opaque) -{ - BlkAioEmAIOCB *acb = opaque; - BlkRwCo *rwco = &acb->rwco; - - rwco->ret = blk_co_flush(rwco->blk); - blk_aio_complete(acb); -} - -BlockAIOCB *blk_aio_flush(BlockBackend *blk, - BlockCompletionFunc *cb, void *opaque) -{ - return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque); -} - -static void blk_aio_pdiscard_entry(void *opaque) -{ - BlkAioEmAIOCB *acb = opaque; - BlkRwCo *rwco = &acb->rwco; - - rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, acb->bytes); - blk_aio_complete(acb); -} - -BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, - int64_t offset, int bytes, - BlockCompletionFunc *cb, void *opaque) -{ - return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0, - cb, opaque); -} - void blk_aio_cancel(BlockAIOCB *acb) { bdrv_aio_cancel(acb); @@ -1530,7 +1522,9 @@ void blk_aio_cancel_async(BlockAIOCB *acb) bdrv_aio_cancel_async(acb); } -int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf) +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_do_ioctl(BlockBackend *blk, unsigned long int req, void *buf) { blk_wait_while_drained(blk); @@ -1546,8 +1540,7 @@ static void blk_ioctl_entry(void *opaque) BlkRwCo *rwco = opaque; QEMUIOVector *qiov = rwco->iobuf; - rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, - qiov->iov[0].iov_base); + rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, qiov->iov[0].iov_base); aio_wait_kick(); } @@ -1561,7 +1554,7 @@ static void blk_aio_ioctl_entry(void *opaque) BlkAioEmAIOCB *acb = opaque; BlkRwCo *rwco = &acb->rwco; - rwco->ret = blk_co_ioctl(rwco->blk, rwco->offset, rwco->iobuf); + rwco->ret = blk_do_ioctl(rwco->blk, rwco->offset, rwco->iobuf); blk_aio_complete(acb); } @@ -1572,7 +1565,9 @@ BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, return blk_aio_prwv(blk, req, 0, buf, blk_aio_ioctl_entry, 0, cb, opaque); } -int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes) +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn +blk_do_pdiscard(BlockBackend *blk, int64_t offset, int bytes) { int ret; @@ -1586,7 +1581,50 @@ int blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes) return bdrv_co_pdiscard(blk->root, offset, bytes); } -int blk_co_flush(BlockBackend *blk) +static void blk_aio_pdiscard_entry(void *opaque) +{ + BlkAioEmAIOCB *acb = opaque; + BlkRwCo *rwco = &acb->rwco; + + rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, acb->bytes); + blk_aio_complete(acb); +} + +BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, + int64_t offset, int bytes, + BlockCompletionFunc *cb, void *opaque) +{ + return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_pdiscard_entry, 0, + cb, opaque); +} + +int coroutine_fn blk_co_pdiscard(BlockBackend *blk, int64_t offset, int bytes) +{ + int ret; + + blk_inc_in_flight(blk); + ret = blk_do_pdiscard(blk, offset, bytes); + blk_dec_in_flight(blk); + + return ret; +} + +static void blk_pdiscard_entry(void *opaque) +{ + BlkRwCo *rwco = opaque; + QEMUIOVector *qiov = rwco->iobuf; + + rwco->ret = blk_do_pdiscard(rwco->blk, rwco->offset, qiov->size); + aio_wait_kick(); +} + +int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes) +{ + return blk_prw(blk, offset, NULL, bytes, blk_pdiscard_entry, 0); +} + +/* To be called between exactly one pair of blk_inc/dec_in_flight() */ +static int coroutine_fn blk_do_flush(BlockBackend *blk) { blk_wait_while_drained(blk); @@ -1597,10 +1635,36 @@ int blk_co_flush(BlockBackend *blk) return bdrv_co_flush(blk_bs(blk)); } +static void blk_aio_flush_entry(void *opaque) +{ + BlkAioEmAIOCB *acb = opaque; + BlkRwCo *rwco = &acb->rwco; + + rwco->ret = blk_do_flush(rwco->blk); + blk_aio_complete(acb); +} + +BlockAIOCB *blk_aio_flush(BlockBackend *blk, + BlockCompletionFunc *cb, void *opaque) +{ + return blk_aio_prwv(blk, 0, 0, NULL, blk_aio_flush_entry, 0, cb, opaque); +} + +int coroutine_fn blk_co_flush(BlockBackend *blk) +{ + int ret; + + blk_inc_in_flight(blk); + ret = blk_do_flush(blk); + blk_dec_in_flight(blk); + + return ret; +} + static void blk_flush_entry(void *opaque) { BlkRwCo *rwco = opaque; - rwco->ret = blk_co_flush(rwco->blk); + rwco->ret = blk_do_flush(rwco->blk); aio_wait_kick(); } @@ -2083,20 +2147,6 @@ int blk_truncate(BlockBackend *blk, int64_t offset, bool exact, return bdrv_truncate(blk->root, offset, exact, prealloc, errp); } -static void blk_pdiscard_entry(void *opaque) -{ - BlkRwCo *rwco = opaque; - QEMUIOVector *qiov = rwco->iobuf; - - rwco->ret = blk_co_pdiscard(rwco->blk, rwco->offset, qiov->size); - aio_wait_kick(); -} - -int blk_pdiscard(BlockBackend *blk, int64_t offset, int bytes) -{ - return blk_prw(blk, offset, NULL, bytes, blk_pdiscard_entry, 0); -} - int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf, int64_t pos, int size) { diff --git a/block/qcow2.c b/block/qcow2.c index 2bb536b014..b524b0c53f 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -3784,6 +3784,12 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs, int ret; BDRVQcow2State *s = bs->opaque; + /* If the image does not support QCOW_OFLAG_ZERO then discarding + * clusters could expose stale data from the backing file. */ + if (s->qcow_version < 3 && bs->backing) { + return -ENOTSUP; + } + if (!QEMU_IS_ALIGNED(offset | bytes, s->cluster_size)) { assert(bytes < s->cluster_size); /* Ignore partial clusters, except for the special case of the @@ -4349,6 +4355,11 @@ qcow2_co_pwritev_compressed_part(BlockDriverState *bs, return -EINVAL; } + if (offset_into_cluster(s, bytes) && + (offset + bytes) != (bs->total_sectors << BDRV_SECTOR_BITS)) { + return -EINVAL; + } + while (bytes && aio_task_pool_status(aio) == 0) { uint64_t chunk_size = MIN(bytes, s->cluster_size); diff --git a/block/replication.c b/block/replication.c index 413d95407d..da013c2041 100644 --- a/block/replication.c +++ b/block/replication.c @@ -144,12 +144,15 @@ fail: static void replication_close(BlockDriverState *bs) { BDRVReplicationState *s = bs->opaque; + Job *commit_job; if (s->stage == BLOCK_REPLICATION_RUNNING) { replication_stop(s->rs, false, NULL); } if (s->stage == BLOCK_REPLICATION_FAILOVER) { - job_cancel_sync(&s->commit_job->job); + commit_job = &s->commit_job->job; + assert(commit_job->aio_context == qemu_get_current_aio_context()); + job_cancel_sync(commit_job); } if (s->mode == REPLICATION_MODE_SECONDARY) { diff --git a/block/vpc.c b/block/vpc.c index 6df75e22dc..d8141b52da 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -835,7 +835,7 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf, /* Write the footer (twice: at the beginning and at the end) */ block_size = 0x200000; - num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512); + num_bat_entries = DIV_ROUND_UP(total_sectors, block_size / 512); ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0); if (ret < 0) { diff --git a/blockdev.c b/blockdev.c index fa8630cb41..5faddaa705 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3612,7 +3612,16 @@ void qmp_block_job_finalize(const char *id, Error **errp) } trace_qmp_block_job_finalize(job); + job_ref(&job->job); job_finalize(&job->job, errp); + + /* + * Job's context might have changed via job_finalize (and job_txn_apply + * automatically acquires the new one), so make sure we release the correct + * one. + */ + aio_context = blk_get_aio_context(job->blk); + job_unref(&job->job); aio_context_release(aio_context); } diff --git a/hw/block/dataplane/xen-block.c b/hw/block/dataplane/xen-block.c index 288a87a814..5f8f15778b 100644 --- a/hw/block/dataplane/xen-block.c +++ b/hw/block/dataplane/xen-block.c @@ -64,6 +64,8 @@ struct XenBlockDataPlane { AioContext *ctx; }; +static int xen_block_send_response(XenBlockRequest *request); + static void reset_request(XenBlockRequest *request) { memset(&request->req, 0, sizeof(request->req)); @@ -115,23 +117,26 @@ out: return request; } -static void xen_block_finish_request(XenBlockRequest *request) +static void xen_block_complete_request(XenBlockRequest *request) { XenBlockDataPlane *dataplane = request->dataplane; - QLIST_REMOVE(request, list); - dataplane->requests_inflight--; -} + if (xen_block_send_response(request)) { + Error *local_err = NULL; -static void xen_block_release_request(XenBlockRequest *request) -{ - XenBlockDataPlane *dataplane = request->dataplane; + xen_device_notify_event_channel(dataplane->xendev, + dataplane->event_channel, + &local_err); + if (local_err) { + error_report_err(local_err); + } + } QLIST_REMOVE(request, list); + dataplane->requests_inflight--; reset_request(request); request->dataplane = dataplane; QLIST_INSERT_HEAD(&dataplane->freelist, request, list); - dataplane->requests_inflight--; } /* @@ -246,7 +251,6 @@ static int xen_block_copy_request(XenBlockRequest *request) } static int xen_block_do_aio(XenBlockRequest *request); -static int xen_block_send_response(XenBlockRequest *request); static void xen_block_complete_aio(void *opaque, int ret) { @@ -286,7 +290,6 @@ static void xen_block_complete_aio(void *opaque, int ret) } request->status = request->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY; - xen_block_finish_request(request); switch (request->req.operation) { case BLKIF_OP_WRITE: @@ -306,17 +309,8 @@ static void xen_block_complete_aio(void *opaque, int ret) default: break; } - if (xen_block_send_response(request)) { - Error *local_err = NULL; - xen_device_notify_event_channel(dataplane->xendev, - dataplane->event_channel, - &local_err); - if (local_err) { - error_report_err(local_err); - } - } - xen_block_release_request(request); + xen_block_complete_request(request); if (dataplane->more_work) { qemu_bh_schedule(dataplane->bh); @@ -420,8 +414,8 @@ static int xen_block_do_aio(XenBlockRequest *request) return 0; err: - xen_block_finish_request(request); request->status = BLKIF_RSP_ERROR; + xen_block_complete_request(request); return -1; } @@ -575,17 +569,7 @@ static bool xen_block_handle_requests(XenBlockDataPlane *dataplane) break; }; - if (xen_block_send_response(request)) { - Error *local_err = NULL; - - xen_device_notify_event_channel(dataplane->xendev, - dataplane->event_channel, - &local_err); - if (local_err) { - error_report_err(local_err); - } - } - xen_block_release_request(request); + xen_block_complete_request(request); continue; } diff --git a/hw/block/xen-block.c b/hw/block/xen-block.c index 07bb32e22b..99cb4c67cb 100644 --- a/hw/block/xen-block.c +++ b/hw/block/xen-block.c @@ -860,7 +860,7 @@ static XenBlockIOThread *xen_block_iothread_create(const char *id, XenBlockIOThread *iothread = g_new(XenBlockIOThread, 1); Error *local_err = NULL; QDict *opts; - QObject *ret_data; + QObject *ret_data = NULL; iothread->id = g_strdup(id); diff --git a/hw/display/ati_2d.c b/hw/display/ati_2d.c index 42e82311eb..23a8ae0cd8 100644 --- a/hw/display/ati_2d.c +++ b/hw/display/ati_2d.c @@ -53,12 +53,20 @@ void ati_2d_blt(ATIVGAState *s) s->vga.vbe_start_addr, surface_data(ds), surface_stride(ds), surface_bits_per_pixel(ds), (s->regs.dp_mix & GMC_ROP3_MASK) >> 16); - int dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? - s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width); - int dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? - s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height); + unsigned dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? + s->regs.dst_x : s->regs.dst_x + 1 - s->regs.dst_width); + unsigned dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? + s->regs.dst_y : s->regs.dst_y + 1 - s->regs.dst_height); int bpp = ati_bpp_from_datatype(s); + if (!bpp) { + qemu_log_mask(LOG_GUEST_ERROR, "Invalid bpp\n"); + return; + } int dst_stride = DEFAULT_CNTL ? s->regs.dst_pitch : s->regs.default_pitch; + if (!dst_stride) { + qemu_log_mask(LOG_GUEST_ERROR, "Zero dest pitch\n"); + return; + } uint8_t *dst_bits = s->vga.vram_ptr + (DEFAULT_CNTL ? s->regs.dst_offset : s->regs.default_offset); @@ -82,12 +90,16 @@ void ati_2d_blt(ATIVGAState *s) switch (s->regs.dp_mix & GMC_ROP3_MASK) { case ROP3_SRCCOPY: { - int src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? - s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); - int src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? - s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height); + unsigned src_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? + s->regs.src_x : s->regs.src_x + 1 - s->regs.dst_width); + unsigned src_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? + s->regs.src_y : s->regs.src_y + 1 - s->regs.dst_height); int src_stride = DEFAULT_CNTL ? s->regs.src_pitch : s->regs.default_pitch; + if (!src_stride) { + qemu_log_mask(LOG_GUEST_ERROR, "Zero source pitch\n"); + return; + } uint8_t *src_bits = s->vga.vram_ptr + (DEFAULT_CNTL ? s->regs.src_offset : s->regs.default_offset); @@ -137,8 +149,10 @@ void ati_2d_blt(ATIVGAState *s) dst_y * surface_stride(ds), s->regs.dst_height * surface_stride(ds)); } - s->regs.dst_x += s->regs.dst_width; - s->regs.dst_y += s->regs.dst_height; + s->regs.dst_x = (s->regs.dp_cntl & DST_X_LEFT_TO_RIGHT ? + dst_x + s->regs.dst_width : dst_x); + s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? + dst_y + s->regs.dst_height : dst_y); break; } case ROP3_PATCOPY: @@ -179,7 +193,8 @@ void ati_2d_blt(ATIVGAState *s) dst_y * surface_stride(ds), s->regs.dst_height * surface_stride(ds)); } - s->regs.dst_y += s->regs.dst_height; + s->regs.dst_y = (s->regs.dp_cntl & DST_Y_TOP_TO_BOTTOM ? + dst_y + s->regs.dst_height : dst_y); break; } default: diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c index 854cd3ac46..0d1f41197c 100644 --- a/hw/ppc/e500.c +++ b/hw/ppc/e500.c @@ -1047,6 +1047,10 @@ void ppce500_init(MachineState *machine) } filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, payload_name); + if (!filename) { + error_report("could not find firmware/kernel file '%s'", payload_name); + exit(1); + } payload_size = load_elf(filename, NULL, NULL, NULL, &bios_entry, &loadaddr, NULL, NULL, diff --git a/hw/ppc/pnv.c b/hw/ppc/pnv.c index b75ad06390..c9cb6fa357 100644 --- a/hw/ppc/pnv.c +++ b/hw/ppc/pnv.c @@ -571,10 +571,29 @@ static void pnv_powerdown_notify(Notifier *n, void *opaque) static void pnv_reset(MachineState *machine) { + PnvMachineState *pnv = PNV_MACHINE(machine); + IPMIBmc *bmc; void *fdt; qemu_devices_reset(); + /* + * The machine should provide by default an internal BMC simulator. + * If not, try to use the BMC device that was provided on the command + * line. + */ + bmc = pnv_bmc_find(&error_fatal); + if (!pnv->bmc) { + if (!bmc) { + warn_report("machine has no BMC device. Use '-device " + "ipmi-bmc-sim,id=bmc0 -device isa-ipmi-bt,bmc=bmc0,irq=10' " + "to define one"); + } else { + pnv_bmc_set_pnor(bmc, pnv->pnor); + pnv->bmc = bmc; + } + } + fdt = pnv_dt_create(machine); /* Pack resulting tree */ @@ -833,9 +852,6 @@ static void pnv_init(MachineState *machine) } g_free(chip_typename); - /* Create the machine BMC simulator */ - pnv->bmc = pnv_bmc_create(pnv->pnor); - /* Instantiate ISA bus on chip 0 */ pnv->isa_bus = pnv_isa_create(pnv->chips[0], &error_fatal); @@ -845,8 +861,14 @@ static void pnv_init(MachineState *machine) /* Create an RTC ISA device too */ mc146818_rtc_init(pnv->isa_bus, 2000, NULL); - /* Create the IPMI BT device for communication with the BMC */ - pnv_ipmi_bt_init(pnv->isa_bus, pnv->bmc, 10); + /* + * Create the machine BMC simulator and the IPMI BT device for + * communication with the BMC + */ + if (defaults_enabled()) { + pnv->bmc = pnv_bmc_create(pnv->pnor); + pnv_ipmi_bt_init(pnv->isa_bus, pnv->bmc, 10); + } /* * OpenPOWER systems use a IPMI SEL Event message to notify the diff --git a/hw/ppc/pnv_bmc.c b/hw/ppc/pnv_bmc.c index 8863354c1c..4e018b8b70 100644 --- a/hw/ppc/pnv_bmc.c +++ b/hw/ppc/pnv_bmc.c @@ -213,6 +213,18 @@ static const IPMINetfn hiomap_netfn = { .cmd_handlers = hiomap_cmds }; + +void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor) +{ + object_ref(OBJECT(pnor)); + object_property_add_const_link(OBJECT(bmc), "pnor", OBJECT(pnor), + &error_abort); + + /* Install the HIOMAP protocol handlers to access the PNOR */ + ipmi_sim_register_netfn(IPMI_BMC_SIMULATOR(bmc), IPMI_NETFN_OEM, + &hiomap_netfn); +} + /* * Instantiate the machine BMC. PowerNV uses the QEMU internal * simulator but it could also be external. @@ -232,3 +244,36 @@ IPMIBmc *pnv_bmc_create(PnvPnor *pnor) return IPMI_BMC(obj); } + +typedef struct ForeachArgs { + const char *name; + Object *obj; +} ForeachArgs; + +static int bmc_find(Object *child, void *opaque) +{ + ForeachArgs *args = opaque; + + if (object_dynamic_cast(child, args->name)) { + if (args->obj) { + return 1; + } + args->obj = child; + } + return 0; +} + +IPMIBmc *pnv_bmc_find(Error **errp) +{ + ForeachArgs args = { TYPE_IPMI_BMC_SIMULATOR, NULL }; + int ret; + + ret = object_child_foreach_recursive(object_get_root(), bmc_find, &args); + if (ret) { + error_setg(errp, "machine should have only one BMC device. " + "Use '-nodefaults'"); + return NULL; + } + + return args.obj ? IPMI_BMC(args.obj) : NULL; +} diff --git a/hw/ppc/ppc440_uc.c b/hw/ppc/ppc440_uc.c index d5ea962249..b30e093cbb 100644 --- a/hw/ppc/ppc440_uc.c +++ b/hw/ppc/ppc440_uc.c @@ -13,7 +13,6 @@ #include "qemu/error-report.h" #include "qapi/error.h" #include "qemu/log.h" -#include "qemu/main-loop.h" #include "qemu/module.h" #include "cpu.h" #include "hw/irq.h" @@ -1183,9 +1182,7 @@ static void dcr_write_pcie(void *opaque, int dcrn, uint32_t val) case PEGPL_CFGMSK: s->cfg_mask = val; size = ~(val & 0xfffffffe) + 1; - qemu_mutex_lock_iothread(); pcie_host_mmcfg_update(PCIE_HOST_BRIDGE(s), val & 1, s->cfg_base, size); - qemu_mutex_unlock_iothread(); break; case PEGPL_MSGBAH: s->msg_base = ((uint64_t)val << 32) | (s->msg_base & 0xffffffff); diff --git a/hw/ppc/spapr_caps.c b/hw/ppc/spapr_caps.c index 679ae7959f..eb54f94227 100644 --- a/hw/ppc/spapr_caps.c +++ b/hw/ppc/spapr_caps.c @@ -517,9 +517,10 @@ static void cap_fwnmi_apply(SpaprMachineState *spapr, uint8_t val, } if (kvm_enabled()) { - if (kvmppc_set_fwnmi() < 0) { - error_setg(errp, "Firmware Assisted Non-Maskable Interrupts(FWNMI) " - "not supported by KVM"); + if (!kvmppc_get_fwnmi()) { + error_setg(errp, +"Firmware Assisted Non-Maskable Interrupts(FWNMI) not supported by KVM."); + error_append_hint(errp, "Try appending -machine cap-fwnmi=off\n"); } } } diff --git a/hw/ppc/spapr_events.c b/hw/ppc/spapr_events.c index a4a540f43d..1069d0197b 100644 --- a/hw/ppc/spapr_events.c +++ b/hw/ppc/spapr_events.c @@ -833,11 +833,28 @@ static void spapr_mce_dispatch_elog(PowerPCCPU *cpu, bool recovered) /* get rtas addr from fdt */ rtas_addr = spapr_get_rtas_addr(); if (!rtas_addr) { - qemu_system_guest_panicked(NULL); + if (!recovered) { + error_report( +"FWNMI: Unable to deliver machine check to guest: rtas_addr not found."); + qemu_system_guest_panicked(NULL); + } else { + warn_report( +"FWNMI: Unable to deliver machine check to guest: rtas_addr not found. " +"Machine check recovered."); + } g_free(ext_elog); return; } + /* + * By taking the interlock, we assume that the MCE will be + * delivered to the guest. CAUTION: don't add anything that could + * prevent the MCE to be delivered after this line, otherwise the + * guest won't be able to release the interlock and ultimately + * hang/crash? + */ + spapr->fwnmi_machine_check_interlock = cpu->vcpu_id; + stq_be_phys(&address_space_memory, rtas_addr + RTAS_ERROR_LOG_OFFSET, env->gpr[3]); cpu_physical_memory_write(rtas_addr + RTAS_ERROR_LOG_OFFSET + @@ -860,17 +877,13 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered) Error *local_err = NULL; if (spapr->fwnmi_machine_check_addr == -1) { - /* - * This implies that we have hit a machine check either when the - * guest has not registered FWNMI (i.e., "ibm,nmi-register" not - * called) or between system reset and "ibm,nmi-register". - * Fall back to the old machine check behavior in such cases. - */ + /* Non-FWNMI case, deliver it like an architected CPU interrupt. */ cs->exception_index = POWERPC_EXCP_MCHECK; ppc_cpu_do_interrupt(cs); return; } + /* Wait for FWNMI interlock. */ while (spapr->fwnmi_machine_check_interlock != -1) { /* * Check whether the same CPU got machine check error @@ -878,12 +891,25 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered) * that CPU called "ibm,nmi-interlock") */ if (spapr->fwnmi_machine_check_interlock == cpu->vcpu_id) { - qemu_system_guest_panicked(NULL); + if (!recovered) { + error_report( +"FWNMI: Unable to deliver machine check to guest: nested machine check."); + qemu_system_guest_panicked(NULL); + } else { + warn_report( +"FWNMI: Unable to deliver machine check to guest: nested machine check. " +"Machine check recovered."); + } return; } qemu_cond_wait_iothread(&spapr->fwnmi_machine_check_interlock_cond); - /* Meanwhile if the system is reset, then just return */ if (spapr->fwnmi_machine_check_addr == -1) { + /* + * If the machine was reset while waiting for the interlock, + * abort the delivery. The machine check applies to a context + * that no longer exists, so it wouldn't make sense to deliver + * it now. + */ return; } } @@ -894,12 +920,13 @@ void spapr_mce_req_event(PowerPCCPU *cpu, bool recovered) * We don't want to abort so we let the migration to continue. * In a rare case, the machine check handler will run on the target. * Though this is not preferable, it is better than aborting - * the migration or killing the VM. + * the migration or killing the VM. It is okay to call + * migrate_del_blocker on a blocker that was not added (which the + * nmi-interlock handler would do when it's called after this). */ warn_report("Received a fwnmi while migration was in progress"); } - spapr->fwnmi_machine_check_interlock = cpu->vcpu_id; spapr_mce_dispatch_elog(cpu, recovered); } diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 709a52780d..55ca9dee1e 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -1663,6 +1663,7 @@ static void spapr_pci_unplug_request(HotplugHandler *plug_handler, if (pc->is_bridge) { error_setg(errp, "PCI: Hot unplug of PCI bridges not supported"); + return; } /* ensure any other present functions are pending unplug */ diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 9fb8c8632a..bcac0d00e7 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -437,6 +437,13 @@ static void rtas_ibm_nmi_register(PowerPCCPU *cpu, return; } + if (kvm_enabled()) { + if (kvmppc_set_fwnmi() < 0) { + rtas_st(rets, 0, RTAS_OUT_NOT_SUPPORTED); + return; + } + } + spapr->fwnmi_system_reset_addr = sreset_addr; spapr->fwnmi_machine_check_addr = mce_addr; @@ -455,6 +462,9 @@ static void rtas_ibm_nmi_interlock(PowerPCCPU *cpu, } if (spapr->fwnmi_machine_check_addr == -1) { + qemu_log_mask(LOG_GUEST_ERROR, +"FWNMI: ibm,nmi-interlock RTAS called with FWNMI not registered.\n"); + /* NMI register not called */ rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); return; diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c index 1fc2f32ce9..961190d0f7 100644 --- a/hw/usb/xen-usb.c +++ b/hw/usb/xen-usb.c @@ -347,13 +347,11 @@ static int32_t usbback_xlat_status(int status) return -ESHUTDOWN; } -static void usbback_packet_complete(USBPacket *packet) +static void usbback_packet_complete(struct usbback_req *usbback_req) { - struct usbback_req *usbback_req; + USBPacket *packet = &usbback_req->packet; int32_t status; - usbback_req = container_of(packet, struct usbback_req, packet); - QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); status = usbback_xlat_status(packet->status); @@ -566,7 +564,7 @@ static void usbback_dispatch(struct usbback_req *usbback_req) usb_handle_packet(usbback_req->stub->dev, &usbback_req->packet); if (usbback_req->packet.status != USB_RET_ASYNC) { - usbback_packet_complete(&usbback_req->packet); + usbback_packet_complete(usbback_req); } return; @@ -993,7 +991,7 @@ static void xen_bus_complete(USBPort *port, USBPacket *packet) usbif = usbback_req->usbif; TR_REQ(&usbif->xendev, "\n"); - usbback_packet_complete(packet); + usbback_packet_complete(usbback_req); } static USBPortOps xen_usb_port_ops = { diff --git a/hw/vfio/spapr.c b/hw/vfio/spapr.c index 33692fc86f..2900bd1941 100644 --- a/hw/vfio/spapr.c +++ b/hw/vfio/spapr.c @@ -147,7 +147,7 @@ int vfio_spapr_create_window(VFIOContainer *container, { int ret = 0; IOMMUMemoryRegion *iommu_mr = IOMMU_MEMORY_REGION(section->mr); - uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr); + uint64_t pagesize = memory_region_iommu_get_min_page_size(iommu_mr), pgmask; unsigned entries, bits_total, bits_per_level, max_levels; struct vfio_iommu_spapr_tce_create create = { .argsz = sizeof(create) }; long rampagesize = qemu_minrampagesize(); @@ -159,8 +159,8 @@ int vfio_spapr_create_window(VFIOContainer *container, if (pagesize > rampagesize) { pagesize = rampagesize; } - pagesize = 1ULL << (63 - clz64(container->pgsizes & - (pagesize | (pagesize - 1)))); + pgmask = container->pgsizes & (pagesize | (pagesize - 1)); + pagesize = pgmask ? (1ULL << (63 - clz64(pgmask))) : 0; if (!pagesize) { error_report("Host doesn't support page size 0x%"PRIx64 ", the supported mask is 0x%lx", diff --git a/include/hw/ppc/pnv.h b/include/hw/ppc/pnv.h index fb4d0c0234..d4b0b0e2ff 100644 --- a/include/hw/ppc/pnv.h +++ b/include/hw/ppc/pnv.h @@ -241,6 +241,8 @@ struct PnvMachineState { void pnv_dt_bmc_sensors(IPMIBmc *bmc, void *fdt); void pnv_bmc_powerdown(IPMIBmc *bmc); IPMIBmc *pnv_bmc_create(PnvPnor *pnor); +IPMIBmc *pnv_bmc_find(Error **errp); +void pnv_bmc_set_pnor(IPMIBmc *bmc, PnvPnor *pnor); /* * POWER8 MMIO base addresses diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h index b198deca0b..9bbdbd63d7 100644 --- a/include/sysemu/block-backend.h +++ b/include/sysemu/block-backend.h @@ -171,7 +171,6 @@ BlockAIOCB *blk_aio_pdiscard(BlockBackend *blk, int64_t offset, int bytes, BlockCompletionFunc *cb, void *opaque); void blk_aio_cancel(BlockAIOCB *acb); void blk_aio_cancel_async(BlockAIOCB *acb); -int blk_co_ioctl(BlockBackend *blk, unsigned long int req, void *buf); int blk_ioctl(BlockBackend *blk, unsigned long int req, void *buf); BlockAIOCB *blk_aio_ioctl(BlockBackend *blk, unsigned long int req, void *buf, BlockCompletionFunc *cb, void *opaque); @@ -114,7 +114,16 @@ void qmp_job_finalize(const char *id, Error **errp) } trace_qmp_job_finalize(job); + job_ref(job); job_finalize(job, errp); + + /* + * Job's context might have changed via job_finalize (and job_txn_apply + * automatically acquires the new one), so make sure we release the correct + * one. + */ + aio_context = job->aio_context; + job_unref(job); aio_context_release(aio_context); } @@ -136,17 +136,38 @@ static void job_txn_del_job(Job *job) } } -static int job_txn_apply(JobTxn *txn, int fn(Job *)) +static int job_txn_apply(Job *job, int fn(Job *)) { - Job *job, *next; + AioContext *inner_ctx; + Job *other_job, *next; + JobTxn *txn = job->txn; int rc = 0; - QLIST_FOREACH_SAFE(job, &txn->jobs, txn_list, next) { - rc = fn(job); + /* + * Similar to job_completed_txn_abort, we take each job's lock before + * applying fn, but since we assume that outer_ctx is held by the caller, + * we need to release it here to avoid holding the lock twice - which would + * break AIO_WAIT_WHILE from within fn. + */ + job_ref(job); + aio_context_release(job->aio_context); + + QLIST_FOREACH_SAFE(other_job, &txn->jobs, txn_list, next) { + inner_ctx = other_job->aio_context; + aio_context_acquire(inner_ctx); + rc = fn(other_job); + aio_context_release(inner_ctx); if (rc) { break; } } + + /* + * Note that job->aio_context might have been changed by calling fn, so we + * can't use a local variable to cache it. + */ + aio_context_acquire(job->aio_context); + job_unref(job); return rc; } @@ -774,11 +795,11 @@ static void job_do_finalize(Job *job) assert(job && job->txn); /* prepare the transaction to complete */ - rc = job_txn_apply(job->txn, job_prepare); + rc = job_txn_apply(job, job_prepare); if (rc) { job_completed_txn_abort(job); } else { - job_txn_apply(job->txn, job_finalize_single); + job_txn_apply(job, job_finalize_single); } } @@ -824,10 +845,10 @@ static void job_completed_txn_success(Job *job) assert(other_job->ret == 0); } - job_txn_apply(txn, job_transition_to_pending); + job_txn_apply(job, job_transition_to_pending); /* If no jobs need manual finalization, automatically do so */ - if (job_txn_apply(txn, job_needs_finalize) == 0) { + if (job_txn_apply(job, job_needs_finalize) == 0) { job_do_finalize(job); } } @@ -849,9 +870,10 @@ static void job_completed(Job *job) static void job_exit(void *opaque) { Job *job = (Job *)opaque; - AioContext *ctx = job->aio_context; + AioContext *ctx; - aio_context_acquire(ctx); + job_ref(job); + aio_context_acquire(job->aio_context); /* This is a lie, we're not quiescent, but still doing the completion * callbacks. However, completion callbacks tend to involve operations that @@ -862,6 +884,14 @@ static void job_exit(void *opaque) job_completed(job); + /* + * Note that calling job_completed can move the job to a different + * aio_context, so we cannot cache from above. job_txn_apply takes care of + * acquiring the new lock, and we ref/unref to avoid job_completed freeing + * the job underneath us. + */ + ctx = job->aio_context; + job_unref(job); aio_context_release(ctx); } diff --git a/pc-bios/README b/pc-bios/README index f54c2743d0..a5a770f066 100644 --- a/pc-bios/README +++ b/pc-bios/README @@ -14,7 +14,7 @@ - SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware implementation for certain IBM POWER hardware. The sources are at https://github.com/aik/SLOF, and the image currently in qemu is - built from git tag qemu-slof-20200317. + built from git tag qemu-slof-20200327. - sgabios (the Serial Graphics Adapter option ROM) provides a means for legacy x86 software to communicate with an attached serial console as diff --git a/pc-bios/slof.bin b/pc-bios/slof.bin Binary files differindex 40499a1451..80bbf91a18 100644 --- a/pc-bios/slof.bin +++ b/pc-bios/slof.bin diff --git a/qemu-img.c b/qemu-img.c index b167376bd7..821cbf610e 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -1924,8 +1924,8 @@ retry: if (status == BLK_DATA && !copy_range) { ret = convert_co_read(s, sector_num, n, buf); if (ret < 0) { - error_report("error while reading sector %" PRId64 - ": %s", sector_num, strerror(-ret)); + error_report("error while reading at byte %lld: %s", + sector_num * BDRV_SECTOR_SIZE, strerror(-ret)); s->ret = ret; } } else if (!s->min_sparse && status == BLK_ZERO) { @@ -1953,8 +1953,8 @@ retry: ret = convert_co_write(s, sector_num, n, buf, status); } if (ret < 0) { - error_report("error while writing sector %" PRId64 - ": %s", sector_num, strerror(-ret)); + error_report("error while writing at byte %lld: %s", + sector_num * BDRV_SECTOR_SIZE, strerror(-ret)); s->ret = ret; } } diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c index 47dd7ea576..b93d97b995 100644 --- a/qobject/json-streamer.c +++ b/qobject/json-streamer.c @@ -85,7 +85,7 @@ void json_message_process_token(JSONLexer *lexer, GString *input, g_queue_push_tail(&parser->tokens, token); if ((parser->brace_count > 0 || parser->bracket_count > 0) - && parser->bracket_count >= 0 && parser->bracket_count >= 0) { + && parser->brace_count >= 0 && parser->bracket_count >= 0) { return; } diff --git a/roms/SLOF b/roms/SLOF -Subproject ab6984f5a6d054e1f634dda855b32e535711197 +Subproject 8e012d6fddb62be833d746cef3f03e6c8beecde diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c index 597f72be1b..03d0667e8f 100644 --- a/target/ppc/kvm.c +++ b/target/ppc/kvm.c @@ -88,6 +88,7 @@ static int cap_ppc_safe_indirect_branch; static int cap_ppc_count_cache_flush_assist; static int cap_ppc_nested_kvm_hv; static int cap_large_decr; +static int cap_fwnmi; static uint32_t debug_inst_opcode; @@ -136,6 +137,7 @@ int kvm_arch_init(MachineState *ms, KVMState *s) kvmppc_get_cpu_characteristics(s); cap_ppc_nested_kvm_hv = kvm_vm_check_extension(s, KVM_CAP_PPC_NESTED_HV); cap_large_decr = kvmppc_get_dec_bits(); + cap_fwnmi = kvm_vm_check_extension(s, KVM_CAP_PPC_FWNMI); /* * Note: setting it to false because there is not such capability * in KVM at this moment. @@ -2064,6 +2066,11 @@ void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) } } +bool kvmppc_get_fwnmi(void) +{ + return cap_fwnmi; +} + int kvmppc_set_fwnmi(void) { PowerPCCPU *cpu = POWERPC_CPU(first_cpu); diff --git a/target/ppc/kvm_ppc.h b/target/ppc/kvm_ppc.h index 332fa0aa1c..fcaf745516 100644 --- a/target/ppc/kvm_ppc.h +++ b/target/ppc/kvm_ppc.h @@ -27,6 +27,7 @@ void kvmppc_enable_h_page_init(void); void kvmppc_set_papr(PowerPCCPU *cpu); int kvmppc_set_compat(PowerPCCPU *cpu, uint32_t compat_pvr); void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy); +bool kvmppc_get_fwnmi(void); int kvmppc_set_fwnmi(void); int kvmppc_smt_threads(void); void kvmppc_error_append_smt_possible_hint(Error *const *errp); @@ -163,6 +164,11 @@ static inline void kvmppc_set_mpic_proxy(PowerPCCPU *cpu, int mpic_proxy) { } +static inline bool kvmppc_get_fwnmi(void) +{ + return false; +} + static inline int kvmppc_set_fwnmi(void) { return -1; diff --git a/tests/acceptance/machine_sparc_leon3.py b/tests/acceptance/machine_sparc_leon3.py index f77e210ccb..2405cd7a0d 100644 --- a/tests/acceptance/machine_sparc_leon3.py +++ b/tests/acceptance/machine_sparc_leon3.py @@ -7,12 +7,16 @@ from avocado_qemu import Test from avocado_qemu import wait_for_console_pattern +from avocado import skip class Leon3Machine(Test): timeout = 60 + @skip("Test currently broken") + # A Window Underflow exception occurs before booting the kernel, + # and QEMU exit calling cpu_abort(), which makes this test to fail. def test_leon3_helenos_uimage(self): """ :avocado: tags=arch:sparc diff --git a/tests/acceptance/migration.py b/tests/acceptance/migration.py index a8367ca023..0365289cda 100644 --- a/tests/acceptance/migration.py +++ b/tests/acceptance/migration.py @@ -70,8 +70,8 @@ class Migration(Test): @skipUnless(find_command('nc', default=False), "'nc' command not found") def test_migration_with_exec(self): - """ - The test works for both netcat-traditional and netcat-openbsd packages - """ + """The test works for both netcat-traditional and netcat-openbsd packages.""" free_port = self._get_free_port() dest_uri = 'exec:nc -l localhost %u' % free_port + src_uri = 'exec:nc localhost %u' % free_port + self.do_migrate(dest_uri, src_uri) diff --git a/tests/acceptance/ppc_prep_40p.py b/tests/acceptance/ppc_prep_40p.py index b27572f212..1515561249 100644 --- a/tests/acceptance/ppc_prep_40p.py +++ b/tests/acceptance/ppc_prep_40p.py @@ -30,11 +30,12 @@ class IbmPrep40pMachine(Test): :avocado: tags=machine:40p :avocado: tags=slowness:high """ - bios_url = ('ftp://ftp.boulder.ibm.com/rs6000/firmware/' + bios_url = ('http://ftpmirror.your.org/pub/misc/' + 'ftp.software.ibm.com/rs6000/firmware/' '7020-40p/P12H0456.IMG') bios_hash = '1775face4e6dc27f3a6ed955ef6eb331bf817f03' bios_path = self.fetch_asset(bios_url, asset_hash=bios_hash) - drive_url = ('https://ftp.netbsd.org/pub/NetBSD/NetBSD-archive/' + drive_url = ('https://cdn.netbsd.org/pub/NetBSD/NetBSD-archive/' 'NetBSD-4.0/prep/installation/floppy/generic_com0.fs') drive_hash = 'dbcfc09912e71bd5f0d82c7c1ee43082fb596ceb' drive_path = self.fetch_asset(drive_url, asset_hash=drive_hash) @@ -66,7 +67,7 @@ class IbmPrep40pMachine(Test): :avocado: tags=arch:ppc :avocado: tags=machine:40p """ - drive_url = ('https://ftp.netbsd.org/pub/NetBSD/iso/7.1.2/' + drive_url = ('https://cdn.netbsd.org/pub/NetBSD/iso/7.1.2/' 'NetBSD-7.1.2-prep.iso') drive_hash = 'ac6fa2707d888b36d6fa64de6e7fe48e' drive_path = self.fetch_asset(drive_url, asset_hash=drive_hash, diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046 index a066eec605..ecbe5fc0f4 100755 --- a/tests/qemu-iotests/046 +++ b/tests/qemu-iotests/046 @@ -193,8 +193,8 @@ echo "== Verify image content ==" verify_io() { if ($QEMU_IMG info -U -f "$IMGFMT" "$TEST_IMG" | grep "compat: 0.10" > /dev/null); then - # For v2 images, discarded clusters are read from the backing file - # Keep the variable empty so that the backing file value can be used as + # In v2 images clusters are not discarded when there is a backing file. + # Keep the variable empty so that the previous value can be used as # the default below discarded= else @@ -230,14 +230,16 @@ verify_io() echo read -P 70 0x78000 0x6000 echo read -P 7 0x7e000 0x2000 - echo read -P ${discarded:-8} 0x80000 0x6000 + echo read -P ${discarded:-89} 0x80000 0x1000 + echo read -P ${discarded:-8} 0x81000 0x5000 echo read -P 80 0x86000 0x2000 echo read -P ${discarded:-8} 0x88000 0x2000 echo read -P 81 0x8a000 0xe000 echo read -P 90 0x98000 0x6000 echo read -P 9 0x9e000 0x2000 - echo read -P ${discarded:-10} 0xa0000 0x6000 + echo read -P ${discarded:-109} 0xa0000 0x1000 + echo read -P ${discarded:-10} 0xa1000 0x5000 echo read -P 100 0xa6000 0x2000 echo read -P ${discarded:-10} 0xa8000 0x2000 echo read -P 101 0xaa000 0xe000 diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out index ca2c7404a9..70783041e2 100644 --- a/tests/qemu-iotests/046.out +++ b/tests/qemu-iotests/046.out @@ -187,8 +187,10 @@ read 24576/24576 bytes at offset 491520 24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 8192/8192 bytes at offset 516096 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read 24576/24576 bytes at offset 524288 -24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 524288 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 20480/20480 bytes at offset 528384 +20 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 8192/8192 bytes at offset 548864 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 8192/8192 bytes at offset 557056 @@ -199,8 +201,10 @@ read 24576/24576 bytes at offset 622592 24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 8192/8192 bytes at offset 647168 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -read 24576/24576 bytes at offset 655360 -24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 4096/4096 bytes at offset 655360 +4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +read 20480/20480 bytes at offset 659456 +20 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 8192/8192 bytes at offset 679936 8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) read 8192/8192 bytes at offset 688128 diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060 index 043f12904a..32c0ecce9e 100755 --- a/tests/qemu-iotests/060 +++ b/tests/qemu-iotests/060 @@ -160,18 +160,16 @@ TEST_IMG=$BACKING_IMG _make_test_img 1G $QEMU_IO -c 'write 0k 64k' "$BACKING_IMG" | _filter_qemu_io -# compat=0.10 is required in order to make the following discard actually -# unallocate the sector rather than make it a zero sector - we want COW, after -# all. -_make_test_img -o 'compat=0.10' -b "$BACKING_IMG" 1G +_make_test_img -b "$BACKING_IMG" 1G # Write two clusters, the second one enforces creation of an L2 table after # the first data cluster. $QEMU_IO -c 'write 0k 64k' -c 'write 512M 64k' "$TEST_IMG" | _filter_qemu_io -# Discard the first cluster. This cluster will soon enough be reallocated and +# Free the first cluster. This cluster will soon enough be reallocated and # used for COW. -$QEMU_IO -c 'discard 0k 64k' "$TEST_IMG" | _filter_qemu_io +poke_file "$TEST_IMG" "$l2_offset" "\x00\x00\x00\x00\x00\x00\x00\x00" +poke_file "$TEST_IMG" "$(($rb_offset+10))" "\x00\x00" # Now, corrupt the image by marking the second L2 table cluster as free. -poke_file "$TEST_IMG" '131084' "\x00\x00" # 0x2000c +poke_file "$TEST_IMG" "$(($rb_offset+12))" "\x00\x00" # Start a write operation requiring COW on the image stopping it right before # doing the read; then, trigger the corruption prevention by writing anything to # any unallocated cluster, leading to an attempt to overwrite the second L2 diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out index d27692a33c..09caaea865 100644 --- a/tests/qemu-iotests/060.out +++ b/tests/qemu-iotests/060.out @@ -105,8 +105,6 @@ wrote 65536/65536 bytes at offset 0 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) wrote 65536/65536 bytes at offset 536870912 64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -discard 65536/65536 bytes at offset 0 -64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) qcow2: Marking image as corrupt: Preventing invalid write on metadata (overlaps with active L2 table); further corruption events will be suppressed blkdebug: Suspended request '0' write failed: Input/output error diff --git a/tests/qemu-iotests/177 b/tests/qemu-iotests/177 index 752d29f8ad..eadc2c7ef6 100755 --- a/tests/qemu-iotests/177 +++ b/tests/qemu-iotests/177 @@ -89,8 +89,9 @@ verify_io() { if ($QEMU_IMG info -f "$IMGFMT" "$TEST_IMG" | grep "compat: 0.10" > /dev/null); then - # For v2 images, discarded clusters are read from the backing file - discarded=11 + # In v2 images clusters are not discarded when there is a backing file + # so the previous value is read + discarded=22 else # Discarded clusters are zeroed for v3 or later discarded=0 diff --git a/tests/qemu-iotests/244.out b/tests/qemu-iotests/244.out index e6f4dc7993..56329deb4b 100644 --- a/tests/qemu-iotests/244.out +++ b/tests/qemu-iotests/244.out @@ -33,7 +33,7 @@ Convert to compressed target with data file: Formatting 'TEST_DIR/t.IMGFMT.src', fmt=IMGFMT size=67108864 wrote 1048576/1048576 bytes at offset 0 1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) -qemu-img: error while writing sector 0: Operation not supported +qemu-img: error while writing at byte 0: Operation not supported Convert uncompressed, then write compressed data manually: Images are identical. diff --git a/tests/qemu-iotests/290 b/tests/qemu-iotests/290 new file mode 100755 index 0000000000..776b65e915 --- /dev/null +++ b/tests/qemu-iotests/290 @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# +# Test how 'qemu-io -c discard' behaves on v2 and v3 qcow2 images +# +# Copyright (C) 2020 Igalia, S.L. +# Author: Alberto Garcia <berto@igalia.com> +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +# + +# creator +owner=berto@igalia.com + +seq=`basename $0` +echo "QA output created by $seq" + +status=1 # failure is the default! + +_cleanup() +{ + _cleanup_test_img +} +trap "_cleanup; exit \$status" 0 1 2 3 15 + +# get standard environment, filters and checks +. ./common.rc +. ./common.filter + +_supported_fmt qcow2 +_supported_proto file +_supported_os Linux +_unsupported_imgopts 'compat=0.10' refcount_bits data_file + +echo +echo "### Test 'qemu-io -c discard' on a QCOW2 image without a backing file" +echo +for qcow2_compat in 0.10 1.1; do + echo "# Create an image with compat=$qcow2_compat without a backing file" + _make_test_img -o "compat=$qcow2_compat" 128k + + echo "# Fill all clusters with data and then discard them" + $QEMU_IO -c 'write -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io + $QEMU_IO -c 'discard 0 128k' "$TEST_IMG" | _filter_qemu_io + + echo "# Read the data from the discarded clusters" + $QEMU_IO -c 'read -P 0x00 0 128k' "$TEST_IMG" | _filter_qemu_io + + echo "# Output of qemu-img map" + $QEMU_IMG map "$TEST_IMG" | _filter_testdir +done + +echo +echo "### Test 'qemu-io -c discard' on a QCOW2 image with a backing file" +echo + +echo "# Create a backing image and fill it with data" +BACKING_IMG="$TEST_IMG.base" +TEST_IMG="$BACKING_IMG" _make_test_img 128k +$QEMU_IO -c 'write -P 0xff 0 128k' "$BACKING_IMG" | _filter_qemu_io + +for qcow2_compat in 0.10 1.1; do + echo "# Create an image with compat=$qcow2_compat and a backing file" + _make_test_img -o "compat=$qcow2_compat" -b "$BACKING_IMG" + + echo "# Fill all clusters with data and then discard them" + $QEMU_IO -c 'write -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io + $QEMU_IO -c 'discard 0 128k' "$TEST_IMG" | _filter_qemu_io + + echo "# Read the data from the discarded clusters" + if [ "$qcow2_compat" = "1.1" ]; then + # In qcow2 v3 clusters are zeroed (with QCOW_OFLAG_ZERO) + $QEMU_IO -c 'read -P 0x00 0 128k' "$TEST_IMG" | _filter_qemu_io + else + # In qcow2 v2 if there's a backing image we cannot zero the clusters + # without exposing the backing file data so discard does nothing + $QEMU_IO -c 'read -P 0x01 0 128k' "$TEST_IMG" | _filter_qemu_io + fi + + echo "# Output of qemu-img map" + $QEMU_IMG map "$TEST_IMG" | _filter_testdir +done + +# success, all done +echo "*** done" +rm -f $seq.full +status=0 diff --git a/tests/qemu-iotests/290.out b/tests/qemu-iotests/290.out new file mode 100644 index 0000000000..d2259c823b --- /dev/null +++ b/tests/qemu-iotests/290.out @@ -0,0 +1,61 @@ +QA output created by 290 + +### Test 'qemu-io -c discard' on a QCOW2 image without a backing file + +# Create an image with compat=0.10 without a backing file +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 +# Fill all clusters with data and then discard them +wrote 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Read the data from the discarded clusters +read 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Output of qemu-img map +Offset Length Mapped to File +# Create an image with compat=1.1 without a backing file +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 +# Fill all clusters with data and then discard them +wrote 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Read the data from the discarded clusters +read 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Output of qemu-img map +Offset Length Mapped to File + +### Test 'qemu-io -c discard' on a QCOW2 image with a backing file + +# Create a backing image and fill it with data +Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=131072 +wrote 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Create an image with compat=0.10 and a backing file +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base +# Fill all clusters with data and then discard them +wrote 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Read the data from the discarded clusters +read 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Output of qemu-img map +Offset Length Mapped to File +0 0x20000 0x50000 TEST_DIR/t.qcow2 +# Create an image with compat=1.1 and a backing file +Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072 backing_file=TEST_DIR/t.IMGFMT.base +# Fill all clusters with data and then discard them +wrote 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +discard 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Read the data from the discarded clusters +read 131072/131072 bytes at offset 0 +128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec) +# Output of qemu-img map +Offset Length Mapped to File +*** done diff --git a/tests/qemu-iotests/common.pattern b/tests/qemu-iotests/common.pattern index 4f5e5bcea0..4caa5de187 100644 --- a/tests/qemu-iotests/common.pattern +++ b/tests/qemu-iotests/common.pattern @@ -23,7 +23,7 @@ do_is_allocated() { local count=$4 for ((i=1;i<=$count;i++)); do - echo alloc $(( start + (i - 1) * step )) $size + echo "alloc $(( start + (i - 1) * step )) $size" done } @@ -39,9 +39,9 @@ do_io() { local count=$5 local pattern=$6 - echo === IO: pattern $pattern >&2 + echo "=== IO: pattern $pattern" >&2 for ((i=1;i<=$count;i++)); do - echo $op -P $pattern $(( start + (i - 1) * step )) $size + echo "$op -P $pattern $(( start + (i - 1) * step )) $size" done } @@ -110,31 +110,31 @@ io_test2() { # free - free - compressed # Write the clusters to be compressed - echo === Clusters to be compressed [1] + echo '=== Clusters to be compressed [1]' io_pattern writev $((offset + 4 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 - echo === Clusters to be compressed [2] + echo '=== Clusters to be compressed [2]' io_pattern writev $((offset + 5 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 - echo === Clusters to be compressed [3] + echo '=== Clusters to be compressed [3]' io_pattern writev $((offset + 8 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 mv "$TEST_IMG" "$TEST_IMG.orig" $QEMU_IMG convert -f $IMGFMT -O $IMGFMT -c "$TEST_IMG.orig" "$TEST_IMG" # Write the used clusters - echo === Used clusters [1] + echo '=== Used clusters [1]' io_pattern writev $((offset + 0 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 - echo === Used clusters [2] + echo '=== Used clusters [2]' io_pattern writev $((offset + 1 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 - echo === Used clusters [3] + echo '=== Used clusters [3]' io_pattern writev $((offset + 3 * $cluster_size)) $cluster_size $((9 * $cluster_size)) $num 165 # Read them - echo === Read used/compressed clusters + echo '=== Read used/compressed clusters' io_pattern readv $((offset + 0 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num 165 io_pattern readv $((offset + 3 * $cluster_size)) $((3 * $cluster_size)) $((9 * $cluster_size)) $num 165 io_pattern readv $((offset + 8 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num 165 - echo === Read zeros + echo '=== Read zeros' io_zero readv $((offset + 2 * $cluster_size)) $((1 * $cluster_size)) $((9 * $cluster_size)) $num io_zero readv $((offset + 6 * $cluster_size)) $((2 * $cluster_size)) $((9 * $cluster_size)) $num } diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group index 79c6dfc85d..435dccd5af 100644 --- a/tests/qemu-iotests/group +++ b/tests/qemu-iotests/group @@ -296,3 +296,4 @@ 286 rw quick 288 quick 289 rw quick +290 rw auto quick diff --git a/tests/test-blockjob.c b/tests/test-blockjob.c index 4eeb184caf..7519847912 100644 --- a/tests/test-blockjob.c +++ b/tests/test-blockjob.c @@ -367,7 +367,9 @@ static void test_cancel_concluded(void) aio_poll(qemu_get_aio_context(), true); assert(job->status == JOB_STATUS_PENDING); + aio_context_acquire(job->aio_context); job_finalize(job, &error_abort); + aio_context_release(job->aio_context); assert(job->status == JOB_STATUS_CONCLUDED); cancel_common(s); |