mirror of https://github.com/xemu-project/xemu.git
-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJYGI7oAAoJEL2+eyfA3jBX6MAQAKVMnzZabedEdwvuw5AjTp3P eL1CYsb/6l8PXD8r0djOicC2xrroyPo2nyB/X9Obrb5U8MiwdDU2mYPF9Er/yHea 00sWhl5Z5c2ZKxgQ0Iv2D3af3jVHyWDZ0E5TuHhYpolsJ28ASklZQH/MOL7T06sd P6+CMgGW37W2/gmBcPkMRPOskri+7iga5UVbInehTEFnBSwLga+0FyU4mrnx1X0F 2fFEvXYWwKtLnEZQDPKaYC3tUnfPmurY4+TyhvvXW82iTqEfzdSplANbL4VaORgv J+tS8px1fpIiCUkR/Af5MtyBJS95ssc2+1Xgxjg2vI0H1ZiydnxlCFJh8giCeX2H 1DjaCUzuY6c272DwG+Y92p8jzjE93jvi0yKGDhlnEPZCP6hlfxB3nCN+WwEd7I1H RC+edslEJbIri9v0clEsAHvMQB+zHnM/W4Y+VYIn+7+wuBOVZ4efc0q0jt7/IVtE IcXgDj1EF42pp6zRe5LCq3iD6PbspJcAwhv2htQkarEWuFUty2REP5wFoSJkcQeo Q2lOd7nK0CCJxqosUZklhCQw6qfmVowAfkKCZqrfI6Ei8dVvhcWoIRpGT4tD44sC tXjgkiiXBIj9bIViSVIiZ48DQKo2g+EswP8UQA79YPRC8hdyJTuXYFow30g0Atkh lXgP9VvGQugkFJIdVMIV =0tUH -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/cody/tags/block-pull-request' into staging # gpg: Signature made Tue 01 Nov 2016 12:47:36 GMT # gpg: using RSA key 0xBDBE7B27C0DE3057 # gpg: Good signature from "Jeffrey Cody <jcody@redhat.com>" # gpg: aka "Jeffrey Cody <jeff@codyprime.org>" # gpg: aka "Jeffrey Cody <codyprime@gmail.com>" # Primary key fingerprint: 9957 4B4D 3474 90E7 9D98 D624 BDBE 7B27 C0DE 3057 * remotes/cody/tags/block-pull-request: blockjobs: fix documentation blockjobs: split interface into public/private, Part 1 Blockjobs: Internalize user_pause logic blockjob: centralize QMP event emissions Replication/Blockjobs: Create replication jobs as internal blockjobs: Allow creating internal jobs blockjobs: hide internal jobs from management API block/gluster: fix port type in the QAPI options list block/gluster: improve defense over string to int conversion block: Turn on "unmap" in active commit block/gluster: memory usage: use one glfs instance per volume block: add gluster ifdef guard checks for SEEK_DATA/SEEK_HOLE support rbd: make the code more readable qapi: add release designator to gluster logfile option Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
c46ef897db
|
@ -16,7 +16,7 @@
|
|||
#include "trace.h"
|
||||
#include "block/block.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "block/block_backup.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
@ -543,6 +543,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
|
|||
bool compress,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
int creation_flags,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
BlockJobTxn *txn, Error **errp)
|
||||
{
|
||||
|
@ -612,7 +613,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
|
|||
}
|
||||
|
||||
job = block_job_create(job_id, &backup_job_driver, bs, speed,
|
||||
cb, opaque, errp);
|
||||
creation_flags, cb, opaque, errp);
|
||||
if (!job) {
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "trace.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/ratelimit.h"
|
||||
|
@ -209,8 +209,8 @@ static const BlockJobDriver commit_job_driver = {
|
|||
|
||||
void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, BlockDriverState *top, int64_t speed,
|
||||
BlockdevOnError on_error, BlockCompletionFunc *cb,
|
||||
void *opaque, const char *backing_file_str, Error **errp)
|
||||
BlockdevOnError on_error, const char *backing_file_str,
|
||||
Error **errp)
|
||||
{
|
||||
CommitBlockJob *s;
|
||||
BlockReopenQueue *reopen_queue = NULL;
|
||||
|
@ -234,7 +234,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||
}
|
||||
|
||||
s = block_job_create(job_id, &commit_job_driver, bs, speed,
|
||||
cb, opaque, errp);
|
||||
BLOCK_JOB_DEFAULT, NULL, NULL, errp);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
@ -290,7 +290,7 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||
s->on_error = on_error;
|
||||
s->common.co = qemu_coroutine_create(commit_run, s);
|
||||
|
||||
trace_commit_start(bs, base, top, s, s->common.co, opaque);
|
||||
trace_commit_start(bs, base, top, s, s->common.co);
|
||||
qemu_coroutine_enter(s->common.co);
|
||||
}
|
||||
|
||||
|
|
124
block/gluster.c
124
block/gluster.c
|
@ -14,6 +14,7 @@
|
|||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/uri.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/cutils.h"
|
||||
|
||||
#define GLUSTER_OPT_FILENAME "filename"
|
||||
#define GLUSTER_OPT_VOLUME "volume"
|
||||
|
@ -56,6 +57,19 @@ typedef struct BDRVGlusterReopenState {
|
|||
} BDRVGlusterReopenState;
|
||||
|
||||
|
||||
typedef struct GlfsPreopened {
|
||||
char *volume;
|
||||
glfs_t *fs;
|
||||
int ref;
|
||||
} GlfsPreopened;
|
||||
|
||||
typedef struct ListElement {
|
||||
QLIST_ENTRY(ListElement) list;
|
||||
GlfsPreopened saved;
|
||||
} ListElement;
|
||||
|
||||
static QLIST_HEAD(glfs_list, ListElement) glfs_list;
|
||||
|
||||
static QemuOptsList qemu_gluster_create_opts = {
|
||||
.name = "qemu-gluster-create-opts",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
|
||||
|
@ -172,7 +186,7 @@ static QemuOptsList runtime_tcp_opts = {
|
|||
},
|
||||
{
|
||||
.name = GLUSTER_OPT_PORT,
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
.type = QEMU_OPT_STRING,
|
||||
.help = "port number on which glusterd is listening (default 24007)",
|
||||
},
|
||||
{
|
||||
|
@ -194,6 +208,57 @@ static QemuOptsList runtime_tcp_opts = {
|
|||
},
|
||||
};
|
||||
|
||||
static void glfs_set_preopened(const char *volume, glfs_t *fs)
|
||||
{
|
||||
ListElement *entry = NULL;
|
||||
|
||||
entry = g_new(ListElement, 1);
|
||||
|
||||
entry->saved.volume = g_strdup(volume);
|
||||
|
||||
entry->saved.fs = fs;
|
||||
entry->saved.ref = 1;
|
||||
|
||||
QLIST_INSERT_HEAD(&glfs_list, entry, list);
|
||||
}
|
||||
|
||||
static glfs_t *glfs_find_preopened(const char *volume)
|
||||
{
|
||||
ListElement *entry = NULL;
|
||||
|
||||
QLIST_FOREACH(entry, &glfs_list, list) {
|
||||
if (strcmp(entry->saved.volume, volume) == 0) {
|
||||
entry->saved.ref++;
|
||||
return entry->saved.fs;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void glfs_clear_preopened(glfs_t *fs)
|
||||
{
|
||||
ListElement *entry = NULL;
|
||||
|
||||
if (fs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(entry, &glfs_list, list) {
|
||||
if (entry->saved.fs == fs) {
|
||||
if (--entry->saved.ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
QLIST_REMOVE(entry, list);
|
||||
|
||||
glfs_fini(entry->saved.fs);
|
||||
g_free(entry->saved.volume);
|
||||
g_free(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_volume_options(BlockdevOptionsGluster *gconf, char *path)
|
||||
{
|
||||
char *p, *q;
|
||||
|
@ -330,22 +395,37 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
|||
int ret;
|
||||
int old_errno;
|
||||
GlusterServerList *server;
|
||||
unsigned long long port;
|
||||
|
||||
glfs = glfs_find_preopened(gconf->volume);
|
||||
if (glfs) {
|
||||
return glfs;
|
||||
}
|
||||
|
||||
glfs = glfs_new(gconf->volume);
|
||||
if (!glfs) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
glfs_set_preopened(gconf->volume, glfs);
|
||||
|
||||
for (server = gconf->server; server; server = server->next) {
|
||||
if (server->value->type == GLUSTER_TRANSPORT_UNIX) {
|
||||
ret = glfs_set_volfile_server(glfs,
|
||||
GlusterTransport_lookup[server->value->type],
|
||||
server->value->u.q_unix.path, 0);
|
||||
} else {
|
||||
if (parse_uint_full(server->value->u.tcp.port, &port, 10) < 0 ||
|
||||
port > 65535) {
|
||||
error_setg(errp, "'%s' is not a valid port number",
|
||||
server->value->u.tcp.port);
|
||||
errno = EINVAL;
|
||||
goto out;
|
||||
}
|
||||
ret = glfs_set_volfile_server(glfs,
|
||||
GlusterTransport_lookup[server->value->type],
|
||||
server->value->u.tcp.host,
|
||||
atoi(server->value->u.tcp.port));
|
||||
(int)port);
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
|
@ -387,7 +467,7 @@ static struct glfs *qemu_gluster_glfs_init(BlockdevOptionsGluster *gconf,
|
|||
out:
|
||||
if (glfs) {
|
||||
old_errno = errno;
|
||||
glfs_fini(glfs);
|
||||
glfs_clear_preopened(glfs);
|
||||
errno = old_errno;
|
||||
}
|
||||
return NULL;
|
||||
|
@ -668,7 +748,10 @@ static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
|||
*/
|
||||
static bool qemu_gluster_test_seek(struct glfs_fd *fd)
|
||||
{
|
||||
off_t ret, eof;
|
||||
off_t ret = 0;
|
||||
|
||||
#if defined SEEK_HOLE && defined SEEK_DATA
|
||||
off_t eof;
|
||||
|
||||
eof = glfs_lseek(fd, 0, SEEK_END);
|
||||
if (eof < 0) {
|
||||
|
@ -678,6 +761,8 @@ static bool qemu_gluster_test_seek(struct glfs_fd *fd)
|
|||
|
||||
/* this should always fail with ENXIO if SEEK_DATA is supported */
|
||||
ret = glfs_lseek(fd, eof, SEEK_DATA);
|
||||
#endif
|
||||
|
||||
return (ret < 0) && (errno == ENXIO);
|
||||
}
|
||||
|
||||
|
@ -762,9 +847,9 @@ out:
|
|||
if (s->fd) {
|
||||
glfs_close(s->fd);
|
||||
}
|
||||
if (s->glfs) {
|
||||
glfs_fini(s->glfs);
|
||||
}
|
||||
|
||||
glfs_clear_preopened(s->glfs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -831,9 +916,8 @@ static void qemu_gluster_reopen_commit(BDRVReopenState *state)
|
|||
if (s->fd) {
|
||||
glfs_close(s->fd);
|
||||
}
|
||||
if (s->glfs) {
|
||||
glfs_fini(s->glfs);
|
||||
}
|
||||
|
||||
glfs_clear_preopened(s->glfs);
|
||||
|
||||
/* use the newly opened image / connection */
|
||||
s->fd = reop_s->fd;
|
||||
|
@ -858,9 +942,7 @@ static void qemu_gluster_reopen_abort(BDRVReopenState *state)
|
|||
glfs_close(reop_s->fd);
|
||||
}
|
||||
|
||||
if (reop_s->glfs) {
|
||||
glfs_fini(reop_s->glfs);
|
||||
}
|
||||
glfs_clear_preopened(reop_s->glfs);
|
||||
|
||||
g_free(state->opaque);
|
||||
state->opaque = NULL;
|
||||
|
@ -984,9 +1066,7 @@ static int qemu_gluster_create(const char *filename,
|
|||
out:
|
||||
g_free(tmp);
|
||||
qapi_free_BlockdevOptionsGluster(gconf);
|
||||
if (glfs) {
|
||||
glfs_fini(glfs);
|
||||
}
|
||||
glfs_clear_preopened(glfs);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1059,7 +1139,7 @@ static void qemu_gluster_close(BlockDriverState *bs)
|
|||
glfs_close(s->fd);
|
||||
s->fd = NULL;
|
||||
}
|
||||
glfs_fini(s->glfs);
|
||||
glfs_clear_preopened(s->glfs);
|
||||
}
|
||||
|
||||
static coroutine_fn int qemu_gluster_co_flush_to_disk(BlockDriverState *bs)
|
||||
|
@ -1178,12 +1258,14 @@ static int find_allocation(BlockDriverState *bs, off_t start,
|
|||
off_t *data, off_t *hole)
|
||||
{
|
||||
BDRVGlusterState *s = bs->opaque;
|
||||
off_t offs;
|
||||
|
||||
if (!s->supports_seek_data) {
|
||||
return -ENOTSUP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
#if defined SEEK_HOLE && defined SEEK_DATA
|
||||
off_t offs;
|
||||
|
||||
/*
|
||||
* SEEK_DATA cases:
|
||||
* D1. offs == start: start is in data
|
||||
|
@ -1247,6 +1329,10 @@ static int find_allocation(BlockDriverState *bs, off_t start,
|
|||
|
||||
/* D1 and H1 */
|
||||
return -EBUSY;
|
||||
#endif
|
||||
|
||||
exit:
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include "qemu/osdep.h"
|
||||
#include "trace.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qapi/error.h"
|
||||
|
@ -937,9 +937,9 @@ static const BlockJobDriver commit_active_job_driver = {
|
|||
};
|
||||
|
||||
static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *target, const char *replaces,
|
||||
int64_t speed, uint32_t granularity,
|
||||
int64_t buf_size,
|
||||
int creation_flags, BlockDriverState *target,
|
||||
const char *replaces, int64_t speed,
|
||||
uint32_t granularity, int64_t buf_size,
|
||||
BlockMirrorBackingMode backing_mode,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
|
@ -967,7 +967,8 @@ static void mirror_start_job(const char *job_id, BlockDriverState *bs,
|
|||
buf_size = DEFAULT_MIRROR_BUF_SIZE;
|
||||
}
|
||||
|
||||
s = block_job_create(job_id, driver, bs, speed, cb, opaque, errp);
|
||||
s = block_job_create(job_id, driver, bs, speed, creation_flags,
|
||||
cb, opaque, errp);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
@ -1017,9 +1018,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
|||
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
bool unmap,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp)
|
||||
bool unmap, Error **errp)
|
||||
{
|
||||
bool is_none_mode;
|
||||
BlockDriverState *base;
|
||||
|
@ -1030,17 +1029,16 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
|||
}
|
||||
is_none_mode = mode == MIRROR_SYNC_MODE_NONE;
|
||||
base = mode == MIRROR_SYNC_MODE_TOP ? backing_bs(bs) : NULL;
|
||||
mirror_start_job(job_id, bs, target, replaces,
|
||||
mirror_start_job(job_id, bs, BLOCK_JOB_DEFAULT, target, replaces,
|
||||
speed, granularity, buf_size, backing_mode,
|
||||
on_source_error, on_target_error, unmap, cb, opaque, errp,
|
||||
on_source_error, on_target_error, unmap, NULL, NULL, errp,
|
||||
&mirror_job_driver, is_none_mode, base, false);
|
||||
}
|
||||
|
||||
void commit_active_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, int64_t speed,
|
||||
BlockdevOnError on_error,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp,
|
||||
BlockDriverState *base, int creation_flags,
|
||||
int64_t speed, BlockdevOnError on_error,
|
||||
BlockCompletionFunc *cb, void *opaque, Error **errp,
|
||||
bool auto_complete)
|
||||
{
|
||||
int64_t length, base_length;
|
||||
|
@ -1079,9 +1077,9 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
|
|||
}
|
||||
}
|
||||
|
||||
mirror_start_job(job_id, bs, base, NULL, speed, 0, 0,
|
||||
mirror_start_job(job_id, bs, creation_flags, base, NULL, speed, 0, 0,
|
||||
MIRROR_LEAVE_BACKING_CHAIN,
|
||||
on_error, on_error, false, cb, opaque, &local_err,
|
||||
on_error, on_error, true, cb, opaque, &local_err,
|
||||
&commit_active_job_driver, false, base, auto_complete);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
|
|
25
block/rbd.c
25
block/rbd.c
|
@ -365,45 +365,44 @@ static int qemu_rbd_create(const char *filename, QemuOpts *opts, Error **errp)
|
|||
rados_conf_read_file(cluster, NULL);
|
||||
} else if (conf[0] != '\0' &&
|
||||
qemu_rbd_set_conf(cluster, conf, true, &local_err) < 0) {
|
||||
rados_shutdown(cluster);
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
if (conf[0] != '\0' &&
|
||||
qemu_rbd_set_conf(cluster, conf, false, &local_err) < 0) {
|
||||
rados_shutdown(cluster);
|
||||
error_propagate(errp, local_err);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
if (qemu_rbd_set_auth(cluster, secretid, errp) < 0) {
|
||||
rados_shutdown(cluster);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
ret = rados_connect(cluster);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "error connecting");
|
||||
rados_shutdown(cluster);
|
||||
return ret;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
ret = rados_ioctx_create(cluster, pool, &io_ctx);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "error opening pool %s", pool);
|
||||
rados_shutdown(cluster);
|
||||
return ret;
|
||||
goto shutdown;
|
||||
}
|
||||
|
||||
ret = rbd_create(io_ctx, name, bytes, &obj_order);
|
||||
rados_ioctx_destroy(io_ctx);
|
||||
rados_shutdown(cluster);
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, -ret, "error rbd create");
|
||||
return ret;
|
||||
}
|
||||
|
||||
rados_ioctx_destroy(io_ctx);
|
||||
|
||||
shutdown:
|
||||
rados_shutdown(cluster);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -508,10 +508,11 @@ static void replication_start(ReplicationState *rs, ReplicationMode mode,
|
|||
bdrv_op_block_all(top_bs, s->blocker);
|
||||
bdrv_op_unblock(top_bs, BLOCK_OP_TYPE_DATAPLANE, s->blocker);
|
||||
|
||||
backup_start("replication-backup", s->secondary_disk->bs,
|
||||
s->hidden_disk->bs, 0, MIRROR_SYNC_MODE_NONE, NULL, false,
|
||||
backup_start(NULL, s->secondary_disk->bs, s->hidden_disk->bs, 0,
|
||||
MIRROR_SYNC_MODE_NONE, NULL, false,
|
||||
BLOCKDEV_ON_ERROR_REPORT, BLOCKDEV_ON_ERROR_REPORT,
|
||||
backup_job_completed, bs, NULL, &local_err);
|
||||
BLOCK_JOB_INTERNAL, backup_job_completed, bs,
|
||||
NULL, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
backup_job_cleanup(bs);
|
||||
|
@ -633,10 +634,9 @@ static void replication_stop(ReplicationState *rs, bool failover, Error **errp)
|
|||
}
|
||||
|
||||
s->replication_state = BLOCK_REPLICATION_FAILOVER;
|
||||
commit_active_start("replication-commit", s->active_disk->bs,
|
||||
s->secondary_disk->bs, 0, BLOCKDEV_ON_ERROR_REPORT,
|
||||
replication_done,
|
||||
bs, errp, true);
|
||||
commit_active_start(NULL, s->active_disk->bs, s->secondary_disk->bs,
|
||||
BLOCK_JOB_INTERNAL, 0, BLOCKDEV_ON_ERROR_REPORT,
|
||||
replication_done, bs, errp, true);
|
||||
break;
|
||||
default:
|
||||
aio_context_release(aio_context);
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "trace.h"
|
||||
#include "block/block_int.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
#include "qemu/ratelimit.h"
|
||||
|
@ -222,15 +222,14 @@ static const BlockJobDriver stream_job_driver = {
|
|||
|
||||
void stream_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, const char *backing_file_str,
|
||||
int64_t speed, BlockdevOnError on_error,
|
||||
BlockCompletionFunc *cb, void *opaque, Error **errp)
|
||||
int64_t speed, BlockdevOnError on_error, Error **errp)
|
||||
{
|
||||
StreamBlockJob *s;
|
||||
BlockDriverState *iter;
|
||||
int orig_bs_flags;
|
||||
|
||||
s = block_job_create(job_id, &stream_job_driver, bs, speed,
|
||||
cb, opaque, errp);
|
||||
BLOCK_JOB_DEFAULT, NULL, NULL, errp);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
@ -256,6 +255,6 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
|||
|
||||
s->on_error = on_error;
|
||||
s->common.co = qemu_coroutine_create(stream_run, s);
|
||||
trace_stream_start(bs, base, s, s->common.co, opaque);
|
||||
trace_stream_start(bs, base, s, s->common.co);
|
||||
qemu_coroutine_enter(s->common.co);
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ bdrv_co_do_copy_on_readv(void *bs, int64_t offset, unsigned int bytes, int64_t c
|
|||
|
||||
# block/stream.c
|
||||
stream_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
|
||||
stream_start(void *bs, void *base, void *s, void *co, void *opaque) "bs %p base %p s %p co %p opaque %p"
|
||||
stream_start(void *bs, void *base, void *s, void *co) "bs %p base %p s %p co %p"
|
||||
|
||||
# block/commit.c
|
||||
commit_one_iteration(void *s, int64_t sector_num, int nb_sectors, int is_allocated) "s %p sector_num %"PRId64" nb_sectors %d is_allocated %d"
|
||||
commit_start(void *bs, void *base, void *top, void *s, void *co, void *opaque) "bs %p base %p top %p s %p co %p opaque %p"
|
||||
commit_start(void *bs, void *base, void *top, void *s, void *co) "bs %p base %p top %p s %p co %p"
|
||||
|
||||
# block/mirror.c
|
||||
mirror_start(void *bs, void *s, void *co, void *opaque) "bs %p s %p co %p opaque %p"
|
||||
|
@ -51,7 +51,6 @@ qmp_block_job_cancel(void *job) "job %p"
|
|||
qmp_block_job_pause(void *job) "job %p"
|
||||
qmp_block_job_resume(void *job) "job %p"
|
||||
qmp_block_job_complete(void *job) "job %p"
|
||||
block_job_cb(void *bs, void *job, int ret) "bs %p job %p ret %d"
|
||||
qmp_block_stream(void *bs, void *job) "bs %p job %p"
|
||||
|
||||
# block/raw-win32.c
|
||||
|
|
74
blockdev.c
74
blockdev.c
|
@ -2905,31 +2905,6 @@ out:
|
|||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
static void block_job_cb(void *opaque, int ret)
|
||||
{
|
||||
/* Note that this function may be executed from another AioContext besides
|
||||
* the QEMU main loop. If you need to access anything that assumes the
|
||||
* QEMU global mutex, use a BH or introduce a mutex.
|
||||
*/
|
||||
|
||||
BlockDriverState *bs = opaque;
|
||||
const char *msg = NULL;
|
||||
|
||||
trace_block_job_cb(bs, bs->job, ret);
|
||||
|
||||
assert(bs->job);
|
||||
|
||||
if (ret < 0) {
|
||||
msg = strerror(-ret);
|
||||
}
|
||||
|
||||
if (block_job_is_cancelled(bs->job)) {
|
||||
block_job_event_cancelled(bs->job);
|
||||
} else {
|
||||
block_job_event_completed(bs->job, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
|
||||
bool has_base, const char *base,
|
||||
bool has_base_node, const char *base_node,
|
||||
|
@ -3005,7 +2980,7 @@ void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
|
|||
base_name = has_backing_file ? backing_file : base_name;
|
||||
|
||||
stream_start(has_job_id ? job_id : NULL, bs, base_bs, base_name,
|
||||
has_speed ? speed : 0, on_error, block_job_cb, bs, &local_err);
|
||||
has_speed ? speed : 0, on_error, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto out;
|
||||
|
@ -3110,16 +3085,17 @@ void qmp_block_commit(bool has_job_id, const char *job_id, const char *device,
|
|||
" but 'top' is the active layer");
|
||||
goto out;
|
||||
}
|
||||
commit_active_start(has_job_id ? job_id : NULL, bs, base_bs, speed,
|
||||
on_error, block_job_cb, bs, &local_err, false);
|
||||
commit_active_start(has_job_id ? job_id : NULL, bs, base_bs,
|
||||
BLOCK_JOB_DEFAULT, speed, on_error, NULL, NULL,
|
||||
&local_err, false);
|
||||
} else {
|
||||
BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs);
|
||||
if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) {
|
||||
goto out;
|
||||
}
|
||||
commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, speed,
|
||||
on_error, block_job_cb, bs,
|
||||
has_backing_file ? backing_file : NULL, &local_err);
|
||||
on_error, has_backing_file ? backing_file : NULL,
|
||||
&local_err);
|
||||
}
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
|
@ -3239,7 +3215,8 @@ static void do_drive_backup(DriveBackup *backup, BlockJobTxn *txn, Error **errp)
|
|||
|
||||
backup_start(backup->job_id, bs, target_bs, backup->speed, backup->sync,
|
||||
bmap, backup->compress, backup->on_source_error,
|
||||
backup->on_target_error, block_job_cb, bs, txn, &local_err);
|
||||
backup->on_target_error, BLOCK_JOB_DEFAULT,
|
||||
NULL, NULL, txn, &local_err);
|
||||
bdrv_unref(target_bs);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
|
@ -3309,7 +3286,8 @@ void do_blockdev_backup(BlockdevBackup *backup, BlockJobTxn *txn, Error **errp)
|
|||
}
|
||||
backup_start(backup->job_id, bs, target_bs, backup->speed, backup->sync,
|
||||
NULL, backup->compress, backup->on_source_error,
|
||||
backup->on_target_error, block_job_cb, bs, txn, &local_err);
|
||||
backup->on_target_error, BLOCK_JOB_DEFAULT,
|
||||
NULL, NULL, txn, &local_err);
|
||||
if (local_err != NULL) {
|
||||
error_propagate(errp, local_err);
|
||||
}
|
||||
|
@ -3388,8 +3366,7 @@ static void blockdev_mirror_common(const char *job_id, BlockDriverState *bs,
|
|||
mirror_start(job_id, bs, target,
|
||||
has_replaces ? replaces : NULL,
|
||||
speed, granularity, buf_size, sync, backing_mode,
|
||||
on_source_error, on_target_error, unmap,
|
||||
block_job_cb, bs, errp);
|
||||
on_source_error, on_target_error, unmap, errp);
|
||||
}
|
||||
|
||||
void qmp_drive_mirror(DriveMirror *arg, Error **errp)
|
||||
|
@ -3633,7 +3610,7 @@ void qmp_block_job_cancel(const char *device,
|
|||
force = false;
|
||||
}
|
||||
|
||||
if (job->user_paused && !force) {
|
||||
if (block_job_user_paused(job) && !force) {
|
||||
error_setg(errp, "The block job for device '%s' is currently paused",
|
||||
device);
|
||||
goto out;
|
||||
|
@ -3650,13 +3627,12 @@ void qmp_block_job_pause(const char *device, Error **errp)
|
|||
AioContext *aio_context;
|
||||
BlockJob *job = find_block_job(device, &aio_context, errp);
|
||||
|
||||
if (!job || job->user_paused) {
|
||||
if (!job || block_job_user_paused(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
job->user_paused = true;
|
||||
trace_qmp_block_job_pause(job);
|
||||
block_job_pause(job);
|
||||
block_job_user_pause(job);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
|
@ -3665,14 +3641,13 @@ void qmp_block_job_resume(const char *device, Error **errp)
|
|||
AioContext *aio_context;
|
||||
BlockJob *job = find_block_job(device, &aio_context, errp);
|
||||
|
||||
if (!job || !job->user_paused) {
|
||||
if (!job || !block_job_user_paused(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
job->user_paused = false;
|
||||
trace_qmp_block_job_resume(job);
|
||||
block_job_iostatus_reset(job);
|
||||
block_job_resume(job);
|
||||
block_job_user_resume(job);
|
||||
aio_context_release(aio_context);
|
||||
}
|
||||
|
||||
|
@ -3946,13 +3921,22 @@ BlockJobInfoList *qmp_query_block_jobs(Error **errp)
|
|||
BlockJob *job;
|
||||
|
||||
for (job = block_job_next(NULL); job; job = block_job_next(job)) {
|
||||
BlockJobInfoList *elem = g_new0(BlockJobInfoList, 1);
|
||||
AioContext *aio_context = blk_get_aio_context(job->blk);
|
||||
BlockJobInfoList *elem;
|
||||
AioContext *aio_context;
|
||||
|
||||
if (block_job_is_internal(job)) {
|
||||
continue;
|
||||
}
|
||||
elem = g_new0(BlockJobInfoList, 1);
|
||||
aio_context = blk_get_aio_context(job->blk);
|
||||
aio_context_acquire(aio_context);
|
||||
elem->value = block_job_query(job);
|
||||
elem->value = block_job_query(job, errp);
|
||||
aio_context_release(aio_context);
|
||||
|
||||
if (!elem->value) {
|
||||
g_free(elem);
|
||||
qapi_free_BlockJobInfoList(head);
|
||||
return NULL;
|
||||
}
|
||||
*p_next = elem;
|
||||
p_next = &elem->next;
|
||||
}
|
||||
|
|
113
blockjob.c
113
blockjob.c
|
@ -27,7 +27,7 @@
|
|||
#include "qemu-common.h"
|
||||
#include "trace.h"
|
||||
#include "block/block.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "block/block_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
@ -38,6 +38,9 @@
|
|||
#include "qemu/timer.h"
|
||||
#include "qapi-event.h"
|
||||
|
||||
static void block_job_event_cancelled(BlockJob *job);
|
||||
static void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
|
||||
/* Transactional group of block jobs */
|
||||
struct BlockJobTxn {
|
||||
|
||||
|
@ -66,7 +69,7 @@ BlockJob *block_job_get(const char *id)
|
|||
BlockJob *job;
|
||||
|
||||
QLIST_FOREACH(job, &block_jobs, job_list) {
|
||||
if (!strcmp(id, job->id)) {
|
||||
if (job->id && !strcmp(id, job->id)) {
|
||||
return job;
|
||||
}
|
||||
}
|
||||
|
@ -121,19 +124,18 @@ void block_job_add_bdrv(BlockJob *job, BlockDriverState *bs)
|
|||
}
|
||||
|
||||
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
BlockDriverState *bs, int64_t speed,
|
||||
BlockDriverState *bs, int64_t speed, int flags,
|
||||
BlockCompletionFunc *cb, void *opaque, Error **errp)
|
||||
{
|
||||
BlockBackend *blk;
|
||||
BlockJob *job;
|
||||
|
||||
assert(cb);
|
||||
if (bs->job) {
|
||||
error_setg(errp, QERR_DEVICE_IN_USE, bdrv_get_device_name(bs));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (job_id == NULL) {
|
||||
if (job_id == NULL && !(flags & BLOCK_JOB_INTERNAL)) {
|
||||
job_id = bdrv_get_device_name(bs);
|
||||
if (!*job_id) {
|
||||
error_setg(errp, "An explicit job ID is required for this node");
|
||||
|
@ -141,14 +143,21 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
|||
}
|
||||
}
|
||||
|
||||
if (!id_wellformed(job_id)) {
|
||||
error_setg(errp, "Invalid job ID '%s'", job_id);
|
||||
return NULL;
|
||||
}
|
||||
if (job_id) {
|
||||
if (flags & BLOCK_JOB_INTERNAL) {
|
||||
error_setg(errp, "Cannot specify job ID for internal block job");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (block_job_get(job_id)) {
|
||||
error_setg(errp, "Job ID '%s' already in use", job_id);
|
||||
return NULL;
|
||||
if (!id_wellformed(job_id)) {
|
||||
error_setg(errp, "Invalid job ID '%s'", job_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (block_job_get(job_id)) {
|
||||
error_setg(errp, "Job ID '%s' already in use", job_id);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
blk = blk_new();
|
||||
|
@ -188,6 +197,11 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
|||
return job;
|
||||
}
|
||||
|
||||
bool block_job_is_internal(BlockJob *job)
|
||||
{
|
||||
return (job->id == NULL);
|
||||
}
|
||||
|
||||
void block_job_ref(BlockJob *job)
|
||||
{
|
||||
++job->refcnt;
|
||||
|
@ -227,7 +241,20 @@ static void block_job_completed_single(BlockJob *job)
|
|||
job->driver->abort(job);
|
||||
}
|
||||
}
|
||||
job->cb(job->opaque, job->ret);
|
||||
|
||||
if (job->cb) {
|
||||
job->cb(job->opaque, job->ret);
|
||||
}
|
||||
if (block_job_is_cancelled(job)) {
|
||||
block_job_event_cancelled(job);
|
||||
} else {
|
||||
const char *msg = NULL;
|
||||
if (job->ret < 0) {
|
||||
msg = strerror(-job->ret);
|
||||
}
|
||||
block_job_event_completed(job, msg);
|
||||
}
|
||||
|
||||
if (job->txn) {
|
||||
block_job_txn_unref(job->txn);
|
||||
}
|
||||
|
@ -330,6 +357,8 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
|||
|
||||
void block_job_complete(BlockJob *job, Error **errp)
|
||||
{
|
||||
/* Should not be reachable via external interface for internal jobs */
|
||||
assert(job->id);
|
||||
if (job->pause_count || job->cancelled || !job->driver->complete) {
|
||||
error_setg(errp, "The active block job '%s' cannot be completed",
|
||||
job->id);
|
||||
|
@ -344,11 +373,22 @@ void block_job_pause(BlockJob *job)
|
|||
job->pause_count++;
|
||||
}
|
||||
|
||||
void block_job_user_pause(BlockJob *job)
|
||||
{
|
||||
job->user_paused = true;
|
||||
block_job_pause(job);
|
||||
}
|
||||
|
||||
static bool block_job_should_pause(BlockJob *job)
|
||||
{
|
||||
return job->pause_count > 0;
|
||||
}
|
||||
|
||||
bool block_job_user_paused(BlockJob *job)
|
||||
{
|
||||
return job ? job->user_paused : 0;
|
||||
}
|
||||
|
||||
void coroutine_fn block_job_pause_point(BlockJob *job)
|
||||
{
|
||||
if (!block_job_should_pause(job)) {
|
||||
|
@ -385,6 +425,14 @@ void block_job_resume(BlockJob *job)
|
|||
block_job_enter(job);
|
||||
}
|
||||
|
||||
void block_job_user_resume(BlockJob *job)
|
||||
{
|
||||
if (job && job->user_paused && job->pause_count > 0) {
|
||||
job->user_paused = false;
|
||||
block_job_resume(job);
|
||||
}
|
||||
}
|
||||
|
||||
void block_job_enter(BlockJob *job)
|
||||
{
|
||||
if (job->co && !job->busy) {
|
||||
|
@ -510,9 +558,15 @@ void block_job_yield(BlockJob *job)
|
|||
block_job_pause_point(job);
|
||||
}
|
||||
|
||||
BlockJobInfo *block_job_query(BlockJob *job)
|
||||
BlockJobInfo *block_job_query(BlockJob *job, Error **errp)
|
||||
{
|
||||
BlockJobInfo *info = g_new0(BlockJobInfo, 1);
|
||||
BlockJobInfo *info;
|
||||
|
||||
if (block_job_is_internal(job)) {
|
||||
error_setg(errp, "Cannot query QEMU internal jobs");
|
||||
return NULL;
|
||||
}
|
||||
info = g_new0(BlockJobInfo, 1);
|
||||
info->type = g_strdup(BlockJobType_lookup[job->driver->job_type]);
|
||||
info->device = g_strdup(job->id);
|
||||
info->len = job->len;
|
||||
|
@ -533,8 +587,12 @@ static void block_job_iostatus_set_err(BlockJob *job, int error)
|
|||
}
|
||||
}
|
||||
|
||||
void block_job_event_cancelled(BlockJob *job)
|
||||
static void block_job_event_cancelled(BlockJob *job)
|
||||
{
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qapi_event_send_block_job_cancelled(job->driver->job_type,
|
||||
job->id,
|
||||
job->len,
|
||||
|
@ -543,8 +601,12 @@ void block_job_event_cancelled(BlockJob *job)
|
|||
&error_abort);
|
||||
}
|
||||
|
||||
void block_job_event_completed(BlockJob *job, const char *msg)
|
||||
static void block_job_event_completed(BlockJob *job, const char *msg)
|
||||
{
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qapi_event_send_block_job_completed(job->driver->job_type,
|
||||
job->id,
|
||||
job->len,
|
||||
|
@ -559,6 +621,10 @@ void block_job_event_ready(BlockJob *job)
|
|||
{
|
||||
job->ready = true;
|
||||
|
||||
if (block_job_is_internal(job)) {
|
||||
return;
|
||||
}
|
||||
|
||||
qapi_event_send_block_job_ready(job->driver->job_type,
|
||||
job->id,
|
||||
job->len,
|
||||
|
@ -589,14 +655,15 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
|||
default:
|
||||
abort();
|
||||
}
|
||||
qapi_event_send_block_job_error(job->id,
|
||||
is_read ? IO_OPERATION_TYPE_READ :
|
||||
IO_OPERATION_TYPE_WRITE,
|
||||
action, &error_abort);
|
||||
if (!block_job_is_internal(job)) {
|
||||
qapi_event_send_block_job_error(job->id,
|
||||
is_read ? IO_OPERATION_TYPE_READ :
|
||||
IO_OPERATION_TYPE_WRITE,
|
||||
action, &error_abort);
|
||||
}
|
||||
if (action == BLOCK_ERROR_ACTION_STOP) {
|
||||
/* make the pause user visible, which will be resumed from QMP. */
|
||||
job->user_paused = true;
|
||||
block_job_pause(job);
|
||||
block_job_user_pause(job);
|
||||
block_job_iostatus_set_err(job, error);
|
||||
}
|
||||
return action;
|
||||
|
|
|
@ -7,16 +7,15 @@
|
|||
#include "qemu/coroutine.h"
|
||||
#include "block/accounting.h"
|
||||
#include "block/dirty-bitmap.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "qapi/qmp/qobject.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qemu/hbitmap.h"
|
||||
|
||||
/* block.c */
|
||||
typedef struct BlockDriver BlockDriver;
|
||||
typedef struct BlockJob BlockJob;
|
||||
typedef struct BdrvChild BdrvChild;
|
||||
typedef struct BdrvChildRole BdrvChildRole;
|
||||
typedef struct BlockJobTxn BlockJobTxn;
|
||||
|
||||
typedef struct BlockDriverInfo {
|
||||
/* in bytes, 0 if irrelevant */
|
||||
|
|
|
@ -665,8 +665,6 @@ int is_windows_drive(const char *filename);
|
|||
* the new backing file if the job completes. Ignored if @base is %NULL.
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @on_error: The action to take upon error.
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @errp: Error object.
|
||||
*
|
||||
* Start a streaming operation on @bs. Clusters that are unallocated
|
||||
|
@ -678,8 +676,7 @@ int is_windows_drive(const char *filename);
|
|||
*/
|
||||
void stream_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, const char *backing_file_str,
|
||||
int64_t speed, BlockdevOnError on_error,
|
||||
BlockCompletionFunc *cb, void *opaque, Error **errp);
|
||||
int64_t speed, BlockdevOnError on_error, Error **errp);
|
||||
|
||||
/**
|
||||
* commit_start:
|
||||
|
@ -690,22 +687,22 @@ void stream_start(const char *job_id, BlockDriverState *bs,
|
|||
* @base: Block device that will be written into, and become the new top.
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @on_error: The action to take upon error.
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @backing_file_str: String to use as the backing file in @top's overlay
|
||||
* @errp: Error object.
|
||||
*
|
||||
*/
|
||||
void commit_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, BlockDriverState *top, int64_t speed,
|
||||
BlockdevOnError on_error, BlockCompletionFunc *cb,
|
||||
void *opaque, const char *backing_file_str, Error **errp);
|
||||
BlockdevOnError on_error, const char *backing_file_str,
|
||||
Error **errp);
|
||||
/**
|
||||
* commit_active_start:
|
||||
* @job_id: The id of the newly-created job, or %NULL to use the
|
||||
* device name of @bs.
|
||||
* @bs: Active block device to be committed.
|
||||
* @base: Block device that will be written into, and become the new top.
|
||||
* @creation_flags: Flags that control the behavior of the Job lifetime.
|
||||
* See @BlockJobCreateFlags
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @on_error: The action to take upon error.
|
||||
* @cb: Completion function for the job.
|
||||
|
@ -715,8 +712,8 @@ void commit_start(const char *job_id, BlockDriverState *bs,
|
|||
*
|
||||
*/
|
||||
void commit_active_start(const char *job_id, BlockDriverState *bs,
|
||||
BlockDriverState *base, int64_t speed,
|
||||
BlockdevOnError on_error,
|
||||
BlockDriverState *base, int creation_flags,
|
||||
int64_t speed, BlockdevOnError on_error,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp, bool auto_complete);
|
||||
/*
|
||||
|
@ -735,8 +732,6 @@ void commit_active_start(const char *job_id, BlockDriverState *bs,
|
|||
* @on_source_error: The action to take upon error reading from the source.
|
||||
* @on_target_error: The action to take upon error writing to the target.
|
||||
* @unmap: Whether to unmap target where source sectors only contain zeroes.
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @errp: Error object.
|
||||
*
|
||||
* Start a mirroring operation on @bs. Clusters that are allocated
|
||||
|
@ -750,9 +745,7 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
|||
MirrorSyncMode mode, BlockMirrorBackingMode backing_mode,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
bool unmap,
|
||||
BlockCompletionFunc *cb,
|
||||
void *opaque, Error **errp);
|
||||
bool unmap, Error **errp);
|
||||
|
||||
/*
|
||||
* backup_start:
|
||||
|
@ -765,6 +758,8 @@ void mirror_start(const char *job_id, BlockDriverState *bs,
|
|||
* @sync_bitmap: The dirty bitmap if sync_mode is MIRROR_SYNC_MODE_INCREMENTAL.
|
||||
* @on_source_error: The action to take upon error reading from the source.
|
||||
* @on_target_error: The action to take upon error writing to the target.
|
||||
* @creation_flags: Flags that control the behavior of the Job lifetime.
|
||||
* See @BlockJobCreateFlags
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @txn: Transaction that this job is part of (may be NULL).
|
||||
|
@ -778,6 +773,7 @@ void backup_start(const char *job_id, BlockDriverState *bs,
|
|||
bool compress,
|
||||
BlockdevOnError on_source_error,
|
||||
BlockdevOnError on_target_error,
|
||||
int creation_flags,
|
||||
BlockCompletionFunc *cb, void *opaque,
|
||||
BlockJobTxn *txn, Error **errp);
|
||||
|
||||
|
|
|
@ -28,85 +28,15 @@
|
|||
|
||||
#include "block/block.h"
|
||||
|
||||
/**
|
||||
* BlockJobDriver:
|
||||
*
|
||||
* A class type for block job driver.
|
||||
*/
|
||||
typedef struct BlockJobDriver {
|
||||
/** Derived BlockJob struct size */
|
||||
size_t instance_size;
|
||||
|
||||
/** String describing the operation, part of query-block-jobs QMP API */
|
||||
BlockJobType job_type;
|
||||
|
||||
/** Optional callback for job types that support setting a speed limit */
|
||||
void (*set_speed)(BlockJob *job, int64_t speed, Error **errp);
|
||||
|
||||
/** Optional callback for job types that need to forward I/O status reset */
|
||||
void (*iostatus_reset)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* Optional callback for job types whose completion must be triggered
|
||||
* manually.
|
||||
*/
|
||||
void (*complete)(BlockJob *job, Error **errp);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when all the jobs
|
||||
* belonging to the same transaction complete; or upon this job's
|
||||
* completion if it is not in a transaction. Skipped if NULL.
|
||||
*
|
||||
* All jobs will complete with a call to either .commit() or .abort() but
|
||||
* never both.
|
||||
*/
|
||||
void (*commit)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when any job in the
|
||||
* same transaction fails; or upon this job's failure (due to error or
|
||||
* cancellation) if it is not in a transaction. Skipped if NULL.
|
||||
*
|
||||
* All jobs will complete with a call to either .commit() or .abort() but
|
||||
* never both.
|
||||
*/
|
||||
void (*abort)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when the job transitions
|
||||
* into the paused state. Paused jobs must not perform any asynchronous
|
||||
* I/O or event loop activity. This callback is used to quiesce jobs.
|
||||
*/
|
||||
void coroutine_fn (*pause)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when the job transitions
|
||||
* out of the paused state. Any asynchronous I/O or event loop activity
|
||||
* should be restarted from this callback.
|
||||
*/
|
||||
void coroutine_fn (*resume)(BlockJob *job);
|
||||
|
||||
/*
|
||||
* If the callback is not NULL, it will be invoked before the job is
|
||||
* resumed in a new AioContext. This is the place to move any resources
|
||||
* besides job->blk to the new AioContext.
|
||||
*/
|
||||
void (*attached_aio_context)(BlockJob *job, AioContext *new_context);
|
||||
|
||||
/*
|
||||
* If the callback is not NULL, it will be invoked when the job has to be
|
||||
* synchronously cancelled or completed; it should drain BlockDriverStates
|
||||
* as required to ensure progress.
|
||||
*/
|
||||
void (*drain)(BlockJob *job);
|
||||
} BlockJobDriver;
|
||||
typedef struct BlockJobDriver BlockJobDriver;
|
||||
typedef struct BlockJobTxn BlockJobTxn;
|
||||
|
||||
/**
|
||||
* BlockJob:
|
||||
*
|
||||
* Long-running operation on a BlockDriverState.
|
||||
*/
|
||||
struct BlockJob {
|
||||
typedef struct BlockJob {
|
||||
/** The job type, including the job vtable. */
|
||||
const BlockJobDriver *driver;
|
||||
|
||||
|
@ -114,7 +44,7 @@ struct BlockJob {
|
|||
BlockBackend *blk;
|
||||
|
||||
/**
|
||||
* The ID of the block job.
|
||||
* The ID of the block job. May be NULL for internal jobs.
|
||||
*/
|
||||
char *id;
|
||||
|
||||
|
@ -208,7 +138,12 @@ struct BlockJob {
|
|||
/** Non-NULL if this job is part of a transaction */
|
||||
BlockJobTxn *txn;
|
||||
QLIST_ENTRY(BlockJob) txn_list;
|
||||
};
|
||||
} BlockJob;
|
||||
|
||||
typedef enum BlockJobCreateFlags {
|
||||
BLOCK_JOB_DEFAULT = 0x00,
|
||||
BLOCK_JOB_INTERNAL = 0x01,
|
||||
} BlockJobCreateFlags;
|
||||
|
||||
/**
|
||||
* block_job_next:
|
||||
|
@ -231,30 +166,6 @@ BlockJob *block_job_next(BlockJob *job);
|
|||
*/
|
||||
BlockJob *block_job_get(const char *id);
|
||||
|
||||
/**
|
||||
* block_job_create:
|
||||
* @job_id: The id of the newly-created job, or %NULL to have one
|
||||
* generated automatically.
|
||||
* @job_type: The class object for the newly-created job.
|
||||
* @bs: The block
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @errp: Error object.
|
||||
*
|
||||
* Create a new long-running block device job and return it. The job
|
||||
* will call @cb asynchronously when the job completes. Note that
|
||||
* @bs may have been closed at the time the @cb it is called. If
|
||||
* this is the case, the job may be reported as either cancelled or
|
||||
* completed.
|
||||
*
|
||||
* This function is not part of the public job interface; it should be
|
||||
* called from a wrapper that is specific to the job type.
|
||||
*/
|
||||
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
BlockDriverState *bs, int64_t speed,
|
||||
BlockCompletionFunc *cb, void *opaque, Error **errp);
|
||||
|
||||
/**
|
||||
* block_job_add_bdrv:
|
||||
* @job: A block job
|
||||
|
@ -266,52 +177,6 @@ void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
|||
*/
|
||||
void block_job_add_bdrv(BlockJob *job, BlockDriverState *bs);
|
||||
|
||||
/**
|
||||
* 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, QEMUClockType type, int64_t ns);
|
||||
|
||||
/**
|
||||
* block_job_yield:
|
||||
* @job: The job that calls the function.
|
||||
*
|
||||
* Yield the block job coroutine.
|
||||
*/
|
||||
void block_job_yield(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_ref:
|
||||
* @bs: The block device.
|
||||
*
|
||||
* Grab a reference to the block job. Should be paired with block_job_unref.
|
||||
*/
|
||||
void block_job_ref(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_unref:
|
||||
* @bs: The block device.
|
||||
*
|
||||
* Release reference to the block job and release resources if it is the last
|
||||
* reference.
|
||||
*/
|
||||
void block_job_unref(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_completed:
|
||||
* @job: The job being completed.
|
||||
* @ret: The status code.
|
||||
*
|
||||
* Call the completion function that was registered at creation time, and
|
||||
* free @job.
|
||||
*/
|
||||
void block_job_completed(BlockJob *job, int ret);
|
||||
|
||||
/**
|
||||
* block_job_set_speed:
|
||||
* @job: The job to set the speed for.
|
||||
|
@ -340,30 +205,13 @@ void block_job_cancel(BlockJob *job);
|
|||
*/
|
||||
void block_job_complete(BlockJob *job, Error **errp);
|
||||
|
||||
/**
|
||||
* block_job_is_cancelled:
|
||||
* @job: The job being queried.
|
||||
*
|
||||
* Returns whether the job is scheduled for cancellation.
|
||||
*/
|
||||
bool block_job_is_cancelled(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_query:
|
||||
* @job: The job to get information about.
|
||||
*
|
||||
* Return information about a job.
|
||||
*/
|
||||
BlockJobInfo *block_job_query(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_pause_point:
|
||||
* @job: The job that is ready to pause.
|
||||
*
|
||||
* Pause now if block_job_pause() has been called. Block jobs that perform
|
||||
* lots of I/O must call this between requests so that the job can be paused.
|
||||
*/
|
||||
void coroutine_fn block_job_pause_point(BlockJob *job);
|
||||
BlockJobInfo *block_job_query(BlockJob *job, Error **errp);
|
||||
|
||||
/**
|
||||
* block_job_pause:
|
||||
|
@ -373,6 +221,23 @@ void coroutine_fn block_job_pause_point(BlockJob *job);
|
|||
*/
|
||||
void block_job_pause(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_user_pause:
|
||||
* @job: The job to be paused.
|
||||
*
|
||||
* Asynchronously pause the specified job.
|
||||
* Do not allow a resume until a matching call to block_job_user_resume.
|
||||
*/
|
||||
void block_job_user_pause(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_paused:
|
||||
* @job: The job to query.
|
||||
*
|
||||
* Returns true if the job is user-paused.
|
||||
*/
|
||||
bool block_job_user_paused(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_resume:
|
||||
* @job: The job to be resumed.
|
||||
|
@ -382,37 +247,13 @@ void block_job_pause(BlockJob *job);
|
|||
void block_job_resume(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_enter:
|
||||
* @job: The job to enter.
|
||||
* block_job_user_resume:
|
||||
* @job: The job to be resumed.
|
||||
*
|
||||
* Continue the specified job by entering the coroutine.
|
||||
* Resume the specified job.
|
||||
* Must be paired with a preceding block_job_user_pause.
|
||||
*/
|
||||
void block_job_enter(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_event_cancelled:
|
||||
* @job: The job whose information is requested.
|
||||
*
|
||||
* Send a BLOCK_JOB_CANCELLED event for the specified job.
|
||||
*/
|
||||
void block_job_event_cancelled(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_ready:
|
||||
* @job: The job which is now ready to complete.
|
||||
* @msg: Error message. Only present on failure.
|
||||
*
|
||||
* Send a BLOCK_JOB_COMPLETED event for the specified job.
|
||||
*/
|
||||
void block_job_event_completed(BlockJob *job, const char *msg);
|
||||
|
||||
/**
|
||||
* block_job_ready:
|
||||
* @job: The job which is now ready to complete.
|
||||
*
|
||||
* Send a BLOCK_JOB_READY event for the specified job.
|
||||
*/
|
||||
void block_job_event_ready(BlockJob *job);
|
||||
void block_job_user_resume(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_cancel_sync:
|
||||
|
@ -459,37 +300,6 @@ int block_job_complete_sync(BlockJob *job, Error **errp);
|
|||
*/
|
||||
void block_job_iostatus_reset(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_error_action:
|
||||
* @job: The job to signal an error for.
|
||||
* @on_err: The error action setting.
|
||||
* @is_read: Whether the operation was a read.
|
||||
* @error: The error that was reported.
|
||||
*
|
||||
* Report an I/O error for a block job and possibly stop the VM. Return the
|
||||
* action that was selected based on @on_err and @error.
|
||||
*/
|
||||
BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
||||
int is_read, int error);
|
||||
|
||||
typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque);
|
||||
|
||||
/**
|
||||
* block_job_defer_to_main_loop:
|
||||
* @job: The job
|
||||
* @fn: The function to run in the main loop
|
||||
* @opaque: The opaque value that is passed to @fn
|
||||
*
|
||||
* Execute a given function in the main loop with the BlockDriverState
|
||||
* AioContext acquired. Block jobs must call bdrv_unref(), bdrv_close(), and
|
||||
* anything that uses bdrv_drain_all() in the main loop.
|
||||
*
|
||||
* The @job AioContext is held while @fn executes.
|
||||
*/
|
||||
void block_job_defer_to_main_loop(BlockJob *job,
|
||||
BlockJobDeferToMainLoopFn *fn,
|
||||
void *opaque);
|
||||
|
||||
/**
|
||||
* block_job_txn_new:
|
||||
*
|
||||
|
@ -525,4 +335,12 @@ void block_job_txn_unref(BlockJobTxn *txn);
|
|||
*/
|
||||
void block_job_txn_add_job(BlockJobTxn *txn, BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_is_internal:
|
||||
* @job: The job to determine if it is user-visible or not.
|
||||
*
|
||||
* Returns true if the job should not be visible to the management layer.
|
||||
*/
|
||||
bool block_job_is_internal(BlockJob *job);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* Declarations for long-running block device operations
|
||||
*
|
||||
* Copyright (c) 2011 IBM Corp.
|
||||
* Copyright (c) 2012 Red Hat, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BLOCKJOB_INT_H
|
||||
#define BLOCKJOB_INT_H
|
||||
|
||||
#include "block/blockjob.h"
|
||||
#include "block/block.h"
|
||||
|
||||
/**
|
||||
* BlockJobDriver:
|
||||
*
|
||||
* A class type for block job driver.
|
||||
*/
|
||||
struct BlockJobDriver {
|
||||
/** Derived BlockJob struct size */
|
||||
size_t instance_size;
|
||||
|
||||
/** String describing the operation, part of query-block-jobs QMP API */
|
||||
BlockJobType job_type;
|
||||
|
||||
/** Optional callback for job types that support setting a speed limit */
|
||||
void (*set_speed)(BlockJob *job, int64_t speed, Error **errp);
|
||||
|
||||
/** Optional callback for job types that need to forward I/O status reset */
|
||||
void (*iostatus_reset)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* Optional callback for job types whose completion must be triggered
|
||||
* manually.
|
||||
*/
|
||||
void (*complete)(BlockJob *job, Error **errp);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when all the jobs
|
||||
* belonging to the same transaction complete; or upon this job's
|
||||
* completion if it is not in a transaction. Skipped if NULL.
|
||||
*
|
||||
* All jobs will complete with a call to either .commit() or .abort() but
|
||||
* never both.
|
||||
*/
|
||||
void (*commit)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when any job in the
|
||||
* same transaction fails; or upon this job's failure (due to error or
|
||||
* cancellation) if it is not in a transaction. Skipped if NULL.
|
||||
*
|
||||
* All jobs will complete with a call to either .commit() or .abort() but
|
||||
* never both.
|
||||
*/
|
||||
void (*abort)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when the job transitions
|
||||
* into the paused state. Paused jobs must not perform any asynchronous
|
||||
* I/O or event loop activity. This callback is used to quiesce jobs.
|
||||
*/
|
||||
void coroutine_fn (*pause)(BlockJob *job);
|
||||
|
||||
/**
|
||||
* If the callback is not NULL, it will be invoked when the job transitions
|
||||
* out of the paused state. Any asynchronous I/O or event loop activity
|
||||
* should be restarted from this callback.
|
||||
*/
|
||||
void coroutine_fn (*resume)(BlockJob *job);
|
||||
|
||||
/*
|
||||
* If the callback is not NULL, it will be invoked before the job is
|
||||
* resumed in a new AioContext. This is the place to move any resources
|
||||
* besides job->blk to the new AioContext.
|
||||
*/
|
||||
void (*attached_aio_context)(BlockJob *job, AioContext *new_context);
|
||||
|
||||
/*
|
||||
* If the callback is not NULL, it will be invoked when the job has to be
|
||||
* synchronously cancelled or completed; it should drain BlockDriverStates
|
||||
* as required to ensure progress.
|
||||
*/
|
||||
void (*drain)(BlockJob *job);
|
||||
};
|
||||
|
||||
/**
|
||||
* block_job_create:
|
||||
* @job_id: The id of the newly-created job, or %NULL to have one
|
||||
* generated automatically.
|
||||
* @job_type: The class object for the newly-created job.
|
||||
* @bs: The block
|
||||
* @speed: The maximum speed, in bytes per second, or 0 for unlimited.
|
||||
* @cb: Completion function for the job.
|
||||
* @opaque: Opaque pointer value passed to @cb.
|
||||
* @errp: Error object.
|
||||
*
|
||||
* Create a new long-running block device job and return it. The job
|
||||
* will call @cb asynchronously when the job completes. Note that
|
||||
* @bs may have been closed at the time the @cb it is called. If
|
||||
* this is the case, the job may be reported as either cancelled or
|
||||
* completed.
|
||||
*
|
||||
* This function is not part of the public job interface; it should be
|
||||
* called from a wrapper that is specific to the job type.
|
||||
*/
|
||||
void *block_job_create(const char *job_id, const BlockJobDriver *driver,
|
||||
BlockDriverState *bs, int64_t speed, int flags,
|
||||
BlockCompletionFunc *cb, 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, QEMUClockType type, int64_t ns);
|
||||
|
||||
/**
|
||||
* block_job_yield:
|
||||
* @job: The job that calls the function.
|
||||
*
|
||||
* Yield the block job coroutine.
|
||||
*/
|
||||
void block_job_yield(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_ref:
|
||||
* @bs: The block device.
|
||||
*
|
||||
* Grab a reference to the block job. Should be paired with block_job_unref.
|
||||
*/
|
||||
void block_job_ref(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_unref:
|
||||
* @bs: The block device.
|
||||
*
|
||||
* Release reference to the block job and release resources if it is the last
|
||||
* reference.
|
||||
*/
|
||||
void block_job_unref(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_completed:
|
||||
* @job: The job being completed.
|
||||
* @ret: The status code.
|
||||
*
|
||||
* Call the completion function that was registered at creation time, and
|
||||
* free @job.
|
||||
*/
|
||||
void block_job_completed(BlockJob *job, int ret);
|
||||
|
||||
/**
|
||||
* block_job_is_cancelled:
|
||||
* @job: The job being queried.
|
||||
*
|
||||
* Returns whether the job is scheduled for cancellation.
|
||||
*/
|
||||
bool block_job_is_cancelled(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_pause_point:
|
||||
* @job: The job that is ready to pause.
|
||||
*
|
||||
* Pause now if block_job_pause() has been called. Block jobs that perform
|
||||
* lots of I/O must call this between requests so that the job can be paused.
|
||||
*/
|
||||
void coroutine_fn block_job_pause_point(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_enter:
|
||||
* @job: The job to enter.
|
||||
*
|
||||
* Continue the specified job by entering the coroutine.
|
||||
*/
|
||||
void block_job_enter(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_event_ready:
|
||||
* @job: The job which is now ready to be completed.
|
||||
*
|
||||
* Send a BLOCK_JOB_READY event for the specified job.
|
||||
*/
|
||||
void block_job_event_ready(BlockJob *job);
|
||||
|
||||
/**
|
||||
* block_job_error_action:
|
||||
* @job: The job to signal an error for.
|
||||
* @on_err: The error action setting.
|
||||
* @is_read: Whether the operation was a read.
|
||||
* @error: The error that was reported.
|
||||
*
|
||||
* Report an I/O error for a block job and possibly stop the VM. Return the
|
||||
* action that was selected based on @on_err and @error.
|
||||
*/
|
||||
BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
||||
int is_read, int error);
|
||||
|
||||
typedef void BlockJobDeferToMainLoopFn(BlockJob *job, void *opaque);
|
||||
|
||||
/**
|
||||
* block_job_defer_to_main_loop:
|
||||
* @job: The job
|
||||
* @fn: The function to run in the main loop
|
||||
* @opaque: The opaque value that is passed to @fn
|
||||
*
|
||||
* Execute a given function in the main loop with the BlockDriverState
|
||||
* AioContext acquired. Block jobs must call bdrv_unref(), bdrv_close(), and
|
||||
* anything that uses bdrv_drain_all() in the main loop.
|
||||
*
|
||||
* The @job AioContext is held while @fn executes.
|
||||
*/
|
||||
void block_job_defer_to_main_loop(BlockJob *job,
|
||||
BlockJobDeferToMainLoopFn *fn,
|
||||
void *opaque);
|
||||
|
||||
#endif
|
|
@ -2197,7 +2197,7 @@
|
|||
#
|
||||
# @debug-level: #optional libgfapi log level (default '4' which is Error)
|
||||
#
|
||||
# @logfile: #optional libgfapi log file (default /dev/stderr)
|
||||
# @logfile: #optional libgfapi log file (default /dev/stderr) (Since 2.8)
|
||||
#
|
||||
# Since: 2.7
|
||||
##
|
||||
|
|
|
@ -933,8 +933,9 @@ static int img_commit(int argc, char **argv)
|
|||
|
||||
aio_context = bdrv_get_aio_context(bs);
|
||||
aio_context_acquire(aio_context);
|
||||
commit_active_start("commit", bs, base_bs, 0, BLOCKDEV_ON_ERROR_REPORT,
|
||||
common_block_job_cb, &cbi, &local_err, false);
|
||||
commit_active_start("commit", bs, base_bs, BLOCK_JOB_DEFAULT, 0,
|
||||
BLOCKDEV_ON_ERROR_REPORT, common_block_job_cb, &cbi,
|
||||
&local_err, false);
|
||||
aio_context_release(aio_context);
|
||||
if (local_err) {
|
||||
goto done;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
typedef struct {
|
||||
|
@ -98,7 +98,8 @@ static BlockJob *test_block_job_start(unsigned int iterations,
|
|||
bs = bdrv_new();
|
||||
snprintf(job_id, sizeof(job_id), "job%u", counter++);
|
||||
s = block_job_create(job_id, &test_block_job_driver, bs, 0,
|
||||
test_block_job_cb, data, &error_abort);
|
||||
BLOCK_JOB_DEFAULT, test_block_job_cb,
|
||||
data, &error_abort);
|
||||
s->iterations = iterations;
|
||||
s->use_timer = use_timer;
|
||||
s->rc = rc;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "block/blockjob.h"
|
||||
#include "block/blockjob_int.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
|
||||
static const BlockJobDriver test_block_job_driver = {
|
||||
|
@ -31,7 +31,7 @@ static BlockJob *do_test_id(BlockBackend *blk, const char *id,
|
|||
Error *errp = NULL;
|
||||
|
||||
job = block_job_create(id, &test_block_job_driver, blk_bs(blk), 0,
|
||||
block_job_cb, NULL, &errp);
|
||||
BLOCK_JOB_DEFAULT, block_job_cb, NULL, &errp);
|
||||
if (should_succeed) {
|
||||
g_assert_null(errp);
|
||||
g_assert_nonnull(job);
|
||||
|
|
Loading…
Reference in New Issue