void bdrv_io_limits_enable(BlockDriverState *bs)
{
- qemu_co_queue_init(&bs->throttled_reqs);
bs->block_timer = qemu_new_timer_ns(vm_clock, bdrv_block_timer, bs);
bs->io_limits_enabled = true;
}
bdrv_iostatus_disable(bs);
notifier_list_init(&bs->close_notifiers);
notifier_with_return_list_init(&bs->before_write_notifiers);
+ qemu_co_queue_init(&bs->throttled_reqs);
return bs;
}
bs->open_flags = flags;
bs->buffer_alignment = 512;
+ bs->zero_beyond_eof = true;
open_flags = bdrv_open_flags(bs, flags);
bs->read_only = !(open_flags & BDRV_O_RDWR);
bs->valid_key = 0;
bs->sg = 0;
bs->growable = 0;
+ bs->zero_beyond_eof = false;
QDECREF(bs->options);
bs->options = NULL;
}
}
+/* Check if any requests are in-flight (including throttled requests) */
+static bool bdrv_requests_pending(BlockDriverState *bs)
+{
+ if (!QLIST_EMPTY(&bs->tracked_requests)) {
+ return true;
+ }
+ if (!qemu_co_queue_empty(&bs->throttled_reqs)) {
+ return true;
+ }
+ if (bs->file && bdrv_requests_pending(bs->file)) {
+ return true;
+ }
+ if (bs->backing_hd && bdrv_requests_pending(bs->backing_hd)) {
+ return true;
+ }
+ return false;
+}
+
+static bool bdrv_requests_pending_all(void)
+{
+ BlockDriverState *bs;
+ QTAILQ_FOREACH(bs, &bdrv_states, list) {
+ if (bdrv_requests_pending(bs)) {
+ return true;
+ }
+ }
+ return false;
+}
+
/*
* Wait for pending requests to complete across all BlockDriverStates
*
*/
void bdrv_drain_all(void)
{
+ /* Always run first iteration so any pending completion BHs run */
+ bool busy = true;
BlockDriverState *bs;
- bool busy;
-
- do {
- busy = qemu_aio_wait();
+ while (busy) {
/* FIXME: We do not have timer support here, so this is effectively
* a busy wait.
*/
busy = true;
}
}
- } while (busy);
- /* If requests are still pending there is a bug somewhere */
- QTAILQ_FOREACH(bs, &bdrv_states, list) {
- assert(QLIST_EMPTY(&bs->tracked_requests));
- assert(qemu_co_queue_empty(&bs->throttled_reqs));
+ busy = bdrv_requests_pending_all();
+ busy |= aio_poll(qemu_get_aio_context(), busy);
}
}
assert(!bs->job);
assert(!bs->in_use);
+ bdrv_close(bs);
+
/* remove from list, if necessary */
bdrv_make_anon(bs);
- bdrv_close(bs);
-
g_free(bs);
}
}
}
- ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
+ if (!(bs->zero_beyond_eof && bs->growable)) {
+ ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
+ } else {
+ /* Read zeros after EOF of growable BDSes */
+ int64_t len, total_sectors, max_nb_sectors;
+
+ len = bdrv_getlength(bs);
+ if (len < 0) {
+ ret = len;
+ goto out;
+ }
+
+ total_sectors = len >> BDRV_SECTOR_BITS;
+ max_nb_sectors = MAX(0, total_sectors - sector_num);
+ if (max_nb_sectors > 0) {
+ ret = drv->bdrv_co_readv(bs, sector_num,
+ MIN(nb_sectors, max_nb_sectors), qiov);
+ } else {
+ ret = 0;
+ }
+
+ /* Reading beyond end of file is supposed to produce zeroes */
+ if (ret == 0 && total_sectors < sector_num + nb_sectors) {
+ uint64_t offset = MAX(0, total_sectors - sector_num);
+ uint64_t bytes = (sector_num + nb_sectors - offset) *
+ BDRV_SECTOR_SIZE;
+ qemu_iovec_memset(qiov, offset * BDRV_SECTOR_SIZE, 0, bytes);
+ }
+ }
out:
tracked_request_end(&req);