Block layer patches
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJX+3x6AAoJEH8JsnLIjy/WTF4QAKCqL6am3Y4JR3ke04tCmElD x9i5TjQvaqD2iK91Scf7hSvfk2TiFifhQq/bO21YY7JrDktVFOzLVpWcEID4XPK/ 0pAVx1JJXTW3MV9FW2qxxvASznnQlu6s1Truyh++GmVt5kloc1HR7qFzIWs4jyWw olNZ5tEEqputdxtPsQmy93fxFJxKVkDWtqKbWavl3mQEgkGz25GrkQu6dwzmIQLA lGuE/7k3vbCPzMyrdnuoYhkzan7RiwiV3lVqHzyk79xsKTP0sqFscSltoydL9P5p A59MJCR1PqHutMmAicgc6zo3ZIYJuj8mcHXSkGgunnUGpqtwJ8JoeVl2bsM1sJTH 3HK02Z/a/BZIxdGtop0lqNRGNUL9HM3tjV5KyxKX5MMRX3QYrn4poeZXPZOk/oxg URdACBXa5oKvrwZ4ZURU+59+JvgzZ8IzfVYXJxELBW0Gg+hotnxB3+XBZLq7HI3y GEhj7CmmMrfs7wDJHoQvZlsbmwZgLbnYxcpsP9+q8mbCfioetUAMXy7IxCzkPaDk h5aqDMP1+zeMeWtzQGM0ur/nMDFaMegXh3X3tS+9gzxDdFd4D7pif0lOEI7m1lOr Dch4m25EuarigE2GcY00WZgD0zvI0j7b5j8TqG4RoIFkuvjuJBZYwaeM9aRSwtrS 1xZZKe7WPk4kvauOk8pt =td0H -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging Block layer patches # gpg: Signature made Mon 10 Oct 2016 12:33:14 BST # gpg: using RSA key 0x7F09B272C88F2FD6 # gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>" # Primary key fingerprint: DC3D EB15 9A9A F95D 3D74 56FE 7F09 B272 C88F 2FD6 * remotes/kevin/tags/for-upstream: dmg: Move libbz2 code to dmg-bz2.so module: Don't load the same module if requested multiple times scripts: Allow block module to not define BlockDriver block: Add qdev ID to DEVICE_TRAY_MOVED block-backend: Remember if attached device is non-qdev block: Add node name to BLOCK_IO_ERROR event block: Add bdrv_runtime_opts to query-command-line-options block: use aio_bh_schedule_oneshot async: add aio_bh_schedule_oneshot block: use bdrv_add_before_write_notifier Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
0f183e679d
27
async.c
27
async.c
@ -44,6 +44,25 @@ struct QEMUBH {
|
||||
bool deleted;
|
||||
};
|
||||
|
||||
void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||
{
|
||||
QEMUBH *bh;
|
||||
bh = g_new(QEMUBH, 1);
|
||||
*bh = (QEMUBH){
|
||||
.ctx = ctx,
|
||||
.cb = cb,
|
||||
.opaque = opaque,
|
||||
};
|
||||
qemu_mutex_lock(&ctx->bh_lock);
|
||||
bh->next = ctx->first_bh;
|
||||
bh->scheduled = 1;
|
||||
bh->deleted = 1;
|
||||
/* Make sure that the members are ready before putting bh into list */
|
||||
smp_wmb();
|
||||
ctx->first_bh = bh;
|
||||
qemu_mutex_unlock(&ctx->bh_lock);
|
||||
}
|
||||
|
||||
QEMUBH *aio_bh_new(AioContext *ctx, QEMUBHFunc *cb, void *opaque)
|
||||
{
|
||||
QEMUBH *bh;
|
||||
@ -86,7 +105,7 @@ int aio_bh_poll(AioContext *ctx)
|
||||
* thread sees the zero before bh->cb has run, and thus will call
|
||||
* aio_notify again if necessary.
|
||||
*/
|
||||
if (!bh->deleted && atomic_xchg(&bh->scheduled, 0)) {
|
||||
if (atomic_xchg(&bh->scheduled, 0)) {
|
||||
/* Idle BHs and the notify BH don't count as progress */
|
||||
if (!bh->idle && bh != ctx->notify_dummy_bh) {
|
||||
ret = 1;
|
||||
@ -104,7 +123,7 @@ int aio_bh_poll(AioContext *ctx)
|
||||
bhp = &ctx->first_bh;
|
||||
while (*bhp) {
|
||||
bh = *bhp;
|
||||
if (bh->deleted) {
|
||||
if (bh->deleted && !bh->scheduled) {
|
||||
*bhp = bh->next;
|
||||
g_free(bh);
|
||||
} else {
|
||||
@ -168,7 +187,7 @@ aio_compute_timeout(AioContext *ctx)
|
||||
QEMUBH *bh;
|
||||
|
||||
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
||||
if (!bh->deleted && bh->scheduled) {
|
||||
if (bh->scheduled) {
|
||||
if (bh->idle) {
|
||||
/* idle bottom halves will be polled at least
|
||||
* every 10ms */
|
||||
@ -216,7 +235,7 @@ aio_ctx_check(GSource *source)
|
||||
aio_notify_accept(ctx);
|
||||
|
||||
for (bh = ctx->first_bh; bh; bh = bh->next) {
|
||||
if (!bh->deleted && bh->scheduled) {
|
||||
if (bh->scheduled) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
9
block.c
9
block.c
@ -926,7 +926,7 @@ out:
|
||||
g_free(gen_node_name);
|
||||
}
|
||||
|
||||
static QemuOptsList bdrv_runtime_opts = {
|
||||
QemuOptsList bdrv_runtime_opts = {
|
||||
.name = "bdrv_common",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(bdrv_runtime_opts.head),
|
||||
.desc = {
|
||||
@ -3360,17 +3360,10 @@ int bdrv_media_changed(BlockDriverState *bs)
|
||||
void bdrv_eject(BlockDriverState *bs, bool eject_flag)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
const char *device_name;
|
||||
|
||||
if (drv && drv->bdrv_eject) {
|
||||
drv->bdrv_eject(bs, eject_flag);
|
||||
}
|
||||
|
||||
device_name = bdrv_get_device_name(bs);
|
||||
if (device_name[0] != '\0') {
|
||||
qapi_event_send_device_tray_moved(device_name,
|
||||
eject_flag, &error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -41,6 +41,7 @@ gluster.o-libs := $(GLUSTERFS_LIBS)
|
||||
ssh.o-cflags := $(LIBSSH2_CFLAGS)
|
||||
ssh.o-libs := $(LIBSSH2_LIBS)
|
||||
archipelago.o-libs := $(ARCHIPELAGO_LIBS)
|
||||
dmg.o-libs := $(BZIP2_LIBS)
|
||||
block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
|
||||
dmg-bz2.o-libs := $(BZIP2_LIBS)
|
||||
qcow.o-libs := -lz
|
||||
linux-aio.o-libs := -laio
|
||||
|
@ -87,7 +87,6 @@ typedef enum {
|
||||
|
||||
typedef struct ArchipelagoAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
struct BDRVArchipelagoState *s;
|
||||
QEMUIOVector *qiov;
|
||||
ARCHIPCmd cmd;
|
||||
@ -154,11 +153,10 @@ static void archipelago_finish_aiocb(AIORequestData *reqdata)
|
||||
} else if (reqdata->aio_cb->ret == reqdata->segreq->total) {
|
||||
reqdata->aio_cb->ret = 0;
|
||||
}
|
||||
reqdata->aio_cb->bh = aio_bh_new(
|
||||
aio_bh_schedule_oneshot(
|
||||
bdrv_get_aio_context(reqdata->aio_cb->common.bs),
|
||||
qemu_archipelago_complete_aio, reqdata
|
||||
);
|
||||
qemu_bh_schedule(reqdata->aio_cb->bh);
|
||||
}
|
||||
|
||||
static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port,
|
||||
@ -313,7 +311,6 @@ static void qemu_archipelago_complete_aio(void *opaque)
|
||||
AIORequestData *reqdata = (AIORequestData *) opaque;
|
||||
ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
|
||||
|
||||
qemu_bh_delete(aio_cb->bh);
|
||||
aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
|
||||
aio_cb->status = 0;
|
||||
|
||||
|
@ -49,7 +49,6 @@ typedef struct BDRVBlkdebugState {
|
||||
|
||||
typedef struct BlkdebugAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int ret;
|
||||
} BlkdebugAIOCB;
|
||||
|
||||
@ -410,7 +409,6 @@ out:
|
||||
static void error_callback_bh(void *opaque)
|
||||
{
|
||||
struct BlkdebugAIOCB *acb = opaque;
|
||||
qemu_bh_delete(acb->bh);
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
@ -421,7 +419,6 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
BDRVBlkdebugState *s = bs->opaque;
|
||||
int error = rule->options.inject.error;
|
||||
struct BlkdebugAIOCB *acb;
|
||||
QEMUBH *bh;
|
||||
bool immediately = rule->options.inject.immediately;
|
||||
|
||||
if (rule->options.inject.once) {
|
||||
@ -436,9 +433,7 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
|
||||
acb = qemu_aio_get(&blkdebug_aiocb_info, bs, cb, opaque);
|
||||
acb->ret = -error;
|
||||
|
||||
bh = aio_bh_new(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
||||
acb->bh = bh;
|
||||
qemu_bh_schedule(bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), error_callback_bh, acb);
|
||||
|
||||
return &acb->common;
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ typedef struct {
|
||||
typedef struct BlkverifyAIOCB BlkverifyAIOCB;
|
||||
struct BlkverifyAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
|
||||
/* Request metadata */
|
||||
bool is_write;
|
||||
@ -175,7 +174,6 @@ static BlkverifyAIOCB *blkverify_aio_get(BlockDriverState *bs, bool is_write,
|
||||
{
|
||||
BlkverifyAIOCB *acb = qemu_aio_get(&blkverify_aiocb_info, bs, cb, opaque);
|
||||
|
||||
acb->bh = NULL;
|
||||
acb->is_write = is_write;
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
@ -191,7 +189,6 @@ static void blkverify_aio_bh(void *opaque)
|
||||
{
|
||||
BlkverifyAIOCB *acb = opaque;
|
||||
|
||||
qemu_bh_delete(acb->bh);
|
||||
if (acb->buf) {
|
||||
qemu_iovec_destroy(&acb->raw_qiov);
|
||||
qemu_vfree(acb->buf);
|
||||
@ -218,9 +215,8 @@ static void blkverify_aio_cb(void *opaque, int ret)
|
||||
acb->verify(acb);
|
||||
}
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
||||
blkverify_aio_bh, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||
blkverify_aio_bh, acb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ struct BlockBackend {
|
||||
BlockBackendPublic public;
|
||||
|
||||
void *dev; /* attached device model, if any */
|
||||
bool legacy_dev; /* true if dev is not a DeviceState */
|
||||
/* TODO change to DeviceState when all users are qdevified */
|
||||
const BlockDevOps *dev_ops;
|
||||
void *dev_opaque;
|
||||
@ -65,7 +66,6 @@ struct BlockBackend {
|
||||
|
||||
typedef struct BlockBackendAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
BlockBackend *blk;
|
||||
int ret;
|
||||
} BlockBackendAIOCB;
|
||||
@ -507,32 +507,38 @@ void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach device model @dev to @blk.
|
||||
* Return 0 on success, -EBUSY when a device model is attached already.
|
||||
*/
|
||||
int blk_attach_dev(BlockBackend *blk, void *dev)
|
||||
/* TODO change to DeviceState *dev when all users are qdevified */
|
||||
static int blk_do_attach_dev(BlockBackend *blk, void *dev)
|
||||
{
|
||||
if (blk->dev) {
|
||||
return -EBUSY;
|
||||
}
|
||||
blk_ref(blk);
|
||||
blk->dev = dev;
|
||||
blk->legacy_dev = false;
|
||||
blk_iostatus_reset(blk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach device model @dev to @blk.
|
||||
* Return 0 on success, -EBUSY when a device model is attached already.
|
||||
*/
|
||||
int blk_attach_dev(BlockBackend *blk, DeviceState *dev)
|
||||
{
|
||||
return blk_do_attach_dev(blk, dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* Attach device model @dev to @blk.
|
||||
* @blk must not have a device model attached already.
|
||||
* TODO qdevified devices don't use this, remove when devices are qdevified
|
||||
*/
|
||||
void blk_attach_dev_nofail(BlockBackend *blk, void *dev)
|
||||
void blk_attach_dev_legacy(BlockBackend *blk, void *dev)
|
||||
{
|
||||
if (blk_attach_dev(blk, dev) < 0) {
|
||||
if (blk_do_attach_dev(blk, dev) < 0) {
|
||||
abort();
|
||||
}
|
||||
blk->legacy_dev = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -559,6 +565,23 @@ void *blk_get_attached_dev(BlockBackend *blk)
|
||||
return blk->dev;
|
||||
}
|
||||
|
||||
/* Return the qdev ID, or if no ID is assigned the QOM path, of the block
|
||||
* device attached to the BlockBackend. */
|
||||
static char *blk_get_attached_dev_id(BlockBackend *blk)
|
||||
{
|
||||
DeviceState *dev;
|
||||
|
||||
assert(!blk->legacy_dev);
|
||||
dev = blk->dev;
|
||||
|
||||
if (!dev) {
|
||||
return g_strdup("");
|
||||
} else if (dev->id) {
|
||||
return g_strdup(dev->id);
|
||||
}
|
||||
return object_get_canonical_path(OBJECT(dev));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the BlockBackend which has the device model @dev attached if it
|
||||
* exists, else null.
|
||||
@ -586,6 +609,11 @@ BlockBackend *blk_by_dev(void *dev)
|
||||
void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
|
||||
void *opaque)
|
||||
{
|
||||
/* All drivers that use blk_set_dev_ops() are qdevified and we want to keep
|
||||
* it that way, so we can assume blk->dev is a DeviceState if blk->dev_ops
|
||||
* is set. */
|
||||
assert(!blk->legacy_dev);
|
||||
|
||||
blk->dev_ops = ops;
|
||||
blk->dev_opaque = opaque;
|
||||
}
|
||||
@ -601,13 +629,17 @@ void blk_dev_change_media_cb(BlockBackend *blk, bool load)
|
||||
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
|
||||
bool tray_was_open, tray_is_open;
|
||||
|
||||
assert(!blk->legacy_dev);
|
||||
|
||||
tray_was_open = blk_dev_is_tray_open(blk);
|
||||
blk->dev_ops->change_media_cb(blk->dev_opaque, load);
|
||||
tray_is_open = blk_dev_is_tray_open(blk);
|
||||
|
||||
if (tray_was_open != tray_is_open) {
|
||||
qapi_event_send_device_tray_moved(blk_name(blk), tray_is_open,
|
||||
char *id = blk_get_attached_dev_id(blk);
|
||||
qapi_event_send_device_tray_moved(blk_name(blk), id, tray_is_open,
|
||||
&error_abort);
|
||||
g_free(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -898,7 +930,6 @@ int blk_make_zero(BlockBackend *blk, BdrvRequestFlags flags)
|
||||
static void error_callback_bh(void *opaque)
|
||||
{
|
||||
struct BlockBackendAIOCB *acb = opaque;
|
||||
qemu_bh_delete(acb->bh);
|
||||
acb->common.cb(acb->common.opaque, acb->ret);
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
@ -908,16 +939,12 @@ BlockAIOCB *blk_abort_aio_request(BlockBackend *blk,
|
||||
void *opaque, int ret)
|
||||
{
|
||||
struct BlockBackendAIOCB *acb;
|
||||
QEMUBH *bh;
|
||||
|
||||
acb = blk_aio_get(&block_backend_aiocb_info, blk, cb, opaque);
|
||||
acb->blk = blk;
|
||||
acb->ret = ret;
|
||||
|
||||
bh = aio_bh_new(blk_get_aio_context(blk), error_callback_bh, acb);
|
||||
acb->bh = bh;
|
||||
qemu_bh_schedule(bh);
|
||||
|
||||
aio_bh_schedule_oneshot(blk_get_aio_context(blk), error_callback_bh, acb);
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
@ -926,7 +953,6 @@ typedef struct BlkAioEmAIOCB {
|
||||
BlkRwCo rwco;
|
||||
int bytes;
|
||||
bool has_returned;
|
||||
QEMUBH* bh;
|
||||
} BlkAioEmAIOCB;
|
||||
|
||||
static const AIOCBInfo blk_aio_em_aiocb_info = {
|
||||
@ -935,10 +961,6 @@ static const AIOCBInfo blk_aio_em_aiocb_info = {
|
||||
|
||||
static void blk_aio_complete(BlkAioEmAIOCB *acb)
|
||||
{
|
||||
if (acb->bh) {
|
||||
assert(acb->has_returned);
|
||||
qemu_bh_delete(acb->bh);
|
||||
}
|
||||
if (acb->has_returned) {
|
||||
acb->common.cb(acb->common.opaque, acb->rwco.ret);
|
||||
qemu_aio_unref(acb);
|
||||
@ -947,7 +969,10 @@ static void blk_aio_complete(BlkAioEmAIOCB *acb)
|
||||
|
||||
static void blk_aio_complete_bh(void *opaque)
|
||||
{
|
||||
blk_aio_complete(opaque);
|
||||
BlkAioEmAIOCB *acb = opaque;
|
||||
|
||||
assert(acb->has_returned);
|
||||
blk_aio_complete(acb);
|
||||
}
|
||||
|
||||
static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
||||
@ -967,7 +992,6 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
||||
.ret = NOT_DONE,
|
||||
};
|
||||
acb->bytes = bytes;
|
||||
acb->bh = NULL;
|
||||
acb->has_returned = false;
|
||||
|
||||
co = qemu_coroutine_create(co_entry, acb);
|
||||
@ -975,8 +999,8 @@ static BlockAIOCB *blk_aio_prwv(BlockBackend *blk, int64_t offset, int bytes,
|
||||
|
||||
acb->has_returned = true;
|
||||
if (acb->rwco.ret != NOT_DONE) {
|
||||
acb->bh = aio_bh_new(blk_get_aio_context(blk), blk_aio_complete_bh, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(blk_get_aio_context(blk),
|
||||
blk_aio_complete_bh, acb);
|
||||
}
|
||||
|
||||
return &acb->common;
|
||||
@ -1206,8 +1230,9 @@ static void send_qmp_error_event(BlockBackend *blk,
|
||||
IoOperationType optype;
|
||||
|
||||
optype = is_read ? IO_OPERATION_TYPE_READ : IO_OPERATION_TYPE_WRITE;
|
||||
qapi_event_send_block_io_error(blk_name(blk), optype, action,
|
||||
blk_iostatus_is_enabled(blk),
|
||||
qapi_event_send_block_io_error(blk_name(blk),
|
||||
bdrv_get_node_name(blk_bs(blk)), optype,
|
||||
action, blk_iostatus_is_enabled(blk),
|
||||
error == ENOSPC, strerror(error),
|
||||
&error_abort);
|
||||
}
|
||||
@ -1312,9 +1337,19 @@ void blk_lock_medium(BlockBackend *blk, bool locked)
|
||||
void blk_eject(BlockBackend *blk, bool eject_flag)
|
||||
{
|
||||
BlockDriverState *bs = blk_bs(blk);
|
||||
char *id;
|
||||
|
||||
/* blk_eject is only called by qdevified devices */
|
||||
assert(!blk->legacy_dev);
|
||||
|
||||
if (bs) {
|
||||
bdrv_eject(bs, eject_flag);
|
||||
|
||||
id = blk_get_attached_dev_id(blk);
|
||||
qapi_event_send_device_tray_moved(blk_name(blk), id,
|
||||
eject_flag, &error_abort);
|
||||
g_free(id);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,6 @@ struct BDRVCURLState;
|
||||
|
||||
typedef struct CURLAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
QEMUIOVector *qiov;
|
||||
|
||||
int64_t sector_num;
|
||||
@ -739,9 +738,6 @@ static void curl_readv_bh_cb(void *p)
|
||||
CURLAIOCB *acb = p;
|
||||
BDRVCURLState *s = acb->common.bs->opaque;
|
||||
|
||||
qemu_bh_delete(acb->bh);
|
||||
acb->bh = NULL;
|
||||
|
||||
size_t start = acb->sector_num * SECTOR_SIZE;
|
||||
size_t end;
|
||||
|
||||
@ -805,8 +801,7 @@ static BlockAIOCB *curl_aio_readv(BlockDriverState *bs,
|
||||
acb->sector_num = sector_num;
|
||||
acb->nb_sectors = nb_sectors;
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), curl_readv_bh_cb, acb);
|
||||
return &acb->common;
|
||||
}
|
||||
|
||||
|
61
block/dmg-bz2.c
Normal file
61
block/dmg-bz2.c
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* DMG bzip2 uncompression
|
||||
*
|
||||
* Copyright (c) 2004 Johannes E. Schindelin
|
||||
* Copyright (c) 2016 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.
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "dmg.h"
|
||||
#include <bzlib.h>
|
||||
|
||||
static int dmg_uncompress_bz2_do(char *next_in, unsigned int avail_in,
|
||||
char *next_out, unsigned int avail_out)
|
||||
{
|
||||
int ret;
|
||||
uint64_t total_out;
|
||||
bz_stream bzstream = {};
|
||||
|
||||
ret = BZ2_bzDecompressInit(&bzstream, 0, 0);
|
||||
if (ret != BZ_OK) {
|
||||
return -1;
|
||||
}
|
||||
bzstream.next_in = next_in;
|
||||
bzstream.avail_in = avail_in;
|
||||
bzstream.next_out = next_out;
|
||||
bzstream.avail_out = avail_out;
|
||||
ret = BZ2_bzDecompress(&bzstream);
|
||||
total_out = ((uint64_t)bzstream.total_out_hi32 << 32) +
|
||||
bzstream.total_out_lo32;
|
||||
BZ2_bzDecompressEnd(&bzstream);
|
||||
if (ret != BZ_STREAM_END ||
|
||||
total_out != avail_out) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void dmg_bz2_init(void)
|
||||
{
|
||||
assert(!dmg_uncompress_bz2);
|
||||
dmg_uncompress_bz2 = dmg_uncompress_bz2_do;
|
||||
}
|
69
block/dmg.c
69
block/dmg.c
@ -28,10 +28,10 @@
|
||||
#include "qemu/bswap.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/module.h"
|
||||
#include <zlib.h>
|
||||
#ifdef CONFIG_BZIP2
|
||||
#include <bzlib.h>
|
||||
#endif
|
||||
#include "dmg.h"
|
||||
|
||||
int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
|
||||
char *next_out, unsigned int avail_out);
|
||||
|
||||
enum {
|
||||
/* Limit chunk sizes to prevent unreasonable amounts of memory being used
|
||||
@ -41,31 +41,6 @@ enum {
|
||||
DMG_SECTORCOUNTS_MAX = DMG_LENGTHS_MAX / 512,
|
||||
};
|
||||
|
||||
typedef struct BDRVDMGState {
|
||||
CoMutex lock;
|
||||
/* each chunk contains a certain number of sectors,
|
||||
* offsets[i] is the offset in the .dmg file,
|
||||
* lengths[i] is the length of the compressed chunk,
|
||||
* sectors[i] is the sector beginning at offsets[i],
|
||||
* sectorcounts[i] is the number of sectors in that chunk,
|
||||
* the sectors array is ordered
|
||||
* 0<=i<n_chunks */
|
||||
|
||||
uint32_t n_chunks;
|
||||
uint32_t* types;
|
||||
uint64_t* offsets;
|
||||
uint64_t* lengths;
|
||||
uint64_t* sectors;
|
||||
uint64_t* sectorcounts;
|
||||
uint32_t current_chunk;
|
||||
uint8_t *compressed_chunk;
|
||||
uint8_t *uncompressed_chunk;
|
||||
z_stream zstream;
|
||||
#ifdef CONFIG_BZIP2
|
||||
bz_stream bzstream;
|
||||
#endif
|
||||
} BDRVDMGState;
|
||||
|
||||
static int dmg_probe(const uint8_t *buf, int buf_size, const char *filename)
|
||||
{
|
||||
int len;
|
||||
@ -210,10 +185,9 @@ static bool dmg_is_known_block_type(uint32_t entry_type)
|
||||
case 0x00000001: /* uncompressed */
|
||||
case 0x00000002: /* zeroes */
|
||||
case 0x80000005: /* zlib */
|
||||
#ifdef CONFIG_BZIP2
|
||||
case 0x80000006: /* bzip2 */
|
||||
#endif
|
||||
return true;
|
||||
case 0x80000006: /* bzip2 */
|
||||
return !!dmg_uncompress_bz2;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@ -439,6 +413,7 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
|
||||
int64_t offset;
|
||||
int ret;
|
||||
|
||||
block_module_load_one("dmg-bz2");
|
||||
bs->read_only = true;
|
||||
|
||||
s->n_chunks = 0;
|
||||
@ -587,9 +562,6 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||
if (!is_sector_in_chunk(s, s->current_chunk, sector_num)) {
|
||||
int ret;
|
||||
uint32_t chunk = search_chunk(s, sector_num);
|
||||
#ifdef CONFIG_BZIP2
|
||||
uint64_t total_out;
|
||||
#endif
|
||||
|
||||
if (chunk >= s->n_chunks) {
|
||||
return -1;
|
||||
@ -620,8 +592,10 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||
return -1;
|
||||
}
|
||||
break; }
|
||||
#ifdef CONFIG_BZIP2
|
||||
case 0x80000006: /* bzip2 compressed */
|
||||
if (!dmg_uncompress_bz2) {
|
||||
break;
|
||||
}
|
||||
/* we need to buffer, because only the chunk as whole can be
|
||||
* inflated. */
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
@ -630,24 +604,15 @@ static inline int dmg_read_chunk(BlockDriverState *bs, uint64_t sector_num)
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = BZ2_bzDecompressInit(&s->bzstream, 0, 0);
|
||||
if (ret != BZ_OK) {
|
||||
return -1;
|
||||
}
|
||||
s->bzstream.next_in = (char *)s->compressed_chunk;
|
||||
s->bzstream.avail_in = (unsigned int) s->lengths[chunk];
|
||||
s->bzstream.next_out = (char *)s->uncompressed_chunk;
|
||||
s->bzstream.avail_out = (unsigned int) 512 * s->sectorcounts[chunk];
|
||||
ret = BZ2_bzDecompress(&s->bzstream);
|
||||
total_out = ((uint64_t)s->bzstream.total_out_hi32 << 32) +
|
||||
s->bzstream.total_out_lo32;
|
||||
BZ2_bzDecompressEnd(&s->bzstream);
|
||||
if (ret != BZ_STREAM_END ||
|
||||
total_out != 512 * s->sectorcounts[chunk]) {
|
||||
return -1;
|
||||
ret = dmg_uncompress_bz2((char *)s->compressed_chunk,
|
||||
(unsigned int) s->lengths[chunk],
|
||||
(char *)s->uncompressed_chunk,
|
||||
(unsigned int)
|
||||
(512 * s->sectorcounts[chunk]));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
#endif /* CONFIG_BZIP2 */
|
||||
case 1: /* copy */
|
||||
ret = bdrv_pread(bs->file, s->offsets[chunk],
|
||||
s->uncompressed_chunk, s->lengths[chunk]);
|
||||
|
59
block/dmg.h
Normal file
59
block/dmg.h
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Header for DMG driver
|
||||
*
|
||||
* Copyright (c) 2004-2006 Fabrice Bellard
|
||||
* Copyright (c) 2016 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 BLOCK_DMG_H
|
||||
#define BLOCK_DMG_H
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu-common.h"
|
||||
#include "block/block_int.h"
|
||||
#include <zlib.h>
|
||||
|
||||
typedef struct BDRVDMGState {
|
||||
CoMutex lock;
|
||||
/* each chunk contains a certain number of sectors,
|
||||
* offsets[i] is the offset in the .dmg file,
|
||||
* lengths[i] is the length of the compressed chunk,
|
||||
* sectors[i] is the sector beginning at offsets[i],
|
||||
* sectorcounts[i] is the number of sectors in that chunk,
|
||||
* the sectors array is ordered
|
||||
* 0<=i<n_chunks */
|
||||
|
||||
uint32_t n_chunks;
|
||||
uint32_t *types;
|
||||
uint64_t *offsets;
|
||||
uint64_t *lengths;
|
||||
uint64_t *sectors;
|
||||
uint64_t *sectorcounts;
|
||||
uint32_t current_chunk;
|
||||
uint8_t *compressed_chunk;
|
||||
uint8_t *uncompressed_chunk;
|
||||
z_stream zstream;
|
||||
} BDRVDMGState;
|
||||
|
||||
extern int (*dmg_uncompress_bz2)(char *next_in, unsigned int avail_in,
|
||||
char *next_out, unsigned int avail_out);
|
||||
|
||||
#endif
|
@ -38,7 +38,6 @@
|
||||
typedef struct GlusterAIOCB {
|
||||
int64_t size;
|
||||
int ret;
|
||||
QEMUBH *bh;
|
||||
Coroutine *coroutine;
|
||||
AioContext *aio_context;
|
||||
} GlusterAIOCB;
|
||||
@ -622,8 +621,6 @@ static void qemu_gluster_complete_aio(void *opaque)
|
||||
{
|
||||
GlusterAIOCB *acb = (GlusterAIOCB *)opaque;
|
||||
|
||||
qemu_bh_delete(acb->bh);
|
||||
acb->bh = NULL;
|
||||
qemu_coroutine_enter(acb->coroutine);
|
||||
}
|
||||
|
||||
@ -642,8 +639,7 @@ static void gluster_finish_aiocb(struct glfs_fd *fd, ssize_t ret, void *arg)
|
||||
acb->ret = -EIO; /* Partial read/write - fail it */
|
||||
}
|
||||
|
||||
acb->bh = aio_bh_new(acb->aio_context, qemu_gluster_complete_aio, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(acb->aio_context, qemu_gluster_complete_aio, acb);
|
||||
}
|
||||
|
||||
static void qemu_gluster_parse_flags(int bdrv_flags, int *open_flags)
|
||||
|
11
block/io.c
11
block/io.c
@ -171,7 +171,6 @@ static void bdrv_drain_recurse(BlockDriverState *bs)
|
||||
typedef struct {
|
||||
Coroutine *co;
|
||||
BlockDriverState *bs;
|
||||
QEMUBH *bh;
|
||||
bool done;
|
||||
} BdrvCoDrainData;
|
||||
|
||||
@ -191,7 +190,6 @@ static void bdrv_co_drain_bh_cb(void *opaque)
|
||||
BdrvCoDrainData *data = opaque;
|
||||
Coroutine *co = data->co;
|
||||
|
||||
qemu_bh_delete(data->bh);
|
||||
bdrv_drain_poll(data->bs);
|
||||
data->done = true;
|
||||
qemu_coroutine_enter(co);
|
||||
@ -210,9 +208,9 @@ static void coroutine_fn bdrv_co_yield_to_drain(BlockDriverState *bs)
|
||||
.co = qemu_coroutine_self(),
|
||||
.bs = bs,
|
||||
.done = false,
|
||||
.bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_drain_bh_cb, &data),
|
||||
};
|
||||
qemu_bh_schedule(data.bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs),
|
||||
bdrv_co_drain_bh_cb, &data);
|
||||
|
||||
qemu_coroutine_yield();
|
||||
/* If we are resumed from some other event (such as an aio completion or a
|
||||
@ -2095,7 +2093,6 @@ typedef struct BlockAIOCBCoroutine {
|
||||
bool is_write;
|
||||
bool need_bh;
|
||||
bool *done;
|
||||
QEMUBH* bh;
|
||||
} BlockAIOCBCoroutine;
|
||||
|
||||
static const AIOCBInfo bdrv_em_co_aiocb_info = {
|
||||
@ -2115,7 +2112,6 @@ static void bdrv_co_em_bh(void *opaque)
|
||||
BlockAIOCBCoroutine *acb = opaque;
|
||||
|
||||
assert(!acb->need_bh);
|
||||
qemu_bh_delete(acb->bh);
|
||||
bdrv_co_complete(acb);
|
||||
}
|
||||
|
||||
@ -2125,8 +2121,7 @@ static void bdrv_co_maybe_schedule_bh(BlockAIOCBCoroutine *acb)
|
||||
if (acb->req.error != -EINPROGRESS) {
|
||||
BlockDriverState *bs = acb->common.bs;
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), bdrv_co_em_bh, acb);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,6 @@ typedef struct IscsiTask {
|
||||
int do_retry;
|
||||
struct scsi_task *task;
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
IscsiLun *iscsilun;
|
||||
QEMUTimer retry_timer;
|
||||
int err_code;
|
||||
@ -167,7 +166,6 @@ static void iscsi_co_generic_bh_cb(void *opaque)
|
||||
{
|
||||
struct IscsiTask *iTask = opaque;
|
||||
iTask->complete = 1;
|
||||
qemu_bh_delete(iTask->bh);
|
||||
qemu_coroutine_enter(iTask->co);
|
||||
}
|
||||
|
||||
@ -299,9 +297,8 @@ iscsi_co_generic_cb(struct iscsi_context *iscsi, int status,
|
||||
|
||||
out:
|
||||
if (iTask->co) {
|
||||
iTask->bh = aio_bh_new(iTask->iscsilun->aio_context,
|
||||
iscsi_co_generic_bh_cb, iTask);
|
||||
qemu_bh_schedule(iTask->bh);
|
||||
aio_bh_schedule_oneshot(iTask->iscsilun->aio_context,
|
||||
iscsi_co_generic_bh_cb, iTask);
|
||||
} else {
|
||||
iTask->complete = 1;
|
||||
}
|
||||
|
@ -57,7 +57,6 @@ typedef struct NFSRPC {
|
||||
QEMUIOVector *iov;
|
||||
struct stat *st;
|
||||
Coroutine *co;
|
||||
QEMUBH *bh;
|
||||
NFSClient *client;
|
||||
} NFSRPC;
|
||||
|
||||
@ -103,7 +102,6 @@ static void nfs_co_generic_bh_cb(void *opaque)
|
||||
{
|
||||
NFSRPC *task = opaque;
|
||||
task->complete = 1;
|
||||
qemu_bh_delete(task->bh);
|
||||
qemu_coroutine_enter(task->co);
|
||||
}
|
||||
|
||||
@ -127,9 +125,8 @@ nfs_co_generic_cb(int ret, struct nfs_context *nfs, void *data,
|
||||
error_report("NFS Error: %s", nfs_get_error(nfs));
|
||||
}
|
||||
if (task->co) {
|
||||
task->bh = aio_bh_new(task->client->aio_context,
|
||||
nfs_co_generic_bh_cb, task);
|
||||
qemu_bh_schedule(task->bh);
|
||||
aio_bh_schedule_oneshot(task->client->aio_context,
|
||||
nfs_co_generic_bh_cb, task);
|
||||
} else {
|
||||
task->complete = 1;
|
||||
}
|
||||
|
@ -124,7 +124,6 @@ static coroutine_fn int null_co_flush(BlockDriverState *bs)
|
||||
|
||||
typedef struct {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
QEMUTimer timer;
|
||||
} NullAIOCB;
|
||||
|
||||
@ -136,7 +135,6 @@ static void null_bh_cb(void *opaque)
|
||||
{
|
||||
NullAIOCB *acb = opaque;
|
||||
acb->common.cb(acb->common.opaque, 0);
|
||||
qemu_bh_delete(acb->bh);
|
||||
qemu_aio_unref(acb);
|
||||
}
|
||||
|
||||
@ -164,8 +162,7 @@ static inline BlockAIOCB *null_aio_common(BlockDriverState *bs,
|
||||
timer_mod_ns(&acb->timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_REALTIME) + s->latency_ns);
|
||||
} else {
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(bs), null_bh_cb, acb);
|
||||
}
|
||||
return &acb->common;
|
||||
}
|
||||
|
@ -909,7 +909,6 @@ static void qed_aio_complete_bh(void *opaque)
|
||||
void *user_opaque = acb->common.opaque;
|
||||
int ret = acb->bh_ret;
|
||||
|
||||
qemu_bh_delete(acb->bh);
|
||||
qemu_aio_unref(acb);
|
||||
|
||||
/* Invoke callback */
|
||||
@ -934,9 +933,8 @@ static void qed_aio_complete(QEDAIOCB *acb, int ret)
|
||||
|
||||
/* Arrange for a bh to invoke the completion function */
|
||||
acb->bh_ret = ret;
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
||||
qed_aio_complete_bh, acb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||
qed_aio_complete_bh, acb);
|
||||
|
||||
/* Start next allocating write request waiting behind this one. Note that
|
||||
* requests enqueue themselves when they first hit an unallocated cluster
|
||||
|
@ -130,7 +130,6 @@ enum {
|
||||
|
||||
typedef struct QEDAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int bh_ret; /* final return status for completion bh */
|
||||
QSIMPLEQ_ENTRY(QEDAIOCB) next; /* next request */
|
||||
int flags; /* QED_AIOCB_* bits ORed together */
|
||||
|
@ -71,7 +71,6 @@ typedef enum {
|
||||
|
||||
typedef struct RBDAIOCB {
|
||||
BlockAIOCB common;
|
||||
QEMUBH *bh;
|
||||
int64_t ret;
|
||||
QEMUIOVector *qiov;
|
||||
char *bounce;
|
||||
@ -602,7 +601,6 @@ static const AIOCBInfo rbd_aiocb_info = {
|
||||
static void rbd_finish_bh(void *opaque)
|
||||
{
|
||||
RADOSCB *rcb = opaque;
|
||||
qemu_bh_delete(rcb->acb->bh);
|
||||
qemu_rbd_complete_aio(rcb);
|
||||
}
|
||||
|
||||
@ -621,9 +619,8 @@ static void rbd_finish_aiocb(rbd_completion_t c, RADOSCB *rcb)
|
||||
rcb->ret = rbd_aio_get_return_value(c);
|
||||
rbd_aio_release(c);
|
||||
|
||||
acb->bh = aio_bh_new(bdrv_get_aio_context(acb->common.bs),
|
||||
rbd_finish_bh, rcb);
|
||||
qemu_bh_schedule(acb->bh);
|
||||
aio_bh_schedule_oneshot(bdrv_get_aio_context(acb->common.bs),
|
||||
rbd_finish_bh, rcb);
|
||||
}
|
||||
|
||||
static int rbd_aio_discard_wrapper(rbd_image_t image,
|
||||
@ -679,7 +676,6 @@ static BlockAIOCB *rbd_start_aio(BlockDriverState *bs,
|
||||
acb->ret = 0;
|
||||
acb->error = 0;
|
||||
acb->s = s;
|
||||
acb->bh = NULL;
|
||||
|
||||
if (cmd == RBD_AIO_WRITE) {
|
||||
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
|
||||
|
@ -76,8 +76,7 @@ static int coroutine_fn before_write_notify(NotifierWithReturn *notifier,
|
||||
static void write_threshold_register_notifier(BlockDriverState *bs)
|
||||
{
|
||||
bs->write_threshold_notifier.notify = before_write_notify;
|
||||
notifier_with_return_list_add(&bs->before_write_notifiers,
|
||||
&bs->write_threshold_notifier);
|
||||
bdrv_add_before_write_notifier(bs, &bs->write_threshold_notifier);
|
||||
}
|
||||
|
||||
static void write_threshold_update(BlockDriverState *bs,
|
||||
|
@ -588,7 +588,6 @@ BlockErrorAction block_job_error_action(BlockJob *job, BlockdevOnError on_err,
|
||||
|
||||
typedef struct {
|
||||
BlockJob *job;
|
||||
QEMUBH *bh;
|
||||
AioContext *aio_context;
|
||||
BlockJobDeferToMainLoopFn *fn;
|
||||
void *opaque;
|
||||
@ -599,8 +598,6 @@ static void block_job_defer_to_main_loop_bh(void *opaque)
|
||||
BlockJobDeferToMainLoopData *data = opaque;
|
||||
AioContext *aio_context;
|
||||
|
||||
qemu_bh_delete(data->bh);
|
||||
|
||||
/* Prevent race with block_job_defer_to_main_loop() */
|
||||
aio_context_acquire(data->aio_context);
|
||||
|
||||
@ -624,13 +621,13 @@ void block_job_defer_to_main_loop(BlockJob *job,
|
||||
{
|
||||
BlockJobDeferToMainLoopData *data = g_malloc(sizeof(*data));
|
||||
data->job = job;
|
||||
data->bh = qemu_bh_new(block_job_defer_to_main_loop_bh, data);
|
||||
data->aio_context = blk_get_aio_context(job->blk);
|
||||
data->fn = fn;
|
||||
data->opaque = opaque;
|
||||
job->deferred_to_main_loop = true;
|
||||
|
||||
qemu_bh_schedule(data->bh);
|
||||
aio_bh_schedule_oneshot(qemu_get_aio_context(),
|
||||
block_job_defer_to_main_loop_bh, data);
|
||||
}
|
||||
|
||||
BlockJobTxn *block_job_txn_new(void)
|
||||
|
@ -3239,6 +3239,7 @@ Example:
|
||||
"microseconds": 716996 },
|
||||
"event": "DEVICE_TRAY_MOVED",
|
||||
"data": { "device": "ide1-cd0",
|
||||
"id": "ide0-1-0",
|
||||
"tray-open": true } }
|
||||
|
||||
<- { "return": {} }
|
||||
@ -3267,6 +3268,7 @@ Example:
|
||||
"microseconds": 272147 },
|
||||
"event": "DEVICE_TRAY_MOVED",
|
||||
"data": { "device": "ide1-cd0",
|
||||
"id": "ide0-1-0",
|
||||
"tray-open": false } }
|
||||
|
||||
<- { "return": {} }
|
||||
@ -3303,6 +3305,7 @@ Example:
|
||||
"microseconds": 549958 },
|
||||
"event": "DEVICE_TRAY_MOVED",
|
||||
"data": { "device": "ide1-cd0",
|
||||
"id": "ide0-1-0",
|
||||
"tray-open": true } }
|
||||
|
||||
<- { "return": {} }
|
||||
|
@ -65,7 +65,12 @@ Emitted when a disk I/O error occurs.
|
||||
|
||||
Data:
|
||||
|
||||
- "device": device name (json-string)
|
||||
- "device": device name. This is always present for compatibility
|
||||
reasons, but it can be empty ("") if the image does not
|
||||
have a device name associated. (json-string)
|
||||
- "node-name": node name. Note that errors may be reported for the root node
|
||||
that is directly attached to a guest device rather than for the
|
||||
node where the error occurred. (json-string)
|
||||
- "operation": I/O operation (json-string, "read" or "write")
|
||||
- "action": action that has been taken, it's one of the following (json-string):
|
||||
"ignore": error has been ignored
|
||||
@ -76,6 +81,7 @@ Example:
|
||||
|
||||
{ "event": "BLOCK_IO_ERROR",
|
||||
"data": { "device": "ide0-hd1",
|
||||
"node-name": "#block212",
|
||||
"operation": "write",
|
||||
"action": "stop" },
|
||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
@ -214,12 +220,16 @@ or by HMP/QMP commands.
|
||||
|
||||
Data:
|
||||
|
||||
- "device": device name (json-string)
|
||||
- "device": Block device name. This is always present for compatibility
|
||||
reasons, but it can be empty ("") if the image does not have a
|
||||
device name associated. (json-string)
|
||||
- "id": The name or QOM path of the guest device (json-string)
|
||||
- "tray-open": true if the tray has been opened or false if it has been closed
|
||||
(json-bool)
|
||||
|
||||
{ "event": "DEVICE_TRAY_MOVED",
|
||||
"data": { "device": "ide1-cd0",
|
||||
"id": "/machine/unattached/device[22]",
|
||||
"tray-open": true
|
||||
},
|
||||
"timestamp": { "seconds": 1265044230, "microseconds": 450486 } }
|
||||
|
@ -1079,7 +1079,7 @@ static int blk_connect(struct XenDevice *xendev)
|
||||
* so we can blk_unref() unconditionally */
|
||||
blk_ref(blkdev->blk);
|
||||
}
|
||||
blk_attach_dev_nofail(blkdev->blk, blkdev);
|
||||
blk_attach_dev_legacy(blkdev->blk, blkdev);
|
||||
blkdev->file_size = blk_getlength(blkdev->blk);
|
||||
if (blkdev->file_size < 0) {
|
||||
BlockDriverState *bs = blk_bs(blkdev->blk);
|
||||
|
@ -180,6 +180,12 @@ void aio_context_acquire(AioContext *ctx);
|
||||
/* Relinquish ownership of the AioContext. */
|
||||
void aio_context_release(AioContext *ctx);
|
||||
|
||||
/**
|
||||
* aio_bh_schedule_oneshot: Allocate a new bottom half structure that will run
|
||||
* only once and as soon as possible.
|
||||
*/
|
||||
void aio_bh_schedule_oneshot(AioContext *ctx, QEMUBHFunc *cb, void *opaque);
|
||||
|
||||
/**
|
||||
* aio_bh_new: Allocate a new bottom half structure.
|
||||
*
|
||||
|
@ -107,8 +107,8 @@ BlockDeviceIoStatus blk_iostatus(const BlockBackend *blk);
|
||||
void blk_iostatus_disable(BlockBackend *blk);
|
||||
void blk_iostatus_reset(BlockBackend *blk);
|
||||
void blk_iostatus_set_err(BlockBackend *blk, int error);
|
||||
int blk_attach_dev(BlockBackend *blk, void *dev);
|
||||
void blk_attach_dev_nofail(BlockBackend *blk, void *dev);
|
||||
int blk_attach_dev(BlockBackend *blk, DeviceState *dev);
|
||||
void blk_attach_dev_legacy(BlockBackend *blk, void *dev);
|
||||
void blk_detach_dev(BlockBackend *blk, void *dev);
|
||||
void *blk_get_attached_dev(BlockBackend *blk);
|
||||
BlockBackend *blk_by_dev(void *dev);
|
||||
|
@ -235,6 +235,7 @@ bool defaults_enabled(void);
|
||||
extern QemuOptsList qemu_legacy_drive_opts;
|
||||
extern QemuOptsList qemu_common_drive_opts;
|
||||
extern QemuOptsList qemu_drive_opts;
|
||||
extern QemuOptsList bdrv_runtime_opts;
|
||||
extern QemuOptsList qemu_chardev_opts;
|
||||
extern QemuOptsList qemu_device_opts;
|
||||
extern QemuOptsList qemu_netdev_opts;
|
||||
|
@ -2540,7 +2540,13 @@
|
||||
#
|
||||
# Emitted when a disk I/O error occurs
|
||||
#
|
||||
# @device: device name
|
||||
# @device: device name. This is always present for compatibility
|
||||
# reasons, but it can be empty ("") if the image does not
|
||||
# have a device name associated.
|
||||
#
|
||||
# @node-name: node name. Note that errors may be reported for the root node
|
||||
# that is directly attached to a guest device rather than for the
|
||||
# node where the error occurred. (Since: 2.8)
|
||||
#
|
||||
# @operation: I/O operation
|
||||
#
|
||||
@ -2561,7 +2567,7 @@
|
||||
# Since: 0.13.0
|
||||
##
|
||||
{ 'event': 'BLOCK_IO_ERROR',
|
||||
'data': { 'device': 'str', 'operation': 'IoOperationType',
|
||||
'data': { 'device': 'str', 'node-name': 'str', 'operation': 'IoOperationType',
|
||||
'action': 'BlockErrorAction', '*nospace': 'bool',
|
||||
'reason': 'str' } }
|
||||
|
||||
|
@ -195,14 +195,18 @@
|
||||
# Emitted whenever the tray of a removable device is moved by the guest or by
|
||||
# HMP/QMP commands
|
||||
#
|
||||
# @device: device name
|
||||
# @device: Block device name. This is always present for compatibility
|
||||
# reasons, but it can be empty ("") if the image does not
|
||||
# have a device name associated.
|
||||
#
|
||||
# @id: The name or QOM path of the guest device
|
||||
#
|
||||
# @tray-open: true if the tray has been opened or false if it has been closed
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'event': 'DEVICE_TRAY_MOVED',
|
||||
'data': { 'device': 'str', 'tray-open': 'bool' } }
|
||||
'data': { 'device': 'str', 'id': 'str', 'tray-open': 'bool' } }
|
||||
|
||||
##
|
||||
# @QuorumOpType
|
||||
|
@ -37,7 +37,6 @@ def add_module(fheader, library, format_name, protocol_name):
|
||||
def process_file(fheader, filename):
|
||||
# This parser assumes the coding style rules are being followed
|
||||
with open(filename, "r") as cfile:
|
||||
found_something = False
|
||||
found_start = False
|
||||
library, _ = os.path.splitext(os.path.basename(filename))
|
||||
for line in cfile:
|
||||
@ -51,16 +50,10 @@ def process_file(fheader, filename):
|
||||
add_module(fheader, library, format_name, protocol_name)
|
||||
found_start = False
|
||||
elif line.find("static BlockDriver") != -1:
|
||||
found_something = True
|
||||
found_start = True
|
||||
format_name = ""
|
||||
protocol_name = ""
|
||||
|
||||
if not found_something:
|
||||
print("No BlockDriver struct found in " + filename + ". \
|
||||
Is this really a module?", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def print_top(fheader):
|
||||
fheader.write('''/* AUTOMATICALLY GENERATED, DO NOT MODIFY */
|
||||
/*
|
||||
|
@ -163,14 +163,28 @@ void module_load_one(const char *prefix, const char *lib_name)
|
||||
char *fname = NULL;
|
||||
char *exec_dir;
|
||||
char *dirs[3];
|
||||
char *module_name;
|
||||
int i = 0;
|
||||
int ret;
|
||||
static GHashTable *loaded_modules;
|
||||
|
||||
if (!g_module_supported()) {
|
||||
fprintf(stderr, "Module is not supported by system.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!loaded_modules) {
|
||||
loaded_modules = g_hash_table_new(g_str_hash, g_str_equal);
|
||||
}
|
||||
|
||||
module_name = g_strdup_printf("%s%s", prefix, lib_name);
|
||||
|
||||
if (g_hash_table_lookup(loaded_modules, module_name)) {
|
||||
g_free(module_name);
|
||||
return;
|
||||
}
|
||||
g_hash_table_insert(loaded_modules, module_name, module_name);
|
||||
|
||||
exec_dir = qemu_get_exec_dir();
|
||||
dirs[i++] = g_strdup_printf("%s", CONFIG_QEMU_MODDIR);
|
||||
dirs[i++] = g_strdup_printf("%s/..", exec_dir ? : "");
|
||||
@ -180,8 +194,8 @@ void module_load_one(const char *prefix, const char *lib_name)
|
||||
exec_dir = NULL;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dirs); i++) {
|
||||
fname = g_strdup_printf("%s/%s%s%s",
|
||||
dirs[i], prefix, lib_name, HOST_DSOSUF);
|
||||
fname = g_strdup_printf("%s/%s%s",
|
||||
dirs[i], module_name, HOST_DSOSUF);
|
||||
ret = module_load_file(fname);
|
||||
g_free(fname);
|
||||
fname = NULL;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "qmp-commands.h"
|
||||
|
||||
static QemuOptsList *vm_config_groups[48];
|
||||
static QemuOptsList *drive_config_groups[4];
|
||||
static QemuOptsList *drive_config_groups[5];
|
||||
|
||||
static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
|
||||
Error **errp)
|
||||
|
1
vl.c
1
vl.c
@ -3039,6 +3039,7 @@ int main(int argc, char **argv, char **envp)
|
||||
qemu_add_drive_opts(&qemu_legacy_drive_opts);
|
||||
qemu_add_drive_opts(&qemu_common_drive_opts);
|
||||
qemu_add_drive_opts(&qemu_drive_opts);
|
||||
qemu_add_drive_opts(&bdrv_runtime_opts);
|
||||
qemu_add_opts(&qemu_chardev_opts);
|
||||
qemu_add_opts(&qemu_device_opts);
|
||||
qemu_add_opts(&qemu_netdev_opts);
|
||||
|
Loading…
Reference in New Issue
Block a user