diff --git a/include/qemu/job-driver.h b/include/qemu/job-driver.h
index 1efd196da8..19ae5ce8f0 100644
--- a/include/qemu/job-driver.h
+++ b/include/qemu/job-driver.h
@@ -149,4 +149,25 @@ void job_early_fail(Job *job);
 /** Moves the @job from RUNNING to READY */
 void job_transition_to_ready(Job *job);
 
+/** Enters the @job if it is not paused */
+void job_enter_not_paused(Job *job);
+
+/** returns @job->ret */
+bool job_has_failed(Job *job);
+
+/** Returns the @job->status */
+JobStatus job_get_status(Job *job);
+
+/** Returns the @job->pause_count */
+int job_get_pause_count(Job *job);
+
+/** Returns @job->paused */
+bool job_get_paused(Job *job);
+
+/** Returns @job->busy */
+bool job_get_busy(Job *job);
+
+/** Return true if @job not paused and not cancelled */
+bool job_not_paused_nor_cancelled(Job *job);
+
 #endif /* JOB_DRIVER_H */
diff --git a/blockjob.c b/blockjob.c
index 4982f6a2b5..53c1e9c406 100644
--- a/blockjob.c
+++ b/blockjob.c
@@ -36,21 +36,6 @@
 #include "qemu/main-loop.h"
 #include "qemu/timer.h"
 
-/*
- * The block job API is composed of two categories of functions.
- *
- * The first includes functions used by the monitor.  The monitor is
- * peculiar in that it accesses the block job list with block_job_get, and
- * therefore needs consistency across block_job_get and the actual operation
- * (e.g. block_job_set_speed).  The consistency is achieved with
- * aio_context_acquire/release.  These functions are declared in blockjob.h.
- *
- * The second includes functions used by the block job drivers and sometimes
- * by the core block layer.  These do not care about locking, because the
- * whole coroutine runs under the AioContext lock, and are declared in
- * blockjob_int.h.
- */
-
 static bool is_block_job(Job *job)
 {
     return job_type(job) == JOB_TYPE_BACKUP ||
@@ -433,11 +418,6 @@ static void block_job_event_ready(Notifier *n, void *opaque)
 }
 
 
-/*
- * API for block job drivers and the block layer.  These functions are
- * declared in blockjob_int.h.
- */
-
 void *block_job_create(const char *job_id, const BlockJobDriver *driver,
                        JobTxn *txn, BlockDriverState *bs, uint64_t perm,
                        uint64_t shared_perm, int64_t speed, int flags,
diff --git a/job.c b/job.c
index b66d59b746..db7ad79745 100644
--- a/job.c
+++ b/job.c
@@ -32,6 +32,23 @@
 #include "trace/trace-root.h"
 #include "qapi/qapi-events-job.h"
 
+/*
+ * The job API is composed of two categories of functions.
+ *
+ * The first includes functions used by the monitor.  The monitor is
+ * peculiar in that it accesses the block job list with job_get, and
+ * therefore needs consistency across job_get and the actual operation
+ * (e.g. job_user_cancel). To achieve this consistency, the caller
+ * calls job_lock/job_unlock itself around the whole operation.
+ * These functions are declared in job-monitor.h.
+ *
+ *
+ * The second includes functions used by the block job drivers and sometimes
+ * by the core block layer. These delegate the locking to the callee instead,
+ * and are declared in job-driver.h.
+ */
+
+
 /* job_mutex protects the jobs list, but also makes the job API thread-safe. */
 static QemuMutex job_mutex;
 
@@ -213,18 +230,94 @@ const char *job_type_str(const Job *job)
     return JobType_str(job_type(job));
 }
 
-bool job_is_cancelled(Job *job)
+JobStatus job_get_status(Job *job)
+{
+    JobStatus status;
+    job_lock();
+    status = job->status;
+    job_unlock();
+    return status;
+}
+
+int job_get_pause_count(Job *job)
+{
+    int ret;
+    job_lock();
+    ret = job->pause_count;
+    job_unlock();
+    return ret;
+}
+
+bool job_get_paused(Job *job)
+{
+    bool ret;
+    job_lock();
+    ret = job->paused;
+    job_unlock();
+    return ret;
+}
+
+bool job_get_busy(Job *job)
+{
+    bool ret;
+    job_lock();
+    ret = job->busy;
+    job_unlock();
+    return ret;
+}
+
+bool job_has_failed(Job *job)
+{
+    bool ret;
+    job_lock();
+    ret = job->ret < 0;
+    job_unlock();
+    return ret;
+}
+
+/* Called with job_mutex held. */
+static bool job_is_cancelled_locked(Job *job)
 {
     /* force_cancel may be true only if cancelled is true, too */
     assert(job->cancelled || !job->force_cancel);
     return job->force_cancel;
 }
 
-bool job_cancel_requested(Job *job)
+/* Called with job_mutex *not* held. */
+bool job_is_cancelled(Job *job)
+{
+    bool ret;
+    job_lock();
+    ret = job_is_cancelled_locked(job);
+    job_unlock();
+    return ret;
+}
+
+bool job_not_paused_nor_cancelled(Job *job)
+{
+    bool ret;
+    job_lock();
+    ret = !job->paused && !job_is_cancelled_locked(job);
+    job_unlock();
+    return ret;
+}
+
+/* Called with job_mutex held. */
+static bool job_cancel_requested_locked(Job *job)
 {
     return job->cancelled;
 }
 
+/* Called with job_mutex *not* held. */
+bool job_cancel_requested(Job *job)
+{
+    bool ret;
+    job_lock();
+    ret = job_cancel_requested_locked(job);
+    job_unlock();
+    return ret;
+}
+
 /* Called with job_mutex held. */
 bool job_is_ready_locked(Job *job)
 {
@@ -280,6 +373,16 @@ bool job_is_completed(Job *job)
     return false;
 }
 
+/* Called with job_mutex lock *not* held */
+static bool job_is_completed_unlocked(Job *job)
+{
+    bool res;
+    job_lock();
+    res = job_is_completed(job);
+    job_unlock();
+    return res;
+}
+
 static bool job_started(Job *job)
 {
     return job->co;
@@ -579,6 +682,15 @@ void job_pause(Job *job)
     }
 }
 
+void job_enter_not_paused(Job *job)
+{
+    job_lock();
+    if (!job->paused) {
+        job_enter_cond(job, NULL);
+    }
+    job_unlock();
+}
+
 void job_resume(Job *job)
 {
     assert(job->pause_count > 0);
