Block pull request
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJTupIoAAoJEJykq7OBq3PIwWMIAJQ91tz0Rs29maKfU08hXL47 2lOOtU53Y8q65ZRCa4x/9RVybXsemrGiIm4vB5zztOOXQiLjYsUYOBPV9FzN3cgX /gZQXWCRQ0TpISoLOmACn4KlW8A90acULYYaJ7B3N7x4SgaRd+Np+O/IhdgA++mo tQ+/uTBGpbQXH5xSK8H+4+AwvVRgDbLhGqy6ZmZmyE/KqqYNf6Y7Y04n0lLGzV6c UrI4K57sTYyOQJY4XCAPTwIvEdQ10usGyRcEQPvdP7zkBIz5TKkPUtKUAPuFJhij hO+bF+nRgS/4gQr2teY9DLIiEZEhs7hgQnW1O7ByZlBBH/spmh19Mh0G6PUpB2w= =fF3v -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/stefanha/tags/block-pull-request' into staging Block pull request # gpg: Signature made Mon 07 Jul 2014 13:27:20 BST using RSA key ID 81AB73C8 # gpg: Good signature from "Stefan Hajnoczi <stefanha@redhat.com>" # gpg: aka "Stefan Hajnoczi <stefanha@gmail.com>" * remotes/stefanha/tags/block-pull-request: qmp: show QOM properties in device-list-properties dataplane: submit I/O as a batch linux-aio: implement io plug, unplug and flush io queue block: block: introduce APIs for submitting IO as a batch ahci: map memory via device's address space instead of address_space_memory raw-posix: Fix raw_getlength() to always return -errno on error qemu-iotests: Disable Quorum testing in 041 when Quorum is not builtin ahci.c: mask unused flags when reading size PRDT DBC MAINTAINERS: add Stefan Hajnoczi to IDE maintainers mirror: Fix qiov size for short requests Fix nocow typos in manpage Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
9540d1f8d9
@ -563,6 +563,7 @@ Devices
|
|||||||
-------
|
-------
|
||||||
IDE
|
IDE
|
||||||
M: Kevin Wolf <kwolf@redhat.com>
|
M: Kevin Wolf <kwolf@redhat.com>
|
||||||
|
M: Stefan Hajnoczi <stefanha@redhat.com>
|
||||||
S: Odd Fixes
|
S: Odd Fixes
|
||||||
F: include/hw/ide.h
|
F: include/hw/ide.h
|
||||||
F: hw/ide/
|
F: hw/ide/
|
||||||
|
31
block.c
31
block.c
@ -1905,6 +1905,7 @@ void bdrv_drain_all(void)
|
|||||||
bool bs_busy;
|
bool bs_busy;
|
||||||
|
|
||||||
aio_context_acquire(aio_context);
|
aio_context_acquire(aio_context);
|
||||||
|
bdrv_flush_io_queue(bs);
|
||||||
bdrv_start_throttled_reqs(bs);
|
bdrv_start_throttled_reqs(bs);
|
||||||
bs_busy = bdrv_requests_pending(bs);
|
bs_busy = bdrv_requests_pending(bs);
|
||||||
bs_busy |= aio_poll(aio_context, bs_busy);
|
bs_busy |= aio_poll(aio_context, bs_busy);
|
||||||
@ -5782,3 +5783,33 @@ BlockDriverState *check_to_replace_node(const char *node_name, Error **errp)
|
|||||||
|
|
||||||
return to_replace_bs;
|
return to_replace_bs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void bdrv_io_plug(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BlockDriver *drv = bs->drv;
|
||||||
|
if (drv && drv->bdrv_io_plug) {
|
||||||
|
drv->bdrv_io_plug(bs);
|
||||||
|
} else if (bs->file) {
|
||||||
|
bdrv_io_plug(bs->file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_io_unplug(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BlockDriver *drv = bs->drv;
|
||||||
|
if (drv && drv->bdrv_io_unplug) {
|
||||||
|
drv->bdrv_io_unplug(bs);
|
||||||
|
} else if (bs->file) {
|
||||||
|
bdrv_io_unplug(bs->file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void bdrv_flush_io_queue(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
BlockDriver *drv = bs->drv;
|
||||||
|
if (drv && drv->bdrv_flush_io_queue) {
|
||||||
|
drv->bdrv_flush_io_queue(bs);
|
||||||
|
} else if (bs->file) {
|
||||||
|
bdrv_flush_io_queue(bs->file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -25,6 +25,8 @@
|
|||||||
*/
|
*/
|
||||||
#define MAX_EVENTS 128
|
#define MAX_EVENTS 128
|
||||||
|
|
||||||
|
#define MAX_QUEUED_IO 128
|
||||||
|
|
||||||
struct qemu_laiocb {
|
struct qemu_laiocb {
|
||||||
BlockDriverAIOCB common;
|
BlockDriverAIOCB common;
|
||||||
struct qemu_laio_state *ctx;
|
struct qemu_laio_state *ctx;
|
||||||
@ -36,9 +38,19 @@ struct qemu_laiocb {
|
|||||||
QLIST_ENTRY(qemu_laiocb) node;
|
QLIST_ENTRY(qemu_laiocb) node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct iocb *iocbs[MAX_QUEUED_IO];
|
||||||
|
int plugged;
|
||||||
|
unsigned int size;
|
||||||
|
unsigned int idx;
|
||||||
|
} LaioQueue;
|
||||||
|
|
||||||
struct qemu_laio_state {
|
struct qemu_laio_state {
|
||||||
io_context_t ctx;
|
io_context_t ctx;
|
||||||
EventNotifier e;
|
EventNotifier e;
|
||||||
|
|
||||||
|
/* io queue for submit at batch */
|
||||||
|
LaioQueue io_q;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline ssize_t io_event_ret(struct io_event *ev)
|
static inline ssize_t io_event_ret(struct io_event *ev)
|
||||||
@ -135,6 +147,79 @@ static const AIOCBInfo laio_aiocb_info = {
|
|||||||
.cancel = laio_cancel,
|
.cancel = laio_cancel,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void ioq_init(LaioQueue *io_q)
|
||||||
|
{
|
||||||
|
io_q->size = MAX_QUEUED_IO;
|
||||||
|
io_q->idx = 0;
|
||||||
|
io_q->plugged = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioq_submit(struct qemu_laio_state *s)
|
||||||
|
{
|
||||||
|
int ret, i = 0;
|
||||||
|
int len = s->io_q.idx;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret = io_submit(s->ctx, len, s->io_q.iocbs);
|
||||||
|
} while (i++ < 3 && ret == -EAGAIN);
|
||||||
|
|
||||||
|
/* empty io queue */
|
||||||
|
s->io_q.idx = 0;
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
i = 0;
|
||||||
|
} else {
|
||||||
|
i = ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < len; i++) {
|
||||||
|
struct qemu_laiocb *laiocb =
|
||||||
|
container_of(s->io_q.iocbs[i], struct qemu_laiocb, iocb);
|
||||||
|
|
||||||
|
laiocb->ret = (ret < 0) ? ret : -EIO;
|
||||||
|
qemu_laio_process_completion(s, laiocb);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ioq_enqueue(struct qemu_laio_state *s, struct iocb *iocb)
|
||||||
|
{
|
||||||
|
unsigned int idx = s->io_q.idx;
|
||||||
|
|
||||||
|
s->io_q.iocbs[idx++] = iocb;
|
||||||
|
s->io_q.idx = idx;
|
||||||
|
|
||||||
|
/* submit immediately if queue is full */
|
||||||
|
if (idx == s->io_q.size) {
|
||||||
|
ioq_submit(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void laio_io_plug(BlockDriverState *bs, void *aio_ctx)
|
||||||
|
{
|
||||||
|
struct qemu_laio_state *s = aio_ctx;
|
||||||
|
|
||||||
|
s->io_q.plugged++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug)
|
||||||
|
{
|
||||||
|
struct qemu_laio_state *s = aio_ctx;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
assert(s->io_q.plugged > 0 || !unplug);
|
||||||
|
|
||||||
|
if (unplug && --s->io_q.plugged > 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s->io_q.idx > 0) {
|
||||||
|
ret = ioq_submit(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
BlockDriverCompletionFunc *cb, void *opaque, int type)
|
||||||
@ -168,8 +253,13 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||||||
}
|
}
|
||||||
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
io_set_eventfd(&laiocb->iocb, event_notifier_get_fd(&s->e));
|
||||||
|
|
||||||
if (io_submit(s->ctx, 1, &iocbs) < 0)
|
if (!s->io_q.plugged) {
|
||||||
goto out_free_aiocb;
|
if (io_submit(s->ctx, 1, &iocbs) < 0) {
|
||||||
|
goto out_free_aiocb;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ioq_enqueue(s, iocbs);
|
||||||
|
}
|
||||||
return &laiocb->common;
|
return &laiocb->common;
|
||||||
|
|
||||||
out_free_aiocb:
|
out_free_aiocb:
|
||||||
@ -204,6 +294,8 @@ void *laio_init(void)
|
|||||||
goto out_close_efd;
|
goto out_close_efd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ioq_init(&s->io_q);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
|
|
||||||
out_close_efd:
|
out_close_efd:
|
||||||
|
@ -265,9 +265,11 @@ static uint64_t coroutine_fn mirror_iteration(MirrorBlockJob *s)
|
|||||||
next_sector = sector_num;
|
next_sector = sector_num;
|
||||||
while (nb_chunks-- > 0) {
|
while (nb_chunks-- > 0) {
|
||||||
MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free);
|
MirrorBuffer *buf = QSIMPLEQ_FIRST(&s->buf_free);
|
||||||
|
size_t remaining = (nb_sectors * BDRV_SECTOR_SIZE) - op->qiov.size;
|
||||||
|
|
||||||
QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next);
|
QSIMPLEQ_REMOVE_HEAD(&s->buf_free, next);
|
||||||
s->buf_free_count--;
|
s->buf_free_count--;
|
||||||
qemu_iovec_add(&op->qiov, buf, s->granularity);
|
qemu_iovec_add(&op->qiov, buf, MIN(s->granularity, remaining));
|
||||||
|
|
||||||
/* Advance the HBitmapIter in parallel, so that we do not examine
|
/* Advance the HBitmapIter in parallel, so that we do not examine
|
||||||
* the same sector twice.
|
* the same sector twice.
|
||||||
|
@ -40,6 +40,8 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
|
|||||||
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
BlockDriverCompletionFunc *cb, void *opaque, int type);
|
||||||
void laio_detach_aio_context(void *s, AioContext *old_context);
|
void laio_detach_aio_context(void *s, AioContext *old_context);
|
||||||
void laio_attach_aio_context(void *s, AioContext *new_context);
|
void laio_attach_aio_context(void *s, AioContext *new_context);
|
||||||
|
void laio_io_plug(BlockDriverState *bs, void *aio_ctx);
|
||||||
|
int laio_io_unplug(BlockDriverState *bs, void *aio_ctx, bool unplug);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -1057,6 +1057,36 @@ static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
|
|||||||
cb, opaque, type);
|
cb, opaque, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void raw_aio_plug(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_LINUX_AIO
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
if (s->use_aio) {
|
||||||
|
laio_io_plug(bs, s->aio_ctx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raw_aio_unplug(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_LINUX_AIO
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
if (s->use_aio) {
|
||||||
|
laio_io_unplug(bs, s->aio_ctx, true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void raw_aio_flush_io_queue(BlockDriverState *bs)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_LINUX_AIO
|
||||||
|
BDRVRawState *s = bs->opaque;
|
||||||
|
if (s->use_aio) {
|
||||||
|
laio_io_unplug(bs, s->aio_ctx, false);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
|
||||||
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
|
||||||
BlockDriverCompletionFunc *cb, void *opaque)
|
BlockDriverCompletionFunc *cb, void *opaque)
|
||||||
@ -1133,12 +1163,12 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (fstat(fd, &st))
|
if (fstat(fd, &st))
|
||||||
return -1;
|
return -errno;
|
||||||
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
|
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
|
||||||
struct disklabel dl;
|
struct disklabel dl;
|
||||||
|
|
||||||
if (ioctl(fd, DIOCGDINFO, &dl))
|
if (ioctl(fd, DIOCGDINFO, &dl))
|
||||||
return -1;
|
return -errno;
|
||||||
return (uint64_t)dl.d_secsize *
|
return (uint64_t)dl.d_secsize *
|
||||||
dl.d_partitions[DISKPART(st.st_rdev)].p_size;
|
dl.d_partitions[DISKPART(st.st_rdev)].p_size;
|
||||||
} else
|
} else
|
||||||
@ -1152,7 +1182,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
||||||
if (fstat(fd, &st))
|
if (fstat(fd, &st))
|
||||||
return -1;
|
return -errno;
|
||||||
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
|
if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
|
||||||
struct dkwedge_info dkw;
|
struct dkwedge_info dkw;
|
||||||
|
|
||||||
@ -1162,7 +1192,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||||||
struct disklabel dl;
|
struct disklabel dl;
|
||||||
|
|
||||||
if (ioctl(fd, DIOCGDINFO, &dl))
|
if (ioctl(fd, DIOCGDINFO, &dl))
|
||||||
return -1;
|
return -errno;
|
||||||
return (uint64_t)dl.d_secsize *
|
return (uint64_t)dl.d_secsize *
|
||||||
dl.d_partitions[DISKPART(st.st_rdev)].p_size;
|
dl.d_partitions[DISKPART(st.st_rdev)].p_size;
|
||||||
}
|
}
|
||||||
@ -1175,6 +1205,7 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
struct dk_minfo minfo;
|
struct dk_minfo minfo;
|
||||||
int ret;
|
int ret;
|
||||||
|
int64_t size;
|
||||||
|
|
||||||
ret = fd_open(bs);
|
ret = fd_open(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -1193,7 +1224,11 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||||||
* There are reports that lseek on some devices fails, but
|
* There are reports that lseek on some devices fails, but
|
||||||
* irc discussion said that contingency on contingency was overkill.
|
* irc discussion said that contingency on contingency was overkill.
|
||||||
*/
|
*/
|
||||||
return lseek(s->fd, 0, SEEK_END);
|
size = lseek(s->fd, 0, SEEK_END);
|
||||||
|
if (size < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
#elif defined(CONFIG_BSD)
|
#elif defined(CONFIG_BSD)
|
||||||
static int64_t raw_getlength(BlockDriverState *bs)
|
static int64_t raw_getlength(BlockDriverState *bs)
|
||||||
@ -1231,6 +1266,9 @@ again:
|
|||||||
size = LLONG_MAX;
|
size = LLONG_MAX;
|
||||||
#else
|
#else
|
||||||
size = lseek(fd, 0LL, SEEK_END);
|
size = lseek(fd, 0LL, SEEK_END);
|
||||||
|
if (size < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||||
switch(s->type) {
|
switch(s->type) {
|
||||||
@ -1247,6 +1285,9 @@ again:
|
|||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
size = lseek(fd, 0, SEEK_END);
|
size = lseek(fd, 0, SEEK_END);
|
||||||
|
if (size < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -1255,13 +1296,18 @@ static int64_t raw_getlength(BlockDriverState *bs)
|
|||||||
{
|
{
|
||||||
BDRVRawState *s = bs->opaque;
|
BDRVRawState *s = bs->opaque;
|
||||||
int ret;
|
int ret;
|
||||||
|
int64_t size;
|
||||||
|
|
||||||
ret = fd_open(bs);
|
ret = fd_open(bs);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
return lseek(s->fd, 0, SEEK_END);
|
size = lseek(s->fd, 0, SEEK_END);
|
||||||
|
if (size < 0) {
|
||||||
|
return -errno;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1528,6 +1574,9 @@ static BlockDriver bdrv_file = {
|
|||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_aio_discard = raw_aio_discard,
|
.bdrv_aio_discard = raw_aio_discard,
|
||||||
.bdrv_refresh_limits = raw_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
.bdrv_io_plug = raw_aio_plug,
|
||||||
|
.bdrv_io_unplug = raw_aio_unplug,
|
||||||
|
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@ -1927,6 +1976,9 @@ static BlockDriver bdrv_host_device = {
|
|||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_aio_discard = hdev_aio_discard,
|
.bdrv_aio_discard = hdev_aio_discard,
|
||||||
.bdrv_refresh_limits = raw_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
.bdrv_io_plug = raw_aio_plug,
|
||||||
|
.bdrv_io_unplug = raw_aio_unplug,
|
||||||
|
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@ -2072,6 +2124,9 @@ static BlockDriver bdrv_host_floppy = {
|
|||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_refresh_limits = raw_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
.bdrv_io_plug = raw_aio_plug,
|
||||||
|
.bdrv_io_unplug = raw_aio_unplug,
|
||||||
|
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@ -2200,6 +2255,9 @@ static BlockDriver bdrv_host_cdrom = {
|
|||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_refresh_limits = raw_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
.bdrv_io_plug = raw_aio_plug,
|
||||||
|
.bdrv_io_unplug = raw_aio_unplug,
|
||||||
|
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
@ -2334,6 +2392,9 @@ static BlockDriver bdrv_host_cdrom = {
|
|||||||
.bdrv_aio_writev = raw_aio_writev,
|
.bdrv_aio_writev = raw_aio_writev,
|
||||||
.bdrv_aio_flush = raw_aio_flush,
|
.bdrv_aio_flush = raw_aio_flush,
|
||||||
.bdrv_refresh_limits = raw_refresh_limits,
|
.bdrv_refresh_limits = raw_refresh_limits,
|
||||||
|
.bdrv_io_plug = raw_aio_plug,
|
||||||
|
.bdrv_io_unplug = raw_aio_unplug,
|
||||||
|
.bdrv_flush_io_queue = raw_aio_flush_io_queue,
|
||||||
|
|
||||||
.bdrv_truncate = raw_truncate,
|
.bdrv_truncate = raw_truncate,
|
||||||
.bdrv_getlength = raw_getlength,
|
.bdrv_getlength = raw_getlength,
|
||||||
|
@ -84,6 +84,7 @@ static void handle_notify(EventNotifier *e)
|
|||||||
};
|
};
|
||||||
|
|
||||||
event_notifier_test_and_clear(&s->host_notifier);
|
event_notifier_test_and_clear(&s->host_notifier);
|
||||||
|
bdrv_io_plug(s->blk->conf.bs);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Disable guest->host notifies to avoid unnecessary vmexits */
|
/* Disable guest->host notifies to avoid unnecessary vmexits */
|
||||||
vring_disable_notification(s->vdev, &s->vring);
|
vring_disable_notification(s->vdev, &s->vring);
|
||||||
@ -117,6 +118,7 @@ static void handle_notify(EventNotifier *e)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bdrv_io_unplug(s->blk->conf.bs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Context: QEMU global mutex held */
|
/* Context: QEMU global mutex held */
|
||||||
|
@ -175,17 +175,18 @@ static void ahci_trigger_irq(AHCIState *s, AHCIDevice *d,
|
|||||||
ahci_check_irq(s);
|
ahci_check_irq(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void map_page(uint8_t **ptr, uint64_t addr, uint32_t wanted)
|
static void map_page(AddressSpace *as, uint8_t **ptr, uint64_t addr,
|
||||||
|
uint32_t wanted)
|
||||||
{
|
{
|
||||||
hwaddr len = wanted;
|
hwaddr len = wanted;
|
||||||
|
|
||||||
if (*ptr) {
|
if (*ptr) {
|
||||||
cpu_physical_memory_unmap(*ptr, len, 1, len);
|
dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
*ptr = cpu_physical_memory_map(addr, &len, 1);
|
*ptr = dma_memory_map(as, addr, &len, DMA_DIRECTION_FROM_DEVICE);
|
||||||
if (len < wanted) {
|
if (len < wanted) {
|
||||||
cpu_physical_memory_unmap(*ptr, len, 1, len);
|
dma_memory_unmap(as, *ptr, len, DMA_DIRECTION_FROM_DEVICE, len);
|
||||||
*ptr = NULL;
|
*ptr = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -198,24 +199,24 @@ static void ahci_port_write(AHCIState *s, int port, int offset, uint32_t val)
|
|||||||
switch (offset) {
|
switch (offset) {
|
||||||
case PORT_LST_ADDR:
|
case PORT_LST_ADDR:
|
||||||
pr->lst_addr = val;
|
pr->lst_addr = val;
|
||||||
map_page(&s->dev[port].lst,
|
map_page(s->as, &s->dev[port].lst,
|
||||||
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
||||||
s->dev[port].cur_cmd = NULL;
|
s->dev[port].cur_cmd = NULL;
|
||||||
break;
|
break;
|
||||||
case PORT_LST_ADDR_HI:
|
case PORT_LST_ADDR_HI:
|
||||||
pr->lst_addr_hi = val;
|
pr->lst_addr_hi = val;
|
||||||
map_page(&s->dev[port].lst,
|
map_page(s->as, &s->dev[port].lst,
|
||||||
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
||||||
s->dev[port].cur_cmd = NULL;
|
s->dev[port].cur_cmd = NULL;
|
||||||
break;
|
break;
|
||||||
case PORT_FIS_ADDR:
|
case PORT_FIS_ADDR:
|
||||||
pr->fis_addr = val;
|
pr->fis_addr = val;
|
||||||
map_page(&s->dev[port].res_fis,
|
map_page(s->as, &s->dev[port].res_fis,
|
||||||
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
||||||
break;
|
break;
|
||||||
case PORT_FIS_ADDR_HI:
|
case PORT_FIS_ADDR_HI:
|
||||||
pr->fis_addr_hi = val;
|
pr->fis_addr_hi = val;
|
||||||
map_page(&s->dev[port].res_fis,
|
map_page(s->as, &s->dev[port].res_fis,
|
||||||
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
||||||
break;
|
break;
|
||||||
case PORT_IRQ_STAT:
|
case PORT_IRQ_STAT:
|
||||||
@ -639,6 +640,11 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int prdt_tbl_entry_size(const AHCI_SG *tbl)
|
||||||
|
{
|
||||||
|
return (le32_to_cpu(tbl->flags_size) & AHCI_PRDT_SIZE_MASK) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
||||||
{
|
{
|
||||||
AHCICmdHdr *cmd = ad->cur_cmd;
|
AHCICmdHdr *cmd = ad->cur_cmd;
|
||||||
@ -681,7 +687,7 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
|||||||
sum = 0;
|
sum = 0;
|
||||||
for (i = 0; i < sglist_alloc_hint; i++) {
|
for (i = 0; i < sglist_alloc_hint; i++) {
|
||||||
/* flags_size is zero-based */
|
/* flags_size is zero-based */
|
||||||
tbl_entry_size = (le32_to_cpu(tbl[i].flags_size) + 1);
|
tbl_entry_size = prdt_tbl_entry_size(&tbl[i]);
|
||||||
if (offset <= (sum + tbl_entry_size)) {
|
if (offset <= (sum + tbl_entry_size)) {
|
||||||
off_idx = i;
|
off_idx = i;
|
||||||
off_pos = offset - sum;
|
off_pos = offset - sum;
|
||||||
@ -700,12 +706,12 @@ static int ahci_populate_sglist(AHCIDevice *ad, QEMUSGList *sglist, int offset)
|
|||||||
qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx),
|
qemu_sglist_init(sglist, qbus->parent, (sglist_alloc_hint - off_idx),
|
||||||
ad->hba->as);
|
ad->hba->as);
|
||||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
|
qemu_sglist_add(sglist, le64_to_cpu(tbl[off_idx].addr + off_pos),
|
||||||
le32_to_cpu(tbl[off_idx].flags_size) + 1 - off_pos);
|
prdt_tbl_entry_size(&tbl[off_idx]) - off_pos);
|
||||||
|
|
||||||
for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
|
for (i = off_idx + 1; i < sglist_alloc_hint; i++) {
|
||||||
/* flags_size is zero-based */
|
/* flags_size is zero-based */
|
||||||
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
|
qemu_sglist_add(sglist, le64_to_cpu(tbl[i].addr),
|
||||||
le32_to_cpu(tbl[i].flags_size) + 1);
|
prdt_tbl_entry_size(&tbl[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1260,9 +1266,9 @@ static int ahci_state_post_load(void *opaque, int version_id)
|
|||||||
ad = &s->dev[i];
|
ad = &s->dev[i];
|
||||||
AHCIPortRegs *pr = &ad->port_regs;
|
AHCIPortRegs *pr = &ad->port_regs;
|
||||||
|
|
||||||
map_page(&ad->lst,
|
map_page(s->as, &ad->lst,
|
||||||
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
((uint64_t)pr->lst_addr_hi << 32) | pr->lst_addr, 1024);
|
||||||
map_page(&ad->res_fis,
|
map_page(s->as, &ad->res_fis,
|
||||||
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
|
||||||
/*
|
/*
|
||||||
* All pending i/o should be flushed out on a migrate. However,
|
* All pending i/o should be flushed out on a migrate. However,
|
||||||
|
@ -201,6 +201,8 @@
|
|||||||
|
|
||||||
#define AHCI_COMMAND_TABLE_ACMD 0x40
|
#define AHCI_COMMAND_TABLE_ACMD 0x40
|
||||||
|
|
||||||
|
#define AHCI_PRDT_SIZE_MASK 0x3fffff
|
||||||
|
|
||||||
#define IDE_FEATURE_DMA 1
|
#define IDE_FEATURE_DMA 1
|
||||||
|
|
||||||
#define READ_FPDMA_QUEUED 0x60
|
#define READ_FPDMA_QUEUED 0x60
|
||||||
|
@ -584,4 +584,8 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs);
|
|||||||
*/
|
*/
|
||||||
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
|
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
|
||||||
|
|
||||||
|
void bdrv_io_plug(BlockDriverState *bs);
|
||||||
|
void bdrv_io_unplug(BlockDriverState *bs);
|
||||||
|
void bdrv_flush_io_queue(BlockDriverState *bs);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -261,6 +261,11 @@ struct BlockDriver {
|
|||||||
void (*bdrv_attach_aio_context)(BlockDriverState *bs,
|
void (*bdrv_attach_aio_context)(BlockDriverState *bs,
|
||||||
AioContext *new_context);
|
AioContext *new_context);
|
||||||
|
|
||||||
|
/* io queue for linux-aio */
|
||||||
|
void (*bdrv_io_plug)(BlockDriverState *bs);
|
||||||
|
void (*bdrv_io_unplug)(BlockDriverState *bs);
|
||||||
|
void (*bdrv_flush_io_queue)(BlockDriverState *bs);
|
||||||
|
|
||||||
QLIST_ENTRY(BlockDriver) list;
|
QLIST_ENTRY(BlockDriver) list;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -590,7 +590,7 @@ check -r all} is required, which may take some time.
|
|||||||
This option can only be enabled if @code{compat=1.1} is specified.
|
This option can only be enabled if @code{compat=1.1} is specified.
|
||||||
|
|
||||||
@item nocow
|
@item nocow
|
||||||
If this option is set to @code{on}, it will trun off COW of the file. It's only
|
If this option is set to @code{on}, it will turn off COW of the file. It's only
|
||||||
valid on btrfs, no effect on other file systems.
|
valid on btrfs, no effect on other file systems.
|
||||||
|
|
||||||
Btrfs has low performance when hosting a VM image file, even more when the guest
|
Btrfs has low performance when hosting a VM image file, even more when the guest
|
||||||
@ -603,7 +603,7 @@ does.
|
|||||||
Note: this option is only valid to new or empty files. If there is an existing
|
Note: this option is only valid to new or empty files. If there is an existing
|
||||||
file which is COW and has data blocks already, it couldn't be changed to NOCOW
|
file which is COW and has data blocks already, it couldn't be changed to NOCOW
|
||||||
by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
|
by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
|
||||||
the NOCOW flag is set or not (Capitabl 'C' is NOCOW flag).
|
the NOCOW flag is set or not (Capital 'C' is NOCOW flag).
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
@ -475,7 +475,7 @@ check -r all} is required, which may take some time.
|
|||||||
This option can only be enabled if @code{compat=1.1} is specified.
|
This option can only be enabled if @code{compat=1.1} is specified.
|
||||||
|
|
||||||
@item nocow
|
@item nocow
|
||||||
If this option is set to @code{on}, it will trun off COW of the file. It's only
|
If this option is set to @code{on}, it will turn off COW of the file. It's only
|
||||||
valid on btrfs, no effect on other file systems.
|
valid on btrfs, no effect on other file systems.
|
||||||
|
|
||||||
Btrfs has low performance when hosting a VM image file, even more when the guest
|
Btrfs has low performance when hosting a VM image file, even more when the guest
|
||||||
@ -488,7 +488,7 @@ does.
|
|||||||
Note: this option is only valid to new or empty files. If there is an existing
|
Note: this option is only valid to new or empty files. If there is an existing
|
||||||
file which is COW and has data blocks already, it couldn't be changed to NOCOW
|
file which is COW and has data blocks already, it couldn't be changed to NOCOW
|
||||||
by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
|
by setting @code{nocow=on}. One can issue @code{lsattr filename} to check if
|
||||||
the NOCOW flag is set or not (Capitabl 'C' is NOCOW flag).
|
the NOCOW flag is set or not (Capital 'C' is NOCOW flag).
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
|
101
qmp.c
101
qmp.c
@ -433,11 +433,57 @@ ObjectTypeInfoList *qmp_qom_list_types(bool has_implements,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a DevicePropertyInfo for a qdev property.
|
||||||
|
*
|
||||||
|
* If a qdev property with the given name does not exist, use the given default
|
||||||
|
* type. If the qdev property info should not be shown, return NULL.
|
||||||
|
*
|
||||||
|
* The caller must free the return value.
|
||||||
|
*/
|
||||||
|
static DevicePropertyInfo *make_device_property_info(ObjectClass *klass,
|
||||||
|
const char *name,
|
||||||
|
const char *default_type)
|
||||||
|
{
|
||||||
|
DevicePropertyInfo *info;
|
||||||
|
Property *prop;
|
||||||
|
|
||||||
|
do {
|
||||||
|
for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
|
||||||
|
if (strcmp(name, prop->name) != 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO Properties without a parser are just for dirty hacks.
|
||||||
|
* qdev_prop_ptr is the only such PropertyInfo. It's marked
|
||||||
|
* for removal. This conditional should be removed along with
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
if (!prop->info->set) {
|
||||||
|
return NULL; /* no way to set it, don't show */
|
||||||
|
}
|
||||||
|
|
||||||
|
info = g_malloc0(sizeof(*info));
|
||||||
|
info->name = g_strdup(prop->name);
|
||||||
|
info->type = g_strdup(prop->info->legacy_name ?: prop->info->name);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
klass = object_class_get_parent(klass);
|
||||||
|
} while (klass != object_class_by_name(TYPE_DEVICE));
|
||||||
|
|
||||||
|
/* Not a qdev property, use the default type */
|
||||||
|
info = g_malloc0(sizeof(*info));
|
||||||
|
info->name = g_strdup(name);
|
||||||
|
info->type = g_strdup(default_type);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
|
DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
|
||||||
Error **errp)
|
Error **errp)
|
||||||
{
|
{
|
||||||
ObjectClass *klass;
|
ObjectClass *klass;
|
||||||
Property *prop;
|
Object *obj;
|
||||||
|
ObjectProperty *prop;
|
||||||
DevicePropertyInfoList *prop_list = NULL;
|
DevicePropertyInfoList *prop_list = NULL;
|
||||||
|
|
||||||
klass = object_class_by_name(typename);
|
klass = object_class_by_name(typename);
|
||||||
@ -453,32 +499,39 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
obj = object_new(typename);
|
||||||
for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
|
|
||||||
DevicePropertyInfoList *entry;
|
|
||||||
DevicePropertyInfo *info;
|
|
||||||
|
|
||||||
/*
|
QTAILQ_FOREACH(prop, &obj->properties, node) {
|
||||||
* TODO Properties without a parser are just for dirty hacks.
|
DevicePropertyInfo *info;
|
||||||
* qdev_prop_ptr is the only such PropertyInfo. It's marked
|
DevicePropertyInfoList *entry;
|
||||||
* for removal. This conditional should be removed along with
|
|
||||||
* it.
|
|
||||||
*/
|
|
||||||
if (!prop->info->set) {
|
|
||||||
continue; /* no way to set it, don't show */
|
|
||||||
}
|
|
||||||
|
|
||||||
info = g_malloc0(sizeof(*info));
|
/* Skip Object and DeviceState properties */
|
||||||
info->name = g_strdup(prop->name);
|
if (strcmp(prop->name, "type") == 0 ||
|
||||||
info->type = g_strdup(prop->info->legacy_name ?: prop->info->name);
|
strcmp(prop->name, "realized") == 0 ||
|
||||||
|
strcmp(prop->name, "hotpluggable") == 0 ||
|
||||||
entry = g_malloc0(sizeof(*entry));
|
strcmp(prop->name, "parent_bus") == 0) {
|
||||||
entry->value = info;
|
continue;
|
||||||
entry->next = prop_list;
|
|
||||||
prop_list = entry;
|
|
||||||
}
|
}
|
||||||
klass = object_class_get_parent(klass);
|
|
||||||
} while (klass != object_class_by_name(TYPE_DEVICE));
|
/* Skip legacy properties since they are just string versions of
|
||||||
|
* properties that we already list.
|
||||||
|
*/
|
||||||
|
if (strstart(prop->name, "legacy-", NULL)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = make_device_property_info(klass, prop->name, prop->type);
|
||||||
|
if (!info) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = g_malloc0(sizeof(*entry));
|
||||||
|
entry->value = info;
|
||||||
|
entry->next = prop_list;
|
||||||
|
prop_list = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
object_unref(obj);
|
||||||
|
|
||||||
return prop_list;
|
return prop_list;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,11 @@ class TestSingleDriveZeroLength(TestSingleDrive):
|
|||||||
test_small_buffer2 = None
|
test_small_buffer2 = None
|
||||||
test_large_cluster = None
|
test_large_cluster = None
|
||||||
|
|
||||||
|
class TestSingleDriveUnalignedLength(TestSingleDrive):
|
||||||
|
image_len = 1025 * 1024
|
||||||
|
test_small_buffer2 = None
|
||||||
|
test_large_cluster = None
|
||||||
|
|
||||||
class TestMirrorNoBacking(ImageMirroringTestCase):
|
class TestMirrorNoBacking(ImageMirroringTestCase):
|
||||||
image_len = 2 * 1024 * 1024 # MB
|
image_len = 2 * 1024 * 1024 # MB
|
||||||
|
|
||||||
@ -735,6 +740,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
image_len = 1 * 1024 * 1024 # MB
|
image_len = 1 * 1024 * 1024 # MB
|
||||||
IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
|
IMAGES = [ quorum_img1, quorum_img2, quorum_img3 ]
|
||||||
|
|
||||||
|
def has_quorum(self):
|
||||||
|
return 'quorum' in iotests.qemu_img_pipe('--help')
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.vm = iotests.VM()
|
self.vm = iotests.VM()
|
||||||
|
|
||||||
@ -752,8 +760,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
#assemble the quorum block device from the individual files
|
#assemble the quorum block device from the individual files
|
||||||
args = { "options" : { "driver": "quorum", "id": "quorum0",
|
args = { "options" : { "driver": "quorum", "id": "quorum0",
|
||||||
"vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
|
"vote-threshold": 2, "children": [ "img0", "img1", "img2" ] } }
|
||||||
result = self.vm.qmp("blockdev-add", **args)
|
if self.has_quorum():
|
||||||
self.assert_qmp(result, 'return', {})
|
result = self.vm.qmp("blockdev-add", **args)
|
||||||
|
self.assert_qmp(result, 'return', {})
|
||||||
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
@ -766,6 +775,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def test_complete(self):
|
def test_complete(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
self.assert_no_active_block_jobs()
|
self.assert_no_active_block_jobs()
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
@ -784,6 +796,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
'target image does not match source after mirroring')
|
'target image does not match source after mirroring')
|
||||||
|
|
||||||
def test_cancel(self):
|
def test_cancel(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
self.assert_no_active_block_jobs()
|
self.assert_no_active_block_jobs()
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
@ -800,6 +815,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
self.vm.shutdown()
|
self.vm.shutdown()
|
||||||
|
|
||||||
def test_cancel_after_ready(self):
|
def test_cancel_after_ready(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
self.assert_no_active_block_jobs()
|
self.assert_no_active_block_jobs()
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
@ -818,6 +836,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
'target image does not match source after mirroring')
|
'target image does not match source after mirroring')
|
||||||
|
|
||||||
def test_pause(self):
|
def test_pause(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
self.assert_no_active_block_jobs()
|
self.assert_no_active_block_jobs()
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
@ -846,6 +867,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
'target image does not match source after mirroring')
|
'target image does not match source after mirroring')
|
||||||
|
|
||||||
def test_medium_not_found(self):
|
def test_medium_not_found(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='ide1-cd0', sync='full',
|
||||||
node_name='repair0',
|
node_name='repair0',
|
||||||
replaces='img1',
|
replaces='img1',
|
||||||
@ -853,6 +877,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
|
||||||
def test_image_not_found(self):
|
def test_image_not_found(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
node_name='repair0',
|
node_name='repair0',
|
||||||
replaces='img1',
|
replaces='img1',
|
||||||
@ -861,6 +888,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
|
||||||
def test_device_not_found(self):
|
def test_device_not_found(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
|
result = self.vm.qmp('drive-mirror', device='nonexistent', sync='full',
|
||||||
node_name='repair0',
|
node_name='repair0',
|
||||||
replaces='img1',
|
replaces='img1',
|
||||||
@ -868,6 +898,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
|
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
|
||||||
|
|
||||||
def test_wrong_sync_mode(self):
|
def test_wrong_sync_mode(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0',
|
result = self.vm.qmp('drive-mirror', device='quorum0',
|
||||||
node_name='repair0',
|
node_name='repair0',
|
||||||
replaces='img1',
|
replaces='img1',
|
||||||
@ -875,12 +908,18 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
|
||||||
def test_no_node_name(self):
|
def test_no_node_name(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
replaces='img1',
|
replaces='img1',
|
||||||
target=quorum_repair_img, format=iotests.imgfmt)
|
target=quorum_repair_img, format=iotests.imgfmt)
|
||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
|
||||||
def test_unexistant_replaces(self):
|
def test_unexistant_replaces(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
result = self.vm.qmp('drive-mirror', device='quorum0', sync='full',
|
||||||
node_name='repair0',
|
node_name='repair0',
|
||||||
replaces='img77',
|
replaces='img77',
|
||||||
@ -888,6 +927,9 @@ class TestRepairQuorum(ImageMirroringTestCase):
|
|||||||
self.assert_qmp(result, 'error/class', 'GenericError')
|
self.assert_qmp(result, 'error/class', 'GenericError')
|
||||||
|
|
||||||
def test_after_a_quorum_snapshot(self):
|
def test_after_a_quorum_snapshot(self):
|
||||||
|
if not self.has_quorum():
|
||||||
|
return
|
||||||
|
|
||||||
result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1',
|
result = self.vm.qmp('blockdev-snapshot-sync', node_name='img1',
|
||||||
snapshot_file=quorum_snapshot_file,
|
snapshot_file=quorum_snapshot_file,
|
||||||
snapshot_node_name="snap1");
|
snapshot_node_name="snap1");
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
..............................................
|
......................................................
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 46 tests
|
Ran 54 tests
|
||||||
|
|
||||||
OK
|
OK
|
||||||
|
Loading…
Reference in New Issue
Block a user