M: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
S: Maintained
F: trace/
+F: scripts/tracetool.py
+F: scripts/tracetool/
F: docs/tracing.txt
T: git://github.com/stefanha/qemu.git tracing
ppc_rom.bin openbios-sparc32 openbios-sparc64 openbios-ppc \
pxe-e1000.rom pxe-eepro100.rom pxe-ne2k_pci.rom \
pxe-pcnet.rom pxe-rtl8139.rom pxe-virtio.rom \
+qemu-icon.bmp \
bamboo.dtb petalogix-s3adsp1800.dtb petalogix-ml605.dtb \
mpc8544ds.dtb \
multiboot.bin linuxboot.bin kvmvapic.bin \
endif
install-doc: $(DOCS)
- $(INSTALL_DIR) "$(DESTDIR)$(docdir)"
- $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(docdir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_docdir)"
+ $(INSTALL_DATA) qemu-doc.html qemu-tech.html "$(DESTDIR)$(qemu_docdir)"
ifdef CONFIG_POSIX
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) qemu.1 qemu-img.1 "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
endif
install-sysconfig:
- $(INSTALL_DIR) "$(DESTDIR)$(sysconfdir)/qemu"
- $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(sysconfdir)/qemu"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
+ $(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
endif
ifneq ($(BLOBS),)
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
set -e; for x in $(BLOBS); do \
- $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(datadir)"; \
+ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
done
endif
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)/keymaps"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/keymaps"
set -e; for x in $(KEYMAPS); do \
- $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(datadir)/keymaps"; \
+ $(INSTALL_DATA) $(SRC_PATH)/pc-bios/keymaps/$$x "$(DESTDIR)$(qemu_datadir)/keymaps"; \
done
for d in $(TARGET_DIRS); do \
$(MAKE) -C $$d $@ || exit 1 ; \
trace.h: trace.h-timestamp
endif
trace.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -h < $< > $@," GEN trace.h")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=h --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.h")
@cmp -s $@ trace.h || cp $@ trace.h
trace.c: trace.c-timestamp
trace.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -c < $< > $@," GEN trace.c")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=c --backend=$(TRACE_BACKEND) < $< > $@," GEN trace.c")
@cmp -s $@ trace.c || cp $@ trace.c
trace.o: trace.c $(GENERATED_HEADERS)
# rule file. So we use '.dtrace' instead
trace-dtrace.dtrace: trace-dtrace.dtrace-timestamp
trace-dtrace.dtrace-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool --$(TRACE_BACKEND) -d < $< > $@," GEN trace-dtrace.dtrace")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py --format=d --backend=$(TRACE_BACKEND) < $< > $@," GEN trace-dtrace.dtrace")
@cmp -s $@ trace-dtrace.dtrace || cp $@ trace-dtrace.dtrace
trace-dtrace.o: trace-dtrace.dtrace $(GENERATED_HEADERS)
endif
$(QEMU_PROG).stp: $(SRC_PATH)/trace-events
- $(call quiet-command,sh $(SRC_PATH)/scripts/tracetool \
- --$(TRACE_BACKEND) \
- --binary $(bindir)/$(QEMU_PROG) \
- --target-arch $(TARGET_ARCH) \
- --target-type $(TARGET_TYPE) \
- --stap < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
+ $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/tracetool.py \
+ --format=stap \
+ --backend=$(TRACE_BACKEND) \
+ --binary=$(bindir)/$(QEMU_PROG) \
+ --target-arch=$(TARGET_ARCH) \
+ --target-type=$(TARGET_TYPE) \
+ < $(SRC_PATH)/trace-events > $(QEMU_PROG).stp," GEN $(QEMU_PROG).stp")
else
stap:
endif
libobj-$(CONFIG_NEED_MMU) += mmu.o
libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o
libobj-$(TARGET_ARM) += cpu.o
+libobj-$(TARGET_CRIS) += cpu.o
libobj-$(TARGET_LM32) += cpu.o
+libobj-$(TARGET_MICROBLAZE) += cpu.o
libobj-$(TARGET_S390X) += cpu.o
ifeq ($(TARGET_BASE_ARCH), sparc)
libobj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o
endif
endif
ifdef CONFIG_TRACE_SYSTEMTAP
- $(INSTALL_DIR) "$(DESTDIR)$(datadir)/../systemtap/tapset"
- $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(datadir)/../systemtap/tapset"
+ $(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
+ $(INSTALL_DATA) $(QEMU_PROG).stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
endif
# Include automatically generated dependency files
--- /dev/null
+#!/usr/bin/python
+##
+# QEMU Object Model test tools
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPL, version 2 or later. See
+# the COPYING file in the top-level directory.
+##
+
+import fuse, stat
+from fuse import Fuse
+import os, posix
+from errno import *
+from qmp import QEMUMonitorProtocol
+
+fuse.fuse_python_api = (0, 2)
+
+class QOMFS(Fuse):
+ def __init__(self, qmp, *args, **kwds):
+ Fuse.__init__(self, *args, **kwds)
+ self.qmp = qmp
+ self.qmp.connect()
+ self.ino_map = {}
+ self.ino_count = 1
+
+ def get_ino(self, path):
+ if self.ino_map.has_key(path):
+ return self.ino_map[path]
+ self.ino_map[path] = self.ino_count
+ self.ino_count += 1
+ return self.ino_map[path]
+
+ def is_object(self, path):
+ try:
+ items = self.qmp.command('qom-list', path=path)
+ return True
+ except:
+ return False
+
+ def is_property(self, path):
+ try:
+ path, prop = path.rsplit('/', 1)
+ for item in self.qmp.command('qom-list', path=path):
+ if item['name'] == prop:
+ return True
+ return False
+ except:
+ return False
+
+ def is_link(self, path):
+ try:
+ path, prop = path.rsplit('/', 1)
+ for item in self.qmp.command('qom-list', path=path):
+ if item['name'] == prop:
+ if item['type'].startswith('link<'):
+ return True
+ return False
+ return False
+ except:
+ return False
+
+ def read(self, path, length, offset):
+ if not self.is_property(path):
+ return -ENOENT
+
+ path, prop = path.rsplit('/', 1)
+ try:
+ data = str(self.qmp.command('qom-get', path=path, property=prop))
+ data += '\n' # make values shell friendly
+ except:
+ return -EPERM
+
+ if offset > len(data):
+ return ''
+
+ return str(data[offset:][:length])
+
+ def readlink(self, path):
+ if not self.is_link(path):
+ return False
+ path, prop = path.rsplit('/', 1)
+ prefix = '/'.join(['..'] * (len(path.split('/')) - 1))
+ return prefix + str(self.qmp.command('qom-get', path=path,
+ property=prop))
+
+ def getattr(self, path):
+ if self.is_link(path):
+ value = posix.stat_result((0755 | stat.S_IFLNK,
+ self.get_ino(path),
+ 0,
+ 2,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ elif self.is_object(path):
+ value = posix.stat_result((0755 | stat.S_IFDIR,
+ self.get_ino(path),
+ 0,
+ 2,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ elif self.is_property(path):
+ value = posix.stat_result((0644 | stat.S_IFREG,
+ self.get_ino(path),
+ 0,
+ 1,
+ 1000,
+ 1000,
+ 4096,
+ 0,
+ 0,
+ 0))
+ else:
+ value = -ENOENT
+ return value
+
+ def readdir(self, path, offset):
+ yield fuse.Direntry('.')
+ yield fuse.Direntry('..')
+ for item in self.qmp.command('qom-list', path=path):
+ yield fuse.Direntry(str(item['name']))
+
+if __name__ == '__main__':
+ import sys, os
+
+ fs = QOMFS(QEMUMonitorProtocol(os.environ['QMP_SOCKET']))
+ fs.main(sys.argv)
IOHandler *io_read;
IOHandler *io_write;
AioFlushHandler *io_flush;
- AioProcessQueue *io_process_queue;
int deleted;
void *opaque;
QLIST_ENTRY(AioHandler) node;
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
- AioProcessQueue *io_process_queue,
void *opaque)
{
AioHandler *node;
node->io_read = io_read;
node->io_write = io_write;
node->io_flush = io_flush;
- node->io_process_queue = io_process_queue;
node->opaque = opaque;
}
void qemu_aio_flush(void)
{
- AioHandler *node;
- int ret;
-
- do {
- ret = 0;
-
- /*
- * If there are pending emulated aio start them now so flush
- * will be able to return 1.
- */
- qemu_aio_wait();
-
- QLIST_FOREACH(node, &aio_handlers, node) {
- if (node->io_flush) {
- ret |= node->io_flush(node->opaque);
- }
- }
- } while (qemu_bh_poll() || ret > 0);
+ while (qemu_aio_wait());
}
-int qemu_aio_process_queue(void)
+bool qemu_aio_wait(void)
{
AioHandler *node;
- int ret = 0;
+ fd_set rdfds, wrfds;
+ int max_fd = -1;
+ int ret;
+ bool busy;
+
+ /*
+ * If there are callbacks left that have been queued, we need to call then.
+ * Do not call select in this case, because it is possible that the caller
+ * does not need a complete flush (as is the case for qemu_aio_wait loops).
+ */
+ if (qemu_bh_poll()) {
+ return true;
+ }
walking_handlers = 1;
+ FD_ZERO(&rdfds);
+ FD_ZERO(&wrfds);
+
+ /* fill fd sets */
+ busy = false;
QLIST_FOREACH(node, &aio_handlers, node) {
- if (node->io_process_queue) {
- if (node->io_process_queue(node->opaque)) {
- ret = 1;
+ /* If there aren't pending AIO operations, don't invoke callbacks.
+ * Otherwise, if there are no AIO requests, qemu_aio_wait() would
+ * wait indefinitely.
+ */
+ if (node->io_flush) {
+ if (node->io_flush(node->opaque) == 0) {
+ continue;
}
+ busy = true;
+ }
+ if (!node->deleted && node->io_read) {
+ FD_SET(node->fd, &rdfds);
+ max_fd = MAX(max_fd, node->fd + 1);
+ }
+ if (!node->deleted && node->io_write) {
+ FD_SET(node->fd, &wrfds);
+ max_fd = MAX(max_fd, node->fd + 1);
}
}
walking_handlers = 0;
- return ret;
-}
-
-void qemu_aio_wait(void)
-{
- int ret;
-
- if (qemu_bh_poll())
- return;
-
- /*
- * If there are callbacks left that have been queued, we need to call then.
- * Return afterwards to avoid waiting needlessly in select().
- */
- if (qemu_aio_process_queue())
- return;
+ /* No AIO operations? Get us out of here */
+ if (!busy) {
+ return false;
+ }
- do {
- AioHandler *node;
- fd_set rdfds, wrfds;
- int max_fd = -1;
+ /* wait until next event */
+ ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
+ /* if we have any readable fds, dispatch event */
+ if (ret > 0) {
walking_handlers = 1;
- FD_ZERO(&rdfds);
- FD_ZERO(&wrfds);
+ /* we have to walk very carefully in case
+ * qemu_aio_set_fd_handler is called while we're walking */
+ node = QLIST_FIRST(&aio_handlers);
+ while (node) {
+ AioHandler *tmp;
- /* fill fd sets */
- QLIST_FOREACH(node, &aio_handlers, node) {
- /* If there aren't pending AIO operations, don't invoke callbacks.
- * Otherwise, if there are no AIO requests, qemu_aio_wait() would
- * wait indefinitely.
- */
- if (node->io_flush && node->io_flush(node->opaque) == 0)
- continue;
-
- if (!node->deleted && node->io_read) {
- FD_SET(node->fd, &rdfds);
- max_fd = MAX(max_fd, node->fd + 1);
+ if (!node->deleted &&
+ FD_ISSET(node->fd, &rdfds) &&
+ node->io_read) {
+ node->io_read(node->opaque);
}
- if (!node->deleted && node->io_write) {
- FD_SET(node->fd, &wrfds);
- max_fd = MAX(max_fd, node->fd + 1);
+ if (!node->deleted &&
+ FD_ISSET(node->fd, &wrfds) &&
+ node->io_write) {
+ node->io_write(node->opaque);
}
- }
- walking_handlers = 0;
+ tmp = node;
+ node = QLIST_NEXT(node, node);
- /* No AIO operations? Get us out of here */
- if (max_fd == -1)
- break;
-
- /* wait until next event */
- ret = select(max_fd, &rdfds, &wrfds, NULL, NULL);
- if (ret == -1 && errno == EINTR)
- continue;
-
- /* if we have any readable fds, dispatch event */
- if (ret > 0) {
- walking_handlers = 1;
-
- /* we have to walk very carefully in case
- * qemu_aio_set_fd_handler is called while we're walking */
- node = QLIST_FIRST(&aio_handlers);
- while (node) {
- AioHandler *tmp;
-
- if (!node->deleted &&
- FD_ISSET(node->fd, &rdfds) &&
- node->io_read) {
- node->io_read(node->opaque);
- }
- if (!node->deleted &&
- FD_ISSET(node->fd, &wrfds) &&
- node->io_write) {
- node->io_write(node->opaque);
- }
-
- tmp = node;
- node = QLIST_NEXT(node, node);
-
- if (tmp->deleted) {
- QLIST_REMOVE(tmp, node);
- g_free(tmp);
- }
+ if (tmp->deleted) {
+ QLIST_REMOVE(tmp, node);
+ g_free(tmp);
}
-
- walking_handlers = 0;
}
- } while (ret == 0);
+
+ walking_handlers = 0;
+ }
+
+ return true;
}
bh->deleted = 1;
}
-void qemu_bh_update_timeout(int *timeout)
+void qemu_bh_update_timeout(uint32_t *timeout)
{
QEMUBH *bh;
pa_stream_unref (stream);
}
- qpa_logerr (pa_context_errno (g->context),
- "stream_new() failed\n");
+ *rerror = pa_context_errno (g->context);
return NULL;
}
void *opaque,
bool is_write);
static void coroutine_fn bdrv_co_do_rw(void *opaque);
+static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors);
static bool bdrv_exceed_bps_limits(BlockDriverState *bs, int nb_sectors,
bool is_write, double elapsed_time, uint64_t *wait);
void bdrv_close(BlockDriverState *bs)
{
+ bdrv_flush(bs);
if (bs->drv) {
if (bs->job) {
block_job_cancel_sync(bs->job);
}
+ bdrv_drain_all();
+
if (bs == bs_snapshots) {
bs_snapshots = NULL;
}
if (drv->bdrv_co_write_zeroes &&
buffer_is_zero(bounce_buffer, iov.iov_len)) {
- ret = drv->bdrv_co_write_zeroes(bs, cluster_sector_num,
- cluster_nb_sectors);
+ ret = bdrv_co_do_write_zeroes(bs, cluster_sector_num,
+ cluster_nb_sectors);
} else {
ret = drv->bdrv_co_writev(bs, cluster_sector_num, cluster_nb_sectors,
&bounce_qiov);
struct iovec iov;
int ret;
+ /* TODO Emulate only part of misaligned requests instead of letting block
+ * drivers return -ENOTSUP and emulate everything */
+
/* First try the efficient write zeroes operation */
if (drv->bdrv_co_write_zeroes) {
- return drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+ ret = drv->bdrv_co_write_zeroes(bs, sector_num, nb_sectors);
+ if (ret != -ENOTSUP) {
+ return ret;
+ }
}
/* Fall back to bounce buffer if write zeroes is unsupported */
}
/*
- * XXX(hch): right now these functions are extremely ineffcient.
+ * XXX(hch): right now these functions are extremely inefficient.
* We should just read the whole bitmap we'll need in one go instead.
*/
static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum)
DPRINTF("CURL (AIO): Sock action %d on fd %d\n", action, fd);
switch (action) {
case CURL_POLL_IN:
- qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush,
- NULL, s);
+ qemu_aio_set_fd_handler(fd, curl_multi_do, NULL, curl_aio_flush, s);
break;
case CURL_POLL_OUT:
- qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush,
- NULL, s);
+ qemu_aio_set_fd_handler(fd, NULL, curl_multi_do, curl_aio_flush, s);
break;
case CURL_POLL_INOUT:
qemu_aio_set_fd_handler(fd, curl_multi_do, curl_multi_do,
- curl_aio_flush, NULL, s);
+ curl_aio_flush, s);
break;
case CURL_POLL_REMOVE:
- qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(fd, NULL, NULL, NULL, NULL);
break;
}
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
(iscsi_which_events(iscsi) & POLLOUT)
? iscsi_process_write : NULL,
- iscsi_process_flush, NULL, iscsilun);
+ iscsi_process_flush, iscsilun);
}
static void
IscsiLun *iscsilun = bs->opaque;
struct iscsi_context *iscsi = iscsilun->iscsi;
- qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), NULL, NULL, NULL, NULL);
iscsi_destroy_context(iscsi);
memset(iscsilun, 0, sizeof(IscsiLun));
}
static void nbd_reply_ready(void *opaque)
{
BDRVNBDState *s = opaque;
- int i;
+ uint64_t i;
+ int ret;
if (s->reply.handle == 0) {
- /* No reply already in flight. Fetch a header. */
- if (nbd_receive_reply(s->sock, &s->reply) < 0) {
+ /* No reply already in flight. Fetch a header. It is possible
+ * that another thread has done the same thing in parallel, so
+ * the socket is not readable anymore.
+ */
+ ret = nbd_receive_reply(s->sock, &s->reply);
+ if (ret == -EAGAIN) {
+ return;
+ }
+ if (ret < 0) {
s->reply.handle = 0;
goto fail;
}
* handler acts as a synchronization point and ensures that only
* one coroutine is called until the reply finishes. */
i = HANDLE_TO_INDEX(s, s->reply.handle);
+ if (i >= MAX_NBD_REQUESTS) {
+ goto fail;
+ }
+
if (s->recv_coroutine[i]) {
qemu_coroutine_enter(s->recv_coroutine[i], NULL);
return;
qemu_co_mutex_lock(&s->send_mutex);
s->send_coroutine = qemu_coroutine_self();
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
rc = nbd_send_request(s->sock, request);
- if (rc != -1 && iov) {
+ if (rc >= 0 && iov) {
ret = qemu_co_sendv(s->sock, iov, request->len, offset);
if (ret != request->len) {
- errno = -EIO;
- rc = -1;
+ return -EIO;
}
}
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
s->send_coroutine = NULL;
qemu_co_mutex_unlock(&s->send_mutex);
return rc;
}
/* Failed to establish connection */
- if (sock == -1) {
+ if (sock < 0) {
logout("Failed to establish connection to NBD server\n");
return -errno;
}
/* NBD handshake */
ret = nbd_receive_negotiate(sock, s->export_name, &s->nbdflags, &size,
&blocksize);
- if (ret == -1) {
+ if (ret < 0) {
logout("Failed to negotiate with the NBD server\n");
closesocket(sock);
- return -errno;
+ return ret;
}
/* Now that we're connected, set the socket to be non-blocking and
* kick the reply mechanism. */
socket_set_nonblock(sock);
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL,
- nbd_have_request, NULL, s);
+ nbd_have_request, s);
s->sock = sock;
s->size = size;
request.len = 0;
nbd_send_request(s->sock, &request);
- qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL);
closesocket(s->sock);
}
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
request.type = NBD_CMD_READ;
request.from = sector_num * 512;
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
- reply.error = errno;
+ ret = nbd_co_send_request(s, &request, NULL, 0);
+ if (ret < 0) {
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset);
}
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
request.type = NBD_CMD_WRITE;
if (!bdrv_enable_write_cache(bs) && (s->nbdflags & NBD_FLAG_SEND_FUA)) {
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, qiov->iov, offset) == -1) {
- reply.error = errno;
+ ret = nbd_co_send_request(s, &request, qiov->iov, offset);
+ if (ret < 0) {
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
}
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) {
return 0;
request.len = 0;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
- reply.error = errno;
+ ret = nbd_co_send_request(s, &request, NULL, 0);
+ if (ret < 0) {
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
}
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) {
return 0;
request.len = nb_sectors * 512;
nbd_coroutine_start(s, &request);
- if (nbd_co_send_request(s, &request, NULL, 0) == -1) {
- reply.error = errno;
+ ret = nbd_co_send_request(s, &request, NULL, 0);
+ if (ret < 0) {
+ reply.error = -ret;
} else {
nbd_co_receive_reply(s, &request, &reply, NULL, 0);
}
l2_table = *table;
- if (old_l2_offset == 0) {
+ if ((old_l2_offset & L1E_OFFSET_MASK) == 0) {
/* if there was no old l2 table, clear the new table */
memset(l2_table, 0, s->l2_size * sizeof(uint64_t));
} else {
/* if there was an old l2 table, read it from the disk */
BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ);
- ret = qcow2_cache_get(bs, s->l2_table_cache, old_l2_offset,
+ ret = qcow2_cache_get(bs, s->l2_table_cache,
+ old_l2_offset & L1E_OFFSET_MASK,
(void**) &old_table);
if (ret < 0) {
goto fail;
return ret;
}
+/*
+ * Checks how many clusters in a given L2 table are contiguous in the image
+ * file. As soon as one of the flags in the bitmask stop_flags changes compared
+ * to the first cluster, the search is stopped and the cluster is not counted
+ * as contiguous. (This allows it, for example, to stop at the first compressed
+ * cluster which may require a different handling)
+ */
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
- uint64_t *l2_table, uint64_t start, uint64_t mask)
+ uint64_t *l2_table, uint64_t start, uint64_t stop_flags)
{
int i;
- uint64_t offset = be64_to_cpu(l2_table[0]) & ~mask;
+ uint64_t mask = stop_flags | L2E_OFFSET_MASK;
+ uint64_t offset = be64_to_cpu(l2_table[0]) & mask;
if (!offset)
return 0;
- for (i = start; i < start + nb_clusters; i++)
- if (offset + (uint64_t) i * cluster_size != (be64_to_cpu(l2_table[i]) & ~mask))
+ for (i = start; i < start + nb_clusters; i++) {
+ uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
+ if (offset + (uint64_t) i * cluster_size != l2_entry) {
break;
+ }
+ }
return (i - start);
}
static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
{
- int i = 0;
+ int i;
+
+ for (i = 0; i < nb_clusters; i++) {
+ int type = qcow2_get_cluster_type(be64_to_cpu(l2_table[i]));
- while(nb_clusters-- && l2_table[i] == 0)
- i++;
+ if (type != QCOW2_CLUSTER_UNALLOCATED) {
+ break;
+ }
+ }
return i;
}
*
* on exit, *num is the number of contiguous sectors we can read.
*
- * Return 0, if the offset is found
- * Return -errno, otherwise.
- *
+ * Returns the cluster type (QCOW2_CLUSTER_*) on success, -errno in error
+ * cases.
*/
-
int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num, uint64_t *cluster_offset)
{
/* seek the the l2 offset in the l1 table */
l1_index = offset >> l1_bits;
- if (l1_index >= s->l1_size)
+ if (l1_index >= s->l1_size) {
+ ret = QCOW2_CLUSTER_UNALLOCATED;
goto out;
+ }
- l2_offset = s->l1_table[l1_index];
-
- /* seek the l2 table of the given l2 offset */
-
- if (!l2_offset)
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
+ if (!l2_offset) {
+ ret = QCOW2_CLUSTER_UNALLOCATED;
goto out;
+ }
/* load the l2 table in memory */
- l2_offset &= ~QCOW_OFLAG_COPIED;
ret = l2_load(bs, l2_offset, &l2_table);
if (ret < 0) {
return ret;
*cluster_offset = be64_to_cpu(l2_table[l2_index]);
nb_clusters = size_to_clusters(s, nb_needed << 9);
- if (!*cluster_offset) {
+ ret = qcow2_get_cluster_type(*cluster_offset);
+ switch (ret) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ /* Compressed clusters can only be processed one by one */
+ c = 1;
+ *cluster_offset &= L2E_COMPRESSED_OFFSET_SIZE_MASK;
+ break;
+ case QCOW2_CLUSTER_ZERO:
+ c = count_contiguous_clusters(nb_clusters, s->cluster_size,
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
+ *cluster_offset = 0;
+ break;
+ case QCOW2_CLUSTER_UNALLOCATED:
/* how many empty clusters ? */
c = count_contiguous_free_clusters(nb_clusters, &l2_table[l2_index]);
- } else {
+ *cluster_offset = 0;
+ break;
+ case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], 0, QCOW_OFLAG_COPIED);
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
+ *cluster_offset &= L2E_OFFSET_MASK;
+ break;
}
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
- nb_available = (c * s->cluster_sectors);
+ nb_available = (c * s->cluster_sectors);
+
out:
if (nb_available > nb_needed)
nb_available = nb_needed;
*num = nb_available - index_in_cluster;
- *cluster_offset &=~QCOW_OFLAG_COPIED;
- return 0;
+ return ret;
}
/*
return ret;
}
}
- l2_offset = s->l1_table[l1_index];
+
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
/* seek the l2 table of the given l2 offset */
- if (l2_offset & QCOW_OFLAG_COPIED) {
+ if (s->l1_table[l1_index] & QCOW_OFLAG_COPIED) {
/* load the l2 table in memory */
- l2_offset &= ~QCOW_OFLAG_COPIED;
ret = l2_load(bs, l2_offset, &l2_table);
if (ret < 0) {
return ret;
if (l2_offset) {
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
}
- l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
+ l2_offset = s->l1_table[l1_index] & L1E_OFFSET_MASK;
}
/* find the cluster offset for the given disk offset */
return 0;
}
+ /* Compression can't overwrite anything. Fail if the cluster was already
+ * allocated. */
cluster_offset = be64_to_cpu(l2_table[l2_index]);
- if (cluster_offset & QCOW_OFLAG_COPIED) {
+ if (cluster_offset & L2E_OFFSET_MASK) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
return 0;
}
- if (cluster_offset)
- qcow2_free_any_clusters(bs, cluster_offset, 1);
-
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
if (cluster_offset < 0) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
*/
if (j != 0) {
for (i = 0; i < j; i++) {
- qcow2_free_any_clusters(bs,
- be64_to_cpu(old_cluster[i]) & ~QCOW_OFLAG_COPIED, 1);
+ qcow2_free_any_clusters(bs, be64_to_cpu(old_cluster[i]), 1);
}
}
static int count_cow_clusters(BDRVQcowState *s, int nb_clusters,
uint64_t *l2_table, int l2_index)
{
- int i = 0;
- uint64_t cluster_offset;
+ int i;
- while (i < nb_clusters) {
- i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
- &l2_table[l2_index], i, 0);
- if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
- break;
- }
+ for (i = 0; i < nb_clusters; i++) {
+ uint64_t l2_entry = be64_to_cpu(l2_table[l2_index + i]);
+ int cluster_type = qcow2_get_cluster_type(l2_entry);
- i += count_contiguous_free_clusters(nb_clusters - i,
- &l2_table[l2_index + i]);
- if (i >= nb_clusters) {
+ switch(cluster_type) {
+ case QCOW2_CLUSTER_NORMAL:
+ if (l2_entry & QCOW_OFLAG_COPIED) {
+ goto out;
+ }
break;
- }
-
- cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
-
- if ((cluster_offset & QCOW_OFLAG_COPIED) ||
- (cluster_offset & QCOW_OFLAG_COMPRESSED))
+ case QCOW2_CLUSTER_UNALLOCATED:
+ case QCOW2_CLUSTER_COMPRESSED:
+ case QCOW2_CLUSTER_ZERO:
break;
+ default:
+ abort();
+ }
}
+out:
assert(i <= nb_clusters);
return i;
}
* Check how many clusters are already allocated and don't need COW, and how
* many need a new allocation.
*/
- if (cluster_offset & QCOW_OFLAG_COPIED) {
+ if (qcow2_get_cluster_type(cluster_offset) == QCOW2_CLUSTER_NORMAL
+ && (cluster_offset & QCOW_OFLAG_COPIED))
+ {
/* We keep all QCOW_OFLAG_COPIED clusters */
- keep_clusters = count_contiguous_clusters(nb_clusters, s->cluster_size,
- &l2_table[l2_index], 0, 0);
+ keep_clusters =
+ count_contiguous_clusters(nb_clusters, s->cluster_size,
+ &l2_table[l2_index], 0,
+ QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters);
nb_clusters -= keep_clusters;
} else {
cluster_offset = 0;
}
- cluster_offset &= ~QCOW_OFLAG_COPIED;
+ cluster_offset &= L2E_OFFSET_MASK;
/* If there is something left to allocate, do that now */
*m = (QCowL2Meta) {
fail:
qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
fail_put:
- if (nb_clusters > 0) {
+ if (m->nb_clusters > 0) {
QLIST_REMOVE(m, next_in_flight);
}
return ret;
uint64_t old_offset;
old_offset = be64_to_cpu(l2_table[l2_index + i]);
- old_offset &= ~QCOW_OFLAG_COPIED;
-
- if (old_offset == 0) {
+ if ((old_offset & L2E_OFFSET_MASK) == 0) {
continue;
}
return 0;
}
+
+/*
+ * This zeroes as many clusters of nb_clusters as possible at once (i.e.
+ * all clusters in the same L2 table) and returns the number of zeroed
+ * clusters.
+ */
+static int zero_single_l2(BlockDriverState *bs, uint64_t offset,
+ unsigned int nb_clusters)
+{
+ BDRVQcowState *s = bs->opaque;
+ uint64_t *l2_table;
+ int l2_index;
+ int ret;
+ int i;
+
+ ret = get_cluster_table(bs, offset, &l2_table, &l2_index);
+ if (ret < 0) {
+ return ret;
+ }
+
+ /* Limit nb_clusters to one L2 table */
+ nb_clusters = MIN(nb_clusters, s->l2_size - l2_index);
+
+ for (i = 0; i < nb_clusters; i++) {
+ uint64_t old_offset;
+
+ old_offset = be64_to_cpu(l2_table[l2_index + i]);
+
+ /* Update L2 entries */
+ qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);
+ if (old_offset & QCOW_OFLAG_COMPRESSED) {
+ l2_table[l2_index + i] = cpu_to_be64(QCOW_OFLAG_ZERO);
+ qcow2_free_any_clusters(bs, old_offset, 1);
+ } else {
+ l2_table[l2_index + i] |= cpu_to_be64(QCOW_OFLAG_ZERO);
+ }
+ }
+
+ ret = qcow2_cache_put(bs, s->l2_table_cache, (void**) &l2_table);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return nb_clusters;
+}
+
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
+{
+ BDRVQcowState *s = bs->opaque;
+ unsigned int nb_clusters;
+ int ret;
+
+ /* The zero flag is only supported by version 3 and newer */
+ if (s->qcow_version < 3) {
+ return -ENOTSUP;
+ }
+
+ /* Each L2 table is handled by its own loop iteration */
+ nb_clusters = size_to_clusters(s, nb_sectors << BDRV_SECTOR_BITS);
+
+ while (nb_clusters > 0) {
+ ret = zero_single_l2(bs, offset, nb_clusters);
+ if (ret < 0) {
+ return ret;
+ }
+
+ nb_clusters -= ret;
+ offset += (ret * s->cluster_size);
+ }
+
+ return 0;
+}
if (refcount_table_index < s->refcount_table_size) {
uint64_t refcount_block_offset =
- s->refcount_table[refcount_table_index];
+ s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
/* If it's already there, we're done */
if (refcount_block_offset) {
return ret;
}
- return new_block;
+ return 0;
fail_table:
g_free(new_table);
{
BDRVQcowState *s = bs->opaque;
uint64_t cluster_index;
+ uint64_t old_free_cluster_index;
int i, refcount, ret;
/* Check how many clusters there are free */
}
/* And then allocate them */
+ old_free_cluster_index = s->free_cluster_index;
+ s->free_cluster_index = cluster_index + i;
+
ret = update_refcount(bs, offset, i << s->cluster_bits, 1);
if (ret < 0) {
return ret;
}
+ s->free_cluster_index = old_free_cluster_index;
+
return i;
}
}
/*
- * free_any_clusters
- *
- * free clusters according to its type: compressed or not
- *
+ * Free a cluster using its L2 entry (handles clusters of all types, e.g.
+ * normal cluster, compressed cluster, etc.)
*/
-
void qcow2_free_any_clusters(BlockDriverState *bs,
- uint64_t cluster_offset, int nb_clusters)
+ uint64_t l2_entry, int nb_clusters)
{
BDRVQcowState *s = bs->opaque;
- /* free the cluster */
-
- if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
- int nb_csectors;
- nb_csectors = ((cluster_offset >> s->csize_shift) &
- s->csize_mask) + 1;
- qcow2_free_clusters(bs,
- (cluster_offset & s->cluster_offset_mask) & ~511,
- nb_csectors * 512);
- return;
+ switch (qcow2_get_cluster_type(l2_entry)) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ {
+ int nb_csectors;
+ nb_csectors = ((l2_entry >> s->csize_shift) &
+ s->csize_mask) + 1;
+ qcow2_free_clusters(bs,
+ (l2_entry & s->cluster_offset_mask) & ~511,
+ nb_csectors * 512);
+ }
+ break;
+ case QCOW2_CLUSTER_NORMAL:
+ qcow2_free_clusters(bs, l2_entry & L2E_OFFSET_MASK,
+ nb_clusters << s->cluster_bits);
+ break;
+ case QCOW2_CLUSTER_UNALLOCATED:
+ case QCOW2_CLUSTER_ZERO:
+ break;
+ default:
+ abort();
}
-
- qcow2_free_clusters(bs, cluster_offset, nb_clusters << s->cluster_bits);
-
- return;
}
l2_offset = l1_table[i];
if (l2_offset) {
old_l2_offset = l2_offset;
- l2_offset &= ~QCOW_OFLAG_COPIED;
+ l2_offset &= L1E_OFFSET_MASK;
ret = qcow2_cache_get(bs, s->l2_table_cache, l2_offset,
(void**) &l2_table);
/* compressed clusters are never modified */
refcount = 2;
} else {
+ uint64_t cluster_index = (offset & L2E_OFFSET_MASK) >> s->cluster_bits;
if (addend != 0) {
- refcount = update_cluster_refcount(bs, offset >> s->cluster_bits, addend);
+ refcount = update_cluster_refcount(bs, cluster_index, addend);
} else {
- refcount = get_refcount(bs, offset >> s->cluster_bits);
+ refcount = get_refcount(bs, cluster_index);
}
if (refcount < 0) {
int check_copied)
{
BDRVQcowState *s = bs->opaque;
- uint64_t *l2_table, offset;
+ uint64_t *l2_table, l2_entry;
int i, l2_size, nb_csectors, refcount;
/* Read L2 table from disk */
/* Do the actual checks */
for(i = 0; i < s->l2_size; i++) {
- offset = be64_to_cpu(l2_table[i]);
- if (offset != 0) {
- if (offset & QCOW_OFLAG_COMPRESSED) {
- /* Compressed clusters don't have QCOW_OFLAG_COPIED */
- if (offset & QCOW_OFLAG_COPIED) {
- fprintf(stderr, "ERROR: cluster %" PRId64 ": "
- "copied flag must never be set for compressed "
- "clusters\n", offset >> s->cluster_bits);
- offset &= ~QCOW_OFLAG_COPIED;
- res->corruptions++;
- }
+ l2_entry = be64_to_cpu(l2_table[i]);
+
+ switch (qcow2_get_cluster_type(l2_entry)) {
+ case QCOW2_CLUSTER_COMPRESSED:
+ /* Compressed clusters don't have QCOW_OFLAG_COPIED */
+ if (l2_entry & QCOW_OFLAG_COPIED) {
+ fprintf(stderr, "ERROR: cluster %" PRId64 ": "
+ "copied flag must never be set for compressed "
+ "clusters\n", l2_entry >> s->cluster_bits);
+ l2_entry &= ~QCOW_OFLAG_COPIED;
+ res->corruptions++;
+ }
- /* Mark cluster as used */
- nb_csectors = ((offset >> s->csize_shift) &
- s->csize_mask) + 1;
- offset &= s->cluster_offset_mask;
- inc_refcounts(bs, res, refcount_table, refcount_table_size,
- offset & ~511, nb_csectors * 512);
- } else {
- /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
- if (check_copied) {
- uint64_t entry = offset;
- offset &= ~QCOW_OFLAG_COPIED;
- refcount = get_refcount(bs, offset >> s->cluster_bits);
- if (refcount < 0) {
- fprintf(stderr, "Can't get refcount for offset %"
- PRIx64 ": %s\n", entry, strerror(-refcount));
- goto fail;
- }
- if ((refcount == 1) != ((entry & QCOW_OFLAG_COPIED) != 0)) {
- fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
- PRIx64 " refcount=%d\n", entry, refcount);
- res->corruptions++;
- }
- }
+ /* Mark cluster as used */
+ nb_csectors = ((l2_entry >> s->csize_shift) &
+ s->csize_mask) + 1;
+ l2_entry &= s->cluster_offset_mask;
+ inc_refcounts(bs, res, refcount_table, refcount_table_size,
+ l2_entry & ~511, nb_csectors * 512);
+ break;
- /* Mark cluster as used */
- offset &= ~QCOW_OFLAG_COPIED;
- inc_refcounts(bs, res, refcount_table,refcount_table_size,
- offset, s->cluster_size);
+ case QCOW2_CLUSTER_ZERO:
+ if ((l2_entry & L2E_OFFSET_MASK) == 0) {
+ break;
+ }
+ /* fall through */
- /* Correct offsets are cluster aligned */
- if (offset & (s->cluster_size - 1)) {
- fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
- "properly aligned; L2 entry corrupted.\n", offset);
+ case QCOW2_CLUSTER_NORMAL:
+ {
+ /* QCOW_OFLAG_COPIED must be set iff refcount == 1 */
+ uint64_t offset = l2_entry & L2E_OFFSET_MASK;
+
+ if (check_copied) {
+ refcount = get_refcount(bs, offset >> s->cluster_bits);
+ if (refcount < 0) {
+ fprintf(stderr, "Can't get refcount for offset %"
+ PRIx64 ": %s\n", l2_entry, strerror(-refcount));
+ goto fail;
+ }
+ if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
+ fprintf(stderr, "ERROR OFLAG_COPIED: offset=%"
+ PRIx64 " refcount=%d\n", l2_entry, refcount);
res->corruptions++;
}
}
+
+ /* Mark cluster as used */
+ inc_refcounts(bs, res, refcount_table,refcount_table_size,
+ offset, s->cluster_size);
+
+ /* Correct offsets are cluster aligned */
+ if (offset & (s->cluster_size - 1)) {
+ fprintf(stderr, "ERROR offset=%" PRIx64 ": Cluster is not "
+ "properly aligned; L2 entry corrupted.\n", offset);
+ res->corruptions++;
+ }
+ break;
+ }
+
+ case QCOW2_CLUSTER_UNALLOCATED:
+ break;
+
+ default:
+ abort();
}
}
}
/* Mark L2 table as used */
- l2_offset &= ~QCOW_OFLAG_COPIED;
+ l2_offset &= L1E_OFFSET_MASK;
inc_refcounts(bs, res, refcount_table, refcount_table_size,
l2_offset, s->cluster_size);
typedef struct QEMU_PACKED QCowSnapshotExtraData {
uint64_t vm_state_size_large;
+ uint64_t disk_size;
} QCowSnapshotExtraData;
void qcow2_free_snapshots(BlockDriverState *bs)
sn->vm_state_size = be64_to_cpu(extra.vm_state_size_large);
}
+ if (extra_data_size >= 16) {
+ sn->disk_size = be64_to_cpu(extra.disk_size);
+ } else {
+ sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
+ }
+
/* Read snapshot ID */
sn->id_str = g_malloc(id_str_size + 1);
ret = bdrv_pread(bs->file, offset, sn->id_str, id_str_size);
memset(&extra, 0, sizeof(extra));
extra.vm_state_size_large = cpu_to_be64(sn->vm_state_size);
+ extra.disk_size = cpu_to_be64(sn->disk_size);
id_str_size = strlen(sn->id_str);
name_size = strlen(sn->name);
sn->id_str = g_strdup(sn_info->id_str);
sn->name = g_strdup(sn_info->name);
+ sn->disk_size = bs->total_sectors * BDRV_SECTOR_SIZE;
sn->vm_state_size = sn_info->vm_state_size;
sn->date_sec = sn_info->date_sec;
sn->date_nsec = sn_info->date_nsec;
}
sn = &s->snapshots[snapshot_index];
+ if (sn->disk_size != bs->total_sectors * BDRV_SECTOR_SIZE) {
+ error_report("qcow2: Loading snapshots with different disk "
+ "size is not implemented");
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
/*
* Make sure that the current L1 table is big enough to contain the whole
* L1 table of the snapshot. If the snapshot L1 table is smaller, the
} QCowExtension;
#define QCOW2_EXT_MAGIC_END 0
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
+#define QCOW2_EXT_MAGIC_FEATURE_TABLE 0x6803f857
static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
{
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
- be32_to_cpu(cow_header->version) >= QCOW_VERSION)
+ be32_to_cpu(cow_header->version) >= 2)
return 100;
else
return 0;
* return 0 upon success, non-0 otherwise
*/
static int qcow2_read_extensions(BlockDriverState *bs, uint64_t start_offset,
- uint64_t end_offset)
+ uint64_t end_offset, void **p_feature_table)
{
BDRVQcowState *s = bs->opaque;
QCowExtension ext;
#endif
break;
+ case QCOW2_EXT_MAGIC_FEATURE_TABLE:
+ if (p_feature_table != NULL) {
+ void* feature_table = g_malloc0(ext.len + 2 * sizeof(Qcow2Feature));
+ ret = bdrv_pread(bs->file, offset , feature_table, ext.len);
+ if (ret < 0) {
+ return ret;
+ }
+
+ *p_feature_table = feature_table;
+ }
+ break;
+
default:
/* unknown magic - save it in case we need to rewrite the header */
{
}
}
+static void report_unsupported(BlockDriverState *bs, const char *fmt, ...)
+{
+ char msg[64];
+ va_list ap;
+
+ va_start(ap, fmt);
+ vsnprintf(msg, sizeof(msg), fmt, ap);
+ va_end(ap);
+
+ qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ bs->device_name, "qcow2", msg);
+}
+
+static void report_unsupported_feature(BlockDriverState *bs,
+ Qcow2Feature *table, uint64_t mask)
+{
+ while (table && table->name[0] != '\0') {
+ if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
+ if (mask & (1 << table->bit)) {
+ report_unsupported(bs, "%.46s",table->name);
+ mask &= ~(1 << table->bit);
+ }
+ }
+ table++;
+ }
+
+ if (mask) {
+ report_unsupported(bs, "Unknown incompatible feature: %" PRIx64, mask);
+ }
+}
+
static int qcow2_open(BlockDriverState *bs, int flags)
{
BDRVQcowState *s = bs->opaque;
ret = -EINVAL;
goto fail;
}
- if (header.version != QCOW_VERSION) {
- char version[64];
- snprintf(version, sizeof(version), "QCOW version %d", header.version);
- qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
- bs->device_name, "qcow2", version);
+ if (header.version < 2 || header.version > 3) {
+ report_unsupported(bs, "QCOW version %d", header.version);
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ s->qcow_version = header.version;
+
+ /* Initialise version 3 header fields */
+ if (header.version == 2) {
+ header.incompatible_features = 0;
+ header.compatible_features = 0;
+ header.autoclear_features = 0;
+ header.refcount_order = 4;
+ header.header_length = 72;
+ } else {
+ be64_to_cpus(&header.incompatible_features);
+ be64_to_cpus(&header.compatible_features);
+ be64_to_cpus(&header.autoclear_features);
+ be32_to_cpus(&header.refcount_order);
+ be32_to_cpus(&header.header_length);
+ }
+
+ if (header.header_length > sizeof(header)) {
+ s->unknown_header_fields_size = header.header_length - sizeof(header);
+ s->unknown_header_fields = g_malloc(s->unknown_header_fields_size);
+ ret = bdrv_pread(bs->file, sizeof(header), s->unknown_header_fields,
+ s->unknown_header_fields_size);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
+
+ if (header.backing_file_offset) {
+ ext_end = header.backing_file_offset;
+ } else {
+ ext_end = 1 << header.cluster_bits;
+ }
+
+ /* Handle feature bits */
+ s->incompatible_features = header.incompatible_features;
+ s->compatible_features = header.compatible_features;
+ s->autoclear_features = header.autoclear_features;
+
+ if (s->incompatible_features != 0) {
+ void *feature_table = NULL;
+ qcow2_read_extensions(bs, header.header_length, ext_end,
+ &feature_table);
+ report_unsupported_feature(bs, feature_table,
+ s->incompatible_features);
+ ret = -ENOTSUP;
+ goto fail;
+ }
+
+ if (!bs->read_only && s->autoclear_features != 0) {
+ s->autoclear_features = 0;
+ qcow2_update_header(bs);
+ }
+
+ /* Check support for various header values */
+ if (header.refcount_order != 4) {
+ report_unsupported(bs, "%d bit reference counts",
+ 1 << header.refcount_order);
ret = -ENOTSUP;
goto fail;
}
+
if (header.cluster_bits < MIN_CLUSTER_BITS ||
header.cluster_bits > MAX_CLUSTER_BITS) {
ret = -EINVAL;
QLIST_INIT(&s->cluster_allocs);
/* read qcow2 extensions */
- if (header.backing_file_offset) {
- ext_end = header.backing_file_offset;
- } else {
- ext_end = s->cluster_size;
- }
- if (qcow2_read_extensions(bs, sizeof(header), ext_end)) {
+ if (qcow2_read_extensions(bs, header.header_length, ext_end, NULL)) {
ret = -EINVAL;
goto fail;
}
return ret;
fail:
+ g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
qcow2_free_snapshots(bs);
qcow2_refcount_close(bs);
qemu_iovec_copy(&hd_qiov, qiov, bytes_done,
cur_nr_sectors * 512);
- if (!cluster_offset) {
+ switch (ret) {
+ case QCOW2_CLUSTER_UNALLOCATED:
if (bs->backing_hd) {
/* read from the base image */
/* Note: in this case, no need to wait */
qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
}
- } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {
+ break;
+
+ case QCOW2_CLUSTER_ZERO:
+ if (s->qcow_version < 3) {
+ ret = -EIO;
+ goto fail;
+ }
+ qemu_iovec_memset(&hd_qiov, 0, 512 * cur_nr_sectors);
+ break;
+
+ case QCOW2_CLUSTER_COMPRESSED:
/* add AIO support for compressed blocks ? */
ret = qcow2_decompress_cluster(bs, cluster_offset);
if (ret < 0) {
qemu_iovec_from_buffer(&hd_qiov,
s->cluster_cache + index_in_cluster * 512,
512 * cur_nr_sectors);
- } else {
+ break;
+
+ case QCOW2_CLUSTER_NORMAL:
if ((cluster_offset & 511) != 0) {
ret = -EIO;
goto fail;
qemu_iovec_from_buffer(&hd_qiov, cluster_data,
512 * cur_nr_sectors);
}
+ break;
+
+ default:
+ g_assert_not_reached();
+ ret = -EIO;
+ goto fail;
}
remaining_sectors -= cur_nr_sectors;
qcow2_cache_destroy(bs, s->l2_table_cache);
qcow2_cache_destroy(bs, s->refcount_block_cache);
+ g_free(s->unknown_header_fields);
cleanup_unknown_header_ext(bs);
+
g_free(s->cluster_cache);
qemu_vfree(s->cluster_data);
qcow2_refcount_close(bs);
int ret;
uint64_t total_size;
uint32_t refcount_table_clusters;
+ size_t header_length;
Qcow2UnknownHeaderExtension *uext;
buf = qemu_blockalign(bs, buflen);
- memset(buf, 0, s->cluster_size);
/* Header structure */
header = (QCowHeader*) buf;
goto fail;
}
+ header_length = sizeof(*header) + s->unknown_header_fields_size;
total_size = bs->total_sectors * BDRV_SECTOR_SIZE;
refcount_table_clusters = s->refcount_table_size >> (s->cluster_bits - 3);
*header = (QCowHeader) {
+ /* Version 2 fields */
.magic = cpu_to_be32(QCOW_MAGIC),
- .version = cpu_to_be32(QCOW_VERSION),
+ .version = cpu_to_be32(s->qcow_version),
.backing_file_offset = 0,
.backing_file_size = 0,
.cluster_bits = cpu_to_be32(s->cluster_bits),
.refcount_table_clusters = cpu_to_be32(refcount_table_clusters),
.nb_snapshots = cpu_to_be32(s->nb_snapshots),
.snapshots_offset = cpu_to_be64(s->snapshots_offset),
+
+ /* Version 3 fields */
+ .incompatible_features = cpu_to_be64(s->incompatible_features),
+ .compatible_features = cpu_to_be64(s->compatible_features),
+ .autoclear_features = cpu_to_be64(s->autoclear_features),
+ .refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT),
+ .header_length = cpu_to_be32(header_length),
};
- buf += sizeof(*header);
- buflen -= sizeof(*header);
+ /* For older versions, write a shorter header */
+ switch (s->qcow_version) {
+ case 2:
+ ret = offsetof(QCowHeader, incompatible_features);
+ break;
+ case 3:
+ ret = sizeof(*header);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ buf += ret;
+ buflen -= ret;
+ memset(buf, 0, buflen);
+
+ /* Preserve any unknown field in the header */
+ if (s->unknown_header_fields_size) {
+ if (buflen < s->unknown_header_fields_size) {
+ ret = -ENOSPC;
+ goto fail;
+ }
+
+ memcpy(buf, s->unknown_header_fields, s->unknown_header_fields_size);
+ buf += s->unknown_header_fields_size;
+ buflen -= s->unknown_header_fields_size;
+ }
/* Backing file format header extension */
if (*bs->backing_format) {
buflen -= ret;
}
+ /* Feature table */
+ Qcow2Feature features[] = {
+ /* no feature defined yet */
+ };
+
+ ret = header_ext_add(buf, QCOW2_EXT_MAGIC_FEATURE_TABLE,
+ features, sizeof(features), buflen);
+ if (ret < 0) {
+ goto fail;
+ }
+ buf += ret;
+ buflen -= ret;
+
/* Keep unknown header extensions */
QLIST_FOREACH(uext, &s->unknown_header_ext, next) {
ret = header_ext_add(buf, uext->magic, uext->data, uext->len, buflen);
static int qcow2_create2(const char *filename, int64_t total_size,
const char *backing_file, const char *backing_format,
int flags, size_t cluster_size, int prealloc,
- QEMUOptionParameter *options)
+ QEMUOptionParameter *options, int version)
{
/* Calculate cluster_bits */
int cluster_bits;
/* Write the header */
memset(&header, 0, sizeof(header));
header.magic = cpu_to_be32(QCOW_MAGIC);
- header.version = cpu_to_be32(QCOW_VERSION);
+ header.version = cpu_to_be32(version);
header.cluster_bits = cpu_to_be32(cluster_bits);
header.size = cpu_to_be64(0);
header.l1_table_offset = cpu_to_be64(0);
header.l1_size = cpu_to_be32(0);
header.refcount_table_offset = cpu_to_be64(cluster_size);
header.refcount_table_clusters = cpu_to_be32(1);
+ header.refcount_order = cpu_to_be32(3 + REFCOUNT_SHIFT);
+ header.header_length = cpu_to_be32(sizeof(header));
if (flags & BLOCK_FLAG_ENCRYPT) {
header.crypt_method = cpu_to_be32(QCOW_CRYPT_AES);
int flags = 0;
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
int prealloc = 0;
+ int version = 2;
/* Read out options */
while (options && options->name) {
options->value.s);
return -EINVAL;
}
+ } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
+ if (!options->value.s || !strcmp(options->value.s, "0.10")) {
+ version = 2;
+ } else if (!strcmp(options->value.s, "1.1")) {
+ version = 3;
+ } else {
+ fprintf(stderr, "Invalid compatibility level: '%s'\n",
+ options->value.s);
+ return -EINVAL;
+ }
}
options++;
}
}
return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
- cluster_size, prealloc, options);
+ cluster_size, prealloc, options, version);
}
static int qcow2_make_empty(BlockDriverState *bs)
return 0;
}
+static coroutine_fn int qcow2_co_write_zeroes(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors)
+{
+ int ret;
+ BDRVQcowState *s = bs->opaque;
+
+ /* Emulate misaligned zero writes */
+ if (sector_num % s->cluster_sectors || nb_sectors % s->cluster_sectors) {
+ return -ENOTSUP;
+ }
+
+ /* Whatever is left can use real zero clusters */
+ qemu_co_mutex_lock(&s->lock);
+ ret = qcow2_zero_clusters(bs, sector_num << BDRV_SECTOR_BITS,
+ nb_sectors);
+ qemu_co_mutex_unlock(&s->lock);
+
+ return ret;
+}
+
static coroutine_fn int qcow2_co_discard(BlockDriverState *bs,
int64_t sector_num, int nb_sectors)
{
.type = OPT_SIZE,
.help = "Virtual disk size"
},
+ {
+ .name = BLOCK_OPT_COMPAT_LEVEL,
+ .type = OPT_STRING,
+ .help = "Compatibility level (0.10 or 1.1)"
+ },
{
.name = BLOCK_OPT_BACKING_FILE,
.type = OPT_STRING,
.bdrv_co_writev = qcow2_co_writev,
.bdrv_co_flush_to_os = qcow2_co_flush_to_os,
+ .bdrv_co_write_zeroes = qcow2_co_write_zeroes,
.bdrv_co_discard = qcow2_co_discard,
.bdrv_truncate = qcow2_truncate,
.bdrv_write_compressed = qcow2_write_compressed,
//#define DEBUG_EXT
#define QCOW_MAGIC (('Q' << 24) | ('F' << 16) | ('I' << 8) | 0xfb)
-#define QCOW_VERSION 2
#define QCOW_CRYPT_NONE 0
#define QCOW_CRYPT_AES 1
#define QCOW_OFLAG_COPIED (1LL << 63)
/* indicate that the cluster is compressed (they never have the copied flag) */
#define QCOW_OFLAG_COMPRESSED (1LL << 62)
+/* The cluster reads as all zeros */
+#define QCOW_OFLAG_ZERO (1LL << 0)
#define REFCOUNT_SHIFT 1 /* refcount size is 2 bytes */
uint32_t refcount_table_clusters;
uint32_t nb_snapshots;
uint64_t snapshots_offset;
+
+ /* The following fields are only valid for version >= 3 */
+ uint64_t incompatible_features;
+ uint64_t compatible_features;
+ uint64_t autoclear_features;
+
+ uint32_t refcount_order;
+ uint32_t header_length;
} QCowHeader;
typedef struct QCowSnapshot {
uint32_t l1_size;
char *id_str;
char *name;
+ uint64_t disk_size;
uint64_t vm_state_size;
uint32_t date_sec;
uint32_t date_nsec;
uint8_t data[];
} Qcow2UnknownHeaderExtension;
+enum {
+ QCOW2_FEAT_TYPE_INCOMPATIBLE = 0,
+ QCOW2_FEAT_TYPE_COMPATIBLE = 1,
+ QCOW2_FEAT_TYPE_AUTOCLEAR = 2,
+};
+
+typedef struct Qcow2Feature {
+ uint8_t type;
+ uint8_t bit;
+ char name[46];
+} QEMU_PACKED Qcow2Feature;
+
typedef struct BDRVQcowState {
int cluster_bits;
int cluster_size;
QCowSnapshot *snapshots;
int flags;
+ int qcow_version;
+
+ uint64_t incompatible_features;
+ uint64_t compatible_features;
+ uint64_t autoclear_features;
+
+ size_t unknown_header_fields_size;
+ void* unknown_header_fields;
QLIST_HEAD(, Qcow2UnknownHeaderExtension) unknown_header_ext;
} BDRVQcowState;
QLIST_ENTRY(QCowL2Meta) next_in_flight;
} QCowL2Meta;
+enum {
+ QCOW2_CLUSTER_UNALLOCATED,
+ QCOW2_CLUSTER_NORMAL,
+ QCOW2_CLUSTER_COMPRESSED,
+ QCOW2_CLUSTER_ZERO
+};
+
+#define L1E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_OFFSET_MASK 0x00ffffffffffff00ULL
+#define L2E_COMPRESSED_OFFSET_SIZE_MASK 0x3fffffffffffffffULL
+
+#define REFT_OFFSET_MASK 0xffffffffffffff00ULL
+
static inline int size_to_clusters(BDRVQcowState *s, int64_t size)
{
return (size + (s->cluster_size - 1)) >> s->cluster_bits;
return offset;
}
+static inline int qcow2_get_cluster_type(uint64_t l2_entry)
+{
+ if (l2_entry & QCOW_OFLAG_COMPRESSED) {
+ return QCOW2_CLUSTER_COMPRESSED;
+ } else if (l2_entry & QCOW_OFLAG_ZERO) {
+ return QCOW2_CLUSTER_ZERO;
+ } else if (!(l2_entry & L2E_OFFSET_MASK)) {
+ return QCOW2_CLUSTER_UNALLOCATED;
+ } else {
+ return QCOW2_CLUSTER_NORMAL;
+ }
+}
+
// FIXME Need qcow2_ prefix to global functions
int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
int qcow2_discard_clusters(BlockDriverState *bs, uint64_t offset,
int nb_sectors);
+int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors);
/* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
fcntl(s->fds[0], F_SETFL, O_NONBLOCK);
fcntl(s->fds[1], F_SETFL, O_NONBLOCK);
qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], qemu_rbd_aio_event_reader,
- NULL, qemu_rbd_aio_flush_cb, NULL, s);
+ NULL, qemu_rbd_aio_flush_cb, s);
return 0;
close(s->fds[0]);
close(s->fds[1]);
- qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL , NULL, NULL, NULL,
- NULL);
+ qemu_aio_set_fd_handler(s->fds[RBD_FD_READ], NULL, NULL, NULL, NULL);
rbd_close(s->image);
rados_ioctx_destroy(s->io_ctx);
return -1;
}
- qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request,
- NULL, s);
+ qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
return fd;
}
qemu_co_mutex_lock(&s->lock);
s->co_send = qemu_coroutine_self();
qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request,
- aio_flush_request, NULL, s);
+ aio_flush_request, s);
socket_set_cork(s->fd, 1);
/* send a header */
socket_set_cork(s->fd, 0);
qemu_aio_set_fd_handler(s->fd, co_read_response, NULL,
- aio_flush_request, NULL, s);
+ aio_flush_request, s);
qemu_co_mutex_unlock(&s->lock);
return 0;
g_free(buf);
return 0;
out:
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
if (s->fd >= 0) {
closesocket(s->fd);
}
error_report("%s, %s", sd_strerror(rsp->result), s->name);
}
- qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL, NULL);
+ qemu_aio_set_fd_handler(s->fd, NULL, NULL, NULL, NULL);
closesocket(s->fd);
if (s->cache_enabled) {
closesocket(s->flush_fd);
#define BLOCK_OPT_TABLE_SIZE "table_size"
#define BLOCK_OPT_PREALLOC "preallocation"
#define BLOCK_OPT_SUBFMT "subformat"
+#define BLOCK_OPT_COMPAT_LEVEL "compat"
typedef struct BdrvTrackedRequest BdrvTrackedRequest;
#include "cmd.h"
#include "qemu-aio.h"
+#include "main-loop.h"
#define _(x) x /* not gettext support yet */
{
int *fetchable = opaque;
- qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
*fetchable= 1;
}
if (!prompted) {
printf("%s", get_prompt());
fflush(stdout);
- qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
- NULL, &fetchable);
+ qemu_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, &fetchable);
prompted = 1;
}
- qemu_aio_wait();
+ main_loop_wait(false);
if (!fetchable) {
continue;
prompted = 0;
fetchable = 0;
}
- qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
+ qemu_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL);
}
/* from libxcmd/input.c */
EXESUF=""
prefix="/usr/local"
mandir="\${prefix}/share/man"
-datadir="\${prefix}/share/qemu"
-docdir="\${prefix}/share/doc/qemu"
+datadir="\${prefix}/share"
+qemu_docdir="\${prefix}/share/doc/qemu"
bindir="\${prefix}/bin"
libdir="\${prefix}/lib"
includedir="\${prefix}/include"
prefix="c:/Program Files/QEMU"
mandir="\${prefix}"
datadir="\${prefix}"
- docdir="\${prefix}"
+ qemu_docdir="\${prefix}"
bindir="\${prefix}"
sysconfdir="\${prefix}"
confsuffix=""
;;
--datadir=*) datadir="$optarg"
;;
- --docdir=*) docdir="$optarg"
+ --with-confsuffix=*) confsuffix="$optarg"
+ ;;
+ --docdir=*) qemu_docdir="$optarg"
;;
--sysconfdir=*) sysconfdir="$optarg"
;;
echo " --smbd=SMBD use specified smbd [$smbd]"
echo " --static enable static build [$static]"
echo " --mandir=PATH install man pages in PATH"
-echo " --datadir=PATH install firmware in PATH"
-echo " --docdir=PATH install documentation in PATH"
+echo " --datadir=PATH install firmware in PATH$confsuffix"
+echo " --docdir=PATH install documentation in PATH$confsuffix"
echo " --bindir=PATH install binaries in PATH"
-echo " --sysconfdir=PATH install config in PATH/qemu"
+echo " --sysconfdir=PATH install config in PATH$confsuffix"
+echo " --with-confsuffix=SUFFIX suffix for Qemu data inside datadir and sysconfdir [$confsuffix]"
echo " --enable-debug-tcg enable TCG debugging"
echo " --disable-debug-tcg disable TCG debugging (default)"
echo " --enable-debug enable common debug build options"
echo " --disable-vhost-net disable vhost-net acceleration support"
echo " --enable-vhost-net enable vhost-net acceleration support"
echo " --enable-trace-backend=B Set trace backend"
-echo " Available backends:" $("$source_path"/scripts/tracetool --list-backends)
+echo " Available backends:" $($python "$source_path"/scripts/tracetool.py --list-backends)
echo " --with-trace-file=NAME Full PATH,NAME of file to store traces"
echo " Default:trace-<pid>"
echo " --disable-spice disable spice"
#if !defined(HVM_MAX_VCPUS)
# error HVM_MAX_VCPUS not defined
#endif
+int main(void) {
+ xc_interface *xc;
+ xs_daemon_open();
+ xc = xc_interface_open(0, 0, 0);
+ xc_hvm_set_mem_type(0, 0, HVMMEM_ram_ro, 0, 0);
+ xc_gnttab_open(NULL, 0);
+ xc_domain_add_to_physmap(0, 0, XENMAPSPACE_gmfn, 0, 0);
+ xc_hvm_inject_msi(xc, 0, 0xf0000000, 0x00000000);
+ return 0;
+}
+EOF
+ compile_prog "" "$xen_libs"
+ ) ; then
+ xen_ctrl_version=420
+ xen=yes
+
+ elif (
+ cat > $TMPC <<EOF
+#include <xenctrl.h>
+#include <xs.h>
+#include <stdint.h>
+#include <xen/hvm/hvm_info_table.h>
+#if !defined(HVM_MAX_VCPUS)
+# error HVM_MAX_VCPUS not defined
+#endif
int main(void) {
xc_interface *xc;
xs_daemon_open();
for pthread_lib in $PTHREADLIBS_LIST; do
if compile_prog "" "$pthread_lib" ; then
pthread=yes
- LIBS="$pthread_lib $LIBS"
+ found=no
+ for lib_entry in $LIBS; do
+ if test "$lib_entry" = "$pthread_lib"; then
+ found=yes
+ break
+ fi
+ done
+ if test "$found" = "no"; then
+ LIBS="$pthread_lib $LIBS"
+ fi
break
fi
done
##########################################
# check if trace backend exists
-sh "$source_path/scripts/tracetool" "--$trace_backend" --check-backend > /dev/null 2> /dev/null
+$python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null
if test "$?" -ne 0 ; then
echo
echo "Error: invalid trace backend"
done
fi
-confdir=$sysconfdir$confsuffix
+qemu_confdir=$sysconfdir$confsuffix
+qemu_datadir=$datadir$confsuffix
tools=
if test "$softmmu" = yes ; then
fi
echo "Install prefix $prefix"
-echo "BIOS directory `eval echo $datadir`"
+echo "BIOS directory `eval echo $qemu_datadir`"
echo "binary directory `eval echo $bindir`"
echo "library directory `eval echo $libdir`"
echo "include directory `eval echo $includedir`"
echo "libdir=$libdir" >> $config_host_mak
echo "includedir=$includedir" >> $config_host_mak
echo "mandir=$mandir" >> $config_host_mak
-echo "datadir=$datadir" >> $config_host_mak
echo "sysconfdir=$sysconfdir" >> $config_host_mak
-echo "docdir=$docdir" >> $config_host_mak
-echo "confdir=$confdir" >> $config_host_mak
+echo "qemu_confdir=$qemu_confdir" >> $config_host_mak
+echo "qemu_datadir=$qemu_datadir" >> $config_host_mak
+echo "qemu_docdir=$qemu_docdir" >> $config_host_mak
echo "libexecdir=\${prefix}/libexec" >> $config_host_mak
-echo "CONFIG_QEMU_SHAREDIR=\"$prefix$datasuffix\"" >> $config_host_mak
echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak
echo "ARCH=$ARCH" >> $config_host_mak
QCOW magic string ("QFI\xfb")
4 - 7: version
- Version number (only valid value is 2)
+ Version number (valid values are 2 and 3)
8 - 15: backing_file_offset
Offset into the image file at which the backing file name
Offset into the image file at which the snapshot table
starts. Must be aligned to a cluster boundary.
+If the version is 3 or higher, the header has the following additional fields.
+For version 2, the values are assumed to be zero, unless specified otherwise
+in the description of a field.
+
+ 72 - 79: incompatible_features
+ Bitmask of incompatible features. An implementation must
+ fail to open an image if an unknown bit is set.
+
+ Bits 0-63: Reserved (set to 0)
+
+ 80 - 87: compatible_features
+ Bitmask of compatible features. An implementation can
+ safely ignore any unknown bits that are set.
+
+ Bits 0-63: Reserved (set to 0)
+
+ 88 - 95: autoclear_features
+ Bitmask of auto-clear features. An implementation may only
+ write to an image with unknown auto-clear features if it
+ clears the respective bits from this field first.
+
+ Bits 0-63: Reserved (set to 0)
+
+ 96 - 99: refcount_order
+ Describes the width of a reference count block entry (width
+ in bits = 1 << refcount_order). For version 2 images, the
+ order is always assumed to be 4 (i.e. the width is 16 bits).
+
+ 100 - 103: header_length
+ Length of the header structure in bytes. For version 2
+ images, the length is always assumed to be 72 bytes.
+
Directly after the image header, optional sections called header extensions can
be stored. Each extension has a structure like the following:
Byte 0 - 3: Header extension type:
0x00000000 - End of the header extension area
0xE2792ACA - Backing file format name
+ 0x6803f857 - Feature name table
other - Unknown header extension, can be safely
ignored
n - m: Padding to round up the header extension size to the next
multiple of 8.
+Unless stated otherwise, each header extension type shall appear at most once
+in the same image.
+
The remaining space between the end of the header extension area and the end of
-the first cluster can be used for other data. Usually, the backing file name is
-stored there.
+the first cluster can be used for the backing file name. It is not allowed to
+store other data here, so that an implementation can safely modify the header
+and add extensions without harming data of compatible features that it
+doesn't support. Compatible features that need space for additional data can
+use a header extension.
+
+
+== Feature name table ==
+
+The feature name table is an optional header extension that contains the name
+for features used by the image. It can be used by applications that don't know
+the respective feature (e.g. because the feature was introduced only later) to
+display a useful error message.
+
+The number of entries in the feature name table is determined by the length of
+the header extension data. Each entry look like this:
+
+ Byte 0: Type of feature (select feature bitmap)
+ 0: Incompatible feature
+ 1: Compatible feature
+ 2: Autoclear feature
+
+ 1: Bit number within the selected feature bitmap (valid
+ values: 0-63)
+
+ 2 - 47: Feature name (padded with zeros, but not necessarily null
+ terminated if it has full length)
== Host cluster management ==
been allocated. All refcounts managed by this refcount block
are 0.
-Refcount block entry:
+Refcount block entry (x = refcount_bits - 1):
- Bit 0 - 15: Reference count of the cluster
+ Bit 0 - x: Reference count of the cluster. If refcount_bits implies a
+ sub-byte width, note that bit 0 means the least significant
+ bit in this context.
== Cluster mapping ==
refcount is exactly one. This information is only accurate
in the active L1 table.
-L2 table entry (for normal clusters):
+L2 table entry:
- Bit 0 - 8: Reserved (set to 0)
+ Bit 0 - 61: Cluster descriptor
+
+ 62: 0 for standard clusters
+ 1 for compressed clusters
+
+ 63: 0 for a cluster that is unused or requires COW, 1 if its
+ refcount is exactly one. This information is only accurate
+ in L2 tables that are reachable from the the active L1
+ table.
+
+Standard Cluster Descriptor:
+
+ Bit 0: If set to 1, the cluster reads as all zeros. The host
+ cluster offset can be used to describe a preallocation,
+ but it won't be used for reading data from this cluster,
+ nor is data read from the backing file if the cluster is
+ unallocated.
+
+ With version 2, this is always 0.
+
+ 1 - 8: Reserved (set to 0)
9 - 55: Bits 9-55 of host cluster offset. Must be aligned to a
cluster boundary. If the offset is 0, the cluster is
56 - 61: Reserved (set to 0)
- 62: 0 (this cluster is not compressed)
- 63: 0 for a cluster that is unused or requires COW, 1 if its
- refcount is exactly one. This information is only accurate
- in L2 tables that are reachable from the the active L1
- table.
-
-L2 table entry (for compressed clusters; x = 62 - (cluster_size - 8)):
+Compressed Clusters Descriptor (x = 62 - (cluster_size - 8)):
Bit 0 - x: Host cluster offset. This is usually _not_ aligned to a
cluster boundary!
x+1 - 61: Compressed size of the images in sectors of 512 bytes
- 62: 1 (this cluster is compressed using zlib)
-
- 63: 0 for a cluster that is unused or requires COW, 1 if its
- refcount is exactly one. This information is only accurate
- in L2 tables that are reachable from the the active L1
- table.
-
If a cluster is unallocated, read requests shall read the data from the backing
-file. If there is no backing file or the backing file is smaller than the image,
-they shall read zeros for all parts that are not covered by the backing file.
+file (except if bit 0 in the Standard Cluster Descriptor is set). If there is
+no backing file or the backing file is smaller than the image, they shall read
+zeros for all parts that are not covered by the backing file.
== Snapshots ==
state is saved. If this field is present,
the 32-bit value in bytes 32-35 is ignored.
+ Byte 48 - 55: Virtual disk size of the snapshot in bytes
+
+ Version 3 images must include extra data at least up to
+ byte 55.
+
variable: Unique ID string for the snapshot (not null terminated)
variable: Name of the snapshot (not null terminated)
void error_set_field(Error *err, const char *field, const char *value)
{
QDict *dict = qdict_get_qdict(err->obj, "data");
- return qdict_put(dict, field, qstring_from_str(value));
+ qdict_put(dict, field, qstring_from_str(value));
}
void error_free(Error *err)
},
STEXI
-@item block_job_set_stream
-@findex block_job_set_stream
+@item block_job_set_speed
+@findex block_job_set_speed
Set maximum speed for a background block operation.
ETEXI
} while (split_size -= bytes);
} else if (!tp->tse && tp->cptse) {
// context descriptor TSE is not set, while data descriptor TSE is set
- DBGOUT(TXERR, "TCP segmentaion Error\n");
+ DBGOUT(TXERR, "TCP segmentation error\n");
} else {
split_size = MIN(sizeof(tp->data) - tp->size, split_size);
pci_dma_read(&s->dev, addr, tp->data + tp->size, split_size);
/* some defines */
#define QEMU_HDA_ID_VENDOR 0x1af4
-#define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x10)
-#define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x20)
-
#define QEMU_HDA_PCM_FORMATS (AC_SUPPCM_BITS_16 | \
0x1fc /* 16 -> 96 kHz */)
#define QEMU_HDA_AMP_NONE (0)
#define QEMU_HDA_AMP_STEPS 0x4a
#ifdef CONFIG_MIXEMU
-#define QEMU_HDA_AMP_CAPS \
+# define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x12)
+# define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x22)
+# define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x32)
+# define QEMU_HDA_AMP_CAPS \
(AC_AMPCAP_MUTE | \
(QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT) | \
(QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) | \
(3 << AC_AMPCAP_STEP_SIZE_SHIFT))
#else
-#define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE
+# define QEMU_HDA_ID_OUTPUT ((QEMU_HDA_ID_VENDOR << 16) | 0x11)
+# define QEMU_HDA_ID_DUPLEX ((QEMU_HDA_ID_VENDOR << 16) | 0x21)
+# define QEMU_HDA_ID_MICRO ((QEMU_HDA_ID_VENDOR << 16) | 0x31)
+# define QEMU_HDA_AMP_CAPS QEMU_HDA_AMP_NONE
#endif
/* common: audio output widget */
},
};
+/* common: audio input widget */
+static const desc_param common_params_audio_adc[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_CONN_LIST |
+ AC_WCAP_FORMAT_OVRD |
+ AC_WCAP_AMP_OVRD |
+ AC_WCAP_IN_AMP |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_CONNLIST_LEN,
+ .val = 1,
+ },{
+ .id = AC_PAR_PCM,
+ .val = QEMU_HDA_PCM_FORMATS,
+ },{
+ .id = AC_PAR_STREAM,
+ .val = AC_SUPFMT_PCM,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_CAPS,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
/* common: pin widget (line-out) */
static const desc_param common_params_audio_lineout[] = {
{
},
};
+/* common: pin widget (line-in) */
+static const desc_param common_params_audio_linein[] = {
+ {
+ .id = AC_PAR_AUDIO_WIDGET_CAP,
+ .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
+ AC_WCAP_STEREO),
+ },{
+ .id = AC_PAR_PIN_CAP,
+ .val = AC_PINCAP_IN,
+ },{
+ .id = AC_PAR_AMP_IN_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_AMP_OUT_CAP,
+ .val = QEMU_HDA_AMP_NONE,
+ },
+};
+
/* output: root node */
static const desc_param output_params_root[] = {
{
},
};
-/* duplex: audio input widget */
-static const desc_param duplex_params_audio_adc[] = {
+/* duplex: audio function */
+static const desc_param duplex_params_audio_func[] = {
{
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_AUD_IN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_CONN_LIST |
- AC_WCAP_FORMAT_OVRD |
- AC_WCAP_AMP_OVRD |
- AC_WCAP_IN_AMP |
- AC_WCAP_STEREO),
+ .id = AC_PAR_FUNCTION_TYPE,
+ .val = AC_GRP_AUDIO_FUNCTION,
},{
- .id = AC_PAR_CONNLIST_LEN,
- .val = 1,
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_DUPLEX,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00020004,
},{
.id = AC_PAR_PCM,
.val = QEMU_HDA_PCM_FORMATS,
.val = AC_SUPFMT_PCM,
},{
.id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_CAPS,
+ .val = QEMU_HDA_AMP_NONE,
},{
.id = AC_PAR_AMP_OUT_CAP,
.val = QEMU_HDA_AMP_NONE,
+ },{
+ .id = AC_PAR_GPIO_CAP,
+ .val = 0,
+ },{
+ .id = AC_PAR_AUDIO_FG_CAP,
+ .val = 0x00000808,
+ },{
+ .id = AC_PAR_POWER_STATE,
+ .val = 0,
},
};
-/* duplex: pin widget (line-in) */
-static const desc_param duplex_params_audio_linein[] = {
+/* duplex: nodes */
+static const desc_node duplex_nodes[] = {
{
- .id = AC_PAR_AUDIO_WIDGET_CAP,
- .val = ((AC_WID_PIN << AC_WCAP_TYPE_SHIFT) |
- AC_WCAP_STEREO),
+ .nid = AC_NODE_ROOT,
+ .name = "root",
+ .params = duplex_params_root,
+ .nparams = ARRAY_SIZE(duplex_params_root),
},{
- .id = AC_PAR_PIN_CAP,
- .val = AC_PINCAP_IN,
+ .nid = 1,
+ .name = "func",
+ .params = duplex_params_audio_func,
+ .nparams = ARRAY_SIZE(duplex_params_audio_func),
},{
- .id = AC_PAR_AMP_IN_CAP,
- .val = QEMU_HDA_AMP_NONE,
+ .nid = 2,
+ .name = "dac",
+ .params = common_params_audio_dac,
+ .nparams = ARRAY_SIZE(common_params_audio_dac),
+ .stindex = 0,
},{
- .id = AC_PAR_AMP_OUT_CAP,
- .val = QEMU_HDA_AMP_NONE,
+ .nid = 3,
+ .name = "out",
+ .params = common_params_audio_lineout,
+ .nparams = ARRAY_SIZE(common_params_audio_lineout),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
+ 0x10),
+ .pinctl = AC_PINCTL_OUT_EN,
+ .conn = (uint32_t[]) { 2 },
+ },{
+ .nid = 4,
+ .name = "adc",
+ .params = common_params_audio_adc,
+ .nparams = ARRAY_SIZE(common_params_audio_adc),
+ .stindex = 1,
+ .conn = (uint32_t[]) { 5 },
+ },{
+ .nid = 5,
+ .name = "in",
+ .params = common_params_audio_linein,
+ .nparams = ARRAY_SIZE(common_params_audio_linein),
+ .config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
+ (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
+ (AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
+ 0x20),
+ .pinctl = AC_PINCTL_IN_EN,
+ }
+};
+
+/* duplex: codec */
+static const desc_codec duplex = {
+ .name = "duplex",
+ .iid = QEMU_HDA_ID_DUPLEX,
+ .nodes = duplex_nodes,
+ .nnodes = ARRAY_SIZE(duplex_nodes),
+};
+
+/* micro: root node */
+static const desc_param micro_params_root[] = {
+ {
+ .id = AC_PAR_VENDOR_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_SUBSYSTEM_ID,
+ .val = QEMU_HDA_ID_MICRO,
+ },{
+ .id = AC_PAR_REV_ID,
+ .val = 0x00100101,
+ },{
+ .id = AC_PAR_NODE_COUNT,
+ .val = 0x00010001,
},
};
-/* duplex: audio function */
-static const desc_param duplex_params_audio_func[] = {
+/* micro: audio function */
+static const desc_param micro_params_audio_func[] = {
{
.id = AC_PAR_FUNCTION_TYPE,
.val = AC_GRP_AUDIO_FUNCTION,
},{
.id = AC_PAR_SUBSYSTEM_ID,
- .val = QEMU_HDA_ID_DUPLEX,
+ .val = QEMU_HDA_ID_MICRO,
},{
.id = AC_PAR_NODE_COUNT,
.val = 0x00020004,
},
};
-/* duplex: nodes */
-static const desc_node duplex_nodes[] = {
+/* micro: nodes */
+static const desc_node micro_nodes[] = {
{
.nid = AC_NODE_ROOT,
.name = "root",
- .params = duplex_params_root,
- .nparams = ARRAY_SIZE(duplex_params_root),
+ .params = micro_params_root,
+ .nparams = ARRAY_SIZE(micro_params_root),
},{
.nid = 1,
.name = "func",
- .params = duplex_params_audio_func,
- .nparams = ARRAY_SIZE(duplex_params_audio_func),
+ .params = micro_params_audio_func,
+ .nparams = ARRAY_SIZE(micro_params_audio_func),
},{
.nid = 2,
.name = "dac",
.params = common_params_audio_lineout,
.nparams = ARRAY_SIZE(common_params_audio_lineout),
.config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_OUT << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_SPEAKER << AC_DEFCFG_DEVICE_SHIFT) |
(AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
(AC_JACK_COLOR_GREEN << AC_DEFCFG_COLOR_SHIFT) |
0x10),
},{
.nid = 4,
.name = "adc",
- .params = duplex_params_audio_adc,
- .nparams = ARRAY_SIZE(duplex_params_audio_adc),
+ .params = common_params_audio_adc,
+ .nparams = ARRAY_SIZE(common_params_audio_adc),
.stindex = 1,
.conn = (uint32_t[]) { 5 },
},{
.nid = 5,
.name = "in",
- .params = duplex_params_audio_linein,
- .nparams = ARRAY_SIZE(duplex_params_audio_linein),
+ .params = common_params_audio_linein,
+ .nparams = ARRAY_SIZE(common_params_audio_linein),
.config = ((AC_JACK_PORT_COMPLEX << AC_DEFCFG_PORT_CONN_SHIFT) |
- (AC_JACK_LINE_IN << AC_DEFCFG_DEVICE_SHIFT) |
+ (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT) |
(AC_JACK_CONN_UNKNOWN << AC_DEFCFG_CONN_TYPE_SHIFT) |
(AC_JACK_COLOR_RED << AC_DEFCFG_COLOR_SHIFT) |
0x20),
}
};
-/* duplex: codec */
-static const desc_codec duplex = {
- .name = "duplex",
- .iid = QEMU_HDA_ID_DUPLEX,
- .nodes = duplex_nodes,
- .nnodes = ARRAY_SIZE(duplex_nodes),
+/* micro: codec */
+static const desc_codec micro = {
+ .name = "micro",
+ .iid = QEMU_HDA_ID_MICRO,
+ .nodes = micro_nodes,
+ .nnodes = ARRAY_SIZE(micro_nodes),
};
/* -------------------------------------------------------------------------- */
return hda_audio_init(hda, &duplex);
}
+static int hda_audio_init_micro(HDACodecDevice *hda)
+{
+ return hda_audio_init(hda, µ);
+}
+
static void hda_audio_output_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
k->exit = hda_audio_exit;
k->command = hda_audio_command;
k->stream = hda_audio_stream;
- dc->desc = "HDA Audio Codec, output-only";
+ dc->desc = "HDA Audio Codec, output-only (line-out)";
dc->vmsd = &vmstate_hda_audio;
dc->props = hda_audio_properties;
}
k->exit = hda_audio_exit;
k->command = hda_audio_command;
k->stream = hda_audio_stream;
- dc->desc = "HDA Audio Codec, duplex";
+ dc->desc = "HDA Audio Codec, duplex (line-out, line-in)";
dc->vmsd = &vmstate_hda_audio;
dc->props = hda_audio_properties;
}
.class_init = hda_audio_duplex_class_init,
};
+static void hda_audio_micro_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ HDACodecDeviceClass *k = HDA_CODEC_DEVICE_CLASS(klass);
+
+ k->init = hda_audio_init_micro;
+ k->exit = hda_audio_exit;
+ k->command = hda_audio_command;
+ k->stream = hda_audio_stream;
+ dc->desc = "HDA Audio Codec, duplex (speaker, microphone)";
+ dc->vmsd = &vmstate_hda_audio;
+ dc->props = hda_audio_properties;
+}
+
+static TypeInfo hda_audio_micro_info = {
+ .name = "hda-micro",
+ .parent = TYPE_HDA_CODEC_DEVICE,
+ .instance_size = sizeof(HDAAudioState),
+ .class_init = hda_audio_micro_class_init,
+};
+
static void hda_audio_register_types(void)
{
type_register_static(&hda_audio_output_info);
type_register_static(&hda_audio_duplex_info);
+ type_register_static(&hda_audio_micro_info);
}
type_init(hda_audio_register_types)
ide_set_irq(s->bus);
}
+static void ide_sector_read_cb(void *opaque, int ret)
+{
+ IDEState *s = opaque;
+ int n;
+
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
+ bdrv_acct_done(s->bs, &s->acct);
+ if (ret != 0) {
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
+ BM_STATUS_RETRY_READ)) {
+ return;
+ }
+ }
+
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ /* Allow the guest to read the io_buffer */
+ ide_transfer_start(s, s->io_buffer, n * BDRV_SECTOR_SIZE, ide_sector_read);
+
+ ide_set_irq(s->bus);
+
+ ide_set_sector(s, ide_get_sector(s) + n);
+ s->nsector -= n;
+}
+
void ide_sector_read(IDEState *s)
{
int64_t sector_num;
- int ret, n;
+ int n;
s->status = READY_STAT | SEEK_STAT;
s->error = 0; /* not needed by IDE spec, but needed by Windows */
sector_num = ide_get_sector(s);
n = s->nsector;
+
if (n == 0) {
- /* no more sector to read from disk */
ide_transfer_stop(s);
- } else {
+ return;
+ }
+
+ s->status |= BUSY_STAT;
+
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
#if defined(DEBUG_IDE)
- printf("read sector=%" PRId64 "\n", sector_num);
+ printf("sector=%" PRId64 "\n", sector_num);
#endif
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
- bdrv_acct_done(s->bs, &s->acct);
- if (ret != 0) {
- if (ide_handle_rw_error(s, -ret,
- BM_STATUS_PIO_RETRY | BM_STATUS_RETRY_READ))
- {
- return;
- }
- }
- ide_transfer_start(s, s->io_buffer, 512 * n, ide_sector_read);
- ide_set_irq(s->bus);
- ide_set_sector(s, sector_num + n);
- s->nsector -= n;
- }
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_readv(s->bs, sector_num, &s->qiov, n,
+ ide_sector_read_cb, s);
}
static void dma_buf_commit(IDEState *s)
ide_set_irq(s->bus);
}
-void ide_sector_write(IDEState *s)
+static void ide_sector_write_cb(void *opaque, int ret)
{
- int64_t sector_num;
- int ret, n, n1;
-
- s->status = READY_STAT | SEEK_STAT;
- sector_num = ide_get_sector(s);
-#if defined(DEBUG_IDE)
- printf("write sector=%" PRId64 "\n", sector_num);
-#endif
- n = s->nsector;
- if (n > s->req_nb_sectors)
- n = s->req_nb_sectors;
+ IDEState *s = opaque;
+ int n;
- bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
bdrv_acct_done(s->bs, &s->acct);
+ s->pio_aiocb = NULL;
+ s->status &= ~BUSY_STAT;
+
if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY))
+ if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
return;
+ }
}
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
s->nsector -= n;
if (s->nsector == 0) {
/* no more sectors to write */
ide_transfer_stop(s);
} else {
- n1 = s->nsector;
- if (n1 > s->req_nb_sectors)
+ int n1 = s->nsector;
+ if (n1 > s->req_nb_sectors) {
n1 = s->req_nb_sectors;
- ide_transfer_start(s, s->io_buffer, 512 * n1, ide_sector_write);
+ }
+ ide_transfer_start(s, s->io_buffer, n1 * BDRV_SECTOR_SIZE,
+ ide_sector_write);
}
- ide_set_sector(s, sector_num + n);
+ ide_set_sector(s, ide_get_sector(s) + n);
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
/* It seems there is a bug in the Windows 2000 installer HDD
}
}
+void ide_sector_write(IDEState *s)
+{
+ int64_t sector_num;
+ int n;
+
+ s->status = READY_STAT | SEEK_STAT | BUSY_STAT;
+ sector_num = ide_get_sector(s);
+#if defined(DEBUG_IDE)
+ printf("sector=%" PRId64 "\n", sector_num);
+#endif
+ n = s->nsector;
+ if (n > s->req_nb_sectors) {
+ n = s->req_nb_sectors;
+ }
+
+ s->iov.iov_base = s->io_buffer;
+ s->iov.iov_len = n * BDRV_SECTOR_SIZE;
+ qemu_iovec_init_external(&s->qiov, &s->iov, 1);
+
+ bdrv_acct_start(s->bs, &s->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ s->pio_aiocb = bdrv_aio_writev(s->bs, sector_num, &s->qiov, n,
+ ide_sector_write_cb, s);
+}
+
static void ide_flush_cb(void *opaque, int ret)
{
IDEState *s = opaque;
#ifdef DEBUG_IDE
printf("ide: reset\n");
#endif
+
+ if (s->pio_aiocb) {
+ bdrv_aio_cancel(s->pio_aiocb);
+ s->pio_aiocb = NULL;
+ }
+
if (s->drive_kind == IDE_CFATA)
s->mult_sectors = 0;
else
int cd_sector_size;
int atapi_dma; /* true if dma is requested for the packet cmd */
BlockAcctCookie acct;
+ BlockDriverAIOCB *pio_aiocb;
+ struct iovec iov;
+ QEMUIOVector qiov;
/* ATA DMA state */
int io_buffer_size;
QEMUSGList sg;
break;
case 0x1FF5:
/* alarm date */
- tmp = from_bcd(val & 0x1F);
+ tmp = from_bcd(val & 0x3F);
if (tmp != 0) {
NVRAM->alarm.tm_mday = tmp;
NVRAM->buffer[0x1FF5] = val;
break;
case 0x1FFD:
case 0x07FD:
- /* date */
- tmp = from_bcd(val & 0x1F);
+ /* date (BCD) */
+ tmp = from_bcd(val & 0x3F);
if (tmp != 0) {
get_time(NVRAM, &tm);
tm.tm_mday = tmp;
msi_supported = true;
}
- if (xen_enabled()) {
+ if (xen_msi_support()) {
msi_supported = true;
}
sysfw_dev = (PcSysFwDevice*) qdev_create(NULL, "pc-sysfw");
+ qdev_init_nofail(DEVICE(sysfw_dev));
+
if (sysfw_dev->rom_only) {
old_pc_system_rom_init(rom_memory);
return;
DEFINE_PROP_END_OF_LIST(),
};
+static int pcsysfw_init(DeviceState *dev)
+{
+ return 0;
+}
+
static void pcsysfw_class_init (ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS (klass);
dc->desc = "PC System Firmware";
+ dc->init = pcsysfw_init;
dc->props = pcsysfw_properties;
}
} else {
ret = p[offset];
ret |= p[offset + 1] << 8;
- ret |= p[offset + 1] << 8;
ret |= p[offset + 2] << 16;
ret |= p[offset + 3] << 24;
}
count = limit. */
void ptimer_set_limit(ptimer_state *s, uint64_t limit, int reload)
{
+ /*
+ * Artificially limit timeout rate to something
+ * achievable under QEMU. Otherwise, QEMU spends all
+ * its time generating timer interrupts, and there
+ * is no forward progress.
+ * About ten microseconds is the fastest that really works
+ * on the current generation of host machines.
+ */
+
+ if (limit * s->period < 10000 && s->period) {
+ limit = 10000 / s->period;
+ }
+
s->limit = limit;
if (reload)
s->delta = limit;
static Object *dev;
if (dev == NULL) {
- dev = container_get("/machine/peripheral");
+ dev = container_get(qdev_get_machine(), "/peripheral");
}
return dev;
static Object *dev;
if (dev == NULL) {
- dev = container_get("/machine/peripheral-anon");
+ dev = container_get(qdev_get_machine(), "/peripheral-anon");
}
return dev;
static int unattached_count = 0;
gchar *name = g_strdup_printf("device[%d]", unattached_count++);
- object_property_add_child(container_get("/machine/unattached"), name,
- OBJECT(dev), NULL);
+ object_property_add_child(container_get(qdev_get_machine(),
+ "/unattached"),
+ name, OBJECT(dev), NULL);
g_free(name);
}
static Object *dev;
if (dev == NULL) {
- dev = container_get("/machine");
+ dev = container_get(object_get_root(), "/machine");
}
return dev;
case QXL_IO_DESTROY_SURFACE_WAIT:
if (val >= NUM_SURFACES) {
qxl_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):"
- "%d >= NUM_SURFACES", async, val);
+ "%" PRIu64 " >= NUM_SURFACES", async, val);
goto cancel_async;
}
qxl_spice_destroy_surface_wait(d, val, async);
/* qxl.c */
void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id);
-void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...);
+void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) GCC_FMT_ATTR(2, 3);
void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id,
struct QXLRect *area, struct QXLRect *dirty_rects,
[ UNMAP ] = "UNMAP",
[ READ_TOC ] = "READ_TOC",
[ REPORT_DENSITY_SUPPORT ] = "REPORT_DENSITY_SUPPORT",
+ [ SANITIZE ] = "SANITIZE",
[ GET_CONFIGURATION ] = "GET_CONFIGURATION",
[ LOG_SELECT ] = "LOG_SELECT",
[ LOG_SENSE ] = "LOG_SENSE",
SCSIDevice *d = DO_UPCAST(SCSIDevice, qdev, dev);
DeviceState *hba = dev->parent_bus->parent;
char *id = NULL;
+ char *path;
if (hba && hba->parent_bus && hba->parent_bus->info->get_dev_path) {
id = hba->parent_bus->info->get_dev_path(hba);
}
if (id) {
- return g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
+ path = g_strdup_printf("%s/%d:%d:%d", id, d->channel, d->id, d->lun);
} else {
- return g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
+ path = g_strdup_printf("%d:%d:%d", d->channel, d->id, d->lun);
}
+ g_free(id);
+ return path;
}
static char *scsibus_get_fw_dev_path(DeviceState *dev)
#define READ_TOC 0x43
#define REPORT_DENSITY_SUPPORT 0x44
#define GET_CONFIGURATION 0x46
+#define SANITIZE 0x48
#define GET_EVENT_STATUS_NOTIFICATION 0x4a
#define LOG_SELECT 0x4c
#define LOG_SENSE 0x4d
uint64_t sector;
uint32_t sector_count;
uint32_t buflen;
+ bool started;
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
qemu_iovec_init_external(&r->qiov, &r->iov, 1);
}
-static void scsi_dma_complete(void *opaque, int ret)
+static void scsi_flush_complete(void * opaque, int ret)
{
SCSIDiskReq *r = (SCSIDiskReq *)opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
- if (ret) {
+ if (ret < 0) {
+ if (scsi_handle_rw_error(r, -ret)) {
+ goto done;
+ }
+ }
+
+ scsi_req_complete(&r->req, GOOD);
+
+done:
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+}
+
+static bool scsi_is_cmd_fua(SCSICommand *cmd)
+{
+ switch (cmd->buf[0]) {
+ case READ_10:
+ case READ_12:
+ case READ_16:
+ case WRITE_10:
+ case WRITE_12:
+ case WRITE_16:
+ return (cmd->buf[1] & 8) != 0;
+
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
+ case WRITE_VERIFY_10:
+ case WRITE_VERIFY_12:
+ case WRITE_VERIFY_16:
+ return true;
+
+ case READ_6:
+ case WRITE_6:
+ default:
+ return false;
+ }
+}
+
+static void scsi_write_do_fua(SCSIDiskReq *r)
+{
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ if (scsi_is_cmd_fua(&r->req.cmd)) {
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_flush_complete, r);
+ return;
+ }
+
+ scsi_req_complete(&r->req, GOOD);
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
+}
+
+static void scsi_dma_complete(void *opaque, int ret)
+{
+ SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+
+ if (r->req.aiocb != NULL) {
+ r->req.aiocb = NULL;
+ bdrv_acct_done(s->qdev.conf.bs, &r->acct);
+ }
+
+ if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
r->sector += r->sector_count;
r->sector_count = 0;
- scsi_req_complete(&r->req, GOOD);
+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) {
+ scsi_write_do_fua(r);
+ return;
+ } else {
+ scsi_req_complete(&r->req, GOOD);
+ }
done:
- scsi_req_unref(&r->req);
+ if (!r->req.io_canceled) {
+ scsi_req_unref(&r->req);
+ }
}
static void scsi_read_complete(void * opaque, int ret)
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
- if (ret) {
+ if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
}
}
-static void scsi_flush_complete(void * opaque, int ret)
+/* Actually issue a read to the block device. */
+static void scsi_do_read(void *opaque, int ret)
{
- SCSIDiskReq *r = (SCSIDiskReq *)opaque;
+ SCSIDiskReq *r = opaque;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
+ uint32_t n;
if (r->req.aiocb != NULL) {
r->req.aiocb = NULL;
}
}
- scsi_req_complete(&r->req, GOOD);
+ if (r->req.sg) {
+ dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
+ r->req.resid -= r->req.sg->size;
+ r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
+ scsi_dma_complete, r);
+ } else {
+ n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
+ r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
+ scsi_read_complete, r);
+ }
done:
if (!r->req.io_canceled) {
{
SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req);
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
- uint32_t n;
+ bool first;
if (r->sector_count == (uint32_t)-1) {
DPRINTF("Read buf_len=%zd\n", r->iov.iov_len);
r->sector_count = 0;
+ r->started = true;
scsi_req_data(&r->req, r->iov.iov_len);
return;
}
return;
}
- if (r->req.sg) {
- dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ);
- r->req.resid -= r->req.sg->size;
- r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector,
- scsi_dma_complete, r);
+ first = !r->started;
+ r->started = true;
+ if (first && scsi_is_cmd_fua(&r->req.cmd)) {
+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, 0, BDRV_ACCT_FLUSH);
+ r->req.aiocb = bdrv_aio_flush(s->qdev.conf.bs, scsi_do_read, r);
} else {
- n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
- bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ);
- r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n,
- scsi_read_complete, r);
+ scsi_do_read(r, 0);
}
}
bdrv_acct_done(s->qdev.conf.bs, &r->acct);
}
- if (ret) {
+ if (ret < 0) {
if (scsi_handle_rw_error(r, -ret)) {
goto done;
}
r->sector += n;
r->sector_count -= n;
if (r->sector_count == 0) {
- scsi_req_complete(&r->req, GOOD);
+ scsi_write_do_fua(r);
+ return;
} else {
scsi_init_iovec(r, SCSI_DMA_BUF_SIZE);
DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size);
if (!r->req.sg && !r->qiov.size) {
/* Called for the first time. Ask the driver to send us more data. */
+ r->started = true;
scsi_write_complete(r, 0);
return;
}
return;
}
+ if (r->req.cmd.buf[0] == VERIFY_10 || r->req.cmd.buf[0] == VERIFY_12 ||
+ r->req.cmd.buf[0] == VERIFY_16) {
+ if (r->req.sg) {
+ scsi_dma_complete(r, 0);
+ } else {
+ scsi_write_complete(r, 0);
+ }
+ return;
+ }
+
if (r->req.sg) {
dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE);
r->req.resid -= r->req.sg->size;
{
outbuf[3] = buflen = 8;
outbuf[4] = 0;
- outbuf[5] = 0x40; /* write same with unmap supported */
- outbuf[6] = 0;
+ outbuf[5] = 0x60; /* write_same 10/16 supported */
+ outbuf[6] = s->qdev.conf.discard_granularity ? 2 : 1;
outbuf[7] = 0;
break;
}
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint64_t nb_sectors;
- int page, dbd, buflen, ret, page_control;
+ bool dbd;
+ int page, buflen, ret, page_control;
uint8_t *p;
uint8_t dev_specific_param;
- dbd = r->req.cmd.buf[1] & 0x8;
+ dbd = (r->req.cmd.buf[1] & 0x8) != 0;
page = r->req.cmd.buf[2] & 0x3f;
page_control = (r->req.cmd.buf[2] & 0xc0) >> 6;
DPRINTF("Mode Sense(%d) (page %d, xfer %zd, page_control %d)\n",
memset(outbuf, 0, r->req.cmd.xfer);
p = outbuf;
- if (bdrv_is_read_only(s->qdev.conf.bs)) {
- dev_specific_param = 0x80; /* Readonly. */
+ if (s->qdev.type == TYPE_DISK) {
+ dev_specific_param = 0x10; /* DPOFUA */
+ if (bdrv_is_read_only(s->qdev.conf.bs)) {
+ dev_specific_param |= 0x80; /* Readonly. */
+ }
} else {
+ /* MMC prescribes that CD/DVD drives have no block descriptors,
+ * and defines no device-specific parameter. */
dev_specific_param = 0x00;
+ dbd = true;
}
if (r->req.cmd.buf[0] == MODE_SENSE) {
p += 8;
}
- /* MMC prescribes that CD/DVD drives have no block descriptors. */
bdrv_get_geometry(s->qdev.conf.bs, &nb_sectors);
- if (!dbd && s->qdev.type == TYPE_DISK && nb_sectors) {
+ if (!dbd && nb_sectors) {
if (r->req.cmd.buf[0] == MODE_SENSE) {
outbuf[3] = 8; /* Block descriptor length */
} else { /* MODE_SENSE_10 */
}
DPRINTF("Unsupported Service Action In\n");
goto illegal_request;
- case VERIFY_10:
- break;
default:
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return -1;
case MECHANISM_STATUS:
case SERVICE_ACTION_IN_16:
case REQUEST_SENSE:
- case VERIFY_10:
rc = scsi_disk_emulate_command(r);
if (rc < 0) {
return 0;
r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512);
r->sector_count = len * (s->qdev.blocksize / 512);
break;
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
case WRITE_6:
case WRITE_10:
case WRITE_12:
goto illegal_lba;
}
break;
+ case WRITE_SAME_10:
case WRITE_SAME_16:
len = r->req.cmd.xfer / s->qdev.blocksize;
- DPRINTF("WRITE SAME(16) (sector %" PRId64 ", count %d)\n",
+ DPRINTF("WRITE SAME() (sector %" PRId64 ", count %d)\n",
r->req.cmd.lba, len);
if (r->req.cmd.lba > s->qdev.max_lba) {
case READ_10:
case READ_12:
case READ_16:
+ case VERIFY_10:
+ case VERIFY_12:
+ case VERIFY_16:
case WRITE_6:
case WRITE_10:
case WRITE_12:
VirtIOSCSIConf *conf;
SCSIBus bus;
- VirtQueue *ctrl_vq;
- VirtQueue *event_vq;
- VirtQueue *cmd_vq;
uint32_t sense_size;
uint32_t cdb_size;
int resetting;
+ VirtQueue *ctrl_vq;
+ VirtQueue *event_vq;
+ VirtQueue *cmd_vqs[0];
} VirtIOSCSI;
typedef struct VirtIOSCSIReq {
static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq)
{
VirtIOSCSIReq *req = sreq->hba_private;
+ uint32_t n = virtio_queue_get_id(req->vq) - 2;
+ assert(n < req->dev->conf->num_queues);
+ qemu_put_be32s(f, &n);
qemu_put_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
}
SCSIBus *bus = sreq->bus;
VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus);
VirtIOSCSIReq *req;
+ uint32_t n;
req = g_malloc(sizeof(*req));
+ qemu_get_be32s(f, &n);
+ assert(n < s->conf->num_queues);
qemu_get_buffer(f, (unsigned char *)&req->elem, sizeof(req->elem));
- virtio_scsi_parse_req(s, s->cmd_vq, req);
+ virtio_scsi_parse_req(s, s->cmd_vqs[n], req);
scsi_req_ref(sreq);
req->sreq = sreq;
{
VirtIOSCSI *s;
static int virtio_scsi_id;
+ size_t sz;
+ int i;
+ sz = sizeof(VirtIOSCSI) + proxyconf->num_queues * sizeof(VirtQueue *);
s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI,
- sizeof(VirtIOSCSIConfig),
- sizeof(VirtIOSCSI));
+ sizeof(VirtIOSCSIConfig), sz);
s->qdev = dev;
s->conf = proxyconf;
virtio_scsi_handle_ctrl);
s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
NULL);
- s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
- virtio_scsi_handle_cmd);
+ for (i = 0; i < s->conf->num_queues; i++) {
+ s->cmd_vqs[i] = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE,
+ virtio_scsi_handle_cmd);
+ }
scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info);
if (!dev->hotplugged) {
return vdev->vq[n].vring.num;
}
+int virtio_queue_get_id(VirtQueue *vq)
+{
+ VirtIODevice *vdev = vq->vdev;
+ assert(vq >= &vdev->vq[0] && vq < &vdev->vq[VIRTIO_PCI_QUEUE_MAX]);
+ return vq - &vdev->vq[0];
+}
+
void virtio_queue_notify_vq(VirtQueue *vq)
{
if (vq->vring.desc) {
uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+int virtio_queue_get_id(VirtQueue *vq);
EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
EventNotifier *virtio_queue_get_host_notifier(VirtQueue *vq);
void virtio_queue_notify_vq(VirtQueue *vq);
# define HVM_MAX_VCPUS 32
#endif
+static inline int xen_msi_support(void)
+{
+#if defined(CONFIG_XEN_CTRL_INTERFACE_VERSION) \
+ && CONFIG_XEN_CTRL_INTERFACE_VERSION >= 420
+ return xen_enabled();
+#else
+ return 0;
+#endif
+}
+
#endif /* QEMU_HW_XEN_H */
}
#endif
+/* Xen before 4.2 */
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 420
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+ uint64_t addr, uint32_t data)
+{
+ return -ENOSYS;
+}
+#else
+static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
+ uint64_t addr, uint32_t data)
+{
+ return xc_hvm_inject_msi(xen_xc, dom, addr, data);
+}
+#endif
+
void destroy_hvm_domain(void);
#endif /* QEMU_HW_XEN_COMMON_H */
/**
* container_get:
+ * @root: root of the #path, e.g., object_get_root()
* @path: path to the container
*
* Return a container object whose path is @path. Create more containers
*
* Returns: the container object.
*/
-Object *container_get(const char *path);
+Object *container_get(Object *root, const char *path);
#endif
goto out_close_efd;
qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
- qemu_laio_flush_cb, NULL, s);
+ qemu_laio_flush_cb, s);
return s;
#ifndef _WIN32
static void glib_select_fill(int *max_fd, fd_set *rfds, fd_set *wfds,
- fd_set *xfds, int *cur_timeout)
+ fd_set *xfds, uint32_t *cur_timeout)
{
GMainContext *context = g_main_context_default();
int i;
}
}
-static int os_host_main_loop_wait(int timeout)
+static int os_host_main_loop_wait(uint32_t timeout)
{
- struct timeval tv;
+ struct timeval tv, *tvarg = NULL;
int ret;
glib_select_fill(&nfds, &rfds, &wfds, &xfds, &timeout);
+ if (timeout < UINT32_MAX) {
+ tvarg = &tv;
+ tv.tv_sec = timeout / 1000;
+ tv.tv_usec = (timeout % 1000) * 1000;
+ }
+
if (timeout > 0) {
qemu_mutex_unlock_iothread();
}
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout % 1000) * 1000;
- ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+ ret = select(nfds + 1, &rfds, &wfds, &xfds, tvarg);
if (timeout > 0) {
qemu_mutex_lock_iothread();
FD_CONNECT | FD_WRITE | FD_OOB);
}
-static int os_host_main_loop_wait(int timeout)
+static int os_host_main_loop_wait(uint32_t timeout)
{
GMainContext *context = g_main_context_default();
int ret, i;
int main_loop_wait(int nonblocking)
{
- int ret, timeout;
+ int ret;
+ uint32_t timeout = UINT32_MAX;
if (nonblocking) {
timeout = 0;
} else {
- timeout = qemu_calculate_timeout();
qemu_bh_update_timeout(&timeout);
}
FD_ZERO(&xfds);
#ifdef CONFIG_SLIRP
+ slirp_update_timeout(&timeout);
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
#endif
qemu_iohandler_fill(&nfds, &rfds, &wfds, &xfds);
void qemu_bh_schedule_idle(QEMUBH *bh);
int qemu_bh_poll(void);
-void qemu_bh_update_timeout(int *timeout);
+void qemu_bh_update_timeout(uint32_t *timeout);
#endif
#include "nbd.h"
#include "block.h"
-#include "block_int.h"
#include "qemu-coroutine.h"
/* That's all folks */
-#define read_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, true)
-#define write_sync(fd, buffer, size) nbd_wr_sync(fd, buffer, size, false)
-
-size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
+ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
{
size_t offset = 0;
+ int err;
if (qemu_in_coroutine()) {
if (do_read) {
len = send(fd, buffer + offset, size - offset, 0);
}
- if (len == -1)
- errno = socket_error();
+ if (len < 0) {
+ err = socket_error();
+
+ /* recoverable error */
+ if (err == EINTR || (offset > 0 && err == EAGAIN)) {
+ continue;
+ }
- /* recoverable error */
- if (len == -1 && (errno == EAGAIN || errno == EINTR)) {
- continue;
+ /* unrecoverable error */
+ return -err;
}
/* eof */
break;
}
- /* unrecoverable error */
- if (len == -1) {
- return 0;
- }
-
offset += len;
}
return offset;
}
+static ssize_t read_sync(int fd, void *buffer, size_t size)
+{
+ /* Sockets are kept in blocking mode in the negotiation phase. After
+ * that, a non-readable socket simply means that another thread stole
+ * our request/reply. Synchronization is done with recv_coroutine, so
+ * that this is coroutine-safe.
+ */
+ return nbd_wr_sync(fd, buffer, size, true);
+}
+
+static ssize_t write_sync(int fd, void *buffer, size_t size)
+{
+ int ret;
+ do {
+ /* For writes, we do expect the socket to be writable. */
+ ret = nbd_wr_sync(fd, buffer, size, false);
+ } while (ret == -EAGAIN);
+ return ret;
+}
+
static void combine_addr(char *buf, size_t len, const char* address,
uint16_t port)
{
static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
{
char buf[8 + 8 + 8 + 128];
+ int rc;
/* Negotiate
[ 0 .. 7] passwd ("NBDMAGIC")
[28 .. 151] reserved (0)
*/
+ socket_set_block(csock);
+ rc = -EINVAL;
+
TRACE("Beginning negotiation.");
memcpy(buf, "NBDMAGIC", 8);
cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
LOG("write failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
TRACE("Negotiation succeeded.");
-
- return 0;
+ rc = 0;
+fail:
+ socket_set_nonblock(csock);
+ return rc;
}
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
char buf[256];
uint64_t magic, s;
uint16_t tmp;
+ int rc;
TRACE("Receiving negotiation.");
+ socket_set_block(csock);
+ rc = -EINVAL;
+
if (read_sync(csock, buf, 8) != 8) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
buf[8] = '\0';
if (strlen(buf) == 0) {
LOG("server connection closed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
TRACE("Magic is %c%c%c%c%c%c%c%c",
if (memcmp(buf, "NBDMAGIC", 8) != 0) {
LOG("Invalid magic received");
- errno = EINVAL;
- return -1;
+ goto fail;
}
if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
magic = be64_to_cpu(magic);
TRACE("Magic is 0x%" PRIx64, magic);
TRACE("Checking magic (opts_magic)");
if (magic != 0x49484156454F5054LL) {
LOG("Bad magic received");
- errno = EINVAL;
- return -1;
+ goto fail;
}
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
LOG("flags read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*flags = be16_to_cpu(tmp) << 16;
/* reserved for future use */
if (write_sync(csock, &reserved, sizeof(reserved)) !=
sizeof(reserved)) {
LOG("write failed (reserved)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
/* write the export name */
magic = cpu_to_be64(magic);
if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
LOG("write failed (magic)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
LOG("write failed (opt)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
namesize = cpu_to_be32(strlen(name));
if (write_sync(csock, &namesize, sizeof(namesize)) !=
sizeof(namesize)) {
LOG("write failed (namesize)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
LOG("write failed (name)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
} else {
TRACE("Checking magic (cli_magic)");
if (magic != 0x00420281861253LL) {
LOG("Bad magic received");
- errno = EINVAL;
- return -1;
+ goto fail;
}
}
if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*size = be64_to_cpu(s);
*blocksize = 1024;
if (!name) {
if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
LOG("read failed (flags)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*flags = be32_to_cpup(flags);
} else {
if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
LOG("read failed (tmp)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
*flags |= be32_to_cpu(tmp);
}
if (read_sync(csock, &buf, 124) != 124) {
LOG("read failed (buf)");
- errno = EINVAL;
- return -1;
+ goto fail;
}
- return 0;
+ rc = 0;
+
+fail:
+ socket_set_nonblock(csock);
+ return rc;
}
#ifdef __linux__
{
TRACE("Setting NBD socket");
- if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+ if (ioctl(fd, NBD_SET_SOCK, csock) < 0) {
int serrno = errno;
LOG("Failed to set NBD socket");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Setting block size to %lu", (unsigned long)blocksize);
- if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
+ if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) < 0) {
int serrno = errno;
LOG("Failed setting NBD block size");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
- if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
+ if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) < 0) {
int serrno = errno;
LOG("Failed setting size (in blocks)");
- errno = serrno;
- return -1;
+ return -serrno;
}
if (flags & NBD_FLAG_READ_ONLY) {
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
int serrno = errno;
LOG("Failed setting read-only attribute");
- errno = serrno;
- return -1;
+ return -serrno;
}
}
&& errno != ENOTTY) {
int serrno = errno;
LOG("Failed setting flags");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Negotiation ended");
TRACE("Doing NBD loop");
ret = ioctl(fd, NBD_DO_IT);
- if (ret == -1 && errno == EPIPE) {
+ if (ret < 0 && errno == EPIPE) {
/* NBD_DO_IT normally returns EPIPE when someone has disconnected
* the socket via NBD_DISCONNECT. We do not want to return 1 in
* that case.
#else
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
{
- errno = ENOTSUP;
- return -1;
+ return -ENOTSUP;
}
int nbd_disconnect(int fd)
{
- errno = ENOTSUP;
- return -1;
+ return -ENOTSUP;
}
int nbd_client(int fd)
{
- errno = ENOTSUP;
- return -1;
+ return -ENOTSUP;
}
#endif
-int nbd_send_request(int csock, struct nbd_request *request)
+ssize_t nbd_send_request(int csock, struct nbd_request *request)
{
uint8_t buf[4 + 4 + 8 + 8 + 4];
+ ssize_t ret;
cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
cpu_to_be32w((uint32_t*)(buf + 4), request->type);
"{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
request->from, request->len, request->handle, request->type);
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ ret = write_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret != sizeof(buf)) {
LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
-static int nbd_receive_request(int csock, struct nbd_request *request)
+static ssize_t nbd_receive_request(int csock, struct nbd_request *request)
{
uint8_t buf[4 + 4 + 8 + 8 + 4];
uint32_t magic;
+ ssize_t ret;
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ ret = read_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret != sizeof(buf)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
/* Request
if (magic != NBD_REQUEST_MAGIC) {
LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
-int nbd_receive_reply(int csock, struct nbd_reply *reply)
+ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply)
{
uint8_t buf[NBD_REPLY_SIZE];
uint32_t magic;
+ ssize_t ret;
- memset(buf, 0xAA, sizeof(buf));
+ ret = read_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ if (ret != sizeof(buf)) {
LOG("read failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
/* Reply
if (magic != NBD_REPLY_MAGIC) {
LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
-static int nbd_send_reply(int csock, struct nbd_reply *reply)
+static ssize_t nbd_send_reply(int csock, struct nbd_reply *reply)
{
uint8_t buf[4 + 4 + 8];
+ ssize_t ret;
/* Reply
[ 0 .. 3] magic (NBD_REPLY_MAGIC)
TRACE("Sending response to client");
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ ret = write_sync(csock, buf, sizeof(buf));
+ if (ret < 0) {
+ return ret;
+ }
+
+ if (ret != sizeof(buf)) {
LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
+ return -EINVAL;
}
return 0;
}
exp->bs = bs;
exp->dev_offset = dev_offset;
exp->nbdflags = nbdflags;
- exp->size = size == -1 ? exp->bs->total_sectors * 512 : size;
+ exp->size = size == -1 ? bdrv_getlength(bs) : size;
return exp;
}
static void nbd_read(void *opaque);
static void nbd_restart_write(void *opaque);
-static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
- int len)
+static ssize_t nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
+ int len)
{
NBDClient *client = req->client;
int csock = client->sock;
- int rc, ret;
+ ssize_t rc, ret;
qemu_co_mutex_lock(&client->send_lock);
qemu_set_fd_handler2(csock, nbd_can_read, nbd_read,
if (!len) {
rc = nbd_send_reply(csock, reply);
- if (rc == -1) {
- rc = -errno;
- }
} else {
socket_set_cork(csock, 1);
rc = nbd_send_reply(csock, reply);
- if (rc != -1) {
+ if (rc >= 0) {
ret = qemu_co_send(csock, req->data, len);
if (ret != len) {
- errno = EIO;
- rc = -1;
+ rc = -EIO;
}
}
- if (rc == -1) {
- rc = -errno;
- }
socket_set_cork(csock, 0);
}
return rc;
}
-static int nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
+static ssize_t nbd_co_receive_request(NBDRequest *req, struct nbd_request *request)
{
NBDClient *client = req->client;
int csock = client->sock;
- int rc;
+ ssize_t rc;
client->recv_coroutine = qemu_coroutine_self();
- if (nbd_receive_request(csock, request) == -1) {
- rc = -EIO;
+ rc = nbd_receive_request(csock, request);
+ if (rc < 0) {
+ if (rc != -EAGAIN) {
+ rc = -EIO;
+ }
goto out;
}
NBDExport *exp = client->exp;
struct nbd_request request;
struct nbd_reply reply;
- int ret;
+ ssize_t ret;
TRACE("Reading request.");
ret = nbd_co_receive_request(req, &request);
+ if (ret == -EAGAIN) {
+ goto done;
+ }
if (ret == -EIO) {
goto out;
}
case NBD_CMD_READ:
TRACE("Request type is READ");
+ if (request.type & NBD_CMD_FLAG_FUA) {
+ ret = bdrv_co_flush(exp->bs);
+ if (ret < 0) {
+ LOG("flush failed");
+ reply.error = -ret;
+ goto error_reply;
+ }
+ }
+
ret = bdrv_read(exp->bs, (request.from + exp->dev_offset) / 512,
req->data, request.len / 512);
if (ret < 0) {
}
}
- if (nbd_co_send_reply(req, &reply, 0) < 0)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
case NBD_CMD_DISC:
TRACE("Request type is DISCONNECT");
LOG("flush failed");
reply.error = -ret;
}
-
- if (nbd_co_send_reply(req, &reply, 0) < 0)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
case NBD_CMD_TRIM:
TRACE("Request type is TRIM");
LOG("discard failed");
reply.error = -ret;
}
- if (nbd_co_send_reply(req, &reply, 0) < 0)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
default:
LOG("invalid request type (%u) received", request.type);
invalid_request:
reply.error = -EINVAL;
error_reply:
- if (nbd_co_send_reply(req, &reply, 0) == -1)
+ if (nbd_co_send_reply(req, &reply, 0) < 0) {
goto out;
+ }
break;
}
TRACE("Request/Reply complete");
+done:
nbd_request_put(req);
return;
void (*close)(NBDClient *))
{
NBDClient *client;
- if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) == -1) {
+ if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) < 0) {
return NULL;
}
client = g_malloc0(sizeof(NBDClient));
#define NBD_BUFFER_SIZE (1024*1024)
-size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
+ssize_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read);
int tcp_socket_outgoing(const char *address, uint16_t port);
int tcp_socket_incoming(const char *address, uint16_t port);
int tcp_socket_outgoing_spec(const char *address_and_port);
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
off_t *size, size_t *blocksize);
int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize);
-int nbd_send_request(int csock, struct nbd_request *request);
-int nbd_receive_reply(int csock, struct nbd_reply *reply);
+ssize_t nbd_send_request(int csock, struct nbd_request *request);
+ssize_t nbd_receive_reply(int csock, struct nbd_reply *reply);
int nbd_client(int fd);
int nbd_disconnect(int fd);
#include <sys/prctl.h>
#endif
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
+
static struct passwd *user_pwd;
static const char *chroot_dir;
static int daemonize;
return ret;
}
-static int posix_aio_process_queue(void *opaque)
+static void posix_aio_read(void *opaque)
{
PosixAioState *s = opaque;
struct qemu_paiocb *acb, **pacb;
int ret;
- int result = 0;
+ ssize_t len;
+
+ /* read all bytes from signal pipe */
+ for (;;) {
+ char bytes[16];
+
+ len = read(s->rfd, bytes, sizeof(bytes));
+ if (len == -1 && errno == EINTR)
+ continue; /* try again */
+ if (len == sizeof(bytes))
+ continue; /* more to read */
+ break;
+ }
for(;;) {
pacb = &s->first_aio;
for(;;) {
acb = *pacb;
if (!acb)
- return result;
+ return;
ret = qemu_paio_error(acb);
if (ret == ECANCELED) {
/* remove the request */
*pacb = acb->next;
qemu_aio_release(acb);
- result = 1;
} else if (ret != EINPROGRESS) {
/* end of aio */
if (ret == 0) {
/* call the callback */
acb->common.cb(acb->common.opaque, ret);
qemu_aio_release(acb);
- result = 1;
break;
} else {
pacb = &acb->next;
}
}
}
-
- return result;
-}
-
-static void posix_aio_read(void *opaque)
-{
- PosixAioState *s = opaque;
- ssize_t len;
-
- /* read all bytes from signal pipe */
- for (;;) {
- char bytes[16];
-
- len = read(s->rfd, bytes, sizeof(bytes));
- if (len == -1 && errno == EINTR)
- continue; /* try again */
- if (len == sizeof(bytes))
- continue; /* more to read */
- break;
- }
-
- posix_aio_process_queue(s);
}
static int posix_aio_flush(void *opaque)
fcntl(s->rfd, F_SETFL, O_NONBLOCK);
fcntl(s->wfd, F_SETFL, O_NONBLOCK);
- qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush,
- posix_aio_process_queue, s);
+ qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
ret = pthread_attr_init(&attr);
if (ret)
'data': { 'device': 'str', 'bps': 'int', 'bps_rd': 'int', 'bps_wr': 'int',
'iops': 'int', 'iops_rd': 'int', 'iops_wr': 'int' } }
-# @block_stream:
+##
+# @block-stream:
#
# Copy data from a backing file into a block device.
#
# backing file has been copied. This command returns immediately once streaming
# has started. The status of ongoing block streaming operations can be checked
# with query-block-jobs. The operation can be stopped before it has completed
-# using the block_job_cancel command.
+# using the block-job-cancel command.
#
# If a base file is specified then sectors are not copied from that base file and
# its backing chain. When streaming completes the image file will have the base
#
# Since: 1.1
##
-{ 'command': 'block_stream', 'data': { 'device': 'str', '*base': 'str' } }
+{ 'command': 'block-stream', 'data': { 'device': 'str', '*base': 'str' } }
##
-# @block_job_set_speed:
+# @block-job-set-speed:
#
# Set maximum speed for a background block operation.
#
#
# Since: 1.1
##
-{ 'command': 'block_job_set_speed',
+{ 'command': 'block-job-set-speed',
'data': { 'device': 'str', 'value': 'int' } }
##
-# @block_job_cancel:
+# @block-job-cancel:
#
# Stop an active block streaming operation.
#
#
# Since: 1.1
##
-{ 'command': 'block_job_cancel', 'data': { 'device': 'str' } }
+{ 'command': 'block-job-cancel', 'data': { 'device': 'str' } }
##
# @ObjectTypeInfo:
qiv->nb_stack++;
}
+/** Only for qmp_input_pop. */
+static gboolean always_true(gpointer key, gpointer val, gpointer user_pkey)
+{
+ *(const char **)user_pkey = (const char *)key;
+ return TRUE;
+}
+
static void qmp_input_pop(QmpInputVisitor *qiv, Error **errp)
{
- GHashTableIter iter;
- gpointer key;
+ assert(qiv->nb_stack > 0);
- if (qiv->strict && qiv->stack[qiv->nb_stack - 1].h) {
- g_hash_table_iter_init(&iter, qiv->stack[qiv->nb_stack - 1].h);
- if (g_hash_table_iter_next(&iter, &key, NULL)) {
- error_set(errp, QERR_QMP_EXTRA_MEMBER, (char *) key);
+ if (qiv->strict) {
+ GHashTable * const top_ht = qiv->stack[qiv->nb_stack - 1].h;
+ if (top_ht) {
+ if (g_hash_table_size(top_ht)) {
+ const char *key;
+ g_hash_table_find(top_ht, always_true, &key);
+ error_set(errp, QERR_QMP_EXTRA_MEMBER, key);
+ }
+ g_hash_table_unref(top_ht);
}
- g_hash_table_unref(qiv->stack[qiv->nb_stack - 1].h);
}
- assert(qiv->nb_stack > 0);
qiv->nb_stack--;
}
/* Returns 1 if there are still outstanding AIO requests; 0 otherwise */
typedef int (AioFlushHandler)(void *opaque);
-/* Runs all currently allowed AIO callbacks of completed requests in the
- * respective AIO backend. Returns 0 if no requests was handled, non-zero
- * if at least one queued request was handled. */
-typedef int (AioProcessQueue)(void *opaque);
-
/* Flush any pending AIO operation. This function will block until all
* outstanding AIO operations have been completed or cancelled. */
void qemu_aio_flush(void);
/* Wait for a single AIO completion to occur. This function will wait
* until a single AIO event has completed and it will ensure something
* has moved before returning. This can issue new pending aio as
- * result of executing I/O completion or bh callbacks. */
-void qemu_aio_wait(void);
-
-/*
- * Runs all currently allowed AIO callbacks of completed requests. Returns 0
- * if no requests were handled, non-zero if at least one request was
- * processed.
- */
-int qemu_aio_process_queue(void);
+ * result of executing I/O completion or bh callbacks.
+ *
+ * Return whether there is still any pending AIO operation. */
+bool qemu_aio_wait(void);
/* Register a file descriptor and associated callbacks. Behaves very similarly
* to qemu_set_fd_handler2. Unlike qemu_set_fd_handler2, these callbacks will
IOHandler *io_read,
IOHandler *io_write,
AioFlushHandler *io_flush,
- AioProcessQueue *io_process_queue,
void *opaque);
#endif
void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
{
- s->chr_read(s->handler_opaque, buf, len);
+ if (s->chr_read) {
+ s->chr_read(s->handler_opaque, buf, len);
+ }
}
int qemu_chr_fe_get_msgfd(CharDriverState *s)
{
CoSleepCB *sleep_cb = opaque;
- qemu_free_timer(sleep_cb->ts);
qemu_coroutine_enter(sleep_cb->co, NULL);
}
sleep_cb.ts = qemu_new_timer(clock, SCALE_NS, co_sleep_cb, &sleep_cb);
qemu_mod_timer(sleep_cb.ts, qemu_get_clock_ns(clock) + ns);
qemu_coroutine_yield();
+ qemu_del_timer(sleep_cb.ts);
+ qemu_free_timer(sleep_cb.ts);
}
static void usage(const char *cmd)
{
printf(
-"Usage: %s -c <channel_opts>\n"
+"Usage: %s [-m <method> -p <path>] [<options>]\n"
"QEMU Guest Agent %s\n"
"\n"
" -m, --method transport method: one of unix-listen, virtio-serial, or\n"
" isa-serial (virtio-serial is the default)\n"
-" -p, --path device/socket path (%s is the default for virtio-serial)\n"
+" -p, --path device/socket path (the default for virtio-serial is:\n"
+" %s)\n"
" -l, --logfile set logfile path, logs to stderr by default\n"
" -f, --pidfile specify pidfile (default is %s)\n"
" -v, --verbose log extra debugging information\n"
#ifdef _WIN32
" -s, --service service commands: install, uninstall\n"
#endif
-" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\""
+" -b, --blacklist comma-separated list of RPCs to disable (no spaces, \"?\"\n"
" to list available RPCs)\n"
" -h, --help display this help and exit\n"
"\n"
" 'filename' is a disk image filename\n"
" 'fmt' is the disk image format. It is guessed automatically in most cases\n"
" 'cache' is the cache mode used to write the output disk image, the valid\n"
- " options are: 'none', 'writeback' (default), 'writethrough', 'directsync'\n"
- " and 'unsafe'\n"
+ " options are: 'none', 'writeback' (default, except for convert), 'writethrough',\n"
+ " 'directsync' and 'unsafe' (default for convert)\n"
" 'size' is the disk image size in bytes. Optional suffixes\n"
" 'k' or 'K' (kilobyte, 1024), 'M' (megabyte, 1024k), 'G' (gigabyte, 1024M)\n"
" and T (terabyte, 1024G) are supported. 'b' is ignored.\n"
#include <libgen.h>
#include "qemu-common.h"
+#include "main-loop.h"
#include "block_int.h"
#include "cmd.h"
#include "trace/control.h"
bdrv_aio_readv(bs, offset >> 9, qiov, qiov->size >> 9,
aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) {
- qemu_aio_wait();
+ main_loop_wait(false);
}
*total = qiov->size;
bdrv_aio_writev(bs, offset >> 9, qiov, qiov->size >> 9,
aio_rw_done, &async_ret);
while (async_ret == NOT_DONE) {
- qemu_aio_wait();
+ main_loop_wait(false);
}
*total = qiov->size;
}
while (async_ret.num_done < num_reqs) {
- qemu_aio_wait();
+ main_loop_wait(false);
}
return async_ret.error < 0 ? async_ret.error : 1;
" -g, --growable allow file to grow (only applies to protocols)\n"
" -m, --misalign misalign allocations for O_DIRECT\n"
" -k, --native-aio use kernel AIO implementation (on Linux only)\n"
+" -t, --cache=MODE use the given cache mode for the image\n"
" -T, --trace FILE enable trace events listed in the given file\n"
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
{
int readonly = 0;
int growable = 0;
- const char *sopt = "hVc:rsnmgkT:";
+ const char *sopt = "hVc:rsnmgkt:T:";
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
{ "version", 0, NULL, 'V' },
{ "misalign", 0, NULL, 'm' },
{ "growable", 0, NULL, 'g' },
{ "native-aio", 0, NULL, 'k' },
+ { "cache", 1, NULL, 't' },
{ "trace", 1, NULL, 'T' },
{ NULL, 0, NULL, 0 }
};
case 'k':
flags |= BDRV_O_NATIVE_AIO;
break;
+ case 't':
+ if (bdrv_parse_cache_flags(optarg, &flags) < 0) {
+ error_report("Invalid cache option: %s", optarg);
+ exit(1);
+ }
+ break;
case 'T':
if (!trace_backend_init(optarg, NULL)) {
exit(1); /* error message will have been printed */
*/
#include "qemu-common.h"
-#include "block_int.h"
+#include "block.h"
#include "nbd.h"
#include <stdarg.h>
}
if (data[510] != 0x55 || data[511] != 0xaa) {
- errno = -EINVAL;
- return -1;
+ return -EINVAL;
}
for (i = 0; i < 4; i++) {
}
}
- errno = -ENOENT;
- return -1;
+ return -ENOENT;
}
static void termsig_handler(int signum)
* modprobe nbd max_part=63
*/
nbd = open(device, O_RDWR);
- if (nbd != -1) {
+ if (nbd >= 0) {
close(nbd);
}
return NULL;
pthread_t show_parts_thread;
sock = unix_socket_outgoing(sockpath);
- if (sock == -1) {
+ if (sock < 0) {
goto out;
}
ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
&size, &blocksize);
- if (ret == -1) {
+ if (ret < 0) {
goto out;
}
fd = open(device, O_RDWR);
- if (fd == -1) {
+ if (fd < 0) {
/* Linux-only, we can use %m in printf. */
fprintf(stderr, "Failed to open %s: %m", device);
goto out;
}
ret = nbd_init(fd, sock, nbdflags, size, blocksize);
- if (ret == -1) {
+ if (ret < 0) {
goto out;
}
int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len);
nbd_started = true;
- if (fd != -1 && nbd_client_new(exp, fd, nbd_client_closed)) {
+ if (fd >= 0 && nbd_client_new(exp, fd, nbd_client_closed)) {
nb_fds++;
}
}
if (disconnect) {
fd = open(argv[optind], O_RDWR);
- if (fd == -1)
+ if (fd < 0) {
err(EXIT_FAILURE, "Cannot open %s", argv[optind]);
-
+ }
nbd_disconnect(fd);
close(fd);
pid_t pid;
int ret;
- if (qemu_pipe(stderr_fd) == -1) {
+ if (qemu_pipe(stderr_fd) < 0) {
err(EXIT_FAILURE, "Error setting up communication pipe");
}
/* Temporarily redirect stderr to the parent's pipe... */
dup2(stderr_fd[1], STDERR_FILENO);
- if (ret == -1) {
+ if (ret < 0) {
err(EXIT_FAILURE, "Failed to daemonize");
}
while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
errors = true;
ret = qemu_write_full(STDERR_FILENO, buf, ret);
- if (ret == -1) {
+ if (ret < 0) {
exit(EXIT_FAILURE);
}
}
- if (ret == -1) {
+ if (ret < 0) {
err(EXIT_FAILURE, "Cannot read from daemon");
}
err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
}
- fd_size = bs->total_sectors * 512;
+ fd_size = bdrv_getlength(bs);
- if (partition != -1 &&
- find_partition(bs, partition, &dev_offset, &fd_size)) {
- err(EXIT_FAILURE, "Could not find partition %d", partition);
+ if (partition != -1) {
+ ret = find_partition(bs, partition, &dev_offset, &fd_size);
+ if (ret < 0) {
+ errno = -ret;
+ err(EXIT_FAILURE, "Could not find partition %d", partition);
+ }
}
exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags);
fd = tcp_socket_incoming(bindto, port);
}
- if (fd == -1) {
+ if (fd < 0) {
return 1;
}
static int64_t qemu_next_alarm_deadline(void)
{
- int64_t delta;
+ int64_t delta = INT64_MAX;
int64_t rtdelta;
- if (!use_icount && vm_clock->active_timers) {
+ if (!use_icount && vm_clock->enabled && vm_clock->active_timers) {
delta = vm_clock->active_timers->expire_time -
qemu_get_clock_ns(vm_clock);
- } else {
- delta = INT32_MAX;
}
- if (host_clock->active_timers) {
+ if (host_clock->enabled && host_clock->active_timers) {
int64_t hdelta = host_clock->active_timers->expire_time -
qemu_get_clock_ns(host_clock);
if (hdelta < delta) {
delta = hdelta;
}
}
- if (rt_clock->active_timers) {
+ if (rt_clock->enabled && rt_clock->active_timers) {
rtdelta = (rt_clock->active_timers->expire_time -
qemu_get_clock_ns(rt_clock));
if (rtdelta < delta) {
static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
{
- int nearest_delta_ms = (delta + 999999) / 1000000;
+ int64_t nearest_delta_ms = delta / 1000000;
if (nearest_delta_ms < 1) {
nearest_delta_ms = 1;
}
+ /* UINT_MAX can be 32 bit */
+ if (nearest_delta_ms > UINT_MAX) {
+ nearest_delta_ms = UINT_MAX;
+ }
timeKillEvent(mm_timer);
- mm_timer = timeSetEvent(nearest_delta_ms,
+ mm_timer = timeSetEvent((unsigned int) nearest_delta_ms,
mm_period,
mm_alarm_handler,
(DWORD_PTR)t,
int64_t nearest_delta_ns)
{
HANDLE hTimer = t->timer;
- int nearest_delta_ms;
+ int64_t nearest_delta_ms;
BOOLEAN success;
- nearest_delta_ms = (nearest_delta_ns + 999999) / 1000000;
+ nearest_delta_ms = nearest_delta_ns / 1000000;
if (nearest_delta_ms < 1) {
nearest_delta_ms = 1;
}
+ /* ULONG_MAX can be 32 bit */
+ if (nearest_delta_ms > ULONG_MAX) {
+ nearest_delta_ms = ULONG_MAX;
+ }
success = ChangeTimerQueueTimer(NULL,
hTimer,
- nearest_delta_ms,
+ (unsigned long) nearest_delta_ms,
3600000);
if (!success) {
return err;
}
-int qemu_calculate_timeout(void)
-{
- return 1000;
-}
-
void qemu_run_all_timers(void);
int qemu_alarm_pending(void);
void configure_alarms(char const *opt);
-int qemu_calculate_timeout(void);
void init_clocks(void);
int init_timer_alarm(void);
int64_t cpu_get_clock(void)
{
- return 0;
+ return qemu_get_clock_ns(rt_clock);
}
int64_t cpu_get_icount(void)
{
init_clocks();
init_timer_alarm();
- qemu_clock_enable(vm_clock, false);
return main_loop_init();
}
+void slirp_update_timeout(uint32_t *timeout)
+{
+}
+
void slirp_select_fill(int *pnfds, fd_set *readfds,
fd_set *writefds, fd_set *xfds)
{
#else /* defined(__linux__) */
-GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
+void qmp_guest_suspend_disk(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
-
- return 0;
}
-int64_t qmp_guest_fsfreeze_freeze(Error **err)
+void qmp_guest_suspend_ram(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
-
- return 0;
}
-int64_t qmp_guest_fsfreeze_thaw(Error **err)
+void qmp_guest_suspend_hybrid(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
-
- return 0;
}
-void qmp_guest_suspend_disk(Error **err)
+GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
{
- error_set(err, QERR_UNSUPPORTED);
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
}
-void qmp_guest_suspend_ram(Error **err)
+#endif
+
+#if !defined(CONFIG_FSFREEZE)
+
+GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
}
-void qmp_guest_suspend_hybrid(Error **err)
+int64_t qmp_guest_fsfreeze_freeze(Error **err)
{
error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
}
-GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
+int64_t qmp_guest_fsfreeze_thaw(Error **err)
{
- error_set(errp, QERR_UNSUPPORTED);
- return NULL;
+ error_set(err, QERR_UNSUPPORTED);
+
+ return 0;
}
#endif
EQMP
{
- .name = "block_stream",
+ .name = "block-stream",
.args_type = "device:B,base:s?",
.mhandler.cmd_new = qmp_marshal_input_block_stream,
},
{
- .name = "block_job_set_speed",
+ .name = "block-job-set-speed",
.args_type = "device:B,value:o",
.mhandler.cmd_new = qmp_marshal_input_block_job_set_speed,
},
{
- .name = "block_job_cancel",
+ .name = "block-job-cancel",
.args_type = "device:B",
.mhandler.cmd_new = qmp_marshal_input_block_job_cancel,
},
type_register_static(&container_info);
}
-Object *container_get(const char *path)
+Object *container_get(Object *root, const char *path)
{
Object *obj, *child;
gchar **parts;
parts = g_strsplit(path, "/", 0);
assert(parts != NULL && parts[0] != NULL && !parts[0][0]);
- obj = object_get_root();
+ obj = root;
for (i = 1; parts[i] != NULL; i++, obj = child) {
child = object_resolve_path_component(obj, parts[i]);
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
- tv.tv_sec, tv.tv_usec);
+ tv.tv_sec, (long) tv.tv_usec);
}
static void GCC_FMT_ATTR(2, 3) qtest_send(CharDriverState *chr,
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
- tv.tv_sec, tv.tv_usec);
+ tv.tv_sec, (long) tv.tv_usec);
for (i = 0; words[i]; i++) {
fprintf(qtest_log_fp, " %s", words[i]);
}
qtest_opened = true;
if (qtest_log_fp) {
fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
- start_time.tv_sec, start_time.tv_usec);
+ start_time.tv_sec, (long) start_time.tv_usec);
}
break;
case CHR_EVENT_CLOSED:
qemu_timeval tv;
qtest_get_time(&tv);
fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
- tv.tv_sec, tv.tv_usec);
+ tv.tv_sec, (long) tv.tv_usec);
}
break;
default:
pkgversion=${line#*=}
echo "#define QEMU_PKGVERSION \"$pkgversion\""
;;
- prefix=* | [a-z]*dir=*) # directory configuration
+ qemu_*dir=*) # qemu-specific directory configuration
name=${line%=*}
value=${line#*=}
define_name=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
eval "define_value=\"$value\""
- echo "#define CONFIG_QEMU_$define_name \"$define_value\""
+ echo "#define CONFIG_$define_name \"$define_value\""
# save for the next definitions
eval "$name=\$define_value"
;;
+ prefix=*)
+ # save for the next definitions
+ prefix=${line#*=}
+ ;;
CONFIG_AUDIO_DRIVERS=*)
drivers=${line#*=}
echo "#define CONFIG_AUDIO_DRIVERS \\"
+++ /dev/null
-#!/bin/sh
-#
-# Code generator for trace events
-#
-# Copyright IBM, Corp. 2010
-#
-# This work is licensed under the terms of the GNU GPL, version 2. See
-# the COPYING file in the top-level directory.
-
-# Disable pathname expansion, makes processing text with '*' characters simpler
-set -f
-
-usage()
-{
- cat >&2 <<EOF
-usage: $0 [--nop | --simple | --stderr | --ust | --dtrace] [-h | -c]
-Generate tracing code for a file on stdin.
-
-Backends:
- --nop Tracing disabled
- --simple Simple built-in backend
- --stderr Stderr built-in backend
- --ust LTTng User Space Tracing backend
- --dtrace DTrace/SystemTAP backend
-
-Output formats:
- -h Generate .h file
- -c Generate .c file
- -d Generate .d file (DTrace only)
- --stap Generate .stp file (DTrace with SystemTAP only)
-
-Options:
- --binary [path] Full path to QEMU binary
- --target-arch [arch] QEMU emulator target arch
- --target-type [type] QEMU emulator target type ('system' or 'user')
- --probe-prefix [prefix] Prefix for dtrace probe names
- (default: qemu-\$targettype-\$targetarch)
-
-EOF
- exit 1
-}
-
-# Print a line without interpreting backslash escapes
-#
-# The built-in echo command may interpret backslash escapes without an option
-# to disable this behavior.
-puts()
-{
- printf "%s\n" "$1"
-}
-
-# Get the name of a trace event
-get_name()
-{
- local name
- name=${1%%\(*}
- echo "${name##* }"
-}
-
-# Get the given property of a trace event
-# 1: trace-events line
-# 2: property name
-# -> return 0 if property is present, or 1 otherwise
-has_property()
-{
- local props prop
- props=${1%%\(*}
- props=${props% *}
- for prop in $props; do
- if [ "$prop" = "$2" ]; then
- return 0
- fi
- done
- return 1
-}
-
-# Get the argument list of a trace event, including types and names
-get_args()
-{
- local args
- args=${1#*\(}
- args=${args%%\)*}
- echo "$args"
-
- if (echo "$args" | grep "[ *]next\($\|[, ]\)" > /dev/null 2>&1); then
- echo -e "\n#error 'next' is a bad argument name (clash with systemtap keyword)\n "
- fi
-}
-
-# Get the argument name list of a trace event
-get_argnames()
-{
- local nfields field name sep
- nfields=0
- sep="$2"
- for field in $(get_args "$1"); do
- nfields=$((nfields + 1))
-
- # Drop pointer star
- field=${field#\*}
-
- # Only argument names have commas at the end
- name=${field%,}
- test "$field" = "$name" && continue
-
- printf "%s%s " $name $sep
- done
-
- # Last argument name
- if [ "$nfields" -gt 1 ]
- then
- printf "%s" "$name"
- fi
-}
-
-# Get the number of arguments to a trace event
-get_argc()
-{
- local name argc
- argc=0
- for name in $(get_argnames "$1", ","); do
- argc=$((argc + 1))
- done
- echo $argc
-}
-
-# Get the format string including double quotes for a trace event
-get_fmt()
-{
- puts "${1#*)}"
-}
-
-linetoh_begin_nop()
-{
- return
-}
-
-linetoh_nop()
-{
- local name args
- name=$(get_name "$1")
- args=$(get_args "$1")
-
- # Define an empty function for the trace event
- cat <<EOF
-static inline void trace_$name($args)
-{
-}
-EOF
-}
-
-linetoh_end_nop()
-{
- return
-}
-
-linetoc_begin_nop()
-{
- return
-}
-
-linetoc_nop()
-{
- # No need for function definitions in nop backend
- return
-}
-
-linetod_nop()
-{
- # Used when "disabled" events are processed
- return
-}
-
-linetostap_nop()
-{
- # Used when "disabled" events are processed
- return
-}
-
-linetoc_end_nop()
-{
- return
-}
-
-linetoh_begin_simple()
-{
- cat <<EOF
-#include "trace/simple.h"
-EOF
-
- simple_event_num=0
-}
-
-cast_args_to_uint64_t()
-{
- local arg
- for arg in $(get_argnames "$1", ","); do
- printf "%s" "(uint64_t)(uintptr_t)$arg"
- done
-}
-
-linetoh_simple()
-{
- local name args argc trace_args
- name=$(get_name "$1")
- args=$(get_args "$1")
- argc=$(get_argc "$1")
-
- trace_args="$simple_event_num"
- if [ "$argc" -gt 0 ]
- then
- trace_args="$trace_args, $(cast_args_to_uint64_t "$1")"
- fi
-
- cat <<EOF
-static inline void trace_$name($args)
-{
- trace$argc($trace_args);
-}
-EOF
-
- simple_event_num=$((simple_event_num + 1))
-}
-
-linetoh_end_simple()
-{
- cat <<EOF
-#define NR_TRACE_EVENTS $simple_event_num
-extern TraceEvent trace_list[NR_TRACE_EVENTS];
-EOF
-}
-
-linetoc_begin_simple()
-{
- cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
- simple_event_num=0
-
-}
-
-linetoc_simple()
-{
- local name
- name=$(get_name "$1")
- cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
- simple_event_num=$((simple_event_num + 1))
-}
-
-linetoc_end_simple()
-{
- cat <<EOF
-};
-EOF
-}
-
-#STDERR
-linetoh_begin_stderr()
-{
- cat <<EOF
-#include <stdio.h>
-#include "trace/stderr.h"
-
-extern TraceEvent trace_list[];
-EOF
-
- stderr_event_num=0
-}
-
-linetoh_stderr()
-{
- local name args argnames argc fmt
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1" ",")
- argc=$(get_argc "$1")
- fmt=$(get_fmt "$1")
-
- if [ "$argc" -gt 0 ]; then
- argnames=", $argnames"
- fi
-
- cat <<EOF
-static inline void trace_$name($args)
-{
- if (trace_list[$stderr_event_num].state != 0) {
- fprintf(stderr, "$name " $fmt "\n" $argnames);
- }
-}
-EOF
- stderr_event_num=$((stderr_event_num + 1))
-
-}
-
-linetoh_end_stderr()
-{
- cat <<EOF
-#define NR_TRACE_EVENTS $stderr_event_num
-EOF
-}
-
-linetoc_begin_stderr()
-{
- cat <<EOF
-#include "trace.h"
-
-TraceEvent trace_list[] = {
-EOF
- stderr_event_num=0
-}
-
-linetoc_stderr()
-{
- local name
- name=$(get_name "$1")
- cat <<EOF
-{.tp_name = "$name", .state=0},
-EOF
- stderr_event_num=$(($stderr_event_num + 1))
-}
-
-linetoc_end_stderr()
-{
- cat <<EOF
-};
-EOF
-}
-#END OF STDERR
-
-# Clean up after UST headers which pollute the namespace
-ust_clean_namespace() {
- cat <<EOF
-#undef mutex_lock
-#undef mutex_unlock
-#undef inline
-#undef wmb
-EOF
-}
-
-linetoh_begin_ust()
-{
- echo "#include <ust/tracepoint.h>"
- ust_clean_namespace
-}
-
-linetoh_ust()
-{
- local name args argnames
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
-
- cat <<EOF
-DECLARE_TRACE(ust_$name, TP_PROTO($args), TP_ARGS($argnames));
-#define trace_$name trace_ust_$name
-EOF
-}
-
-linetoh_end_ust()
-{
- return
-}
-
-linetoc_begin_ust()
-{
- cat <<EOF
-#include <ust/marker.h>
-$(ust_clean_namespace)
-#include "trace.h"
-EOF
-}
-
-linetoc_ust()
-{
- local name args argnames fmt
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
- [ -z "$argnames" ] || argnames=", $argnames"
- fmt=$(get_fmt "$1")
-
- cat <<EOF
-DEFINE_TRACE(ust_$name);
-
-static void ust_${name}_probe($args)
-{
- trace_mark(ust, $name, $fmt$argnames);
-}
-EOF
-
- # Collect names for later
- names="$names $name"
-}
-
-linetoc_end_ust()
-{
- cat <<EOF
-static void __attribute__((constructor)) trace_init(void)
-{
-EOF
-
- for name in $names; do
- cat <<EOF
- register_trace_ust_$name(ust_${name}_probe);
-EOF
- done
-
- echo "}"
-}
-
-linetoh_begin_dtrace()
-{
- cat <<EOF
-#include "trace-dtrace.h"
-EOF
-}
-
-linetoh_dtrace()
-{
- local name args argnames nameupper
- name=$(get_name "$1")
- args=$(get_args "$1")
- argnames=$(get_argnames "$1", ",")
-
- nameupper=`echo $name | LC_ALL=C tr '[a-z]' '[A-Z]'`
-
- # Define an empty function for the trace event
- cat <<EOF
-static inline void trace_$name($args) {
- QEMU_${nameupper}($argnames);
-}
-EOF
-}
-
-linetoh_end_dtrace()
-{
- return
-}
-
-linetoc_begin_dtrace()
-{
- return
-}
-
-linetoc_dtrace()
-{
- # No need for function definitions in dtrace backend
- return
-}
-
-linetoc_end_dtrace()
-{
- return
-}
-
-linetod_begin_dtrace()
-{
- cat <<EOF
-provider qemu {
-EOF
-}
-
-linetod_dtrace()
-{
- local name args
- name=$(get_name "$1")
- args=$(get_args "$1")
-
- # DTrace provider syntax expects foo() for empty
- # params, not foo(void)
- if [ "$args" = "void" ]; then
- args=""
- fi
-
- # Define prototype for probe arguments
- cat <<EOF
- probe $name($args);
-EOF
-}
-
-linetod_end_dtrace()
-{
- cat <<EOF
-};
-EOF
-}
-
-linetostap_begin_dtrace()
-{
- return
-}
-
-linetostap_dtrace()
-{
- local i arg name args arglist
- name=$(get_name "$1")
- args=$(get_args "$1")
- arglist=$(get_argnames "$1", "")
-
- # Define prototype for probe arguments
- cat <<EOF
-probe $probeprefix.$name = process("$binary").mark("$name")
-{
-EOF
-
- i=1
- for arg in $arglist
- do
- # postfix reserved words with '_'
- case "$arg" in
- limit|in|next|self)
- arg="${arg}_"
- ;;
- esac
- cat <<EOF
- $arg = \$arg$i;
-EOF
- i="$((i+1))"
- done
-
- cat <<EOF
-}
-EOF
-}
-
-linetostap_end_dtrace()
-{
- return
-}
-
-# Process stdin by calling begin, line, and end functions for the backend
-convert()
-{
- local begin process_line end str name NAME enabled
- begin="lineto$1_begin_$backend"
- process_line="lineto$1_$backend"
- end="lineto$1_end_$backend"
-
- "$begin"
-
- while read -r str; do
- # Skip comments and empty lines
- test -z "${str%%#*}" && continue
-
- echo
- # Process the line. The nop backend handles disabled lines.
- if has_property "$str" "disable"; then
- "lineto$1_nop" "$str"
- enabled=0
- else
- "$process_line" "$str"
- enabled=1
- fi
- if [ "$1" = "h" ]; then
- name=$(get_name "$str")
- NAME=$(echo $name | LC_ALL=C tr '[a-z]' '[A-Z]')
- echo "#define TRACE_${NAME}_ENABLED ${enabled}"
- fi
- done
-
- echo
- "$end"
-}
-
-tracetoh()
-{
- cat <<EOF
-#ifndef TRACE_H
-#define TRACE_H
-
-/* This file is autogenerated by tracetool, do not edit. */
-
-#include "qemu-common.h"
-EOF
- convert h
- echo "#endif /* TRACE_H */"
-}
-
-tracetoc()
-{
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert c
-}
-
-tracetod()
-{
- if [ $backend != "dtrace" ]; then
- echo "DTrace probe generator not applicable to $backend backend"
- exit 1
- fi
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert d
-}
-
-tracetostap()
-{
- if [ $backend != "dtrace" ]; then
- echo "SystemTAP tapset generator not applicable to $backend backend"
- exit 1
- fi
- if [ -z "$binary" ]; then
- echo "--binary is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$probeprefix" -a -z "$targettype" ]; then
- echo "--target-type is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$probeprefix" -a -z "$targetarch" ]; then
- echo "--target-arch is required for SystemTAP tapset generator"
- exit 1
- fi
- if [ -z "$probeprefix" ]; then
- probeprefix="qemu.$targettype.$targetarch";
- fi
- echo "/* This file is autogenerated by tracetool, do not edit. */"
- convert stap
-}
-
-
-backend=
-output=
-binary=
-targettype=
-targetarch=
-probeprefix=
-
-
-until [ -z "$1" ]
-do
- case "$1" in
- "--nop" | "--simple" | "--stderr" | "--ust" | "--dtrace") backend="${1#--}" ;;
-
- "--binary") shift ; binary="$1" ;;
- "--target-arch") shift ; targetarch="$1" ;;
- "--target-type") shift ; targettype="$1" ;;
- "--probe-prefix") shift ; probeprefix="$1" ;;
-
- "-h" | "-c" | "-d") output="${1#-}" ;;
- "--stap") output="${1#--}" ;;
-
- "--check-backend") exit 0 ;; # used by ./configure to test for backend
-
- "--list-backends") # used by ./configure to list available backends
- echo "nop simple stderr ust dtrace"
- exit 0
- ;;
-
- *)
- usage;;
- esac
- shift
-done
-
-if [ "$backend" = "" -o "$output" = "" ]; then
- usage
-fi
-
-gen="traceto$output"
-"$gen"
-
-exit 0
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Command-line wrapper for the tracetool machinery.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+import sys
+import getopt
+
+from tracetool import error_write, out
+import tracetool.backend
+import tracetool.format
+
+
+_SCRIPT = ""
+
+def error_opt(msg = None):
+ if msg is not None:
+ error_write("Error: " + msg + "\n")
+
+ backend_descr = "\n".join([ " %-15s %s" % (n, d)
+ for n,d in tracetool.backend.get_list() ])
+ format_descr = "\n".join([ " %-15s %s" % (n, d)
+ for n,d in tracetool.format.get_list() ])
+ error_write("""\
+Usage: %(script)s --format=<format> --backend=<backend> [<options>]
+
+Backends:
+%(backends)s
+
+Formats:
+%(formats)s
+
+Options:
+ --help This help message.
+ --list-backends Print list of available backends.
+ --check-backend Check if the given backend is valid.
+ --binary <path> Full path to QEMU binary.
+ --target-type <type> QEMU emulator target type ('system' or 'user').
+ --target-arch <arch> QEMU emulator target arch.
+ --probe-prefix <prefix> Prefix for dtrace probe names
+ (default: qemu-<target-type>-<target-arch>).\
+""" % {
+ "script" : _SCRIPT,
+ "backends" : backend_descr,
+ "formats" : format_descr,
+ })
+
+ if msg is None:
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+
+def main(args):
+ global _SCRIPT
+ _SCRIPT = args[0]
+
+ long_opts = [ "backend=", "format=", "help", "list-backends", "check-backend" ]
+ long_opts += [ "binary=", "target-type=", "target-arch=", "probe-prefix=" ]
+
+ try:
+ opts, args = getopt.getopt(args[1:], "", long_opts)
+ except getopt.GetoptError as err:
+ error_opt(str(err))
+
+ check_backend = False
+ arg_backend = ""
+ arg_format = ""
+ binary = None
+ target_type = None
+ target_arch = None
+ probe_prefix = None
+ for opt, arg in opts:
+ if opt == "--help":
+ error_opt()
+
+ elif opt == "--backend":
+ arg_backend = arg
+ elif opt == "--format":
+ arg_format = arg
+
+ elif opt == "--list-backends":
+ backends = tracetool.backend.get_list()
+ out(", ".join([ b for b,_ in backends ]))
+ sys.exit(0)
+ elif opt == "--check-backend":
+ check_backend = True
+
+ elif opt == "--binary":
+ binary = arg
+ elif opt == '--target-type':
+ target_type = arg
+ elif opt == '--target-arch':
+ target_arch = arg
+ elif opt == '--probe-prefix':
+ probe_prefix = arg
+
+ else:
+ error_opt("unhandled option: %s" % opt)
+
+ if arg_backend is None:
+ error_opt("backend not set")
+
+ if check_backend:
+ if tracetool.backend.exists(arg_backend):
+ sys.exit(0)
+ else:
+ sys.exit(1)
+
+ if arg_format == "stap":
+ if binary is None:
+ error_opt("--binary is required for SystemTAP tapset generator")
+ if probe_prefix is None and target_type is None:
+ error_opt("--target-type is required for SystemTAP tapset generator")
+ if probe_prefix is None and target_arch is None:
+ error_opt("--target-arch is required for SystemTAP tapset generator")
+
+ if probe_prefix is None:
+ probe_prefix = ".".join([ "qemu", target_type, target_arch ])
+
+ try:
+ tracetool.generate(sys.stdin, arg_format, arg_backend,
+ binary = binary, probe_prefix = probe_prefix)
+ except tracetool.TracetoolError as e:
+ error_opt(str(e))
+
+if __name__ == "__main__":
+ main(sys.argv)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Machinery for generating tracing-related intermediate files.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+import re
+import sys
+
+import tracetool.format
+import tracetool.backend
+
+
+def error_write(*lines):
+ """Write a set of error lines."""
+ sys.stderr.writelines("\n".join(lines) + "\n")
+
+def error(*lines):
+ """Write a set of error lines and exit."""
+ error_write(*lines)
+ sys.exit(1)
+
+
+def out(*lines, **kwargs):
+ """Write a set of output lines.
+
+ You can use kwargs as a shorthand for mapping variables when formating all
+ the strings in lines.
+ """
+ lines = [ l % kwargs for l in lines ]
+ sys.stdout.writelines("\n".join(lines) + "\n")
+
+
+class Arguments:
+ """Event arguments description."""
+
+ def __init__(self, args):
+ """
+ Parameters
+ ----------
+ args :
+ List of (type, name) tuples.
+ """
+ self._args = args
+
+ @staticmethod
+ def build(arg_str):
+ """Build and Arguments instance from an argument string.
+
+ Parameters
+ ----------
+ arg_str : str
+ String describing the event arguments.
+ """
+ res = []
+ for arg in arg_str.split(","):
+ arg = arg.strip()
+ parts = arg.split()
+ head, sep, tail = parts[-1].rpartition("*")
+ parts = parts[:-1]
+ if tail == "void":
+ assert len(parts) == 0 and sep == ""
+ continue
+ arg_type = " ".join(parts + [ " ".join([head, sep]).strip() ]).strip()
+ res.append((arg_type, tail))
+ return Arguments(res)
+
+ def __iter__(self):
+ """Iterate over the (type, name) pairs."""
+ return iter(self._args)
+
+ def __len__(self):
+ """Number of arguments."""
+ return len(self._args)
+
+ def __str__(self):
+ """String suitable for declaring function arguments."""
+ if len(self._args) == 0:
+ return "void"
+ else:
+ return ", ".join([ " ".join([t, n]) for t,n in self._args ])
+
+ def __repr__(self):
+ """Evaluable string representation for this object."""
+ return "Arguments(\"%s\")" % str(self)
+
+ def names(self):
+ """List of argument names."""
+ return [ name for _, name in self._args ]
+
+ def types(self):
+ """List of argument types."""
+ return [ type_ for type_, _ in self._args ]
+
+
+class Event(object):
+ """Event description.
+
+ Attributes
+ ----------
+ name : str
+ The event name.
+ fmt : str
+ The event format string.
+ properties : set(str)
+ Properties of the event.
+ args : Arguments
+ The event arguments.
+ """
+
+ _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
+
+ _VALID_PROPS = set(["disable"])
+
+ def __init__(self, name, props, fmt, args):
+ """
+ Parameters
+ ----------
+ name : string
+ Event name.
+ props : list of str
+ Property names.
+ fmt : str
+ Event printing format.
+ args : Arguments
+ Event arguments.
+ """
+ self.name = name
+ self.properties = props
+ self.fmt = fmt
+ self.args = args
+
+ unknown_props = set(self.properties) - self._VALID_PROPS
+ if len(unknown_props) > 0:
+ raise ValueError("Unknown properties: %s" % ", ".join(unknown_props))
+
+ @staticmethod
+ def build(line_str):
+ """Build an Event instance from a string.
+
+ Parameters
+ ----------
+ line_str : str
+ Line describing the event.
+ """
+ m = Event._CRE.match(line_str)
+ assert m is not None
+ groups = m.groupdict('')
+
+ name = groups["name"]
+ props = groups["props"].split()
+ fmt = groups["fmt"]
+ args = Arguments.build(groups["args"])
+
+ return Event(name, props, fmt, args)
+
+ def __repr__(self):
+ """Evaluable string representation for this object."""
+ return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
+ self.name,
+ self.args,
+ self.fmt)
+
+def _read_events(fobj):
+ res = []
+ for line in fobj:
+ if not line.strip():
+ continue
+ if line.lstrip().startswith('#'):
+ continue
+ res.append(Event.build(line))
+ return res
+
+
+class TracetoolError (Exception):
+ """Exception for calls to generate."""
+ pass
+
+
+def try_import(mod_name, attr_name = None, attr_default = None):
+ """Try to import a module and get an attribute from it.
+
+ Parameters
+ ----------
+ mod_name : str
+ Module name.
+ attr_name : str, optional
+ Name of an attribute in the module.
+ attr_default : optional
+ Default value if the attribute does not exist in the module.
+
+ Returns
+ -------
+ A pair indicating whether the module could be imported and the module or
+ object or attribute value.
+ """
+ try:
+ module = __import__(mod_name, fromlist=["__package__"])
+ if attr_name is None:
+ return True, module
+ return True, getattr(module, str(attr_name), attr_default)
+ except ImportError:
+ return False, None
+
+
+def generate(fevents, format, backend,
+ binary = None, probe_prefix = None):
+ """Generate the output for the given (format, backend) pair.
+
+ Parameters
+ ----------
+ fevents : file
+ Event description file.
+ format : str
+ Output format name.
+ backend : str
+ Output backend name.
+ binary : str or None
+ See tracetool.backend.dtrace.BINARY.
+ probe_prefix : str or None
+ See tracetool.backend.dtrace.PROBEPREFIX.
+ """
+ # fix strange python error (UnboundLocalError tracetool)
+ import tracetool
+
+ format = str(format)
+ if len(format) is 0:
+ raise TracetoolError("format not set")
+ mformat = format.replace("-", "_")
+ if not tracetool.format.exists(mformat):
+ raise TracetoolError("unknown format: %s" % format)
+
+ backend = str(backend)
+ if len(backend) is 0:
+ raise TracetoolError("backend not set")
+ mbackend = backend.replace("-", "_")
+ if not tracetool.backend.exists(mbackend):
+ raise TracetoolError("unknown backend: %s" % backend)
+
+ if not tracetool.backend.compatible(mbackend, mformat):
+ raise TracetoolError("backend '%s' not compatible with format '%s'" %
+ (backend, format))
+
+ import tracetool.backend.dtrace
+ tracetool.backend.dtrace.BINARY = binary
+ tracetool.backend.dtrace.PROBEPREFIX = probe_prefix
+
+ events = _read_events(fevents)
+
+ if backend == "nop":
+ ( e.properies.add("disable") for e in events )
+
+ tracetool.format.generate_begin(mformat, events)
+ tracetool.backend.generate("nop", format,
+ [ e
+ for e in events
+ if "disable" in e.properties ])
+ tracetool.backend.generate(backend, format,
+ [ e
+ for e in events
+ if "disable" not in e.properties ])
+ tracetool.format.generate_end(mformat, events)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Backend management.
+
+
+Creating new backends
+---------------------
+
+A new backend named 'foo-bar' corresponds to Python module
+'tracetool/backend/foo_bar.py'.
+
+A backend module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All backends must generate their contents through the 'tracetool.out' routine.
+
+
+Backend functions
+-----------------
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+<format> Called to generate the format- and backend-specific code for each of
+ the specified events. If the function does not exist, the backend is
+ considered not compatible with the given format.
+======== =======================================================================
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+ """Get a list of (name, description) pairs."""
+ res = [("nop", "Tracing disabled.")]
+ for _, modname, _ in pkgutil.iter_modules(tracetool.backend.__path__):
+ module = tracetool.try_import("tracetool.backend." + modname)
+
+ # just in case; should never fail unless non-module files are put there
+ if not module[0]:
+ continue
+ module = module[1]
+
+ doc = module.__doc__
+ if doc is None:
+ doc = ""
+ doc = doc.strip().split("\n")[0]
+
+ name = modname.replace("_", "-")
+ res.append((name, doc))
+ return res
+
+
+def exists(name):
+ """Return whether the given backend exists."""
+ if len(name) == 0:
+ return False
+ if name == "nop":
+ return True
+ name = name.replace("-", "_")
+ return tracetool.try_import("tracetool.backend." + name)[1]
+
+
+def compatible(backend, format):
+ """Whether a backend is compatible with the given format."""
+ if not exists(backend):
+ raise ValueError("unknown backend: %s" % backend)
+
+ backend = backend.replace("-", "_")
+ format = format.replace("-", "_")
+
+ if backend == "nop":
+ return True
+ else:
+ func = tracetool.try_import("tracetool.backend." + backend,
+ format, None)[1]
+ return func is not None
+
+
+def _empty(events):
+ pass
+
+def generate(backend, format, events):
+ """Generate the per-event output for the given (backend, format) pair."""
+ if not compatible(backend, format):
+ raise ValueError("backend '%s' not compatible with format '%s'" %
+ (backend, format))
+
+ backend = backend.replace("-", "_")
+ format = format.replace("-", "_")
+
+ if backend == "nop":
+ func = tracetool.try_import("tracetool.format." + format,
+ "nop", _empty)[1]
+ else:
+ func = tracetool.try_import("tracetool.backend." + backend,
+ format, None)[1]
+
+ func(events)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+DTrace/SystemTAP backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+PROBEPREFIX = None
+
+def _probeprefix():
+ if PROBEPREFIX is None:
+ raise ValueError("you must set PROBEPREFIX")
+ return PROBEPREFIX
+
+
+BINARY = None
+
+def _binary():
+ if BINARY is None:
+ raise ValueError("you must set BINARY")
+ return BINARY
+
+
+def c(events):
+ pass
+
+
+def h(events):
+ out('#include "trace-dtrace.h"',
+ '')
+
+ for e in events:
+ out('static inline void trace_%(name)s(%(args)s) {',
+ ' QEMU_%(uppername)s(%(argnames)s);',
+ '}',
+ name = e.name,
+ args = e.args,
+ uppername = e.name.upper(),
+ argnames = ", ".join(e.args.names()),
+ )
+
+
+def d(events):
+ out('provider qemu {')
+
+ for e in events:
+ args = str(e.args)
+
+ # DTrace provider syntax expects foo() for empty
+ # params, not foo(void)
+ if args == 'void':
+ args = ''
+
+ # Define prototype for probe arguments
+ out('',
+ 'probe %(name)s(%(args)s);',
+ name = e.name,
+ args = args,
+ )
+
+ out('',
+ '};')
+
+
+def stap(events):
+ for e in events:
+ # Define prototype for probe arguments
+ out('probe %(probeprefix)s.%(name)s = process("%(binary)s").mark("%(name)s")',
+ '{',
+ probeprefix = _probeprefix(),
+ name = e.name,
+ binary = _binary(),
+ )
+
+ i = 1
+ if len(e.args) > 0:
+ for name in e.args.names():
+ # Append underscore to reserved keywords
+ if name in ('limit', 'in', 'next', 'self'):
+ name += '_'
+ out(' %s = $arg%d;' % (name, i))
+ i += 1
+
+ out('}')
+
+ out()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Simple built-in backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+ out('#include "trace.h"',
+ '',
+ 'TraceEvent trace_list[] = {')
+
+ for e in events:
+ out('{.tp_name = "%(name)s", .state=0},',
+ name = e.name,
+ )
+
+ out('};')
+
+def h(events):
+ out('#include "trace/simple.h"',
+ '')
+
+ for num, e in enumerate(events):
+ if len(e.args):
+ argstr = e.args.names()
+ arg_prefix = ', (uint64_t)(uintptr_t)'
+ cast_args = arg_prefix + arg_prefix.join(argstr)
+ simple_args = (str(num) + cast_args)
+ else:
+ simple_args = str(num)
+
+ out('static inline void trace_%(name)s(%(args)s)',
+ '{',
+ ' trace%(argc)d(%(trace_args)s);',
+ '}',
+ name = e.name,
+ args = e.args,
+ argc = len(e.args),
+ trace_args = simple_args,
+ )
+
+ out('#define NR_TRACE_EVENTS %d' % len(events))
+ out('extern TraceEvent trace_list[NR_TRACE_EVENTS];')
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Stderr built-in backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+ out('#include "trace.h"',
+ '',
+ 'TraceEvent trace_list[] = {')
+
+ for e in events:
+ out('{.tp_name = "%(name)s", .state=0},',
+ name = e.name,
+ )
+
+ out('};')
+
+def h(events):
+ out('#include <stdio.h>',
+ '#include "trace/stderr.h"',
+ '',
+ 'extern TraceEvent trace_list[];')
+
+ for num, e in enumerate(events):
+ argnames = ", ".join(e.args.names())
+ if len(e.args) > 0:
+ argnames = ", " + argnames
+
+ out('static inline void trace_%(name)s(%(args)s)',
+ '{',
+ ' if (trace_list[%(event_num)s].state != 0) {',
+ ' fprintf(stderr, "%(name)s " %(fmt)s "\\n" %(argnames)s);',
+ ' }',
+ '}',
+ name = e.name,
+ args = e.args,
+ event_num = num,
+ fmt = e.fmt,
+ argnames = argnames,
+ )
+
+ out('',
+ '#define NR_TRACE_EVENTS %d' % len(events))
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+LTTng User Space Tracing backend.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def c(events):
+ out('#include <ust/marker.h>',
+ '#undef mutex_lock',
+ '#undef mutex_unlock',
+ '#undef inline',
+ '#undef wmb',
+ '#include "trace.h"')
+
+ for e in events:
+ argnames = ", ".join(e.args.names())
+ if len(e.args) > 0:
+ argnames = ', ' + argnames
+
+ out('DEFINE_TRACE(ust_%(name)s);',
+ '',
+ 'static void ust_%(name)s_probe(%(args)s)',
+ '{',
+ ' trace_mark(ust, %(name)s, %(fmt)s%(argnames)s);',
+ '}',
+ name = e.name,
+ args = e.args,
+ fmt = e.fmt,
+ argnames = argnames,
+ )
+
+ else:
+ out('DEFINE_TRACE(ust_%(name)s);',
+ '',
+ 'static void ust_%(name)s_probe(%(args)s)',
+ '{',
+ ' trace_mark(ust, %(name)s, UST_MARKER_NOARGS);',
+ '}',
+ name = e.name,
+ args = e.args,
+ )
+
+ # register probes
+ out('',
+ 'static void __attribute__((constructor)) trace_init(void)',
+ '{')
+
+ for e in events:
+ out(' register_trace_ust_%(name)s(ust_%(name)s_probe);',
+ name = e.name,
+ )
+
+ out('}')
+
+
+def h(events):
+ out('#include <ust/tracepoint.h>',
+ '#undef mutex_lock',
+ '#undef mutex_unlock',
+ '#undef inline',
+ '#undef wmb')
+
+ for e in events:
+ if len(e.args) > 0:
+ out('DECLARE_TRACE(ust_%(name)s, TP_PROTO(%(args)s), TP_ARGS(%(argnames)s));',
+ '#define trace_%(name)s trace_ust_%(name)s',
+ name = e.name,
+ args = e.args,
+ argnames = ", ".join(e.args.names()),
+ )
+
+ else:
+ out('_DECLARE_TRACEPOINT_NOARGS(ust_%(name)s);',
+ '#define trace_%(name)s trace_ust_%(name)s',
+ name = e.name,
+ )
+
+ out()
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Format management.
+
+
+Creating new formats
+--------------------
+
+A new format named 'foo-bar' corresponds to Python module
+'tracetool/format/foo_bar.py'.
+
+A format module should provide a docstring, whose first non-empty line will be
+considered its short description.
+
+All formats must generate their contents through the 'tracetool.out' routine.
+
+
+Format functions
+----------------
+
+All the following functions are optional, and no output will be generated if
+they do not exist.
+
+======== =======================================================================
+Function Description
+======== =======================================================================
+begin Called to generate the format-specific file header.
+end Called to generate the format-specific file footer.
+nop Called to generate the per-event contents when the event is disabled or
+ the selected backend is 'nop'.
+======== =======================================================================
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+import pkgutil
+
+import tracetool
+
+
+def get_list():
+ """Get a list of (name, description) pairs."""
+ res = []
+ for _, modname, _ in pkgutil.iter_modules(tracetool.format.__path__):
+ module = tracetool.try_import("tracetool.format." + modname)
+
+ # just in case; should never fail unless non-module files are put there
+ if not module[0]:
+ continue
+ module = module[1]
+
+ doc = module.__doc__
+ if doc is None:
+ doc = ""
+ doc = doc.strip().split("\n")[0]
+
+ name = modname.replace("_", "-")
+ res.append((name, doc))
+ return res
+
+
+def exists(name):
+ """Return whether the given format exists."""
+ if len(name) == 0:
+ return False
+ name = name.replace("-", "_")
+ return tracetool.try_import("tracetool.format." + name)[1]
+
+
+def _empty(events):
+ pass
+
+def generate_begin(name, events):
+ """Generate the header of the format-specific file."""
+ if not exists(name):
+ raise ValueError("unknown format: %s" % name)
+
+ name = name.replace("-", "_")
+ func = tracetool.try_import("tracetool.format." + name,
+ "begin", _empty)[1]
+ func(events)
+
+def generate_end(name, events):
+ """Generate the footer of the format-specific file."""
+ if not exists(name):
+ raise ValueError("unknown format: %s" % name)
+
+ name = name.replace("-", "_")
+ func = tracetool.try_import("tracetool.format." + name,
+ "end", _empty)[1]
+ func(events)
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .c file.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */')
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .d file (DTrace only).
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */')
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h file.
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#ifndef TRACE_H',
+ '#define TRACE_H',
+ '',
+ '#include "qemu-common.h"')
+
+def end(events):
+ for e in events:
+ if "disable" in e.properties:
+ enabled = 0
+ else:
+ enabled = 1
+ out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
+ out('',
+ '#endif /* TRACE_H */')
+
+def nop(events):
+ for e in events:
+ out('',
+ 'static inline void trace_%(name)s(%(args)s)',
+ '{',
+ '}',
+ name = e.name,
+ args = e.args,
+ )
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .stp file (DTrace with SystemTAP only).
+"""
+
+__author__ = "LluÃs Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012, LluÃs Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def begin(events):
+ out('/* This file is autogenerated by tracetool, do not edit. */')
struct in_addr vnameserver, void *opaque);
void slirp_cleanup(Slirp *slirp);
+void slirp_update_timeout(uint32_t *timeout);
void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds);
#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
+void slirp_update_timeout(uint32_t *timeout)
+{
+ if (!QTAILQ_EMPTY(&slirp_instances)) {
+ *timeout = MIN(1000, *timeout);
+ }
+}
+
void slirp_select_fill(int *pnfds,
fd_set *readfds, fd_set *writefds, fd_set *xfds)
{
}
}
if (subtype == NULL) {
- fprintf(stderr, "spice-qemu-char: unsupported name\n");
+ fprintf(stderr, "spice-qemu-char: unsupported name: %s\n", name);
print_allowed_subtypes();
return NULL;
}
--- /dev/null
+/*
+ * QEMU CRIS CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_CRIS_CPU_QOM_H
+#define QEMU_CRIS_CPU_QOM_H
+
+#include "qemu/cpu.h"
+
+#define TYPE_CRIS_CPU "cris-cpu"
+
+#define CRIS_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(CRISCPUClass, (klass), TYPE_CRIS_CPU)
+#define CRIS_CPU(obj) \
+ OBJECT_CHECK(CRISCPU, (obj), TYPE_CRIS_CPU)
+#define CRIS_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(CRISCPUClass, (obj), TYPE_CRIS_CPU)
+
+/**
+ * CRISCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A CRIS CPU model.
+ */
+typedef struct CRISCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} CRISCPUClass;
+
+/**
+ * CRISCPU:
+ * @env: #CPUCRISState
+ *
+ * A CRIS CPU.
+ */
+typedef struct CRISCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUCRISState env;
+} CRISCPU;
+
+static inline CRISCPU *cris_env_get_cpu(CPUCRISState *env)
+{
+ return CRIS_CPU(container_of(env, CRISCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(cris_env_get_cpu(e))
+
+
+#endif
--- /dev/null
+/*
+ * QEMU CRIS CPU
+ *
+ * Copyright (c) 2008 AXIS Communications AB
+ * Written by Edgar E. Iglesias.
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+#include "mmu.h"
+
+
+/* CPUClass::reset() */
+static void cris_cpu_reset(CPUState *s)
+{
+ CRISCPU *cpu = CRIS_CPU(s);
+ CRISCPUClass *ccc = CRIS_CPU_GET_CLASS(cpu);
+ CPUCRISState *env = &cpu->env;
+ uint32_t vr;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ ccc->parent_reset(s);
+
+ vr = env->pregs[PR_VR];
+ memset(env, 0, offsetof(CPUCRISState, breakpoints));
+ env->pregs[PR_VR] = vr;
+ tlb_flush(env, 1);
+
+#if defined(CONFIG_USER_ONLY)
+ /* start in user mode with interrupts enabled. */
+ env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
+#else
+ cris_mmu_init(env);
+ env->pregs[PR_CCS] = 0;
+#endif
+}
+
+static void cris_cpu_initfn(Object *obj)
+{
+ CRISCPU *cpu = CRIS_CPU(obj);
+ CPUCRISState *env = &cpu->env;
+
+ cpu_exec_init(env);
+}
+
+static void cris_cpu_class_init(ObjectClass *oc, void *data)
+{
+ CPUClass *cc = CPU_CLASS(oc);
+ CRISCPUClass *ccc = CRIS_CPU_CLASS(oc);
+
+ ccc->parent_reset = cc->reset;
+ cc->reset = cris_cpu_reset;
+}
+
+static const TypeInfo cris_cpu_type_info = {
+ .name = TYPE_CRIS_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(CRISCPU),
+ .instance_init = cris_cpu_initfn,
+ .abstract = false,
+ .class_size = sizeof(CRISCPUClass),
+ .class_init = cris_cpu_class_init,
+};
+
+static void cris_cpu_register_types(void)
+{
+ type_register_static(&cris_cpu_type_info);
+}
+
+type_init(cris_cpu_register_types)
void *load_info;
} CPUCRISState;
+#include "cpu-qom.h"
+
CPUCRISState *cpu_cris_init(const char *cpu_model);
int cpu_cris_exec(CPUCRISState *s);
void cpu_cris_close(CPUCRISState *s);
CPUCRISState *cpu_cris_init (const char *cpu_model)
{
+ CRISCPU *cpu;
CPUCRISState *env;
static int tcg_initialized = 0;
int i;
- env = g_malloc0(sizeof(CPUCRISState));
+ cpu = CRIS_CPU(object_new(TYPE_CRIS_CPU));
+ env = &cpu->env;
env->pregs[PR_VR] = vr_by_name(cpu_model);
- cpu_exec_init(env);
- cpu_state_reset(env);
+
+ cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
if (tcg_initialized)
void cpu_state_reset(CPUCRISState *env)
{
- uint32_t vr;
-
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- vr = env->pregs[PR_VR];
- memset(env, 0, offsetof(CPUCRISState, breakpoints));
- env->pregs[PR_VR] = vr;
- tlb_flush(env, 1);
-
-#if defined(CONFIG_USER_ONLY)
- /* start in user mode with interrupts enabled. */
- env->pregs[PR_CCS] |= U_FLAG | I_FLAG | P_FLAG;
-#else
- cris_mmu_init(env);
- env->pregs[PR_CCS] = 0;
-#endif
+ cpu_reset(ENV_GET_CPU(env));
}
void restore_state_to_opc(CPUCRISState *env, TranslationBlock *tb, int pc_pos)
model_id = "";
}
len = strlen(model_id);
+ memset(env->cpuid_model, 0, 48);
for (i = 0; i < 48; i++) {
if (i >= len) {
c = '\0';
--- /dev/null
+/*
+ * QEMU MicroBlaze CPU
+ *
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+#ifndef QEMU_MICROBLAZE_CPU_QOM_H
+#define QEMU_MICROBLAZE_CPU_QOM_H
+
+#include "qemu/cpu.h"
+
+#define TYPE_MICROBLAZE_CPU "microblaze-cpu"
+
+#define MICROBLAZE_CPU_CLASS(klass) \
+ OBJECT_CLASS_CHECK(MicroBlazeCPUClass, (klass), TYPE_MICROBLAZE_CPU)
+#define MICROBLAZE_CPU(obj) \
+ OBJECT_CHECK(MicroBlazeCPU, (obj), TYPE_MICROBLAZE_CPU)
+#define MICROBLAZE_CPU_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(MicroBlazeCPUClass, (obj), TYPE_MICROBLAZE_CPU)
+
+/**
+ * MicroBlazeCPUClass:
+ * @parent_reset: The parent class' reset handler.
+ *
+ * A MicroBlaze CPU model.
+ */
+typedef struct MicroBlazeCPUClass {
+ /*< private >*/
+ CPUClass parent_class;
+ /*< public >*/
+
+ void (*parent_reset)(CPUState *cpu);
+} MicroBlazeCPUClass;
+
+/**
+ * MicroBlazeCPU:
+ * @env: #CPUMBState
+ *
+ * A MicroBlaze CPU.
+ */
+typedef struct MicroBlazeCPU {
+ /*< private >*/
+ CPUState parent_obj;
+ /*< public >*/
+
+ CPUMBState env;
+} MicroBlazeCPU;
+
+static inline MicroBlazeCPU *mb_env_get_cpu(CPUMBState *env)
+{
+ return MICROBLAZE_CPU(container_of(env, MicroBlazeCPU, env));
+}
+
+#define ENV_GET_CPU(e) CPU(mb_env_get_cpu(e))
+
+
+#endif
--- /dev/null
+/*
+ * QEMU MicroBlaze CPU
+ *
+ * Copyright (c) 2009 Edgar E. Iglesias
+ * Copyright (c) 2009-2012 PetaLogix Qld Pty Ltd.
+ * Copyright (c) 2012 SUSE LINUX Products GmbH
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see
+ * <http://www.gnu.org/licenses/lgpl-2.1.html>
+ */
+
+#include "cpu.h"
+#include "qemu-common.h"
+
+
+/* CPUClass::reset() */
+static void mb_cpu_reset(CPUState *s)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(s);
+ MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_GET_CLASS(cpu);
+ CPUMBState *env = &cpu->env;
+
+ if (qemu_loglevel_mask(CPU_LOG_RESET)) {
+ qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
+ log_cpu_state(env, 0);
+ }
+
+ mcc->parent_reset(s);
+
+ memset(env, 0, offsetof(CPUMBState, breakpoints));
+ tlb_flush(env, 1);
+
+ /* Disable stack protector. */
+ env->shr = ~0;
+
+ env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
+ | PVR0_USE_BARREL_MASK \
+ | PVR0_USE_DIV_MASK \
+ | PVR0_USE_HW_MUL_MASK \
+ | PVR0_USE_EXC_MASK \
+ | PVR0_USE_ICACHE_MASK \
+ | PVR0_USE_DCACHE_MASK \
+ | PVR0_USE_MMU \
+ | (0xb << 8);
+ env->pvr.regs[2] = PVR2_D_OPB_MASK \
+ | PVR2_D_LMB_MASK \
+ | PVR2_I_OPB_MASK \
+ | PVR2_I_LMB_MASK \
+ | PVR2_USE_MSR_INSTR \
+ | PVR2_USE_PCMP_INSTR \
+ | PVR2_USE_BARREL_MASK \
+ | PVR2_USE_DIV_MASK \
+ | PVR2_USE_HW_MUL_MASK \
+ | PVR2_USE_MUL64_MASK \
+ | PVR2_USE_FPU_MASK \
+ | PVR2_USE_FPU2_MASK \
+ | PVR2_FPU_EXC_MASK \
+ | 0;
+ env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
+ env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
+
+#if defined(CONFIG_USER_ONLY)
+ /* start in user mode with interrupts enabled. */
+ env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
+ env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */
+#else
+ env->sregs[SR_MSR] = 0;
+ mmu_init(&env->mmu);
+ env->mmu.c_mmu = 3;
+ env->mmu.c_mmu_tlb_access = 3;
+ env->mmu.c_mmu_zones = 16;
+#endif
+}
+
+static void mb_cpu_initfn(Object *obj)
+{
+ MicroBlazeCPU *cpu = MICROBLAZE_CPU(obj);
+ CPUMBState *env = &cpu->env;
+
+ cpu_exec_init(env);
+
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+}
+
+static void mb_cpu_class_init(ObjectClass *oc, void *data)
+{
+ CPUClass *cc = CPU_CLASS(oc);
+ MicroBlazeCPUClass *mcc = MICROBLAZE_CPU_CLASS(oc);
+
+ mcc->parent_reset = cc->reset;
+ cc->reset = mb_cpu_reset;
+}
+
+static const TypeInfo mb_cpu_type_info = {
+ .name = TYPE_MICROBLAZE_CPU,
+ .parent = TYPE_CPU,
+ .instance_size = sizeof(MicroBlazeCPU),
+ .instance_init = mb_cpu_initfn,
+ .class_size = sizeof(MicroBlazeCPUClass),
+ .class_init = mb_cpu_class_init,
+};
+
+static void mb_cpu_register_types(void)
+{
+ type_register_static(&mb_cpu_type_info);
+}
+
+type_init(mb_cpu_register_types)
CPU_COMMON
};
+#include "cpu-qom.h"
+
CPUMBState *cpu_mb_init(const char *cpu_model);
int cpu_mb_exec(CPUMBState *s);
void cpu_mb_close(CPUMBState *s);
CPUMBState *cpu_mb_init (const char *cpu_model)
{
+ MicroBlazeCPU *cpu;
CPUMBState *env;
static int tcg_initialized = 0;
int i;
- env = g_malloc0(sizeof(CPUMBState));
+ cpu = MICROBLAZE_CPU(object_new(TYPE_MICROBLAZE_CPU));
+ env = &cpu->env;
- cpu_exec_init(env);
- cpu_state_reset(env);
+ cpu_reset(CPU(cpu));
qemu_init_vcpu(env);
- set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
if (tcg_initialized)
return env;
void cpu_state_reset(CPUMBState *env)
{
- if (qemu_loglevel_mask(CPU_LOG_RESET)) {
- qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
- log_cpu_state(env, 0);
- }
-
- memset(env, 0, offsetof(CPUMBState, breakpoints));
- tlb_flush(env, 1);
-
- /* Disable stack protector. */
- env->shr = ~0;
-
- env->pvr.regs[0] = PVR0_PVR_FULL_MASK \
- | PVR0_USE_BARREL_MASK \
- | PVR0_USE_DIV_MASK \
- | PVR0_USE_HW_MUL_MASK \
- | PVR0_USE_EXC_MASK \
- | PVR0_USE_ICACHE_MASK \
- | PVR0_USE_DCACHE_MASK \
- | PVR0_USE_MMU \
- | (0xb << 8);
- env->pvr.regs[2] = PVR2_D_OPB_MASK \
- | PVR2_D_LMB_MASK \
- | PVR2_I_OPB_MASK \
- | PVR2_I_LMB_MASK \
- | PVR2_USE_MSR_INSTR \
- | PVR2_USE_PCMP_INSTR \
- | PVR2_USE_BARREL_MASK \
- | PVR2_USE_DIV_MASK \
- | PVR2_USE_HW_MUL_MASK \
- | PVR2_USE_MUL64_MASK \
- | PVR2_USE_FPU_MASK \
- | PVR2_USE_FPU2_MASK \
- | PVR2_FPU_EXC_MASK \
- | 0;
- env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */
- env->pvr.regs[11] = PVR11_USE_MMU | (16 << 17);
-
-#if defined(CONFIG_USER_ONLY)
- /* start in user mode with interrupts enabled. */
- env->sregs[SR_MSR] = MSR_EE | MSR_IE | MSR_VM | MSR_UM;
- env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */
-#else
- env->sregs[SR_MSR] = 0;
- mmu_init(&env->mmu);
- env->mmu.c_mmu = 3;
- env->mmu.c_mmu_tlb_access = 3;
- env->mmu.c_mmu_zones = 16;
-#endif
+ cpu_reset(ENV_GET_CPU(env));
}
void restore_state_to_opc(CPUMBState *env, TranslationBlock *tb, int pc_pos)
--- /dev/null
+check-qdict
+check-qfloat
+check-qint
+check-qjson
+check-qlist
+check-qstring
+test-qapi-types.[ch]
+test-qapi-visit.[ch]
+test-qmp-commands.h
+test-qmp-commands
+test-qmp-input-strict
+test-qmp-marshal.c
+*-test
#include <unistd.h>
#include <string.h>
+#include "compiler.h"
#include "osdep.h"
#define MAX_IRQ 256
}
}
-static void qtest_sendf(QTestState *s, const char *fmt, ...)
+static void GCC_FMT_ATTR(2, 3) qtest_sendf(QTestState *s, const char *fmt, ...)
{
va_list ap;
gchar *str;
gchar **args;
size_t i;
- qtest_sendf(s, "read 0x%x 0x%x\n", addr, size);
+ qtest_sendf(s, "read 0x%" PRIx64 " 0x%zx\n", addr, size);
args = qtest_rsp(s, 2);
for (i = 0; i < size; i++) {
const uint8_t *ptr = data;
size_t i;
- qtest_sendf(s, "write 0x%x 0x%x 0x", addr, size);
+ qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x", addr, size);
for (i = 0; i < size; i++) {
qtest_sendf(s, "%02x", ptr[i]);
}
echo
echo "small write"
-$QEMU_IO -c "read 8192 4096" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write 8192 4096" $TEST_IMG | _filter_qemu_io
# success, all done
echo "*** done"
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
small write
-read 4096/4096 bytes at offset 8192
+wrote 4096/4096 bytes at offset 8192
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done
QA output created by 013
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Testing empty image
At offset 0:
QA output created by 014
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Testing empty image:
test2: With offset 0
=== Clusters to be compressed [1]
QA output created by 015
creating image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=37748736
creating first snapshot
wrote 37748736/37748736 bytes at offset 0
36 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
QA output created by 019
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Filling base image
=== IO: pattern 42
qemu-io> No errors were found on the image.
Creating test image with backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base' cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
Filling test image
=== IO: pattern 43
QA output created by 022
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
Testing empty image
At offset 10485760:
QA output created by 023
Creating new image; cluster size: 1024
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
qemu-io> No errors were found on the image.
Creating new image; cluster size: 4096
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=4096
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
qemu-io> No errors were found on the image.
Creating new image; cluster size: 16384
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=16384
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
qemu-io> No errors were found on the image.
Creating new image; cluster size: 65536
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
Testing empty image
At offset 0:
qemu-io> No errors were found on the image.
Creating another new image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=8589934592
More complex patterns
test2: With offset 0
QA output created by 024
Creating backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
=== IO: pattern 0x11
qemu-io> wrote 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> Creating new backing file
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
=== IO: pattern 0x22
qemu-io> wrote 131072/131072 bytes at offset 0
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
qemu-io> Creating COW image
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old' cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 backing_file='TEST_DIR/t.IMGFMT.base_old'
=== IO: pattern 0x33
qemu-io> wrote 262144/262144 bytes at offset 0
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
QA output created by 026
Errors while writing 128 kB
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: on; write
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: off; write
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: on; write
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: off; write
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_update; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: on; write
wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: on; write -b
wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: off; write
wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 5; imm: off; once: off; write -b
wrote 131072/131072 bytes at offset 0
write failed: Input/output error
read failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: on; write
wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: on; write -b
wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: off; write
wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_load; errno: 28; imm: off; once: off; write -b
wrote 131072/131072 bytes at offset 0
write failed: No space left on device
read failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: on; write
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: on; write
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
128 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_alloc.write; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
1 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: write_aio; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_load; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: on; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: on; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: off; write
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 5; imm: off; once: off; write -b
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
=== Refcout table growth tests ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write
write failed: No space left on device
55 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.hookup; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
251 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_blocks; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.write_table; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
23 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: on; write -b
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write
write failed: No space left on device
10 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=512
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_alloc.switch_table; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
=== L1 growth tests ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 5; imm: off; once: off
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.alloc_table; errno: 28; imm: off; once: off
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 5; imm: off; once: off
qcow2_free_clusters failed: Input/output error
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.write_table; errno: 28; imm: off; once: off
qcow2_free_clusters failed: No space left on device
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 5; imm: off; once: on
write failed: Input/output error
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 5; imm: off; once: off
qcow2_free_clusters failed: Input/output error
96 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 28; imm: off; once: on
write failed: No space left on device
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l1_grow.activate_table; errno: 28; imm: off; once: off
qcow2_free_clusters failed: No space left on device
QA output created by 029
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216 cluster_size=1024
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=16777216
wrote 4194304/4194304 bytes at offset 0
4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
def test_stream(self):
self.assert_no_active_streams()
- result = self.vm.qmp('block_stream', device='drive0')
+ result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
completed = False
'image file not fully populated after streaming')
def test_device_not_found(self):
- result = self.vm.qmp('block_stream', device='nonexistent')
+ result = self.vm.qmp('block-stream', device='nonexistent')
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
class TestStreamStop(ImageStreamingTestCase):
self.assert_no_active_streams()
- result = self.vm.qmp('block_stream', device='drive0')
+ result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
time.sleep(1)
events = self.vm.get_qmp_events(wait=False)
self.assertEqual(events, [], 'unexpected QMP event: %s' % events)
- self.vm.qmp('block_job_cancel', device='drive0')
+ self.vm.qmp('block-job-cancel', device='drive0')
self.assert_qmp(result, 'return', {})
cancelled = False
def perf_test_set_speed(self):
self.assert_no_active_streams()
- result = self.vm.qmp('block_stream', device='drive0')
+ result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
- result = self.vm.qmp('block_job_set_speed', device='drive0', value=8 * 1024 * 1024)
+ result = self.vm.qmp('block-job-set-speed', device='drive0', value=8 * 1024 * 1024)
self.assert_qmp(result, 'return', {})
completed = False
_supported_os Linux
CLUSTER_SIZE=65536
-echo
-echo === Create image with unknown header extension ===
-echo
-_make_test_img 64M
-./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
-./qcow2.py $TEST_IMG dump-header
-_check_test_img
-echo
-echo === Rewrite header with no backing file ===
-echo
-$QEMU_IMG rebase -u -b "" $TEST_IMG
-./qcow2.py $TEST_IMG dump-header
-_check_test_img
+# qcow2.py output depends on the exact options used, so override the command
+# line here as an exception
+for IMGOPTS in "compat=0.10" "compat=1.1"; do
-echo
-echo === Add a backing file and format ===
-echo
-$QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
-./qcow2.py $TEST_IMG dump-header
+ echo
+ echo ===== Testing with -o $IMGOPTS =====
+ echo
+ echo === Create image with unknown header extension ===
+ echo
+ _make_test_img 64M
+ ./qcow2.py $TEST_IMG add-header-ext 0x12345678 "This is a test header extension"
+ ./qcow2.py $TEST_IMG dump-header
+ _check_test_img
+
+ echo
+ echo === Rewrite header with no backing file ===
+ echo
+ $QEMU_IMG rebase -u -b "" $TEST_IMG
+ ./qcow2.py $TEST_IMG dump-header
+ _check_test_img
+
+ echo
+ echo === Add a backing file and format ===
+ echo
+ $QEMU_IMG rebase -u -b "/some/backing/file/path" -F host_device $TEST_IMG
+ ./qcow2.py $TEST_IMG dump-header
+done
# success, all done
echo "*** done"
QA output created by 031
+===== Testing with -o compat=0.10 =====
+
=== Create image with unknown header extension ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 cluster_size=65536
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
magic 0x514649fb
version 2
backing_file_offset 0x0
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
Header extension:
magic 0x12345678
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
+
+Header extension:
+magic 0x6803f857
+length 0
+data ''
Header extension:
magic 0x12345678
magic 0x514649fb
version 2
-backing_file_offset 0x90
+backing_file_offset 0x98
backing_file_size 0x17
cluster_bits 16
size 67108864
refcount_table_clusters 1
nb_snapshots 0
snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 72
Header extension:
magic 0xe2792aca
length 11
data 'host_device'
+Header extension:
+magic 0x6803f857
+length 0
+data ''
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+
+===== Testing with -o compat=1.1 =====
+
+=== Create image with unknown header extension ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+magic 0x514649fb
+version 3
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+No errors were found on the image.
+
+=== Rewrite header with no backing file ===
+
+magic 0x514649fb
+version 3
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+Header extension:
+magic 0x6803f857
+length 0
+data ''
+
+Header extension:
+magic 0x12345678
+length 31
+data 'This is a test header extension'
+
+No errors were found on the image.
+
+=== Add a backing file and format ===
+
+magic 0x514649fb
+version 3
+backing_file_offset 0xb8
+backing_file_size 0x17
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x0
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+Header extension:
+magic 0xe2792aca
+length 11
+data 'host_device'
+
+Header extension:
+magic 0x6803f857
+length 0
+data ''
+
Header extension:
magic 0x12345678
length 31
--- /dev/null
+#!/bin/bash
+#
+# Test that AIO requests are drained before an image is closed. This used
+# to segfault because the request coroutine kept running even after the
+# BlockDriverState was freed.
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+# This works for any image format (though unlikely to segfault for raw)
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+echo
+echo === Prepare image ===
+echo
+
+CLUSTER_SIZE=65536
+_make_test_img 64M
+
+# Allocate every other cluster so that afterwards a big write request will
+# actually loop a while and issue many I/O requests for the lower layer
+for i in $(seq 0 128 4096); do echo "write ${i}k 64k"; done | $QEMU_IO $TEST_IMG | _filter_qemu_io
+
+echo
+echo === AIO request during close ===
+echo
+$QEMU_IO -c "aio_write 0 4M" -c "close" $TEST_IMG | _filter_qemu_io
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
--- /dev/null
+QA output created by 032
+
+=== Prepare image ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-io> wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 131072
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 262144
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 393216
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 524288
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 655360
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 786432
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 917504
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1179648
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1310720
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1441792
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1572864
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1703936
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1835008
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1966080
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2097152
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2228224
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2359296
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2490368
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2621440
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2752512
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2883584
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3014656
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3145728
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3276800
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3407872
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3538944
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3670016
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3801088
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 3932160
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 4063232
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 4194304
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io>
+=== AIO request during close ===
+
+wrote 4194304/4194304 bytes at offset 0
+4 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+*** done
--- /dev/null
+#!/bin/bash
+#
+# Test aligned and misaligned write zeroes operations.
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=pbonzini@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+
+size=128M
+_make_test_img $size
+
+echo
+echo "== preparing image =="
+$QEMU_IO -c "write -P 0xa 0x200 0x400" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xa 0x20000 0x600" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== verifying patterns (1) =="
+$QEMU_IO -c "read -P 0xa 0x200 0x200" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 0x20400 0x200" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== rewriting zeroes =="
+$QEMU_IO -c "write -P 0xb 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 0x10000 0x10000" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== verifying patterns (2) =="
+$QEMU_IO -c "read -P 0x0 0x400 0x20000" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
--- /dev/null
+QA output created by 033
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+== preparing image ==
+wrote 1024/1024 bytes at offset 512
+1 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 1536/1536 bytes at offset 131072
+2 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verifying patterns (1) ==
+read 512/512 bytes at offset 512
+512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 132096
+512.000000 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== rewriting zeroes ==
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== verifying patterns (2) ==
+read 131072/131072 bytes at offset 1024
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
--- /dev/null
+#!/bin/bash
+#
+# Test bdrv_write_zeroes with backing files
+#
+# Copyright (C) 2012 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow qcow2 vmdk qed
+_supported_proto generic
+_supported_os Linux
+
+CLUSTER_SIZE=4k
+size=128M
+
+echo
+echo "== creating backing file for COW tests =="
+
+_make_test_img $size
+$QEMU_IO -c "write -P 0x55 0 1M" $TEST_IMG | _filter_qemu_io
+mv $TEST_IMG $TEST_IMG.base
+
+_make_test_img -b $TEST_IMG.base 6G
+
+echo
+echo "== zero write with backing file =="
+$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -z 513k 13k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (3) =="
+$QEMU_IO -c "read -P 0x55 0 64k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 256k 257k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== overwriting zero cluster =="
+$QEMU_IO -c "write -P 0xa 60k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xd 252k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "write -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (4) =="
+$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xb 64k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 72k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xc 76k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 80k 168k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xe 248k 8k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 260k 64k" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== re-zeroing overwritten area =="
+$QEMU_IO -c "write -z 64k 192k" $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo "== verifying patterns (5) =="
+$QEMU_IO -c "read -P 0x55 0 60k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xa 60k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 64k 192k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0xd 256k 4k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 260k 253k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x0 513k 13k" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0x55 526k 498k" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
--- /dev/null
+QA output created by 034
+
+== creating backing file for COW tests ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+
+== zero write with backing file ==
+wrote 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (3) ==
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 263168/263168 bytes at offset 262144
+257 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 509952/509952 bytes at offset 538624
+498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== overwriting zero cluster ==
+wrote 8192/8192 bytes at offset 61440
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 4096/4096 bytes at offset 77824
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 258048
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset 253952
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (4) ==
+read 61440/61440 bytes at offset 0
+60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 61440
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 73728
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 77824
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 172032/172032 bytes at offset 81920
+168 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 8192/8192 bytes at offset 253952
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 262144
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65536/65536 bytes at offset 266240
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== re-zeroing overwritten area ==
+wrote 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+== verifying patterns (5) ==
+read 61440/61440 bytes at offset 0
+60 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 61440
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 196608/196608 bytes at offset 65536
+192 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 4096/4096 bytes at offset 262144
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 259072/259072 bytes at offset 266240
+253 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 13312/13312 bytes at offset 525312
+13 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 509952/509952 bytes at offset 538624
+498 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
exit 1
fi
-# we need common
-. ./common
-
# we need common.rc
if ! . ./common.rc
then
exit 1
fi
+# we need common
+. ./common
+
#if [ `id -u` -ne 0 ]
#then
# echo "check: QA must be run as root"
verbose=false
group=false
xgroup=false
+imgopts=false
showme=false
sortme=false
expunge=true
export IMGFMT=raw
export IMGPROTO=file
+export IMGOPTS=""
export QEMU_IO_OPTIONS=""
for r
mv $tmp.tmp $tmp.list
xgroup=false
continue
+
+ elif $imgopts
+ then
+ IMGOPTS="$r"
+ imgopts=false
+ continue
+
fi
xpand=true
-nocache use O_DIRECT on backing file
-misalign misalign memory allocations
-n show me, do not run tests
+ -o options -o options to pass to qemu-img create/convert
-T output timestamps
-r randomize test order
showme=true
xpand=false
;;
+ -o)
+ imgopts=true
+ xpand=false
+ ;;
-r) # randomize test order
randomize=true
xpand=false
done
+# Set default options for qemu-img create -o if they were not specified
+_set_default_imgopts
+
if [ -s $tmp.list ]
then
# found some valid test numbers ... this is good
PATH=".:$PATH"
-HOST=`hostname -s`
+HOST=`hostname -s 2> /dev/null`
HOSTOS=`uname -s`
EMAIL=root@localhost # where auto-qa will send its status messages
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
+_optstr_add()
+{
+ if [ -n "$1" ]; then
+ echo "$1,$2"
+ else
+ echo "$2"
+ fi
+}
+
+_set_default_imgopts()
+{
+ if [ "$IMGFMT" == "qcow2" ] && ! (echo "$IMGOPTS" | grep "compat=" > /dev/null); then
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "compat=1.1")
+ fi
+}
+
_make_test_img()
{
# extra qemu-img options can be added by tests
# at least one argument (the image size) needs to be added
local extra_img_options=""
- local cluster_size_filter="s# cluster_size=[0-9]\\+##g"
local image_size=$*
+ local optstr=""
+
+ if [ -n "$IMGOPTS" ]; then
+ optstr=$(_optstr_add "$optstr" "$IMGOPTS")
+ fi
if [ "$1" = "-b" ]; then
extra_img_options="$1 $2"
image_size=$3
fi
if [ \( "$IMGFMT" = "qcow2" -o "$IMGFMT" = "qed" \) -a -n "$CLUSTER_SIZE" ]; then
- extra_img_options="-o cluster_size=$CLUSTER_SIZE $extra_img_options"
- cluster_size_filter=""
+ optstr=$(_optstr_add "$optstr" "cluster_size=$CLUSTER_SIZE")
+ fi
+
+ if [ -n "$optstr" ]; then
+ extra_img_options="-o $optstr $extra_img_options"
fi
# XXX(hch): have global image options?
sed -e "s#$TEST_DIR#TEST_DIR#g" | \
sed -e "s#$IMGFMT#IMGFMT#g" | \
sed -e "s# encryption=off##g" | \
- sed -e "$cluster_size_filter" | \
+ sed -e "s# cluster_size=[0-9]\\+##g" | \
sed -e "s# table_size=0##g" | \
+ sed -e "s# compat='[^']*'##g" | \
sed -e "s# compat6=off##g" | \
sed -e "s# static=off##g"
}
_full_imgfmt_details()
{
- echo "$IMGFMT"
+ if [ -n "$IMGOPTS" ]; then
+ echo "$IMGFMT ($IMGOPTS)"
+ else
+ echo "$IMGFMT"
+ fi
}
_full_imgproto_details()
029 rw auto quick
030 rw auto
031 rw auto quick
+032 rw auto
+033 rw auto
+034 rw auto backing
[ uint32_t, '%d', 'refcount_table_clusters' ],
[ uint32_t, '%d', 'nb_snapshots' ],
[ uint64_t, '%#x', 'snapshot_offset' ],
+
+ # Version 3 header fields
+ [ uint64_t, '%#x', 'incompatible_features' ],
+ [ uint64_t, '%#x', 'compatible_features' ],
+ [ uint64_t, '%#x', 'autoclear_features' ],
+ [ uint32_t, '%d', 'refcount_order' ],
+ [ uint32_t, '%d', 'header_length' ],
];
fmt = '>' + ''.join(field[0] for field in fields)
self.__dict__ = dict((field[2], header[i])
for i, field in enumerate(QcowHeader.fields))
+ self.set_defaults()
self.cluster_size = 1 << self.cluster_bits
- fd.seek(self.get_header_length())
+ fd.seek(self.header_length)
self.load_extensions(fd)
if self.backing_file_offset:
else:
self.backing_file = None
- def get_header_length(self):
+ def set_defaults(self):
if self.version == 2:
- return 72
- else:
- raise Exception("version != 2 not supported")
+ self.incompatible_features = 0
+ self.compatible_features = 0
+ self.autoclear_features = 0
+ self.refcount_order = 4
+ self.header_length = 72
def load_extensions(self, fd):
self.extensions = []
def update_extensions(self, fd):
- fd.seek(self.get_header_length())
+ fd.seek(self.header_length)
extensions = self.extensions
extensions.append(QcowHeaderExtension(0, 0, ""))
for ex in extensions:
def update(self, fd):
- header_bytes = self.get_header_length()
+ header_bytes = self.header_length
self.update_extensions(fd)
void xen_hvm_inject_msi(uint64_t addr, uint32_t data)
{
- xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
+ xen_xc_hvm_inject_msi(xen_xc, xen_domid, addr, data);
}
static void xen_suspend_notifier(Notifier *notifier, void *data)