summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS2
-rw-r--r--Makefile.objs6
-rw-r--r--Makefile.target13
-rw-r--r--block/nbd.c53
-rwxr-xr-xconfigure29
-rw-r--r--error.c2
-rw-r--r--hmp-commands.hx4
-rw-r--r--hw/e1000.c2
-rw-r--r--hw/pc.c2
-rw-r--r--hw/pflash_cfi01.c1
-rw-r--r--hw/qxl.c2
-rw-r--r--hw/qxl.h2
-rw-r--r--hw/scsi-bus.c8
-rw-r--r--hw/scsi-defs.h1
-rw-r--r--hw/scsi-disk.c170
-rw-r--r--hw/virtio-scsi.c26
-rw-r--r--hw/virtio.c7
-rw-r--r--hw/virtio.h1
-rw-r--r--hw/xen.h10
-rw-r--r--hw/xen_common.h15
-rw-r--r--nbd.c267
-rw-r--r--nbd.h6
-rw-r--r--qemu-ga.c7
-rw-r--r--qemu-nbd.c45
-rw-r--r--qga/commands-posix.c36
-rwxr-xr-xscripts/tracetool666
-rwxr-xr-xscripts/tracetool.py138
-rw-r--r--scripts/tracetool/__init__.py271
-rw-r--r--scripts/tracetool/backend/__init__.py111
-rw-r--r--scripts/tracetool/backend/dtrace.py97
-rw-r--r--scripts/tracetool/backend/simple.py55
-rw-r--r--scripts/tracetool/backend/stderr.py56
-rw-r--r--scripts/tracetool/backend/ust.py90
-rw-r--r--scripts/tracetool/format/__init__.py99
-rw-r--r--scripts/tracetool/format/c.py20
-rw-r--r--scripts/tracetool/format/d.py20
-rw-r--r--scripts/tracetool/format/h.py45
-rw-r--r--scripts/tracetool/format/stap.py20
-rw-r--r--spice-qemu-char.c2
-rw-r--r--tests/.gitignore13
-rw-r--r--xen-all.c2
41 files changed, 1515 insertions, 907 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 922945c..cce37e7 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -553,6 +553,8 @@ Tracing
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
diff --git a/Makefile.objs b/Makefile.objs
index 5c3bcda..6d6f24d 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -378,12 +378,12 @@ else
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)
@@ -396,7 +396,7 @@ trace-dtrace.h: trace-dtrace.dtrace
# 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)
diff --git a/Makefile.target b/Makefile.target
index b6a9330..7eda443 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -59,12 +59,13 @@ TARGET_TYPE=system
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
diff --git a/block/nbd.c b/block/nbd.c
index 161b299..e0af5b4 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -150,11 +150,19 @@ static int nbd_have_request(void *opaque)
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;
}
@@ -164,6 +172,10 @@ static void nbd_reply_ready(void *opaque)
* 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;
@@ -193,11 +205,10 @@ static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request,
qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, nbd_restart_write,
nbd_have_request, NULL, 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,
@@ -256,7 +267,7 @@ static int nbd_establish_connection(BlockDriverState *bs)
}
/* Failed to establish connection */
- if (sock == -1) {
+ if (sock < 0) {
logout("Failed to establish connection to NBD server\n");
return -errno;
}
@@ -264,10 +275,10 @@ static int nbd_establish_connection(BlockDriverState *bs)
/* 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
@@ -327,14 +338,16 @@ static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num,
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);
}
@@ -350,6 +363,7 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
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)) {
@@ -360,8 +374,9 @@ static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num,
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);
}
@@ -412,6 +427,7 @@ static int nbd_co_flush(BlockDriverState *bs)
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) {
return 0;
@@ -426,8 +442,9 @@ static int nbd_co_flush(BlockDriverState *bs)
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);
}
@@ -441,6 +458,7 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
BDRVNBDState *s = bs->opaque;
struct nbd_request request;
struct nbd_reply reply;
+ ssize_t ret;
if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) {
return 0;
@@ -450,8 +468,9 @@ static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num,
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);
}
diff --git a/configure b/configure
index 2d62d12..8ed5a03 100755
--- a/configure
+++ b/configure
@@ -1097,7 +1097,7 @@ echo " --disable-docs disable documentation build"
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"
@@ -1398,6 +1398,31 @@ int main(void) {
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();
+ 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);
return 0;
}
EOF
@@ -2670,7 +2695,7 @@ fi
##########################################
# 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"
diff --git a/error.c b/error.c
index d3455ab..a52b771 100644
--- a/error.c
+++ b/error.c
@@ -93,7 +93,7 @@ QDict *error_get_data(Error *err)
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)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index a6f5a84..461fa59 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -92,8 +92,8 @@ ETEXI
},
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
diff --git a/hw/e1000.c b/hw/e1000.c
index 7babc0b..9c76462 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -481,7 +481,7 @@ process_tx_desc(E1000State *s, struct e1000_tx_desc *dp)
} 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);
diff --git a/hw/pc.c b/hw/pc.c
index 1f5aacb..4d34a33 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -916,7 +916,7 @@ static DeviceState *apic_init(void *env, uint8_t apic_id)
msi_supported = true;
}
- if (xen_enabled()) {
+ if (xen_msi_support()) {
msi_supported = true;
}
diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c
index b03f623..d1c7423 100644
--- a/hw/pflash_cfi01.c
+++ b/hw/pflash_cfi01.c
@@ -144,7 +144,6 @@ static uint32_t pflash_read (pflash_t *pfl, target_phys_addr_t offset,
} else {
ret = p[offset];
ret |= p[offset + 1] << 8;
- ret |= p[offset + 1] << 8;
ret |= p[offset + 2] << 16;
ret |= p[offset + 3] << 24;
}
diff --git a/hw/qxl.c b/hw/qxl.c
index db2318e..c3540c3 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1370,7 +1370,7 @@ async_common:
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);
diff --git a/hw/qxl.h b/hw/qxl.h
index 11a0db3..cbb1e2d 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -127,7 +127,7 @@ typedef struct PCIQXLDevice {
/* 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,
diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c
index 8e76c5d..dbdb99c 100644
--- a/hw/scsi-bus.c
+++ b/hw/scsi-bus.c
@@ -1200,6 +1200,7 @@ static const char *scsi_command_name(uint8_t cmd)
[ 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",
@@ -1430,15 +1431,18 @@ static char *scsibus_get_dev_path(DeviceState *dev)
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)
diff --git a/hw/scsi-defs.h b/hw/scsi-defs.h
index 354ed7b..ca24192 100644
--- a/hw/scsi-defs.h
+++ b/hw/scsi-defs.h
@@ -78,6 +78,7 @@
#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
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 9949786..a029ab6 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -55,6 +55,7 @@ typedef struct SCSIDiskReq {
uint64_t sector;
uint32_t sector_count;
uint32_t buflen;
+ bool started;
struct iovec iov;
QEMUIOVector qiov;
BlockAcctCookie acct;
@@ -153,14 +154,80 @@ static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req)
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;
}
@@ -168,10 +235,17 @@ static void scsi_dma_complete(void *opaque, int ret)
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)
@@ -185,7 +259,7 @@ 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;
}
@@ -204,10 +278,12 @@ 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;
@@ -220,7 +296,17 @@ static void scsi_flush_complete(void * opaque, int ret)
}
}
- 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) {
@@ -233,11 +319,12 @@ static void scsi_read_data(SCSIRequest *req)
{
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;
}
@@ -264,16 +351,13 @@ static void scsi_read_data(SCSIRequest *req)
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);
}
}
@@ -333,7 +417,7 @@ static void scsi_write_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;
}
@@ -343,7 +427,8 @@ static void scsi_write_complete(void * opaque, int ret)
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);
@@ -375,6 +460,7 @@ static void scsi_write_data(SCSIRequest *req)
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;
}
@@ -383,6 +469,16 @@ static void scsi_write_data(SCSIRequest *req)
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;
@@ -531,8 +627,8 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
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;
}
@@ -984,11 +1080,12 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
{
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",
@@ -996,10 +1093,16 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
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) {
@@ -1014,9 +1117,8 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf)
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 */
@@ -1306,8 +1408,6 @@ static int scsi_disk_emulate_command(SCSIDiskReq *r)
}
DPRINTF("Unsupported Service Action In\n");
goto illegal_request;
- case VERIFY_10:
- break;
default:
scsi_check_condition(r, SENSE_CODE(INVALID_OPCODE));
return -1;
@@ -1391,7 +1491,6 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
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;
@@ -1417,6 +1516,9 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
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:
@@ -1456,10 +1558,11 @@ static int32_t scsi_send_command(SCSIRequest *req, uint8_t *buf)
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) {
@@ -1767,6 +1870,9 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag,
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:
diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c
index 45d54fa..e8328f4 100644
--- a/hw/virtio-scsi.c
+++ b/hw/virtio-scsi.c
@@ -129,12 +129,12 @@ typedef struct {
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 {
@@ -240,7 +240,10 @@ static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq)
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));
}
@@ -249,10 +252,13 @@ static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq)
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;
@@ -579,10 +585,12 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf)
{
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;
@@ -597,8 +605,10 @@ VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *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) {
diff --git a/hw/virtio.c b/hw/virtio.c
index 064aecf..314abf8 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -624,6 +624,13 @@ int virtio_queue_get_num(VirtIODevice *vdev, int n)
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) {
diff --git a/hw/virtio.h b/hw/virtio.h
index 400c092..0aef7d1 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -229,6 +229,7 @@ target_phys_addr_t virtio_queue_get_ring_size(VirtIODevice *vdev, int n);
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);
diff --git a/hw/xen.h b/hw/xen.h
index e5926b7..3ae4cd0 100644
--- a/hw/xen.h
+++ b/hw/xen.h
@@ -57,4 +57,14 @@ void xen_register_framebuffer(struct MemoryRegion *mr);
# 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 */
diff --git a/hw/xen_common.h b/hw/xen_common.h
index 0409ac7..7043c14 100644
--- a/hw/xen_common.h
+++ b/hw/xen_common.h
@@ -133,6 +133,21 @@ static inline int xc_fd(xc_interface *xen_xc)
}
#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 */
diff --git a/nbd.c b/nbd.c
index 406e555..153709f 100644
--- a/nbd.c
+++ b/nbd.c
@@ -18,7 +18,6 @@
#include "nbd.h"
#include "block.h"
-#include "block_int.h"
#include "qemu-coroutine.h"
@@ -78,12 +77,10 @@
/* 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) {
@@ -102,12 +99,16 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool 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 */
@@ -115,17 +116,32 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
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)
{
@@ -193,6 +209,7 @@ int unix_socket_outgoing(const char *path)
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")
@@ -202,6 +219,9 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
[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);
@@ -213,13 +233,14 @@ static int nbd_send_negotiate(int csock, off_t size, uint32_t flags)
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,
@@ -228,20 +249,22 @@ 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",
@@ -256,14 +279,12 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
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);
@@ -276,61 +297,52 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
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;
@@ -339,24 +351,25 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
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__
@@ -364,29 +377,26 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
{
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) {
@@ -396,8 +406,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
if (ioctl(fd, BLKROSET, (unsigned long) &read_only) < 0) {
int serrno = errno;
LOG("Failed setting read-only attribute");
- errno = serrno;
- return -1;
+ return -serrno;
}
}
@@ -405,8 +414,7 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize)
&& errno != ENOTTY) {
int serrno = errno;
LOG("Failed setting flags");
- errno = serrno;
- return -1;
+ return -serrno;
}
TRACE("Negotiation ended");
@@ -430,7 +438,7 @@ int nbd_client(int fd)
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.
@@ -453,26 +461,24 @@ int nbd_client(int fd)
#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);
@@ -484,23 +490,32 @@ int nbd_send_request(int csock, struct nbd_request *request)
"{ .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
@@ -523,23 +538,25 @@ static int nbd_receive_request(int csock, struct nbd_request *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
@@ -558,15 +575,15 @@ int nbd_receive_reply(int csock, struct nbd_reply *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)
@@ -579,10 +596,14 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply)
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;
}
@@ -681,7 +702,7 @@ NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset,
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;
}
@@ -702,12 +723,12 @@ static int nbd_can_read(void *opaque);
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,
@@ -716,22 +737,15 @@ static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
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);
}
@@ -741,15 +755,18 @@ static int nbd_co_send_reply(NBDRequest *req, struct nbd_reply *reply,
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;
}
@@ -792,11 +809,14 @@ static void nbd_trip(void *opaque)
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;
}
@@ -822,6 +842,15 @@ static void nbd_trip(void *opaque)
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) {
@@ -862,8 +891,9 @@ static void nbd_trip(void *opaque)
}
}
- 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");
@@ -877,9 +907,9 @@ static void nbd_trip(void *opaque)
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");
@@ -889,21 +919,24 @@ static void nbd_trip(void *opaque)
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;
@@ -941,7 +974,7 @@ NBDClient *nbd_client_new(NBDExport *exp, int csock,
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));
diff --git a/nbd.h b/nbd.h
index a8382f0..40d58d3 100644
--- a/nbd.h
+++ b/nbd.h
@@ -59,7 +59,7 @@ enum {
#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);
@@ -70,8 +70,8 @@ int unix_socket_incoming(const char *path);
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);
diff --git a/qemu-ga.c b/qemu-ga.c
index d6f786e..74a1b02 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -117,12 +117,13 @@ static gboolean register_signal_handlers(void)
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"
@@ -131,7 +132,7 @@ static void usage(const char *cmd)
#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"
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d4e7041..5a0300e 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -17,7 +17,7 @@
*/
#include "qemu-common.h"
-#include "block_int.h"
+#include "block.h"
#include "nbd.h"
#include <stdarg.h>
@@ -126,8 +126,7 @@ static int find_partition(BlockDriverState *bs, int partition,
}
if (data[510] != 0x55 || data[511] != 0xaa) {
- errno = -EINVAL;
- return -1;
+ return -EINVAL;
}
for (i = 0; i < 4; i++) {
@@ -165,8 +164,7 @@ static int find_partition(BlockDriverState *bs, int partition,
}
}
- errno = -ENOENT;
- return -1;
+ return -ENOENT;
}
static void termsig_handler(int signum)
@@ -186,7 +184,7 @@ static void *show_parts(void *arg)
* modprobe nbd max_part=63
*/
nbd = open(device, O_RDWR);
- if (nbd != -1) {
+ if (nbd >= 0) {
close(nbd);
}
return NULL;
@@ -203,25 +201,25 @@ static void *nbd_client_thread(void *arg)
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;
}
@@ -268,7 +266,7 @@ static void nbd_accept(void *opaque)
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++;
}
}
@@ -410,9 +408,9 @@ int main(int argc, char **argv)
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);
@@ -427,7 +425,7 @@ int main(int argc, char **argv)
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");
}
@@ -441,7 +439,7 @@ int main(int argc, char **argv)
/* 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");
}
@@ -459,11 +457,11 @@ int main(int argc, char **argv)
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");
}
@@ -489,11 +487,14 @@ int main(int argc, char **argv)
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);
@@ -504,7 +505,7 @@ int main(int argc, char **argv)
fd = tcp_socket_incoming(bindto, port);
}
- if (fd == -1) {
+ if (fd < 0) {
return 1;
}
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index faf970d..087c3af 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -881,46 +881,50 @@ error:
#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
diff --git a/scripts/tracetool b/scripts/tracetool
deleted file mode 100755
index 7b1c142..0000000
--- a/scripts/tracetool
+++ /dev/null
@@ -1,666 +0,0 @@
-#!/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
diff --git a/scripts/tracetool.py b/scripts/tracetool.py
new file mode 100755
index 0000000..cacfd99
--- /dev/null
+++ b/scripts/tracetool.py
@@ -0,0 +1,138 @@
+#!/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)
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
new file mode 100644
index 0000000..74fe21b
--- /dev/null
+++ b/scripts/tracetool/__init__.py
@@ -0,0 +1,271 @@
+#!/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)
diff --git a/scripts/tracetool/backend/__init__.py b/scripts/tracetool/backend/__init__.py
new file mode 100644
index 0000000..34b7ed8
--- /dev/null
+++ b/scripts/tracetool/backend/__init__.py
@@ -0,0 +1,111 @@
+#!/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)
diff --git a/scripts/tracetool/backend/dtrace.py b/scripts/tracetool/backend/dtrace.py
new file mode 100644
index 0000000..9cab75c
--- /dev/null
+++ b/scripts/tracetool/backend/dtrace.py
@@ -0,0 +1,97 @@
+#!/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()
diff --git a/scripts/tracetool/backend/simple.py b/scripts/tracetool/backend/simple.py
new file mode 100644
index 0000000..fbb5717
--- /dev/null
+++ b/scripts/tracetool/backend/simple.py
@@ -0,0 +1,55 @@
+#!/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];')
diff --git a/scripts/tracetool/backend/stderr.py b/scripts/tracetool/backend/stderr.py
new file mode 100644
index 0000000..917fde7
--- /dev/null
+++ b/scripts/tracetool/backend/stderr.py
@@ -0,0 +1,56 @@
+#!/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))
diff --git a/scripts/tracetool/backend/ust.py b/scripts/tracetool/backend/ust.py
new file mode 100644
index 0000000..31a2ff0
--- /dev/null
+++ b/scripts/tracetool/backend/ust.py
@@ -0,0 +1,90 @@
+#!/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()
diff --git a/scripts/tracetool/format/__init__.py b/scripts/tracetool/format/__init__.py
new file mode 100644
index 0000000..0e4baf0
--- /dev/null
+++ b/scripts/tracetool/format/__init__.py
@@ -0,0 +1,99 @@
+#!/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)
diff --git a/scripts/tracetool/format/c.py b/scripts/tracetool/format/c.py
new file mode 100644
index 0000000..35555ae
--- /dev/null
+++ b/scripts/tracetool/format/c.py
@@ -0,0 +1,20 @@
+#!/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. */')
diff --git a/scripts/tracetool/format/d.py b/scripts/tracetool/format/d.py
new file mode 100644
index 0000000..a2d5947
--- /dev/null
+++ b/scripts/tracetool/format/d.py
@@ -0,0 +1,20 @@
+#!/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. */')
diff --git a/scripts/tracetool/format/h.py b/scripts/tracetool/format/h.py
new file mode 100644
index 0000000..6ffb3c2
--- /dev/null
+++ b/scripts/tracetool/format/h.py
@@ -0,0 +1,45 @@
+#!/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,
+ )
diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py
new file mode 100644
index 0000000..50a4c69
--- /dev/null
+++ b/scripts/tracetool/format/stap.py
@@ -0,0 +1,20 @@
+#!/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. */')
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
index 1e735ff..09aa22d 100644
--- a/spice-qemu-char.c
+++ b/spice-qemu-char.c
@@ -209,7 +209,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
}
}
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;
}
diff --git a/tests/.gitignore b/tests/.gitignore
new file mode 100644
index 0000000..f9041f3
--- /dev/null
+++ b/tests/.gitignore
@@ -0,0 +1,13 @@
+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
diff --git a/xen-all.c b/xen-all.c
index a08eec0..bdf9c0f 100644
--- a/xen-all.c
+++ b/xen-all.c
@@ -129,7 +129,7 @@ void xen_piix_pci_write_config_client(uint32_t address, uint32_t val, int len)
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)
OpenPOWER on IntegriCloud