job->bs = bs;
job->cb = cb;
job->opaque = opaque;
+ job->busy = true;
bs->job = job;
/* Only set speed when necessary to avoid NotSupported error */
qemu_aio_wait();
}
}
+
+void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns)
+{
+ /* Check cancellation *before* setting busy = false, too! */
+ if (!block_job_is_cancelled(job)) {
+ job->busy = false;
+ co_sleep_ns(clock, ns);
+ job->busy = true;
+ }
+}
}
for (sector_num = 0; sector_num < end; sector_num += n) {
-retry:
+ uint64_t delay_ns = 0;
+
+wait:
+ /* Note that even when no rate limit is applied we need to yield
+ * with no pending I/O here so that qemu_aio_flush() returns.
+ */
+ block_job_sleep_ns(&s->common, rt_clock, delay_ns);
if (block_job_is_cancelled(&s->common)) {
break;
}
- s->common.busy = true;
if (base) {
ret = is_allocated_base(bs, base, sector_num,
STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
trace_stream_one_iteration(s, sector_num, n, ret);
if (ret == 0) {
if (s->common.speed) {
- uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
+ delay_ns = ratelimit_calculate_delay(&s->limit, n);
if (delay_ns > 0) {
- s->common.busy = false;
- co_sleep_ns(rt_clock, delay_ns);
-
- /* Recheck cancellation and that sectors are unallocated */
- goto retry;
+ goto wait;
}
}
ret = stream_populate(bs, sector_num, n, buf);
/* Publish progress */
s->common.offset += n * BDRV_SECTOR_SIZE;
-
- /* Note that even when no rate limit is applied we need to yield
- * with no pending I/O here so that qemu_aio_flush() returns.
- */
- s->common.busy = false;
- co_sleep_ns(rt_clock, 0);
}
if (!base) {
/**
* Set to true if the job should cancel itself. The flag must
* always be tested just before toggling the busy flag from false
- * to true. After a job has detected that the cancelled flag is
- * true, it should not anymore issue any I/O operation to the
- * block device.
+ * to true. After a job has been cancelled, it should only yield
+ * if #qemu_aio_wait will ("sooner or later") reenter the coroutine.
*/
bool cancelled;
/**
* Set to false by the job while it is in a quiescent state, where
- * no I/O is pending and cancellation can be processed without
- * issuing new I/O. The busy flag must be set to false when the
- * job goes to sleep on any condition that is not detected by
- * #qemu_aio_wait, such as a timer.
+ * no I/O is pending and the job has yielded on any condition
+ * that is not detected by #qemu_aio_wait, such as a timer.
*/
bool busy;
void *opaque, Error **errp);
/**
+ * block_job_sleep_ns:
+ * @job: The job that calls the function.
+ * @clock: The clock to sleep on.
+ * @ns: How many nanoseconds to stop for.
+ *
+ * Put the job to sleep (assuming that it wasn't canceled) for @ns
+ * nanoseconds. Canceling the job will interrupt the wait immediately.
+ */
+void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns);
+
+/**
* block_job_complete:
* @job: The job being completed.
* @ret: The status code.