}
}
+/* Assumes the block_job_mutex is held */
+static bool block_job_timer_pending(BlockJob *job)
+{
+ return timer_pending(&job->sleep_timer);
+}
+
+/* Assumes the block_job_mutex is held */
+static bool block_job_timer_not_pending(BlockJob *job)
+{
+ return !block_job_timer_pending(job);
+}
+
static void block_job_pause(BlockJob *job)
{
job->pause_count++;
if (job->pause_count) {
return;
}
- block_job_enter(job);
+
+ /* kick only if no timer is pending */
+ block_job_enter_cond(job, block_job_timer_not_pending);
}
void block_job_ref(BlockJob *job)
return job->co;
}
+const BlockJobDriver *block_job_driver(BlockJob *job)
+{
+ return job->driver;
+}
+
/**
* All jobs must allow a pause point before entering their job proper. This
* ensures that jobs can be paused prior to being started, then resumed later.
}
}
-/* Assumes the block_job_mutex is held */
-static bool block_job_timer_pending(BlockJob *job)
-{
- return timer_pending(&job->sleep_timer);
-}
-
void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
{
- Error *local_err = NULL;
int64_t old_speed = job->speed;
- if (!job->driver->set_speed) {
- error_setg(errp, QERR_UNSUPPORTED);
- return;
- }
if (block_job_apply_verb(job, BLOCK_JOB_VERB_SET_SPEED, errp)) {
return;
}
- job->driver->set_speed(job, speed, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
+ if (speed < 0) {
+ error_setg(errp, QERR_INVALID_PARAMETER, "speed");
return;
}
+ ratelimit_set_speed(&job->limit, speed, BLOCK_JOB_SLICE_TIME);
+
job->speed = speed;
if (speed && speed <= old_speed) {
return;
block_job_enter_cond(job, block_job_timer_pending);
}
+int64_t block_job_ratelimit_get_delay(BlockJob *job, uint64_t n)
+{
+ if (!job->speed) {
+ return 0;
+ }
+
+ return ratelimit_calculate_delay(&job->limit, n);
+}
+
void block_job_complete(BlockJob *job, Error **errp)
{
/* Should not be reachable via external interface for internal jobs */
void block_job_finalize(BlockJob *job, Error **errp)
{
- assert(job && job->id && job->txn);
+ assert(job && job->id);
if (block_job_apply_verb(job, BLOCK_JOB_VERB_FINALIZE, errp)) {
return;
}
return block_job_finish_sync(job, &block_job_complete, errp);
}
+void block_job_progress_update(BlockJob *job, uint64_t done)
+{
+ job->offset += done;
+}
+
+void block_job_progress_set_remaining(BlockJob *job, uint64_t remaining)
+{
+ job->len = job->offset + remaining;
+}
+
BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
{
BlockJobInfo *info;
info->status = job->status;
info->auto_finalize = job->auto_finalize;
info->auto_dismiss = job->auto_dismiss;
+ info->has_error = job->ret != 0;
+ info->error = job->ret ? g_strdup(strerror(-job->ret)) : NULL;
return info;
}