diff options
77 files changed, 1736 insertions, 965 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e22bfa1a30..764c92dab6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -473,6 +473,13 @@ M: Mark McLoughlin <markmc@redhat.com> S: Maintained F: net/ +Network Block Device (NBD) +M: Paolo Bonzini <pbonzini@redhat.com> +S: Odd Fixes +F: block/nbd.c +F: nbd.* +F: qemu-nbd.c + SLIRP M: Jan Kiszka <jan.kiszka@siemens.com> S: Maintained @@ -147,8 +147,9 @@ endif qemu-img.o: qemu-img-cmds.h qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-ga.o: $(GENERATED_HEADERS) -tools-obj-y = qemu-tool.o $(oslib-obj-y) $(trace-obj-y) \ - qemu-timer-common.o cutils.o +tools-obj-y = $(oslib-obj-y) $(trace-obj-y) qemu-tool.o qemu-timer.o \ + qemu-timer-common.o main-loop.o notify.o iohandler.o cutils.o async.o +tools-obj-$(CONFIG_POSIX) += compatfd.o qemu-img$(EXESUF): qemu-img.o $(tools-obj-y) $(block-obj-y) qemu-nbd$(EXESUF): qemu-nbd.o $(tools-obj-y) $(block-obj-y) @@ -172,35 +173,37 @@ qapi-dir := $(BUILD_DIR)/qapi-generated test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir) qemu-ga$(EXESUF): LIBS = $(LIBS_QGA) +gen-out-type = $(subst .,-,$@) + $(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") $(qapi-dir)/test-qapi-visit.c $(qapi-dir)/test-qapi-visit.h :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") $(qapi-dir)/test-qmp-commands.h $(qapi-dir)/test-qmp-marshal.c :\ $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, " GEN $@") $(qapi-dir)/qga-qapi-types.c $(qapi-dir)/qga-qapi-types.h :\ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-types.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") $(qapi-dir)/qga-qapi-visit.c $(qapi-dir)/qga-qapi-visit.h :\ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-visit.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") $(qapi-dir)/qga-qmp-commands.h $(qapi-dir)/qga-qmp-marshal.c :\ $(SRC_PATH)/qapi-schema-guest.json $(SRC_PATH)/scripts/qapi-commands.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "qga-" < $<, " GEN $@") qapi-types.c qapi-types.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-types.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py -o "." < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "." < $<, " GEN $@") qapi-visit.c qapi-visit.h :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-visit.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py -o "." < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "." < $<, " GEN $@") qmp-commands.h qmp-marshal.c :\ $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py - $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, " GEN $@") + $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -m -o "." < $<, " GEN $@") test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y) test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o diff --git a/Makefile.objs b/Makefile.objs index f753d838ff..8813673584 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -12,7 +12,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o ####################################################################### # coroutines -coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o +coroutine-obj-y = qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) coroutine-obj-$(CONFIG_POSIX) += coroutine-ucontext.o else diff --git a/arch_init.c b/arch_init.c index ceef26ef17..847bf4edd6 100644 --- a/arch_init.c +++ b/arch_init.c @@ -471,7 +471,7 @@ struct soundhw { int enabled; int isa; union { - int (*init_isa) (qemu_irq *pic); + int (*init_isa) (ISABus *bus); int (*init_pci) (PCIBus *bus); } init; }; @@ -626,15 +626,15 @@ void select_soundhw(const char *optarg) } } -void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus) +void audio_init(ISABus *isa_bus, PCIBus *pci_bus) { struct soundhw *c; for (c = soundhw; c->name; ++c) { if (c->enabled) { if (c->isa) { - if (isa_pic) { - c->init.init_isa(isa_pic); + if (isa_bus) { + c->init.init_isa(isa_bus); } } else { if (pci_bus) { @@ -648,7 +648,7 @@ void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus) void select_soundhw(const char *optarg) { } -void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus) +void audio_init(ISABus *isa_bus, PCIBus *pci_bus) { } #endif diff --git a/arch_init.h b/arch_init.h index a74187a57d..828256cc42 100644 --- a/arch_init.h +++ b/arch_init.h @@ -27,7 +27,7 @@ void do_acpitable_option(const char *optarg); void do_smbios_option(const char *optarg); void cpudef_init(void); int audio_available(void); -void audio_init(qemu_irq *isa_pic, PCIBus *pci_bus); +void audio_init(ISABus *isa_bus, PCIBus *pci_bus); int tcg_available(void); int kvm_available(void); int xen_available(void); diff --git a/block/nbd.c b/block/nbd.c index 95212dac64..161b299855 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -46,14 +46,25 @@ #define logout(fmt, ...) ((void)0) #endif +#define MAX_NBD_REQUESTS 16 +#define HANDLE_TO_INDEX(bs, handle) ((handle) ^ ((uint64_t)(intptr_t)bs)) +#define INDEX_TO_HANDLE(bs, index) ((index) ^ ((uint64_t)(intptr_t)bs)) + typedef struct BDRVNBDState { - CoMutex lock; int sock; uint32_t nbdflags; off_t size; size_t blocksize; char *export_name; /* An NBD server may export several devices */ + CoMutex send_mutex; + CoMutex free_sema; + Coroutine *send_coroutine; + int in_flight; + + Coroutine *recv_coroutine[MAX_NBD_REQUESTS]; + struct nbd_reply reply; + /* If it begins with '/', this is a UNIX domain socket. Otherwise, * it's a string of the form <hostname|ip4|\[ip6\]>:port */ @@ -106,6 +117,130 @@ out: return err; } +static void nbd_coroutine_start(BDRVNBDState *s, struct nbd_request *request) +{ + int i; + + /* Poor man semaphore. The free_sema is locked when no other request + * can be accepted, and unlocked after receiving one reply. */ + if (s->in_flight >= MAX_NBD_REQUESTS - 1) { + qemu_co_mutex_lock(&s->free_sema); + assert(s->in_flight < MAX_NBD_REQUESTS); + } + s->in_flight++; + + for (i = 0; i < MAX_NBD_REQUESTS; i++) { + if (s->recv_coroutine[i] == NULL) { + s->recv_coroutine[i] = qemu_coroutine_self(); + break; + } + } + + assert(i < MAX_NBD_REQUESTS); + request->handle = INDEX_TO_HANDLE(s, i); +} + +static int nbd_have_request(void *opaque) +{ + BDRVNBDState *s = opaque; + + return s->in_flight > 0; +} + +static void nbd_reply_ready(void *opaque) +{ + BDRVNBDState *s = opaque; + int i; + + if (s->reply.handle == 0) { + /* No reply already in flight. Fetch a header. */ + if (nbd_receive_reply(s->sock, &s->reply) < 0) { + s->reply.handle = 0; + goto fail; + } + } + + /* There's no need for a mutex on the receive side, because the + * 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 (s->recv_coroutine[i]) { + qemu_coroutine_enter(s->recv_coroutine[i], NULL); + return; + } + +fail: + for (i = 0; i < MAX_NBD_REQUESTS; i++) { + if (s->recv_coroutine[i]) { + qemu_coroutine_enter(s->recv_coroutine[i], NULL); + } + } +} + +static void nbd_restart_write(void *opaque) +{ + BDRVNBDState *s = opaque; + qemu_coroutine_enter(s->send_coroutine, NULL); +} + +static int nbd_co_send_request(BDRVNBDState *s, struct nbd_request *request, + struct iovec *iov, int offset) +{ + int rc, ret; + + 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); + rc = nbd_send_request(s->sock, request); + if (rc != -1 && iov) { + ret = qemu_co_sendv(s->sock, iov, request->len, offset); + if (ret != request->len) { + errno = -EIO; + rc = -1; + } + } + qemu_aio_set_fd_handler(s->sock, nbd_reply_ready, NULL, + nbd_have_request, NULL, s); + s->send_coroutine = NULL; + qemu_co_mutex_unlock(&s->send_mutex); + return rc; +} + +static void nbd_co_receive_reply(BDRVNBDState *s, struct nbd_request *request, + struct nbd_reply *reply, + struct iovec *iov, int offset) +{ + int ret; + + /* Wait until we're woken up by the read handler. TODO: perhaps + * peek at the next reply and avoid yielding if it's ours? */ + qemu_coroutine_yield(); + *reply = s->reply; + if (reply->handle != request->handle) { + reply->error = EIO; + } else { + if (iov && reply->error == 0) { + ret = qemu_co_recvv(s->sock, iov, request->len, offset); + if (ret != request->len) { + reply->error = EIO; + } + } + + /* Tell the read handler to read another header. */ + s->reply.handle = 0; + } +} + +static void nbd_coroutine_end(BDRVNBDState *s, struct nbd_request *request) +{ + int i = HANDLE_TO_INDEX(s, request->handle); + s->recv_coroutine[i] = NULL; + if (s->in_flight-- == MAX_NBD_REQUESTS) { + qemu_co_mutex_unlock(&s->free_sema); + } +} + static int nbd_establish_connection(BlockDriverState *bs) { BDRVNBDState *s = bs->opaque; @@ -135,8 +270,11 @@ static int nbd_establish_connection(BlockDriverState *bs) return -errno; } - /* Now that we're connected, set the socket to be non-blocking */ + /* 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); s->sock = sock; s->size = size; @@ -152,11 +290,11 @@ static void nbd_teardown_connection(BlockDriverState *bs) struct nbd_request request; request.type = NBD_CMD_DISC; - request.handle = (uint64_t)(intptr_t)bs; request.from = 0; request.len = 0; nbd_send_request(s->sock, &request); + qemu_aio_set_fd_handler(s->sock, NULL, NULL, NULL, NULL, NULL); closesocket(s->sock); } @@ -165,6 +303,9 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags) BDRVNBDState *s = bs->opaque; int result; + qemu_co_mutex_init(&s->send_mutex); + qemu_co_mutex_init(&s->free_sema); + /* Pop the config into our state object. Exit if invalid. */ result = nbd_config(s, filename, flags); if (result != 0) { @@ -176,90 +317,146 @@ static int nbd_open(BlockDriverState *bs, const char* filename, int flags) */ result = nbd_establish_connection(bs); - qemu_co_mutex_init(&s->lock); return result; } -static int nbd_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static int nbd_co_readv_1(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov, + int offset) { BDRVNBDState *s = bs->opaque; struct nbd_request request; struct nbd_reply reply; request.type = NBD_CMD_READ; - request.handle = (uint64_t)(intptr_t)bs; request.from = sector_num * 512; request.len = nb_sectors * 512; - if (nbd_send_request(s->sock, &request) == -1) - return -errno; - - if (nbd_receive_reply(s->sock, &reply) == -1) - return -errno; - - if (reply.error !=0) - return -reply.error; - - if (reply.handle != request.handle) - return -EIO; - - if (nbd_wr_sync(s->sock, buf, request.len, 1) != request.len) - return -EIO; + nbd_coroutine_start(s, &request); + if (nbd_co_send_request(s, &request, NULL, 0) == -1) { + reply.error = errno; + } else { + nbd_co_receive_reply(s, &request, &reply, qiov->iov, offset); + } + nbd_coroutine_end(s, &request); + return -reply.error; - return 0; } -static int nbd_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +static int nbd_co_writev_1(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov, + int offset) { BDRVNBDState *s = bs->opaque; struct nbd_request request; struct nbd_reply reply; request.type = NBD_CMD_WRITE; - request.handle = (uint64_t)(intptr_t)bs; + if (!bdrv_enable_write_cache(bs) && (s->nbdflags & NBD_FLAG_SEND_FUA)) { + request.type |= NBD_CMD_FLAG_FUA; + } + request.from = sector_num * 512; request.len = nb_sectors * 512; - if (nbd_send_request(s->sock, &request) == -1) - return -errno; - - if (nbd_wr_sync(s->sock, (uint8_t*)buf, request.len, 0) != request.len) - return -EIO; - - if (nbd_receive_reply(s->sock, &reply) == -1) - return -errno; - - if (reply.error !=0) - return -reply.error; + nbd_coroutine_start(s, &request); + if (nbd_co_send_request(s, &request, qiov->iov, offset) == -1) { + reply.error = errno; + } else { + nbd_co_receive_reply(s, &request, &reply, NULL, 0); + } + nbd_coroutine_end(s, &request); + return -reply.error; +} - if (reply.handle != request.handle) - return -EIO; +/* qemu-nbd has a limit of slightly less than 1M per request. Try to + * remain aligned to 4K. */ +#define NBD_MAX_SECTORS 2040 - return 0; +static int nbd_co_readv(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov) +{ + int offset = 0; + int ret; + while (nb_sectors > NBD_MAX_SECTORS) { + ret = nbd_co_readv_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset); + if (ret < 0) { + return ret; + } + offset += NBD_MAX_SECTORS * 512; + sector_num += NBD_MAX_SECTORS; + nb_sectors -= NBD_MAX_SECTORS; + } + return nbd_co_readv_1(bs, sector_num, nb_sectors, qiov, offset); } -static coroutine_fn int nbd_co_read(BlockDriverState *bs, int64_t sector_num, - uint8_t *buf, int nb_sectors) +static int nbd_co_writev(BlockDriverState *bs, int64_t sector_num, + int nb_sectors, QEMUIOVector *qiov) { + int offset = 0; int ret; + while (nb_sectors > NBD_MAX_SECTORS) { + ret = nbd_co_writev_1(bs, sector_num, NBD_MAX_SECTORS, qiov, offset); + if (ret < 0) { + return ret; + } + offset += NBD_MAX_SECTORS * 512; + sector_num += NBD_MAX_SECTORS; + nb_sectors -= NBD_MAX_SECTORS; + } + return nbd_co_writev_1(bs, sector_num, nb_sectors, qiov, offset); +} + +static int nbd_co_flush(BlockDriverState *bs) +{ BDRVNBDState *s = bs->opaque; - qemu_co_mutex_lock(&s->lock); - ret = nbd_read(bs, sector_num, buf, nb_sectors); - qemu_co_mutex_unlock(&s->lock); - return ret; + struct nbd_request request; + struct nbd_reply reply; + + if (!(s->nbdflags & NBD_FLAG_SEND_FLUSH)) { + return 0; + } + + request.type = NBD_CMD_FLUSH; + if (s->nbdflags & NBD_FLAG_SEND_FUA) { + request.type |= NBD_CMD_FLAG_FUA; + } + + request.from = 0; + request.len = 0; + + nbd_coroutine_start(s, &request); + if (nbd_co_send_request(s, &request, NULL, 0) == -1) { + reply.error = errno; + } else { + nbd_co_receive_reply(s, &request, &reply, NULL, 0); + } + nbd_coroutine_end(s, &request); + return -reply.error; } -static coroutine_fn int nbd_co_write(BlockDriverState *bs, int64_t sector_num, - const uint8_t *buf, int nb_sectors) +static int nbd_co_discard(BlockDriverState *bs, int64_t sector_num, + int nb_sectors) { - int ret; BDRVNBDState *s = bs->opaque; - qemu_co_mutex_lock(&s->lock); - ret = nbd_write(bs, sector_num, buf, nb_sectors); - qemu_co_mutex_unlock(&s->lock); - return ret; + struct nbd_request request; + struct nbd_reply reply; + + if (!(s->nbdflags & NBD_FLAG_SEND_TRIM)) { + return 0; + } + request.type = NBD_CMD_TRIM; + 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; + } else { + nbd_co_receive_reply(s, &request, &reply, NULL, 0); + } + nbd_coroutine_end(s, &request); + return -reply.error; } static void nbd_close(BlockDriverState *bs) @@ -279,14 +476,16 @@ static int64_t nbd_getlength(BlockDriverState *bs) } static BlockDriver bdrv_nbd = { - .format_name = "nbd", - .instance_size = sizeof(BDRVNBDState), - .bdrv_file_open = nbd_open, - .bdrv_read = nbd_co_read, - .bdrv_write = nbd_co_write, - .bdrv_close = nbd_close, - .bdrv_getlength = nbd_getlength, - .protocol_name = "nbd", + .format_name = "nbd", + .instance_size = sizeof(BDRVNBDState), + .bdrv_file_open = nbd_open, + .bdrv_co_readv = nbd_co_readv, + .bdrv_co_writev = nbd_co_writev, + .bdrv_close = nbd_close, + .bdrv_co_flush_to_os = nbd_co_flush, + .bdrv_co_discard = nbd_co_discard, + .bdrv_getlength = nbd_getlength, + .protocol_name = "nbd", }; static void bdrv_nbd_init(void) diff --git a/block/sheepdog.c b/block/sheepdog.c index aa9707f2ae..17a79beb24 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -443,129 +443,6 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov, return acb; } -#ifdef _WIN32 - -struct msghdr { - struct iovec *msg_iov; - size_t msg_iovlen; -}; - -static ssize_t sendmsg(int s, const struct msghdr *msg, int flags) -{ - size_t size = 0; - char *buf, *p; - int i, ret; - - /* count the msg size */ - for (i = 0; i < msg->msg_iovlen; i++) { - size += msg->msg_iov[i].iov_len; - } - buf = g_malloc(size); - - p = buf; - for (i = 0; i < msg->msg_iovlen; i++) { - memcpy(p, msg->msg_iov[i].iov_base, msg->msg_iov[i].iov_len); - p += msg->msg_iov[i].iov_len; - } - - ret = send(s, buf, size, flags); - - g_free(buf); - return ret; -} - -static ssize_t recvmsg(int s, struct msghdr *msg, int flags) -{ - size_t size = 0; - char *buf, *p; - int i, ret; - - /* count the msg size */ - for (i = 0; i < msg->msg_iovlen; i++) { - size += msg->msg_iov[i].iov_len; - } - buf = g_malloc(size); - - ret = qemu_recv(s, buf, size, flags); - if (ret < 0) { - goto out; - } - - p = buf; - for (i = 0; i < msg->msg_iovlen; i++) { - memcpy(msg->msg_iov[i].iov_base, p, msg->msg_iov[i].iov_len); - p += msg->msg_iov[i].iov_len; - } -out: - g_free(buf); - return ret; -} - -#endif - -/* - * Send/recv data with iovec buffers - * - * This function send/recv data from/to the iovec buffer directly. - * The first `offset' bytes in the iovec buffer are skipped and next - * `len' bytes are used. - * - * For example, - * - * do_send_recv(sockfd, iov, len, offset, 1); - * - * is equals to - * - * char *buf = malloc(size); - * iov_to_buf(iov, iovcnt, buf, offset, size); - * send(sockfd, buf, size, 0); - * free(buf); - */ -static int do_send_recv(int sockfd, struct iovec *iov, int len, int offset, - int write) -{ - struct msghdr msg; - int ret, diff; - - memset(&msg, 0, sizeof(msg)); - msg.msg_iov = iov; - msg.msg_iovlen = 1; - - len += offset; - - while (iov->iov_len < len) { - len -= iov->iov_len; - - iov++; - msg.msg_iovlen++; - } - - diff = iov->iov_len - len; - iov->iov_len -= diff; - - while (msg.msg_iov->iov_len <= offset) { - offset -= msg.msg_iov->iov_len; - - msg.msg_iov++; - msg.msg_iovlen--; - } - - msg.msg_iov->iov_base = (char *) msg.msg_iov->iov_base + offset; - msg.msg_iov->iov_len -= offset; - - if (write) { - ret = sendmsg(sockfd, &msg, 0); - } else { - ret = recvmsg(sockfd, &msg, 0); - } - - msg.msg_iov->iov_base = (char *) msg.msg_iov->iov_base - offset; - msg.msg_iov->iov_len += offset; - - iov->iov_len += diff; - return ret; -} - static int connect_to_sdog(const char *addr, const char *port) { char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; @@ -618,83 +495,19 @@ success: return fd; } -static int do_readv_writev(int sockfd, struct iovec *iov, int len, - int iov_offset, int write) -{ - int ret; -again: - ret = do_send_recv(sockfd, iov, len, iov_offset, write); - if (ret < 0) { - if (errno == EINTR) { - goto again; - } - if (errno == EAGAIN) { - if (qemu_in_coroutine()) { - qemu_coroutine_yield(); - } - goto again; - } - error_report("failed to recv a rsp, %s", strerror(errno)); - return 1; - } - - iov_offset += ret; - len -= ret; - if (len) { - goto again; - } - - return 0; -} - -static int do_readv(int sockfd, struct iovec *iov, int len, int iov_offset) -{ - return do_readv_writev(sockfd, iov, len, iov_offset, 0); -} - -static int do_writev(int sockfd, struct iovec *iov, int len, int iov_offset) -{ - return do_readv_writev(sockfd, iov, len, iov_offset, 1); -} - -static int do_read_write(int sockfd, void *buf, int len, int write) -{ - struct iovec iov; - - iov.iov_base = buf; - iov.iov_len = len; - - return do_readv_writev(sockfd, &iov, len, 0, write); -} - -static int do_read(int sockfd, void *buf, int len) -{ - return do_read_write(sockfd, buf, len, 0); -} - -static int do_write(int sockfd, void *buf, int len) -{ - return do_read_write(sockfd, buf, len, 1); -} - static int send_req(int sockfd, SheepdogReq *hdr, void *data, unsigned int *wlen) { int ret; - struct iovec iov[2]; - iov[0].iov_base = hdr; - iov[0].iov_len = sizeof(*hdr); - - if (*wlen) { - iov[1].iov_base = data; - iov[1].iov_len = *wlen; + ret = qemu_send_full(sockfd, hdr, sizeof(*hdr), 0); + if (ret < sizeof(*hdr)) { + error_report("failed to send a req, %s", strerror(errno)); } - ret = do_writev(sockfd, iov, sizeof(*hdr) + *wlen, 0); - if (ret) { + ret = qemu_send_full(sockfd, data, *wlen, 0); + if (ret < *wlen) { error_report("failed to send a req, %s", strerror(errno)); - ret = -1; } return ret; @@ -705,16 +518,15 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, { int ret; + socket_set_block(sockfd); ret = send_req(sockfd, hdr, data, wlen); - if (ret) { - ret = -1; + if (ret < 0) { goto out; } - ret = do_read(sockfd, hdr, sizeof(*hdr)); - if (ret) { + ret = qemu_recv_full(sockfd, hdr, sizeof(*hdr), 0); + if (ret < sizeof(*hdr)) { error_report("failed to get a rsp, %s", strerror(errno)); - ret = -1; goto out; } @@ -723,15 +535,15 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data, } if (*rlen) { - ret = do_read(sockfd, data, *rlen); - if (ret) { + ret = qemu_recv_full(sockfd, data, *rlen, 0); + if (ret < *rlen) { error_report("failed to get the data, %s", strerror(errno)); - ret = -1; goto out; } } ret = 0; out: + socket_set_nonblock(sockfd); return ret; } @@ -793,8 +605,8 @@ static void coroutine_fn aio_read_response(void *opaque) } /* read a header */ - ret = do_read(fd, &rsp, sizeof(rsp)); - if (ret) { + ret = qemu_co_recv(fd, &rsp, sizeof(rsp)); + if (ret < 0) { error_report("failed to get the header, %s", strerror(errno)); goto out; } @@ -839,9 +651,9 @@ static void coroutine_fn aio_read_response(void *opaque) } break; case AIOCB_READ_UDATA: - ret = do_readv(fd, acb->qiov->iov, rsp.data_length, - aio_req->iov_offset); - if (ret) { + ret = qemu_co_recvv(fd, acb->qiov->iov, rsp.data_length, + aio_req->iov_offset); + if (ret < 0) { error_report("failed to get the data, %s", strerror(errno)); goto out; } @@ -890,22 +702,6 @@ static int aio_flush_request(void *opaque) return !QLIST_EMPTY(&s->outstanding_aio_head); } -#if !defined(SOL_TCP) || !defined(TCP_CORK) - -static int set_cork(int fd, int v) -{ - return 0; -} - -#else - -static int set_cork(int fd, int v) -{ - return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v)); -} - -#endif - static int set_nodelay(int fd) { int ret, opt; @@ -1111,26 +907,26 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req, s->co_send = qemu_coroutine_self(); qemu_aio_set_fd_handler(s->fd, co_read_response, co_write_request, aio_flush_request, NULL, s); - set_cork(s->fd, 1); + socket_set_cork(s->fd, 1); /* send a header */ - ret = do_write(s->fd, &hdr, sizeof(hdr)); - if (ret) { + ret = qemu_co_send(s->fd, &hdr, sizeof(hdr)); + if (ret < 0) { qemu_co_mutex_unlock(&s->lock); error_report("failed to send a req, %s", strerror(errno)); return -EIO; } if (wlen) { - ret = do_writev(s->fd, iov, wlen, aio_req->iov_offset); - if (ret) { + ret = qemu_co_sendv(s->fd, iov, wlen, aio_req->iov_offset); + if (ret < 0) { qemu_co_mutex_unlock(&s->lock); error_report("failed to send a data, %s", strerror(errno)); return -EIO; } } - set_cork(s->fd, 0); + socket_set_cork(s->fd, 0); qemu_aio_set_fd_handler(s->fd, co_read_response, NULL, aio_flush_request, NULL, s); qemu_co_mutex_unlock(&s->lock); diff --git a/coroutine-gthread.c b/coroutine-gthread.c index fdea27a106..662801b2fa 100644 --- a/coroutine-gthread.c +++ b/coroutine-gthread.c @@ -36,7 +36,12 @@ static GStaticPrivate coroutine_key = G_STATIC_PRIVATE_INIT; static void __attribute__((constructor)) coroutine_init(void) { if (!g_thread_supported()) { +#if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); +#else + fprintf(stderr, "glib threading failed to initialize.\n"); + exit(1); +#endif } coroutine_cond = g_cond_new(); @@ -25,6 +25,8 @@ #include "host-utils.h" #include <math.h> +#include "qemu_socket.h" + void pstrcpy(char *buf, int buf_size, const char *str) { int c; @@ -403,3 +405,112 @@ int qemu_parse_fd(const char *param) } return fd; } + +/* + * Send/recv data with iovec buffers + * + * This function send/recv data from/to the iovec buffer directly. + * The first `offset' bytes in the iovec buffer are skipped and next + * `len' bytes are used. + * + * For example, + * + * do_sendv_recvv(sockfd, iov, len, offset, 1); + * + * is equal to + * + * char *buf = malloc(size); + * iov_to_buf(iov, iovcnt, buf, offset, size); + * send(sockfd, buf, size, 0); + * free(buf); + */ +static int do_sendv_recvv(int sockfd, struct iovec *iov, int len, int offset, + int do_sendv) +{ + int ret, diff, iovlen; + struct iovec *last_iov; + + /* last_iov is inclusive, so count from one. */ + iovlen = 1; + last_iov = iov; + len += offset; + + while (last_iov->iov_len < len) { + len -= last_iov->iov_len; + + last_iov++; + iovlen++; + } + + diff = last_iov->iov_len - len; + last_iov->iov_len -= diff; + + while (iov->iov_len <= offset) { + offset -= iov->iov_len; + + iov++; + iovlen--; + } + + iov->iov_base = (char *) iov->iov_base + offset; + iov->iov_len -= offset; + + { +#if defined CONFIG_IOVEC && defined CONFIG_POSIX + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = iov; + msg.msg_iovlen = iovlen; + + do { + if (do_sendv) { + ret = sendmsg(sockfd, &msg, 0); + } else { + ret = recvmsg(sockfd, &msg, 0); + } + } while (ret == -1 && errno == EINTR); +#else + struct iovec *p = iov; + ret = 0; + while (iovlen > 0) { + int rc; + if (do_sendv) { + rc = send(sockfd, p->iov_base, p->iov_len, 0); + } else { + rc = qemu_recv(sockfd, p->iov_base, p->iov_len, 0); + } + if (rc == -1) { + if (errno == EINTR) { + continue; + } + if (ret == 0) { + ret = -1; + } + break; + } + if (rc == 0) { + break; + } + ret += rc; + iovlen--, p++; + } +#endif + } + + /* Undo the changes above */ + iov->iov_base = (char *) iov->iov_base - offset; + iov->iov_len += offset; + last_iov->iov_len += diff; + return ret; +} + +int qemu_recvv(int sockfd, struct iovec *iov, int len, int iov_offset) +{ + return do_sendv_recvv(sockfd, iov, len, iov_offset, 0); +} + +int qemu_sendv(int sockfd, struct iovec *iov, int len, int iov_offset) +{ + return do_sendv_recvv(sockfd, iov, len, iov_offset, 1); +} + diff --git a/fsdev/file-op-9p.h b/fsdev/file-op-9p.h index a85ecd30b0..c823fe0aee 100644 --- a/fsdev/file-op-9p.h +++ b/fsdev/file-op-9p.h @@ -74,7 +74,7 @@ typedef struct FsContext } FsContext; typedef struct V9fsPath { - int16_t size; + uint16_t size; char *data; } V9fsPath; diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index 36a862f1f1..df0a8e731b 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -674,40 +674,6 @@ static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src, offset, size, 1); } -static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg) -{ - size_t pos = 0; - int i, j; - struct iovec *src_sg; - unsigned int num; - - if (rx) { - src_sg = pdu->elem.in_sg; - num = pdu->elem.in_num; - } else { - src_sg = pdu->elem.out_sg; - num = pdu->elem.out_num; - } - - j = 0; - for (i = 0; i < num; i++) { - if (offset <= pos) { - sg[j].iov_base = src_sg[i].iov_base; - sg[j].iov_len = src_sg[i].iov_len; - j++; - } else if (offset < (src_sg[i].iov_len + pos)) { - sg[j].iov_base = src_sg[i].iov_base; - sg[j].iov_len = src_sg[i].iov_len; - sg[j].iov_base += (offset - pos); - sg[j].iov_len -= (offset - pos); - j++; - } - pos += src_sg[i].iov_len; - } - - return j; -} - static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) { size_t old_offset = offset; @@ -743,12 +709,6 @@ static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) *valp = le64_to_cpu(val); break; } - case 'v': { - struct iovec *iov = va_arg(ap, struct iovec *); - int *iovcnt = va_arg(ap, int *); - *iovcnt = pdu_copy_sg(pdu, offset, 0, iov); - break; - } case 's': { V9fsString *str = va_arg(ap, V9fsString *); offset += pdu_unmarshal(pdu, offset, "w", &str->size); @@ -827,12 +787,6 @@ static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) offset += pdu_pack(pdu, offset, &val, sizeof(val)); break; } - case 'v': { - struct iovec *iov = va_arg(ap, struct iovec *); - int *iovcnt = va_arg(ap, int *); - *iovcnt = pdu_copy_sg(pdu, offset, 1, iov); - break; - } case 's': { V9fsString *str = va_arg(ap, V9fsString *); offset += pdu_marshal(pdu, offset, "w", str->size); @@ -1143,42 +1097,6 @@ static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf, stat_to_qid(stbuf, &v9lstat->qid); } -static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt) -{ - while (len && *iovcnt) { - if (len < sg->iov_len) { - sg->iov_len -= len; - sg->iov_base += len; - len = 0; - } else { - len -= sg->iov_len; - sg++; - *iovcnt -= 1; - } - } - - return sg; -} - -static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt) -{ - int i; - int total = 0; - - for (i = 0; i < *cnt; i++) { - if ((total + sg[i].iov_len) > cap) { - sg[i].iov_len -= ((total + sg[i].iov_len) - cap); - i++; - break; - } - total += sg[i].iov_len; - } - - *cnt = i; - - return sg; -} - static void print_sg(struct iovec *sg, int cnt) { int i; @@ -1375,17 +1293,18 @@ out_nofid: complete_pdu(s, pdu, retval); } -/* From Linux kernel code */ -#define ATTR_MODE (1 << 0) -#define ATTR_UID (1 << 1) -#define ATTR_GID (1 << 2) -#define ATTR_SIZE (1 << 3) -#define ATTR_ATIME (1 << 4) -#define ATTR_MTIME (1 << 5) -#define ATTR_CTIME (1 << 6) -#define ATTR_MASK 127 -#define ATTR_ATIME_SET (1 << 7) -#define ATTR_MTIME_SET (1 << 8) +/* Attribute flags */ +#define P9_ATTR_MODE (1 << 0) +#define P9_ATTR_UID (1 << 1) +#define P9_ATTR_GID (1 << 2) +#define P9_ATTR_SIZE (1 << 3) +#define P9_ATTR_ATIME (1 << 4) +#define P9_ATTR_MTIME (1 << 5) +#define P9_ATTR_CTIME (1 << 6) +#define P9_ATTR_ATIME_SET (1 << 7) +#define P9_ATTR_MTIME_SET (1 << 8) + +#define P9_ATTR_MASK 127 static void v9fs_setattr(void *opaque) { @@ -1404,16 +1323,16 @@ static void v9fs_setattr(void *opaque) err = -EINVAL; goto out_nofid; } - if (v9iattr.valid & ATTR_MODE) { + if (v9iattr.valid & P9_ATTR_MODE) { err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode); if (err < 0) { goto out; } } - if (v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) { + if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) { struct timespec times[2]; - if (v9iattr.valid & ATTR_ATIME) { - if (v9iattr.valid & ATTR_ATIME_SET) { + if (v9iattr.valid & P9_ATTR_ATIME) { + if (v9iattr.valid & P9_ATTR_ATIME_SET) { times[0].tv_sec = v9iattr.atime_sec; times[0].tv_nsec = v9iattr.atime_nsec; } else { @@ -1422,8 +1341,8 @@ static void v9fs_setattr(void *opaque) } else { times[0].tv_nsec = UTIME_OMIT; } - if (v9iattr.valid & ATTR_MTIME) { - if (v9iattr.valid & ATTR_MTIME_SET) { + if (v9iattr.valid & P9_ATTR_MTIME) { + if (v9iattr.valid & P9_ATTR_MTIME_SET) { times[1].tv_sec = v9iattr.mtime_sec; times[1].tv_nsec = v9iattr.mtime_nsec; } else { @@ -1441,13 +1360,13 @@ static void v9fs_setattr(void *opaque) * If the only valid entry in iattr is ctime we can call * chown(-1,-1) to update the ctime of the file */ - if ((v9iattr.valid & (ATTR_UID | ATTR_GID)) || - ((v9iattr.valid & ATTR_CTIME) - && !((v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) { - if (!(v9iattr.valid & ATTR_UID)) { + if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) || + ((v9iattr.valid & P9_ATTR_CTIME) + && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) { + if (!(v9iattr.valid & P9_ATTR_UID)) { v9iattr.uid = -1; } - if (!(v9iattr.valid & ATTR_GID)) { + if (!(v9iattr.valid & P9_ATTR_GID)) { v9iattr.gid = -1; } err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid, @@ -1456,7 +1375,7 @@ static void v9fs_setattr(void *opaque) goto out; } } - if (v9iattr.valid & (ATTR_SIZE)) { + if (v9iattr.valid & (P9_ATTR_SIZE)) { err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size); if (err < 0) { goto out; @@ -1776,8 +1695,8 @@ out_nofid: complete_pdu(s, pdu, err); } -static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, - V9fsFidState *fidp, int64_t off, int32_t max_count) +static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, + uint64_t off, uint32_t max_count) { size_t offset = 7; int read_count; @@ -1801,7 +1720,7 @@ static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, } static int v9fs_do_readdir_with_stat(V9fsPDU *pdu, - V9fsFidState *fidp, int32_t max_count) + V9fsFidState *fidp, uint32_t max_count) { V9fsPath path; V9fsStat v9stat; @@ -1861,14 +1780,46 @@ out: return count; } +/* + * Create a QEMUIOVector for a sub-region of PDU iovecs + * + * @qiov: uninitialized QEMUIOVector + * @skip: number of bytes to skip from beginning of PDU + * @size: number of bytes to include + * @is_write: true - write, false - read + * + * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up + * with qemu_iovec_destroy(). + */ +static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, + uint64_t skip, size_t size, + bool is_write) +{ + QEMUIOVector elem; + struct iovec *iov; + unsigned int niov; + + if (is_write) { + iov = pdu->elem.out_sg; + niov = pdu->elem.out_num; + } else { + iov = pdu->elem.in_sg; + niov = pdu->elem.in_num; + } + + qemu_iovec_init_external(&elem, iov, niov); + qemu_iovec_init(qiov, niov); + qemu_iovec_copy(qiov, &elem, skip, size); +} + static void v9fs_read(void *opaque) { int32_t fid; - int64_t off; + uint64_t off; ssize_t err = 0; int32_t count = 0; size_t offset = 7; - int32_t max_count; + uint32_t max_count; V9fsFidState *fidp; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; @@ -1895,21 +1846,21 @@ static void v9fs_read(void *opaque) err += pdu_marshal(pdu, offset, "d", count); err += count; } else if (fidp->fid_type == P9_FID_FILE) { - int32_t cnt; + QEMUIOVector qiov_full; + QEMUIOVector qiov; int32_t len; - struct iovec *sg; - struct iovec iov[128]; /* FIXME: bad, bad, bad */ - sg = iov; - pdu_marshal(pdu, offset + 4, "v", sg, &cnt); - sg = cap_sg(sg, max_count, &cnt); + v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false); + qemu_iovec_init(&qiov, qiov_full.niov); do { + qemu_iovec_reset(&qiov); + qemu_iovec_copy(&qiov, &qiov_full, count, qiov_full.size - count); if (0) { - print_sg(sg, cnt); + print_sg(qiov.iov, qiov.niov); } /* Loop in case of EINTR */ do { - len = v9fs_co_preadv(pdu, fidp, sg, cnt, off); + len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off); if (len >= 0) { off += len; count += len; @@ -1920,11 +1871,12 @@ static void v9fs_read(void *opaque) err = len; goto out; } - sg = adjust_sg(sg, len, &cnt); } while (count < max_count && len > 0); err = offset; err += pdu_marshal(pdu, offset, "d", count); err += count; + qemu_iovec_destroy(&qiov); + qemu_iovec_destroy(&qiov_full); } else if (fidp->fid_type == P9_FID_XATTR) { err = v9fs_xattr_read(s, pdu, fidp, off, max_count); } else { @@ -2011,8 +1963,9 @@ static void v9fs_readdir(void *opaque) V9fsFidState *fidp; ssize_t retval = 0; size_t offset = 7; - int64_t initial_offset; - int32_t count, max_count; + uint64_t initial_offset; + int32_t count; + uint32_t max_count; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; @@ -2050,7 +2003,7 @@ out_nofid: } static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, - int64_t off, int32_t count, + uint64_t off, uint32_t count, struct iovec *sg, int cnt) { int i, to_copy; @@ -2095,22 +2048,22 @@ out: static void v9fs_write(void *opaque) { - int cnt; ssize_t err; int32_t fid; - int64_t off; - int32_t count; + uint64_t off; + uint32_t count; int32_t len = 0; int32_t total = 0; size_t offset = 7; V9fsFidState *fidp; - struct iovec iov[128]; /* FIXME: bad, bad, bad */ - struct iovec *sg = iov; V9fsPDU *pdu = opaque; V9fsState *s = pdu->s; + QEMUIOVector qiov_full; + QEMUIOVector qiov; - pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt); - trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt); + offset += pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count); + v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true); + trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2126,20 +2079,23 @@ static void v9fs_write(void *opaque) /* * setxattr operation */ - err = v9fs_xattr_write(s, pdu, fidp, off, count, sg, cnt); + err = v9fs_xattr_write(s, pdu, fidp, off, count, + qiov_full.iov, qiov_full.niov); goto out; } else { err = -EINVAL; goto out; } - sg = cap_sg(sg, count, &cnt); + qemu_iovec_init(&qiov, qiov_full.niov); do { + qemu_iovec_reset(&qiov); + qemu_iovec_copy(&qiov, &qiov_full, total, qiov_full.size - total); if (0) { - print_sg(sg, cnt); + print_sg(qiov.iov, qiov.niov); } /* Loop in case of EINTR */ do { - len = v9fs_co_pwritev(pdu, fidp, sg, cnt, off); + len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off); if (len >= 0) { off += len; total += len; @@ -2148,16 +2104,20 @@ static void v9fs_write(void *opaque) if (len < 0) { /* IO error return the error */ err = len; - goto out; + goto out_qiov; } - sg = adjust_sg(sg, len, &cnt); } while (total < count && len > 0); + + offset = 7; offset += pdu_marshal(pdu, offset, "d", total); err = offset; trace_v9fs_write_return(pdu->tag, pdu->id, total, err); +out_qiov: + qemu_iovec_destroy(&qiov); out: put_fid(pdu, fidp); out_nofid: + qemu_iovec_destroy(&qiov_full); complete_pdu(s, pdu, err); } diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 8b612da529..19a797b727 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -156,7 +156,7 @@ typedef struct V9fsFidState V9fsFidState; typedef struct V9fsString { - int16_t size; + uint16_t size; char *data; } V9fsString; diff --git a/hw/adlib.c b/hw/adlib.c index e4bfcc6420..dd8b1888cf 100644 --- a/hw/adlib.c +++ b/hw/adlib.c @@ -275,7 +275,7 @@ static void Adlib_fini (AdlibState *s) AUD_remove_card (&s->card); } -int Adlib_init (qemu_irq *pic) +int Adlib_init (ISABus *bus) { AdlibState *s = &glob_adlib; struct audsettings as; diff --git a/hw/alpha_dp264.c b/hw/alpha_dp264.c index 598b830e92..876335a773 100644 --- a/hw/alpha_dp264.c +++ b/hw/alpha_dp264.c @@ -50,6 +50,7 @@ static void clipper_init(ram_addr_t ram_size, { CPUState *cpus[4]; PCIBus *pci_bus; + ISABus *isa_bus; qemu_irq rtc_irq; long size, i; const char *palcode_filename; @@ -67,11 +68,12 @@ static void clipper_init(ram_addr_t ram_size, cpus[0]->trap_arg2 = smp_cpus; /* Init the chipset. */ - pci_bus = typhoon_init(ram_size, &rtc_irq, cpus, clipper_pci_map_irq); + pci_bus = typhoon_init(ram_size, &isa_bus, &rtc_irq, cpus, + clipper_pci_map_irq); - rtc_init(1980, rtc_irq); - pit_init(0x40, 0); - isa_create_simple("i8042"); + rtc_init(isa_bus, 1980, rtc_irq); + pit_init(isa_bus, 0x40, 0); + isa_create_simple(isa_bus, "i8042"); /* VGA setup. Don't bother loading the bios. */ alpha_pci_vga_setup(pci_bus); @@ -79,7 +81,7 @@ static void clipper_init(ram_addr_t ram_size, /* Serial code setup. */ for (i = 0; i < MAX_SERIAL_PORTS; ++i) { if (serial_hds[i]) { - serial_isa_init(i, serial_hds[i]); + serial_isa_init(isa_bus, i, serial_hds[i]); } } diff --git a/hw/alpha_sys.h b/hw/alpha_sys.h index 13f017733b..d54b18f8ed 100644 --- a/hw/alpha_sys.h +++ b/hw/alpha_sys.h @@ -12,7 +12,8 @@ #include "irq.h" -PCIBus *typhoon_init(ram_addr_t, qemu_irq *, CPUState *[4], pci_map_irq_fn); +PCIBus *typhoon_init(ram_addr_t, ISABus **, qemu_irq *, CPUState *[4], + pci_map_irq_fn); /* alpha_pci.c. */ extern const MemoryRegionOps alpha_pci_bw_io_ops; diff --git a/hw/alpha_typhoon.c b/hw/alpha_typhoon.c index c7608bbabd..adf738272e 100644 --- a/hw/alpha_typhoon.c +++ b/hw/alpha_typhoon.c @@ -691,7 +691,8 @@ static void typhoon_alarm_timer(void *opaque) cpu_interrupt(s->cchip.cpu[cpu], CPU_INTERRUPT_TIMER); } -PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq, +PCIBus *typhoon_init(ram_addr_t ram_size, ISABus **isa_bus, + qemu_irq *p_rtc_irq, CPUState *cpus[4], pci_map_irq_fn sys_map_irq) { const uint64_t MB = 1024 * 1024; @@ -792,10 +793,10 @@ PCIBus *typhoon_init(ram_addr_t ram_size, qemu_irq *p_rtc_irq, { qemu_irq isa_pci_irq, *isa_irqs; - isa_bus_new(NULL, addr_space_io); + *isa_bus = isa_bus_new(NULL, addr_space_io); isa_pci_irq = *qemu_allocate_irqs(typhoon_set_isa_irq, s, 1); - isa_irqs = i8259_init(isa_pci_irq); - isa_bus_irqs(isa_irqs); + isa_irqs = i8259_init(*isa_bus, isa_pci_irq); + isa_bus_irqs(*isa_bus, isa_irqs); } return b; diff --git a/hw/audiodev.h b/hw/audiodev.h index d60c3498ee..ed2790f5f6 100644 --- a/hw/audiodev.h +++ b/hw/audiodev.h @@ -2,19 +2,19 @@ int es1370_init(PCIBus *bus); /* sb16.c */ -int SB16_init(qemu_irq *pic); +int SB16_init(ISABus *bus); /* adlib.c */ -int Adlib_init(qemu_irq *pic); +int Adlib_init(ISABus *bus); /* gus.c */ -int GUS_init(qemu_irq *pic); +int GUS_init(ISABus *bus); /* ac97.c */ int ac97_init(PCIBus *bus); /* cs4231a.c */ -int cs4231a_init(qemu_irq *pic); +int cs4231a_init(ISABus *bus); /* intel-hda.c + hda-audio.c */ int intel_hda_and_codec_init(PCIBus *bus); diff --git a/hw/cs4231a.c b/hw/cs4231a.c index a7e03a313c..dc77a3aa15 100644 --- a/hw/cs4231a.c +++ b/hw/cs4231a.c @@ -659,9 +659,9 @@ static int cs4231a_initfn (ISADevice *dev) return 0; } -int cs4231a_init (qemu_irq *pic) +int cs4231a_init (ISABus *bus) { - isa_create_simple ("cs4231a"); + isa_create_simple (bus, "cs4231a"); return 0; } @@ -7,11 +7,11 @@ /* fdc.c */ #define MAX_FD 2 -static inline ISADevice *fdctrl_init_isa(DriveInfo **fds) +static inline ISADevice *fdctrl_init_isa(ISABus *bus, DriveInfo **fds) { ISADevice *dev; - dev = isa_try_create("isa-fdc"); + dev = isa_try_create(bus, "isa-fdc"); if (!dev) { return NULL; } @@ -293,9 +293,9 @@ static int gus_initfn (ISADevice *dev) return 0; } -int GUS_init (qemu_irq *pic) +int GUS_init (ISABus *bus) { - isa_create_simple ("gus"); + isa_create_simple (bus, "gus"); return 0; } diff --git a/hw/i8254.c b/hw/i8254.c index 12571efc2a..cf9ed2ff25 100644 --- a/hw/i8254.c +++ b/hw/i8254.c @@ -525,7 +525,7 @@ static int pit_initfn(ISADevice *dev) s = &pit->channels[0]; /* the timer 0 is connected to an IRQ */ s->irq_timer = qemu_new_timer_ns(vm_clock, pit_irq_timer, s); - s->irq = isa_get_irq(pit->irq); + s->irq = isa_get_irq(dev, pit->irq); memory_region_init_io(&pit->ioports, &pit_ioport_ops, pit, "pit", 4); isa_register_ioport(dev, &pit->ioports, pit->iobase); diff --git a/hw/i8259.c b/hw/i8259.c index ab519de5d8..7331e0e61c 100644 --- a/hw/i8259.c +++ b/hw/i8259.c @@ -469,9 +469,9 @@ static int pic_initfn(ISADevice *dev) memory_region_init_io(&s->base_io, &pic_base_ioport_ops, s, "pic", 2); memory_region_init_io(&s->elcr_io, &pic_elcr_ioport_ops, s, "elcr", 1); - isa_register_ioport(NULL, &s->base_io, s->iobase); + isa_register_ioport(dev, &s->base_io, s->iobase); if (s->elcr_addr != -1) { - isa_register_ioport(NULL, &s->elcr_io, s->elcr_addr); + isa_register_ioport(dev, &s->elcr_io, s->elcr_addr); } qdev_init_gpio_out(&dev->qdev, s->int_out, ARRAY_SIZE(s->int_out)); @@ -518,7 +518,7 @@ void irq_info(Monitor *mon) #endif } -qemu_irq *i8259_init(qemu_irq parent_irq) +qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq) { qemu_irq *irq_set; ISADevice *dev; @@ -526,7 +526,7 @@ qemu_irq *i8259_init(qemu_irq parent_irq) irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq)); - dev = isa_create("isa-i8259"); + dev = isa_create(bus, "isa-i8259"); qdev_prop_set_uint32(&dev->qdev, "iobase", 0x20); qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d0); qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xf8); @@ -540,7 +540,7 @@ qemu_irq *i8259_init(qemu_irq parent_irq) isa_pic = DO_UPCAST(PicState, dev, dev); - dev = isa_create("isa-i8259"); + dev = isa_create(bus, "isa-i8259"); qdev_prop_set_uint32(&dev->qdev, "iobase", 0xa0); qdev_prop_set_uint32(&dev->qdev, "elcr_addr", 0x4d1); qdev_prop_set_uint8(&dev->qdev, "elcr_mask", 0xde); @@ -8,7 +8,7 @@ #define MAX_IDE_DEVS 2 /* ide-isa.c */ -ISADevice *isa_ide_init(int iobase, int iobase2, int isairq, +ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, DriveInfo *hd0, DriveInfo *hd1); /* ide-pci.c */ diff --git a/hw/ide/isa.c b/hw/ide/isa.c index 01a9e59cb9..219f3a4c6b 100644 --- a/hw/ide/isa.c +++ b/hw/ide/isa.c @@ -73,13 +73,13 @@ static int isa_ide_initfn(ISADevice *dev) return 0; }; -ISADevice *isa_ide_init(int iobase, int iobase2, int isairq, +ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq, DriveInfo *hd0, DriveInfo *hd1) { ISADevice *dev; ISAIDEState *s; - dev = isa_create("isa-ide"); + dev = isa_create(bus, "isa-ide"); qdev_prop_set_uint32(&dev->qdev, "iobase", iobase); qdev_prop_set_uint32(&dev->qdev, "iobase2", iobase2); qdev_prop_set_uint32(&dev->qdev, "irq", isairq); diff --git a/hw/ide/piix.c b/hw/ide/piix.c index 08cbbe2032..34733454ea 100644 --- a/hw/ide/piix.c +++ b/hw/ide/piix.c @@ -136,7 +136,7 @@ static void pci_piix_init_ports(PCIIDEState *d) { ide_bus_new(&d->bus[i], &d->dev.qdev, i); ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase, port_info[i].iobase2); - ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq)); + ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq)); bmdma_init(&d->bus[i], &d->bmdma[i], d); d->bmdma[i].bus = &d->bus[i]; diff --git a/hw/ide/via.c b/hw/ide/via.c index a57134c12a..4ea2064498 100644 --- a/hw/ide/via.c +++ b/hw/ide/via.c @@ -160,7 +160,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) { ide_bus_new(&d->bus[i], &d->dev.qdev, i); ide_init_ioport(&d->bus[i], NULL, port_info[i].iobase, port_info[i].iobase2); - ide_init2(&d->bus[i], isa_get_irq(port_info[i].isairq)); + ide_init2(&d->bus[i], isa_get_irq(NULL, port_info[i].isairq)); bmdma_init(&d->bus[i], &d->bmdma[i], d); d->bmdma[i].bus = &d->bus[i]; diff --git a/hw/isa-bus.c b/hw/isa-bus.c index 7c2c2619d0..5af790bf81 100644 --- a/hw/isa-bus.c +++ b/hw/isa-bus.c @@ -22,11 +22,6 @@ #include "isa.h" #include "exec-memory.h" -struct ISABus { - BusState qbus; - MemoryRegion *address_space_io; - qemu_irq *irqs; -}; static ISABus *isabus; target_phys_addr_t isa_mem_base = 0; @@ -56,9 +51,12 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io) return isabus; } -void isa_bus_irqs(qemu_irq *irqs) +void isa_bus_irqs(ISABus *bus, qemu_irq *irqs) { - isabus->irqs = irqs; + if (!bus) { + hw_error("Can't set isa irqs with no isa bus present."); + } + bus->irqs = irqs; } /* @@ -67,8 +65,9 @@ void isa_bus_irqs(qemu_irq *irqs) * This function is only for special cases such as the 'ferr', and * temporary use for normal devices until they are converted to qdev. */ -qemu_irq isa_get_irq(int isairq) +qemu_irq isa_get_irq(ISADevice *dev, int isairq) { + assert(!dev || DO_UPCAST(ISABus, qbus, dev->qdev.parent_bus) == isabus); if (isairq < 0 || isairq > 15) { hw_error("isa irq %d invalid", isairq); } @@ -79,7 +78,7 @@ void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq) { assert(dev->nirqs < ARRAY_SIZE(dev->isairq)); dev->isairq[dev->nirqs] = isairq; - *p = isa_get_irq(isairq); + *p = isa_get_irq(dev, isairq); dev->nirqs++; } @@ -129,35 +128,35 @@ void isa_qdev_register(ISADeviceInfo *info) qdev_register(&info->qdev); } -ISADevice *isa_create(const char *name) +ISADevice *isa_create(ISABus *bus, const char *name) { DeviceState *dev; - if (!isabus) { + if (!bus) { hw_error("Tried to create isa device %s with no isa bus present.", name); } - dev = qdev_create(&isabus->qbus, name); + dev = qdev_create(&bus->qbus, name); return DO_UPCAST(ISADevice, qdev, dev); } -ISADevice *isa_try_create(const char *name) +ISADevice *isa_try_create(ISABus *bus, const char *name) { DeviceState *dev; - if (!isabus) { + if (!bus) { hw_error("Tried to create isa device %s with no isa bus present.", name); } - dev = qdev_try_create(&isabus->qbus, name); + dev = qdev_try_create(&bus->qbus, name); return DO_UPCAST(ISADevice, qdev, dev); } -ISADevice *isa_create_simple(const char *name) +ISADevice *isa_create_simple(ISABus *bus, const char *name) { ISADevice *dev; - dev = isa_create(name); + dev = isa_create(bus, name); qdev_init_nofail(&dev->qdev); return dev; } @@ -9,10 +9,15 @@ #define ISA_NUM_IRQS 16 -typedef struct ISABus ISABus; typedef struct ISADevice ISADevice; typedef struct ISADeviceInfo ISADeviceInfo; +struct ISABus { + BusState qbus; + MemoryRegion *address_space_io; + qemu_irq *irqs; +}; + struct ISADevice { DeviceState qdev; uint32_t isairq[2]; @@ -27,14 +32,14 @@ struct ISADeviceInfo { }; ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io); -void isa_bus_irqs(qemu_irq *irqs); -qemu_irq isa_get_irq(int isairq); +void isa_bus_irqs(ISABus *bus, qemu_irq *irqs); +qemu_irq isa_get_irq(ISADevice *dev, int isairq); void isa_init_irq(ISADevice *dev, qemu_irq *p, int isairq); void isa_qdev_register(ISADeviceInfo *info); MemoryRegion *isa_address_space(ISADevice *dev); -ISADevice *isa_create(const char *name); -ISADevice *isa_try_create(const char *name); -ISADevice *isa_create_simple(const char *name); +ISADevice *isa_create(ISABus *bus, const char *name); +ISADevice *isa_try_create(ISABus *bus, const char *name); +ISADevice *isa_create_simple(ISABus *bus, const char *name); /** * isa_register_ioport: Install an I/O port region on the ISA bus. diff --git a/hw/m48t59.c b/hw/m48t59.c index 8d8d495d7a..c0439966cf 100644 --- a/hw/m48t59.c +++ b/hw/m48t59.c @@ -660,13 +660,14 @@ M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base, return state; } -M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type) +M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, + int type) { M48t59ISAState *d; ISADevice *dev; M48t59State *s; - dev = isa_create("m48t59_isa"); + dev = isa_create(bus, "m48t59_isa"); qdev_prop_set_uint32(&dev->qdev, "type", type); qdev_prop_set_uint32(&dev->qdev, "size", size); qdev_prop_set_uint32(&dev->qdev, "io_base", io_base); diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c index 0c23cb0dba..9cbd052694 100644 --- a/hw/mc146818rtc.c +++ b/hw/mc146818rtc.c @@ -677,12 +677,12 @@ static int rtc_initfn(ISADevice *dev) return 0; } -ISADevice *rtc_init(int base_year, qemu_irq intercept_irq) +ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq) { ISADevice *dev; RTCState *s; - dev = isa_create("mc146818rtc"); + dev = isa_create(bus, "mc146818rtc"); s = DO_UPCAST(RTCState, dev, dev); qdev_prop_set_int32(&dev->qdev, "base_year", base_year); qdev_init_nofail(&dev->qdev); diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h index 575968c041..f1199300a4 100644 --- a/hw/mc146818rtc.h +++ b/hw/mc146818rtc.h @@ -5,7 +5,7 @@ #define RTC_ISA_IRQ 8 -ISADevice *rtc_init(int base_year, qemu_irq intercept_irq); +ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq); void rtc_set_memory(ISADevice *dev, int addr, int val); void rtc_set_date(ISADevice *dev, const struct tm *tm); diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c index 04921c147e..5e87665188 100644 --- a/hw/mips_fulong2e.c +++ b/hw/mips_fulong2e.c @@ -264,8 +264,8 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, int64_t kernel_entry; qemu_irq *i8259; qemu_irq *cpu_exit_irq; - int via_devfn; PCIBus *pci_bus; + ISABus *isa_bus; i2c_bus *smbus; int i; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; @@ -337,16 +337,16 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, /* South bridge */ ide_drive_get(hd, MAX_IDE_BUS); - via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); - if (via_devfn < 0) { + isa_bus = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0)); + if (!isa_bus) { fprintf(stderr, "vt82c686b_init error\n"); exit(1); } /* Interrupt controller */ /* The 8259 -> IP5 */ - i8259 = i8259_init(env->irq[5]); - isa_bus_irqs(i8259); + i8259 = i8259_init(isa_bus, env->irq[5]); + isa_bus_irqs(isa_bus, i8259); vt82c686b_ide_init(pci_bus, hd, PCI_DEVFN(FULONG2E_VIA_SLOT, 1)); usb_uhci_vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 2)); @@ -358,23 +358,23 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device, smbus_eeprom_init(smbus, 1, eeprom_spd, sizeof(eeprom_spd)); /* init other devices */ - pit = pit_init(0x40, 0); + pit = pit_init(isa_bus, 0x40, 0); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); /* Super I/O */ - isa_create_simple("i8042"); + isa_create_simple(isa_bus, "i8042"); - rtc_init(2000, NULL); + rtc_init(isa_bus, 2000, NULL); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_isa_init(i, serial_hds[i]); + serial_isa_init(isa_bus, i, serial_hds[i]); } } if (parallel_hds[0]) { - parallel_init(0, parallel_hds[0]); + parallel_init(isa_bus, 0, parallel_hds[0]); } /* Sound card */ diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c index 358de599b0..da0498201a 100644 --- a/hw/mips_jazz.c +++ b/hw/mips_jazz.c @@ -120,6 +120,7 @@ static void mips_jazz_init(MemoryRegion *address_space, NICInfo *nd; DeviceState *dev; SysBusDevice *sysbus; + ISABus *isa_bus; ISADevice *pit; DriveInfo *fds[MAX_FD]; qemu_irq esp_reset, dma_enable; @@ -183,12 +184,12 @@ static void mips_jazz_init(MemoryRegion *address_space, memory_region_add_subregion(address_space, 0x8000d000, dma_dummy); /* ISA devices */ - isa_bus_new(NULL, address_space_io); - i8259 = i8259_init(env->irq[4]); - isa_bus_irqs(i8259); + isa_bus = isa_bus_new(NULL, address_space_io); + i8259 = i8259_init(isa_bus, env->irq[4]); + isa_bus_irqs(isa_bus, i8259); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); - pit = pit_init(0x40, 0); + pit = pit_init(isa_bus, 0x40, 0); pcspk_init(pit); /* ISA IO space at 0x90000000 */ @@ -255,7 +256,7 @@ static void mips_jazz_init(MemoryRegion *address_space, fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds); /* Real time clock */ - rtc_init(1980, NULL); + rtc_init(isa_bus, 1980, NULL); memory_region_init_io(rtc, &rtc_ops, NULL, "rtc", 0x1000); memory_region_add_subregion(address_space, 0x80004000, rtc); @@ -280,7 +281,7 @@ static void mips_jazz_init(MemoryRegion *address_space, /* Sound card */ /* FIXME: missing Jazz sound at 0x8000c000, rc4030[2] */ - audio_init(i8259, NULL); + audio_init(isa_bus, NULL); /* NVRAM */ dev = qdev_create(NULL, "ds1225y"); diff --git a/hw/mips_malta.c b/hw/mips_malta.c index e7dfbd6632..d94ad1d8c1 100644 --- a/hw/mips_malta.c +++ b/hw/mips_malta.c @@ -774,6 +774,7 @@ void mips_malta_init (ram_addr_t ram_size, target_long bios_size; int64_t kernel_entry; PCIBus *pci_bus; + ISABus *isa_bus; CPUState *env; qemu_irq *i8259 = NULL, *isa_irq; qemu_irq *cpu_exit_irq; @@ -941,38 +942,38 @@ void mips_malta_init (ram_addr_t ram_size, /* Southbridge */ ide_drive_get(hd, MAX_IDE_BUS); - piix4_devfn = piix4_init(pci_bus, 80); + piix4_devfn = piix4_init(pci_bus, &isa_bus, 80); /* Interrupt controller */ /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */ - i8259 = i8259_init(env->irq[2]); + i8259 = i8259_init(isa_bus, env->irq[2]); - isa_bus_irqs(i8259); + isa_bus_irqs(isa_bus, i8259); pci_piix4_ide_init(pci_bus, hd, piix4_devfn + 1); usb_uhci_piix4_init(pci_bus, piix4_devfn + 2); - smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, isa_get_irq(9), - NULL, NULL, 0); + smbus = piix4_pm_init(pci_bus, piix4_devfn + 3, 0x1100, + isa_get_irq(NULL, 9), NULL, NULL, 0); /* TODO: Populate SPD eeprom data. */ smbus_eeprom_init(smbus, 8, NULL, 0); - pit = pit_init(0x40, 0); + pit = pit_init(isa_bus, 0x40, 0); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(0, cpu_exit_irq); /* Super I/O */ - isa_create_simple("i8042"); + isa_create_simple(isa_bus, "i8042"); - rtc_init(2000, NULL); - serial_isa_init(0, serial_hds[0]); - serial_isa_init(1, serial_hds[1]); + rtc_init(isa_bus, 2000, NULL); + serial_isa_init(isa_bus, 0, serial_hds[0]); + serial_isa_init(isa_bus, 1, serial_hds[1]); if (parallel_hds[0]) - parallel_init(0, parallel_hds[0]); + parallel_init(isa_bus, 0, parallel_hds[0]); for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } - fdctrl_init_isa(fd); + fdctrl_init_isa(isa_bus, fd); /* Sound card */ - audio_init(NULL, pci_bus); + audio_init(isa_bus, pci_bus); /* Network card */ network_init(); diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c index d0564d4449..c078078264 100644 --- a/hw/mips_r4k.c +++ b/hw/mips_r4k.c @@ -165,6 +165,7 @@ void mips_r4k_init (ram_addr_t ram_size, ResetData *reset_info; int i; qemu_irq *i8259; + ISABus *isa_bus; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *dinfo; int be; @@ -256,36 +257,36 @@ void mips_r4k_init (ram_addr_t ram_size, cpu_mips_clock_init(env); /* The PIC is attached to the MIPS CPU INT0 pin */ - isa_bus_new(NULL, get_system_io()); - i8259 = i8259_init(env->irq[2]); - isa_bus_irqs(i8259); + isa_bus = isa_bus_new(NULL, get_system_io()); + i8259 = i8259_init(isa_bus, env->irq[2]); + isa_bus_irqs(isa_bus, i8259); - rtc_init(2000, NULL); + rtc_init(isa_bus, 2000, NULL); /* Register 64 KB of ISA IO space at 0x14000000 */ isa_mmio_init(0x14000000, 0x00010000); isa_mem_base = 0x10000000; - pit = pit_init(0x40, 0); + pit = pit_init(isa_bus, 0x40, 0); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_isa_init(i, serial_hds[i]); + serial_isa_init(isa_bus, i, serial_hds[i]); } } - isa_vga_init(); + isa_vga_init(isa_bus); if (nd_table[0].vlan) - isa_ne2000_init(0x300, 9, &nd_table[0]); + isa_ne2000_init(isa_bus, 0x300, 9, &nd_table[0]); ide_drive_get(hd, MAX_IDE_BUS); for(i = 0; i < MAX_IDE_BUS; i++) - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i], hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); - isa_create_simple("i8042"); + isa_create_simple(isa_bus, "i8042"); } static QEMUMachine mips_machine = { diff --git a/hw/nvram.h b/hw/nvram.h index 0f55b24418..8924da47d8 100644 --- a/hw/nvram.h +++ b/hw/nvram.h @@ -34,7 +34,8 @@ typedef struct M48t59State M48t59State; void m48t59_write (void *private, uint32_t addr, uint32_t val); uint32_t m48t59_read (void *private, uint32_t addr); void m48t59_toggle_lock (void *private, int lock); -M48t59State *m48t59_init_isa(uint32_t io_base, uint16_t size, int type); +M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size, + int type); M48t59State *m48t59_init(qemu_irq IRQ, target_phys_addr_t mem_base, uint32_t io_base, uint16_t size, int type); void m48t59_set_addr (void *opaque, uint32_t addr); @@ -624,9 +624,9 @@ static void *bochs_bios_init(void) * of nodes, one word for each VCPU->node and one word for each node to * hold the amount of memory. */ - numa_fw_cfg = g_malloc0((1 + smp_cpus + nb_numa_nodes) * 8); + numa_fw_cfg = g_malloc0((1 + max_cpus + nb_numa_nodes) * 8); numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes); - for (i = 0; i < smp_cpus; i++) { + for (i = 0; i < max_cpus; i++) { for (j = 0; j < nb_numa_nodes; j++) { if (node_cpumask[j] & (1 << i)) { numa_fw_cfg[i + 1] = cpu_to_le64(j); @@ -635,10 +635,10 @@ static void *bochs_bios_init(void) } } for (i = 0; i < nb_numa_nodes; i++) { - numa_fw_cfg[smp_cpus + 1 + i] = cpu_to_le64(node_mem[i]); + numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]); } fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, (uint8_t *)numa_fw_cfg, - (1 + smp_cpus + nb_numa_nodes) * 8); + (1 + max_cpus + nb_numa_nodes) * 8); return fw_cfg; } @@ -849,13 +849,13 @@ static const int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; static const int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; static const int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; -void pc_init_ne2k_isa(NICInfo *nd) +void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd) { static int nb_ne2k = 0; if (nb_ne2k == NE2000_NB_MAX) return; - isa_ne2000_init(ne2000_io[nb_ne2k], + isa_ne2000_init(bus, ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd); nb_ne2k++; } @@ -1069,7 +1069,7 @@ qemu_irq *pc_allocate_cpu_irq(void) return qemu_allocate_irqs(pic_irq_request, NULL, 1); } -DeviceState *pc_vga_init(PCIBus *pci_bus) +DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus) { DeviceState *dev = NULL; @@ -1102,7 +1102,7 @@ DeviceState *pc_vga_init(PCIBus *pci_bus) if (pci_bus) { dev = pci_vga_init(pci_bus); } else { - dev = isa_vga_init(); + dev = isa_vga_init(isa_bus); } } @@ -1118,7 +1118,7 @@ static void cpu_request_exit(void *opaque, int irq, int level) } } -void pc_basic_device_init(qemu_irq *gsi, +void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, ISADevice **floppy, bool no_vmport) @@ -1144,31 +1144,31 @@ void pc_basic_device_init(qemu_irq *gsi, rtc_irq = qdev_get_gpio_in(hpet, 0); } } - *rtc_state = rtc_init(2000, rtc_irq); + *rtc_state = rtc_init(isa_bus, 2000, rtc_irq); qemu_register_boot_set(pc_boot_set, *rtc_state); - pit = pit_init(0x40, 0); + pit = pit_init(isa_bus, 0x40, 0); pcspk_init(pit); for(i = 0; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_isa_init(i, serial_hds[i]); + serial_isa_init(isa_bus, i, serial_hds[i]); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { if (parallel_hds[i]) { - parallel_init(i, parallel_hds[i]); + parallel_init(isa_bus, i, parallel_hds[i]); } } a20_line = qemu_allocate_irqs(handle_a20_line_change, first_cpu, 2); - i8042 = isa_create_simple("i8042"); + i8042 = isa_create_simple(isa_bus, "i8042"); i8042_setup_a20_line(i8042, &a20_line[0]); if (!no_vmport) { - vmport_init(); - vmmouse = isa_try_create("vmmouse"); + vmport_init(isa_bus); + vmmouse = isa_try_create(isa_bus, "vmmouse"); } else { vmmouse = NULL; } @@ -1176,7 +1176,7 @@ void pc_basic_device_init(qemu_irq *gsi, qdev_prop_set_ptr(&vmmouse->qdev, "ps2_mouse", i8042); qdev_init_nofail(&vmmouse->qdev); } - port92 = isa_create_simple("port92"); + port92 = isa_create_simple(isa_bus, "port92"); port92_init(port92, &a20_line[1]); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); @@ -1185,7 +1185,7 @@ void pc_basic_device_init(qemu_irq *gsi, for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } - *floppy = fdctrl_init_isa(fd); + *floppy = fdctrl_init_isa(isa_bus, fd); } void pc_pci_device_init(PCIBus *pci_bus) @@ -20,11 +20,12 @@ SerialState *serial_mm_init(MemoryRegion *address_space, target_phys_addr_t base, int it_shift, qemu_irq irq, int baudbase, CharDriverState *chr, enum device_endian); -static inline bool serial_isa_init(int index, CharDriverState *chr) +static inline bool serial_isa_init(ISABus *bus, int index, + CharDriverState *chr) { ISADevice *dev; - dev = isa_try_create("isa-serial"); + dev = isa_try_create(bus, "isa-serial"); if (!dev) { return false; } @@ -39,11 +40,11 @@ static inline bool serial_isa_init(int index, CharDriverState *chr) void serial_set_frequency(SerialState *s, uint32_t frequency); /* parallel.c */ -static inline bool parallel_init(int index, CharDriverState *chr) +static inline bool parallel_init(ISABus *bus, int index, CharDriverState *chr) { ISADevice *dev; - dev = isa_try_create("isa-parallel"); + dev = isa_try_create(bus, "isa-parallel"); if (!dev) { return false; } @@ -63,7 +64,7 @@ bool parallel_mm_init(MemoryRegion *address_space, typedef struct PicState PicState; extern PicState *isa_pic; -qemu_irq *i8259_init(qemu_irq parent_irq); +qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq); int pic_read_irq(PicState *s); int pic_get_output(PicState *s); void pic_info(Monitor *mon); @@ -84,11 +85,11 @@ void gsi_handler(void *opaque, int n, int level); #define PIT_FREQ 1193182 -static inline ISADevice *pit_init(int base, int irq) +static inline ISADevice *pit_init(ISABus *bus, int base, int irq) { ISADevice *dev; - dev = isa_create("isa-pit"); + dev = isa_create(bus, "isa-pit"); qdev_prop_set_uint32(&dev->qdev, "iobase", base); qdev_prop_set_uint32(&dev->qdev, "irq", irq); qdev_init_nofail(&dev->qdev); @@ -106,9 +107,9 @@ void hpet_pit_disable(void); void hpet_pit_enable(void); /* vmport.c */ -static inline void vmport_init(void) +static inline void vmport_init(ISABus *bus) { - isa_create_simple("vmport"); + isa_create_simple(bus, "vmport"); } void vmport_register(unsigned char command, IOPortReadFunc *func, void *opaque); void vmmouse_get_data(uint32_t *data); @@ -140,12 +141,12 @@ void pc_memory_init(MemoryRegion *system_memory, MemoryRegion *rom_memory, MemoryRegion **ram_memory); qemu_irq *pc_allocate_cpu_irq(void); -DeviceState *pc_vga_init(PCIBus *pci_bus); -void pc_basic_device_init(qemu_irq *gsi, +DeviceState *pc_vga_init(ISABus *isa_bus, PCIBus *pci_bus); +void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi, ISADevice **rtc_state, ISADevice **floppy, bool no_vmport); -void pc_init_ne2k_isa(NICInfo *nd); +void pc_init_ne2k_isa(ISABus *bus, NICInfo *nd); void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size, const char *boot_device, ISADevice *floppy, BusState *ide0, BusState *ide1, @@ -175,14 +176,14 @@ extern int no_hpet; /* pcspk.c */ void pcspk_init(ISADevice *pit); -int pcspk_audio_init(qemu_irq *pic); +int pcspk_audio_init(ISABus *bus); /* piix_pci.c */ struct PCII440FXState; typedef struct PCII440FXState PCII440FXState; PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, - qemu_irq *pic, + ISABus **isa_bus, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -195,7 +196,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix_devfn, /* piix4.c */ extern PCIDevice *piix4_dev; -int piix4_init(PCIBus *bus, int devfn); +int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn); /* vga.c */ enum vga_retrace_method { @@ -205,11 +206,11 @@ enum vga_retrace_method { extern enum vga_retrace_method vga_retrace_method; -static inline DeviceState *isa_vga_init(void) +static inline DeviceState *isa_vga_init(ISABus *bus) { ISADevice *dev; - dev = isa_try_create("isa-vga"); + dev = isa_try_create(bus, "isa-vga"); if (!dev) { fprintf(stderr, "Warning: isa-vga not available\n"); return NULL; @@ -228,13 +229,13 @@ DeviceState *pci_cirrus_vga_init(PCIBus *bus); DeviceState *isa_cirrus_vga_init(MemoryRegion *address_space); /* ne2000.c */ -static inline bool isa_ne2000_init(int base, int irq, NICInfo *nd) +static inline bool isa_ne2000_init(ISABus *bus, int base, int irq, NICInfo *nd) { ISADevice *dev; qemu_check_nic_model(nd, "ne2k_isa"); - dev = isa_try_create("ne2k_isa"); + dev = isa_try_create(bus, "ne2k_isa"); if (!dev) { return false; } diff --git a/hw/pc_piix.c b/hw/pc_piix.c index b9bb09d1e0..b70431fe87 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -84,6 +84,7 @@ static void pc_init1(MemoryRegion *system_memory, int i; ram_addr_t below_4g_mem_size, above_4g_mem_size; PCIBus *pci_bus; + ISABus *isa_bus; PCII440FXState *i440fx_state; int piix3_devfn = -1; qemu_irq *cpu_irq; @@ -136,7 +137,7 @@ static void pc_init1(MemoryRegion *system_memory, gsi = qemu_allocate_irqs(gsi_handler, gsi_state, GSI_NUM_PINS); if (pci_enabled) { - pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, gsi, + pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, &isa_bus, gsi, system_memory, system_io, ram_size, below_4g_mem_size, 0x100000000ULL - below_4g_mem_size, @@ -148,14 +149,14 @@ static void pc_init1(MemoryRegion *system_memory, } else { pci_bus = NULL; i440fx_state = NULL; - isa_bus_new(NULL, system_io); + isa_bus = isa_bus_new(NULL, system_io); no_hpet = 1; } - isa_bus_irqs(gsi); + isa_bus_irqs(isa_bus, gsi); if (!xen_enabled()) { cpu_irq = pc_allocate_cpu_irq(); - i8259 = i8259_init(cpu_irq[0]); + i8259 = i8259_init(isa_bus, cpu_irq[0]); } else { i8259 = xen_interrupt_controller_init(); } @@ -169,7 +170,7 @@ static void pc_init1(MemoryRegion *system_memory, pc_register_ferr_irq(gsi[13]); - dev = pc_vga_init(pci_enabled? pci_bus: NULL); + dev = pc_vga_init(isa_bus, pci_enabled ? pci_bus : NULL); if (dev) { qdev_property_add_child(qdev_get_root(), "vga", dev, NULL); } @@ -179,13 +180,13 @@ static void pc_init1(MemoryRegion *system_memory, } /* init basic PC hardware */ - pc_basic_device_init(gsi, &rtc_state, &floppy, xen_enabled()); + pc_basic_device_init(isa_bus, gsi, &rtc_state, &floppy, xen_enabled()); for(i = 0; i < nb_nics; i++) { NICInfo *nd = &nd_table[i]; if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0)) - pc_init_ne2k_isa(nd); + pc_init_ne2k_isa(isa_bus, nd); else pci_nic_init_nofail(nd, "e1000", NULL); } @@ -203,7 +204,8 @@ static void pc_init1(MemoryRegion *system_memory, } else { for(i = 0; i < MAX_IDE_BUS; i++) { ISADevice *dev; - dev = isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + dev = isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], + ide_irq[i], hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]); idebus[i] = qdev_get_child_bus(&dev->qdev, "ide.0"); } @@ -220,7 +222,7 @@ static void pc_init1(MemoryRegion *system_memory, qdev_property_add_child(qdev_resolve_path("/i440fx/piix3", NULL), "rtc", (DeviceState *)rtc_state, NULL); - audio_init(gsi, pci_enabled ? pci_bus : NULL); + audio_init(isa_bus, pci_enabled ? pci_bus : NULL); pc_cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, floppy, idebus[0], idebus[1], rtc_state); diff --git a/hw/pcspk.c b/hw/pcspk.c index 7fa2d36620..acb016773b 100644 --- a/hw/pcspk.c +++ b/hw/pcspk.c @@ -96,7 +96,7 @@ static void pcspk_callback(void *opaque, int free) } } -int pcspk_audio_init(qemu_irq *pic) +int pcspk_audio_init(ISABus *bus) { PCSpkState *s = &pcspk_state; struct audsettings as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0}; diff --git a/hw/piix4.c b/hw/piix4.c index 2fd1171328..51af459073 100644 --- a/hw/piix4.c +++ b/hw/piix4.c @@ -93,11 +93,12 @@ static int piix4_initfn(PCIDevice *dev) return 0; } -int piix4_init(PCIBus *bus, int devfn) +int piix4_init(PCIBus *bus, ISABus **isa_bus, int devfn) { PCIDevice *d; d = pci_create_simple_multifunction(bus, devfn, true, "PIIX4"); + *isa_bus = DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0")); return d->devfn; } diff --git a/hw/piix_pci.c b/hw/piix_pci.c index 43c85aa3d8..3652522e58 100644 --- a/hw/piix_pci.c +++ b/hw/piix_pci.c @@ -81,7 +81,6 @@ struct PCII440FXState { PAMMemoryRegion pam_regions[13]; MemoryRegion smram_region; uint8_t smm_enabled; - PIIX3State *piix3; }; @@ -253,7 +252,7 @@ static int i440fx_initfn(PCIDevice *dev) static PCIBus *i440fx_common_init(const char *device_name, PCII440FXState **pi440fx_state, int *piix3_devfn, - qemu_irq *pic, + ISABus **isa_bus, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -319,8 +318,8 @@ static PCIBus *i440fx_common_init(const char *device_name, } qdev_property_add_child(dev, "piix3", &piix3->dev.qdev, NULL); piix3->pic = pic; - - (*pi440fx_state)->piix3 = piix3; + *isa_bus = DO_UPCAST(ISABus, qbus, + qdev_get_child_bus(&piix3->dev.qdev, "isa.0")); *piix3_devfn = piix3->dev.devfn; @@ -335,7 +334,7 @@ static PCIBus *i440fx_common_init(const char *device_name, } PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, - qemu_irq *pic, + ISABus **isa_bus, qemu_irq *pic, MemoryRegion *address_space_mem, MemoryRegion *address_space_io, ram_addr_t ram_size, @@ -348,7 +347,7 @@ PCIBus *i440fx_init(PCII440FXState **pi440fx_state, int *piix3_devfn, { PCIBus *b; - b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, pic, + b = i440fx_common_init("i440FX", pi440fx_state, piix3_devfn, isa_bus, pic, address_space_mem, address_space_io, ram_size, pci_hole_start, pci_hole_size, pci_hole64_size, pci_hole64_size, diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c index f22d5b98c5..a7d73bfcc7 100644 --- a/hw/ppc_prep.c +++ b/hw/ppc_prep.c @@ -523,6 +523,7 @@ static void ppc_prep_init (ram_addr_t ram_size, uint32_t kernel_base, initrd_base; long kernel_size, initrd_size; PCIBus *pci_bus; + ISABus *isa_bus; qemu_irq *i8259; qemu_irq *cpu_exit_irq; int ppc_boot_device; @@ -628,10 +629,10 @@ static void ppc_prep_init (ram_addr_t ram_size, hw_error("Only 6xx bus is supported on PREP machine\n"); } /* Hmm, prep has no pci-isa bridge ??? */ - isa_bus_new(NULL, get_system_io()); - i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]); + isa_bus = isa_bus_new(NULL, get_system_io()); + i8259 = i8259_init(isa_bus, first_cpu->irq_inputs[PPC6xx_INPUT_INT]); pci_bus = pci_prep_init(i8259, get_system_memory(), get_system_io()); - isa_bus_irqs(i8259); + isa_bus_irqs(isa_bus, i8259); // pci_bus = i440fx_init(); /* Register 8 MB of ISA IO space (needed for non-contiguous map) */ memory_region_init_io(PPC_io_memory, &PPC_prep_io_ops, sysctrl, @@ -642,10 +643,10 @@ static void ppc_prep_init (ram_addr_t ram_size, pci_vga_init(pci_bus); // openpic = openpic_init(0x00000000, 0xF0000000, 1); // pit = pit_init(0x40, 0); - rtc_init(2000, NULL); + rtc_init(isa_bus, 2000, NULL); if (serial_hds[0]) - serial_isa_init(0, serial_hds[0]); + serial_isa_init(isa_bus, 0, serial_hds[0]); nb_nics1 = nb_nics; if (nb_nics1 > NE2000_NB_MAX) nb_nics1 = NE2000_NB_MAX; @@ -654,7 +655,8 @@ static void ppc_prep_init (ram_addr_t ram_size, nd_table[i].model = g_strdup("ne2k_isa"); } if (strcmp(nd_table[i].model, "ne2k_isa") == 0) { - isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]); + isa_ne2000_init(isa_bus, ne2000_io[i], ne2000_irq[i], + &nd_table[i]); } else { pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL); } @@ -662,11 +664,11 @@ static void ppc_prep_init (ram_addr_t ram_size, ide_drive_get(hd, MAX_IDE_BUS); for(i = 0; i < MAX_IDE_BUS; i++) { - isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i], + isa_ide_init(isa_bus, ide_iobase[i], ide_iobase2[i], ide_irq[i], hd[2 * i], hd[2 * i + 1]); } - isa_create_simple("i8042"); + isa_create_simple(isa_bus, "i8042"); cpu_exit_irq = qemu_allocate_irqs(cpu_request_exit, NULL, 1); DMA_init(1, cpu_exit_irq); @@ -676,7 +678,7 @@ static void ppc_prep_init (ram_addr_t ram_size, for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } - fdctrl_init_isa(fd); + fdctrl_init_isa(isa_bus, fd); /* Register speaker port */ register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL); @@ -1529,3 +1529,9 @@ void qdev_property_add_str(DeviceState *dev, const char *name, qdev_property_release_str, prop, errp); } + +void qdev_machine_init(void) +{ + qdev_get_peripheral_anon(); + qdev_get_peripheral(); +} @@ -616,4 +616,12 @@ void qdev_property_add_str(DeviceState *dev, const char *name, */ char *qdev_get_type(DeviceState *dev, Error **errp); +/** + * @qdev_machine_init + * + * Initialize platform devices before machine init. This is a hack until full + * support for composition is added. + */ +void qdev_machine_init(void); + #endif @@ -1385,9 +1385,9 @@ static int sb16_initfn (ISADevice *dev) return 0; } -int SB16_init (qemu_irq *pic) +int SB16_init (ISABus *bus) { - isa_create_simple ("sb16"); + isa_create_simple (bus, "sb16"); return 0; } @@ -51,6 +51,7 @@ typedef enum { sd_r6 = 6, /* Published RCA response */ sd_r7, /* Operating voltage */ sd_r1b = -1, + sd_illegal = -2, } sd_rsp_type_t; struct SDState { @@ -91,6 +92,10 @@ struct SDState { int spi; int current_cmd; + /* True if we will handle the next command as an ACMD. Note that this does + * *not* track the APP_CMD status bit! + */ + int expecting_acmd; int blk_written; uint64_t data_start; uint32_t data_offset; @@ -103,7 +108,7 @@ struct SDState { int enable; }; -static void sd_set_status(SDState *sd) +static void sd_set_mode(SDState *sd) { switch (sd->state) { case sd_inactive_state: @@ -125,9 +130,6 @@ static void sd_set_status(SDState *sd) sd->mode = sd_data_transfer_mode; break; } - - sd->card_status &= ~CURRENT_STATE; - sd->card_status |= sd->state << 9; } static const sd_cmd_type_t sd_cmd_type[64] = { @@ -309,6 +311,11 @@ static void sd_set_rca(SDState *sd) sd->rca += 0x4567; } +/* Card status bits, split by clear condition: + * A : According to the card current state + * B : Always related to the previous command + * C : Cleared by read + */ #define CARD_STATUS_A 0x02004100 #define CARD_STATUS_B 0x00c01e00 #define CARD_STATUS_C 0xfd39a028 @@ -335,14 +342,11 @@ static int sd_req_crc_validate(SDRequest *req) return sd_crc7(buffer, 5) != req->crc; /* TODO */ } -static void sd_response_r1_make(SDState *sd, - uint8_t *response, uint32_t last_status) +static void sd_response_r1_make(SDState *sd, uint8_t *response) { - uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND; - uint32_t status; - - status = (sd->card_status & ~mask) | (last_status & mask); - sd->card_status &= ~CARD_STATUS_C | APP_CMD; + uint32_t status = sd->card_status; + /* Clear the "clear on read" status bits */ + sd->card_status &= ~CARD_STATUS_C; response[0] = (status >> 24) & 0xff; response[1] = (status >> 16) & 0xff; @@ -367,6 +371,7 @@ static void sd_response_r6_make(SDState *sd, uint8_t *response) status = ((sd->card_status >> 8) & 0xc000) | ((sd->card_status >> 6) & 0x2000) | (sd->card_status & 0x1fff); + sd->card_status &= ~(CARD_STATUS_C & 0xc81fff); response[0] = (arg >> 8) & 0xff; response[1] = arg & 0xff; @@ -417,6 +422,7 @@ static void sd_reset(SDState *sd, BlockDriverState *bdrv) sd->size = size; sd->blk_len = 0x200; sd->pwd_len = 0; + sd->expecting_acmd = 0; } static void sd_cardchange(void *opaque, bool load) @@ -608,6 +614,9 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, uint32_t rca = 0x0000; uint64_t addr = (sd->ocr & (1 << 30)) ? (uint64_t) req.arg << 9 : req.arg; + /* Not interpreting this as an app command */ + sd->card_status &= ~APP_CMD; + if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc) rca = req.arg >> 16; @@ -674,8 +683,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, break; case 5: /* CMD5: reserved for SDIO cards */ - sd->card_status |= ILLEGAL_COMMAND; - return sd_r0; + return sd_illegal; case 6: /* CMD6: SWITCH_FUNCTION */ if (sd->spi) @@ -994,7 +1002,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, switch (sd->state) { case sd_transfer_state: if (addr >= sd->size) { - sd->card_status = ADDRESS_ERROR; + sd->card_status |= ADDRESS_ERROR; return sd_r1b; } @@ -1014,7 +1022,7 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, switch (sd->state) { case sd_transfer_state: if (addr >= sd->size) { - sd->card_status = ADDRESS_ERROR; + sd->card_status |= ADDRESS_ERROR; return sd_r1b; } @@ -1110,14 +1118,14 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, * on stderr, as some OSes may use these in their * probing for presence of an SDIO card. */ - sd->card_status |= ILLEGAL_COMMAND; - return sd_r0; + return sd_illegal; /* Application specific commands (Class 8) */ case 55: /* CMD55: APP_CMD */ if (sd->rca != rca) return sd_r0; + sd->expecting_acmd = 1; sd->card_status |= APP_CMD; return sd_r1; @@ -1140,27 +1148,24 @@ static sd_rsp_type_t sd_normal_command(SDState *sd, default: bad_cmd: - sd->card_status |= ILLEGAL_COMMAND; - fprintf(stderr, "SD: Unknown CMD%i\n", req.cmd); - return sd_r0; + return sd_illegal; unimplemented_cmd: /* Commands that are recognised but not yet implemented in SPI mode. */ - sd->card_status |= ILLEGAL_COMMAND; fprintf(stderr, "SD: CMD%i not implemented in SPI mode\n", req.cmd); - return sd_r0; + return sd_illegal; } - sd->card_status |= ILLEGAL_COMMAND; fprintf(stderr, "SD: CMD%i in a wrong state\n", req.cmd); - return sd_r0; + return sd_illegal; } static sd_rsp_type_t sd_app_command(SDState *sd, SDRequest req) { DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg); + sd->card_status |= APP_CMD; switch (req.cmd) { case 6: /* ACMD6: SET_BUS_WIDTH */ switch (sd->state) { @@ -1257,17 +1262,35 @@ static sd_rsp_type_t sd_app_command(SDState *sd, default: /* Fall back to standard commands. */ - sd->card_status &= ~APP_CMD; return sd_normal_command(sd, req); } fprintf(stderr, "SD: ACMD%i in a wrong state\n", req.cmd); - return sd_r0; + return sd_illegal; +} + +static int cmd_valid_while_locked(SDState *sd, SDRequest *req) +{ + /* Valid commands in locked state: + * basic class (0) + * lock card class (7) + * CMD16 + * implicitly, the ACMD prefix CMD55 + * ACMD41 and ACMD42 + * Anything else provokes an "illegal command" response. + */ + if (sd->expecting_acmd) { + return req->cmd == 41 || req->cmd == 42; + } + if (req->cmd == 16 || req->cmd == 55) { + return 1; + } + return sd_cmd_class[req->cmd] == 0 || sd_cmd_class[req->cmd] == 7; } int sd_do_command(SDState *sd, SDRequest *req, uint8_t *response) { - uint32_t last_status = sd->card_status; + int last_state; sd_rsp_type_t rtype; int rsplen; @@ -1276,37 +1299,47 @@ int sd_do_command(SDState *sd, SDRequest *req, } if (sd_req_crc_validate(req)) { - sd->card_status &= ~COM_CRC_ERROR; - return 0; + sd->card_status |= COM_CRC_ERROR; + rtype = sd_illegal; + goto send_response; } - sd->card_status &= ~CARD_STATUS_B; - sd_set_status(sd); - - if (last_status & CARD_IS_LOCKED) - if (((last_status & APP_CMD) && - req->cmd == 41) || - (!(last_status & APP_CMD) && - (sd_cmd_class[req->cmd] == 0 || - sd_cmd_class[req->cmd] == 7 || - req->cmd == 16 || req->cmd == 55))) { + if (sd->card_status & CARD_IS_LOCKED) { + if (!cmd_valid_while_locked(sd, req)) { sd->card_status |= ILLEGAL_COMMAND; + sd->expecting_acmd = 0; fprintf(stderr, "SD: Card is locked\n"); - return 0; + rtype = sd_illegal; + goto send_response; } + } - if (last_status & APP_CMD) { + last_state = sd->state; + sd_set_mode(sd); + + if (sd->expecting_acmd) { + sd->expecting_acmd = 0; rtype = sd_app_command(sd, *req); - sd->card_status &= ~APP_CMD; - } else + } else { rtype = sd_normal_command(sd, *req); + } - sd->current_cmd = req->cmd; + if (rtype == sd_illegal) { + sd->card_status |= ILLEGAL_COMMAND; + } else { + /* Valid command, we can update the 'state before command' bits. + * (Do this now so they appear in r1 responses.) + */ + sd->current_cmd = req->cmd; + sd->card_status &= ~CURRENT_STATE; + sd->card_status |= (last_state << 9); + } +send_response: switch (rtype) { case sd_r1: case sd_r1b: - sd_response_r1_make(sd, response, last_status); + sd_response_r1_make(sd, response); rsplen = 4; break; @@ -1336,13 +1369,18 @@ int sd_do_command(SDState *sd, SDRequest *req, break; case sd_r0: + case sd_illegal: default: rsplen = 0; break; } - if (sd->card_status & ILLEGAL_COMMAND) - rsplen = 0; + if (rtype != sd_illegal) { + /* Clear the "clear on valid command" status bits now we've + * sent any response + */ + sd->card_status &= ~CARD_STATUS_B; + } #ifdef DEBUG_SD if (rsplen) { diff --git a/hw/sun4u.c b/hw/sun4u.c index 97600a942d..e3e8ddebca 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -526,14 +526,19 @@ static void dummy_isa_irq_handler(void *opaque, int n, int level) } /* EBUS (Eight bit bus) bridge */ -static void +static ISABus * pci_ebus_init(PCIBus *bus, int devfn) { qemu_irq *isa_irq; + PCIDevice *pci_dev; + ISABus *isa_bus; - pci_create_simple(bus, devfn, "ebus"); + pci_dev = pci_create_simple(bus, devfn, "ebus"); + isa_bus = DO_UPCAST(ISABus, qbus, + qdev_get_child_bus(&pci_dev->qdev, "isa.0")); isa_irq = qemu_allocate_irqs(dummy_isa_irq_handler, NULL, 16); - isa_bus_irqs(isa_irq); + isa_bus_irqs(isa_bus, isa_irq); + return isa_bus; } static int @@ -744,6 +749,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, unsigned int i; long initrd_size, kernel_size; PCIBus *pci_bus, *pci_bus2, *pci_bus3; + ISABus *isa_bus; qemu_irq *irq; DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS]; DriveInfo *fd[MAX_FD]; @@ -764,7 +770,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_vga_init(pci_bus); // XXX Should be pci_bus3 - pci_ebus_init(pci_bus, -1); + isa_bus = pci_ebus_init(pci_bus, -1); i = 0; if (hwdef->console_serial_base) { @@ -774,13 +780,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem, } for(; i < MAX_SERIAL_PORTS; i++) { if (serial_hds[i]) { - serial_isa_init(i, serial_hds[i]); + serial_isa_init(isa_bus, i, serial_hds[i]); } } for(i = 0; i < MAX_PARALLEL_PORTS; i++) { if (parallel_hds[i]) { - parallel_init(i, parallel_hds[i]); + parallel_init(isa_bus, i, parallel_hds[i]); } } @@ -791,12 +797,12 @@ static void sun4uv_init(MemoryRegion *address_space_mem, pci_cmd646_ide_init(pci_bus, hd, 1); - isa_create_simple("i8042"); + isa_create_simple(isa_bus, "i8042"); for(i = 0; i < MAX_FD; i++) { fd[i] = drive_get(IF_FLOPPY, 0, i); } - fdctrl_init_isa(fd); - nvram = m48t59_init_isa(0x0074, NVRAM_SIZE, 59); + fdctrl_init_isa(isa_bus, fd); + nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59); initrd_size = 0; kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename, diff --git a/hw/sysbus.c b/hw/sysbus.c index 7016903163..2e06fe823c 100644 --- a/hw/sysbus.c +++ b/hw/sysbus.c @@ -50,17 +50,12 @@ void sysbus_mmio_map(SysBusDevice *dev, int n, target_phys_addr_t addr) } if (dev->mmio[n].addr != (target_phys_addr_t)-1) { /* Unregister previous mapping. */ - if (dev->mmio[n].memory) { - memory_region_del_subregion(get_system_memory(), - dev->mmio[n].memory); - } + memory_region_del_subregion(get_system_memory(), dev->mmio[n].memory); } dev->mmio[n].addr = addr; - if (dev->mmio[n].memory) { - memory_region_add_subregion(get_system_memory(), - addr, - dev->mmio[n].memory); - } + memory_region_add_subregion(get_system_memory(), + addr, + dev->mmio[n].memory); } @@ -206,10 +201,7 @@ static void sysbus_dev_print(Monitor *mon, DeviceState *dev, int indent) monitor_printf(mon, "%*sirq %d\n", indent, "", s->num_irq); for (i = 0; i < s->num_mmio; i++) { - size = 0; - if (s->mmio[i].memory) { - size = memory_region_size(s->mmio[i].memory); - } + size = memory_region_size(s->mmio[i].memory); monitor_printf(mon, "%*smmio " TARGET_FMT_plx "/" TARGET_FMT_plx "\n", indent, "", s->mmio[i].addr, size); } diff --git a/hw/virtio-console.c b/hw/virtio-console.c index d3351c83ff..73d866a52d 100644 --- a/hw/virtio-console.c +++ b/hw/virtio-console.c @@ -27,6 +27,11 @@ static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); ssize_t ret; + if (!vcon->chr) { + /* If there's no backend, we can just say we consumed all data. */ + return len; + } + ret = qemu_chr_fe_write(vcon->chr, buf, len); trace_virtio_console_flush_buf(port->id, len, ret); @@ -52,6 +57,9 @@ static void guest_open(VirtIOSerialPort *port) { VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + if (!vcon->chr) { + return; + } qemu_chr_fe_open(vcon->chr); } @@ -60,6 +68,9 @@ static void guest_close(VirtIOSerialPort *port) { VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); + if (!vcon->chr) { + return; + } qemu_chr_fe_close(vcon->chr); } @@ -109,9 +120,6 @@ static int virtconsole_initfn(VirtIOSerialPort *port) if (vcon->chr) { qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, vcon); - info->have_data = flush_buf; - info->guest_open = guest_open; - info->guest_close = guest_close; } return 0; @@ -138,6 +146,9 @@ static VirtIOSerialPortInfo virtconsole_info = { .is_console = true, .init = virtconsole_initfn, .exit = virtconsole_exitfn, + .have_data = flush_buf, + .guest_open = guest_open, + .guest_close = guest_close, .qdev.props = (Property[]) { DEFINE_PROP_CHR("chardev", VirtConsole, chr), DEFINE_PROP_END_OF_LIST(), @@ -155,6 +166,9 @@ static VirtIOSerialPortInfo virtserialport_info = { .qdev.size = sizeof(VirtConsole), .init = virtconsole_initfn, .exit = virtconsole_exitfn, + .have_data = flush_buf, + .guest_open = guest_open, + .guest_close = guest_close, .qdev.props = (Property[]) { DEFINE_PROP_CHR("chardev", VirtConsole, chr), DEFINE_PROP_END_OF_LIST(), diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index a4825b9eeb..fe0233f6f1 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -466,13 +466,11 @@ static void handle_output(VirtIODevice *vdev, VirtQueue *vq) { VirtIOSerial *vser; VirtIOSerialPort *port; - VirtIOSerialPortInfo *info; vser = DO_UPCAST(VirtIOSerial, vdev, vdev); port = find_port_by_vq(vser, vq); - info = port ? DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info) : NULL; - if (!port || !port->host_connected || !info->have_data) { + if (!port || !port->host_connected) { discard_vq_data(vq, vdev); return; } @@ -746,6 +744,8 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) port->vser = bus->vser; port->bh = qemu_bh_new(flush_queued_data_bh, port); + assert(info->have_data); + /* * Is the first console port we're seeing? If so, put it up at * location 0. This is done for backward compatibility (old diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 284595905d..038128b84c 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -507,13 +507,13 @@ static int vt82c686b_initfn(PCIDevice *d) return 0; } -int vt82c686b_init(PCIBus *bus, int devfn) +ISABus *vt82c686b_init(PCIBus *bus, int devfn) { PCIDevice *d; d = pci_create_simple_multifunction(bus, devfn, true, "VT82C686B"); - return d->devfn; + return DO_UPCAST(ISABus, qbus, qdev_get_child_bus(&d->qdev, "isa.0")); } static PCIDeviceInfo via_info = { diff --git a/hw/vt82c686.h b/hw/vt82c686.h index e3270cafd7..6ef876d260 100644 --- a/hw/vt82c686.h +++ b/hw/vt82c686.h @@ -2,7 +2,7 @@ #define HW_VT82C686_H /* vt82c686.c */ -int vt82c686b_init(PCIBus * bus, int devfn); +ISABus *vt82c686b_init(PCIBus * bus, int devfn); void vt82c686b_ac97_init(PCIBus *bus, int devfn); void vt82c686b_mc97_init(PCIBus *bus, int devfn); i2c_bus *vt82c686b_pm_init(PCIBus *bus, int devfn, uint32_t smb_io_base, diff --git a/main-loop.h b/main-loop.h index 876092dd15..f9710136c9 100644 --- a/main-loop.h +++ b/main-loop.h @@ -324,6 +324,9 @@ int qemu_add_child_watch(pid_t pid); * by threads other than the main loop thread when calling * qemu_bh_new(), qemu_set_fd_handler() and basically all other * functions documented in this file. + * + * NOTE: tools currently are single-threaded and qemu_mutex_lock_iothread + * is a no-op there. */ void qemu_mutex_lock_iothread(void); @@ -336,6 +339,9 @@ void qemu_mutex_lock_iothread(void); * as soon as possible by threads other than the main loop thread, * because it prevents the main loop from processing callbacks, * including timers and bottom halves. + * + * NOTE: tools currently are single-threaded and qemu_mutex_unlock_iothread + * is a no-op there. */ void qemu_mutex_unlock_iothread(void); @@ -18,6 +18,9 @@ #include "nbd.h" #include "block.h" +#include "block_int.h" + +#include "qemu-coroutine.h" #include <errno.h> #include <string.h> @@ -35,6 +38,7 @@ #endif #include "qemu_socket.h" +#include "qemu-queue.h" //#define DEBUG_NBD @@ -81,6 +85,14 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read) { size_t offset = 0; + if (qemu_in_coroutine()) { + if (do_read) { + return qemu_co_recv(fd, buffer, size); + } else { + return qemu_co_send(fd, buffer, size); + } + } + while (offset < size) { ssize_t len; @@ -178,7 +190,7 @@ int unix_socket_outgoing(const char *path) Request (type == 2) */ -int nbd_negotiate(int csock, off_t size, uint32_t flags) +static int nbd_send_negotiate(int csock, off_t size, uint32_t flags) { char buf[8 + 8 + 8 + 128]; @@ -194,7 +206,9 @@ int nbd_negotiate(int csock, off_t size, uint32_t flags) memcpy(buf, "NBDMAGIC", 8); cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL); cpu_to_be64w((uint64_t*)(buf + 16), size); - cpu_to_be32w((uint32_t*)(buf + 24), flags | NBD_FLAG_HAS_FLAGS); + cpu_to_be32w((uint32_t*)(buf + 24), + flags | NBD_FLAG_HAS_FLAGS | NBD_FLAG_SEND_TRIM | + NBD_FLAG_SEND_FLUSH | NBD_FLAG_SEND_FUA); memset(buf + 28, 0, 124); if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) { @@ -348,6 +362,15 @@ int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags, #ifdef __linux__ 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) { + int serrno = errno; + LOG("Failed to set NBD socket"); + errno = serrno; + return -1; + } + TRACE("Setting block size to %lu", (unsigned long)blocksize); if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) { @@ -386,24 +409,6 @@ int nbd_init(int fd, int csock, uint32_t flags, off_t size, size_t blocksize) return -1; } - TRACE("Clearing NBD socket"); - - if (ioctl(fd, NBD_CLEAR_SOCK) == -1) { - int serrno = errno; - LOG("Failed clearing NBD socket"); - errno = serrno; - return -1; - } - - TRACE("Setting NBD socket"); - - if (ioctl(fd, NBD_SET_SOCK, csock) == -1) { - int serrno = errno; - LOG("Failed to set NBD socket"); - errno = serrno; - return -1; - } - TRACE("Negotiation ended"); return 0; @@ -582,121 +587,369 @@ static int nbd_send_reply(int csock, struct nbd_reply *reply) return 0; } -int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, - off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size) +#define MAX_NBD_REQUESTS 16 + +typedef struct NBDRequest NBDRequest; + +struct NBDRequest { + QSIMPLEQ_ENTRY(NBDRequest) entry; + NBDClient *client; + uint8_t *data; +}; + +struct NBDExport { + BlockDriverState *bs; + off_t dev_offset; + off_t size; + uint32_t nbdflags; + QSIMPLEQ_HEAD(, NBDRequest) requests; +}; + +struct NBDClient { + int refcount; + void (*close)(NBDClient *client); + + NBDExport *exp; + int sock; + + Coroutine *recv_coroutine; + + CoMutex send_lock; + Coroutine *send_coroutine; + + int nb_requests; +}; + +static void nbd_client_get(NBDClient *client) { - struct nbd_request request; - struct nbd_reply reply; + client->refcount++; +} - TRACE("Reading request."); +static void nbd_client_put(NBDClient *client) +{ + if (--client->refcount == 0) { + g_free(client); + } +} - if (nbd_receive_request(csock, &request) == -1) - return -1; +static void nbd_client_close(NBDClient *client) +{ + qemu_set_fd_handler2(client->sock, NULL, NULL, NULL, NULL); + close(client->sock); + client->sock = -1; + if (client->close) { + client->close(client); + } + nbd_client_put(client); +} + +static NBDRequest *nbd_request_get(NBDClient *client) +{ + NBDRequest *req; + NBDExport *exp = client->exp; - if (request.len + NBD_REPLY_SIZE > data_size) { + assert(client->nb_requests <= MAX_NBD_REQUESTS - 1); + client->nb_requests++; + + if (QSIMPLEQ_EMPTY(&exp->requests)) { + req = g_malloc0(sizeof(NBDRequest)); + req->data = qemu_blockalign(exp->bs, NBD_BUFFER_SIZE); + } else { + req = QSIMPLEQ_FIRST(&exp->requests); + QSIMPLEQ_REMOVE_HEAD(&exp->requests, entry); + } + nbd_client_get(client); + req->client = client; + return req; +} + +static void nbd_request_put(NBDRequest *req) +{ + NBDClient *client = req->client; + QSIMPLEQ_INSERT_HEAD(&client->exp->requests, req, entry); + if (client->nb_requests-- == MAX_NBD_REQUESTS) { + qemu_notify_event(); + } + nbd_client_put(client); +} + +NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, + off_t size, uint32_t nbdflags) +{ + NBDExport *exp = g_malloc0(sizeof(NBDExport)); + QSIMPLEQ_INIT(&exp->requests); + exp->bs = bs; + exp->dev_offset = dev_offset; + exp->nbdflags = nbdflags; + exp->size = size == -1 ? exp->bs->total_sectors * 512 : size; + return exp; +} + +void nbd_export_close(NBDExport *exp) +{ + while (!QSIMPLEQ_EMPTY(&exp->requests)) { + NBDRequest *first = QSIMPLEQ_FIRST(&exp->requests); + QSIMPLEQ_REMOVE_HEAD(&exp->requests, entry); + qemu_vfree(first->data); + g_free(first); + } + + bdrv_close(exp->bs); + g_free(exp); +} + +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) +{ + NBDClient *client = req->client; + int csock = client->sock; + int rc, ret; + + qemu_co_mutex_lock(&client->send_lock); + qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, + nbd_restart_write, client); + client->send_coroutine = qemu_coroutine_self(); + + 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) { + ret = qemu_co_send(csock, req->data, len); + if (ret != len) { + errno = EIO; + rc = -1; + } + } + if (rc == -1) { + rc = -errno; + } + socket_set_cork(csock, 0); + } + + client->send_coroutine = NULL; + qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, NULL, client); + qemu_co_mutex_unlock(&client->send_lock); + return rc; +} + +static int nbd_co_receive_request(NBDRequest *req, struct nbd_request *request) +{ + NBDClient *client = req->client; + int csock = client->sock; + int rc; + + client->recv_coroutine = qemu_coroutine_self(); + if (nbd_receive_request(csock, request) == -1) { + rc = -EIO; + goto out; + } + + if (request->len > NBD_BUFFER_SIZE) { LOG("len (%u) is larger than max len (%u)", - request.len + NBD_REPLY_SIZE, data_size); - errno = EINVAL; - return -1; + request->len, NBD_BUFFER_SIZE); + rc = -EINVAL; + goto out; } - if ((request.from + request.len) < request.from) { + if ((request->from + request->len) < request->from) { LOG("integer overflow detected! " "you're probably being attacked"); - errno = EINVAL; - return -1; + rc = -EINVAL; + goto out; } - if ((request.from + request.len) > size) { - LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 - ", Offset: %" PRIu64 "\n", - request.from, request.len, (uint64_t)size, dev_offset); - LOG("requested operation past EOF--bad client?"); - errno = EINVAL; - return -1; + TRACE("Decoding type"); + + if ((request->type & NBD_CMD_MASK_COMMAND) == NBD_CMD_WRITE) { + TRACE("Reading %u byte(s)", request->len); + + if (qemu_co_recv(csock, req->data, request->len) != request->len) { + LOG("reading from socket failed"); + rc = -EIO; + goto out; + } } + rc = 0; - TRACE("Decoding type"); +out: + client->recv_coroutine = NULL; + return rc; +} + +static void nbd_trip(void *opaque) +{ + NBDClient *client = opaque; + NBDRequest *req = nbd_request_get(client); + NBDExport *exp = client->exp; + struct nbd_request request; + struct nbd_reply reply; + int ret; + + TRACE("Reading request."); + + ret = nbd_co_receive_request(req, &request); + if (ret == -EIO) { + goto out; + } reply.handle = request.handle; reply.error = 0; - switch (request.type) { + if (ret < 0) { + reply.error = -ret; + goto error_reply; + } + + if ((request.from + request.len) > exp->size) { + LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64 + ", Offset: %" PRIu64 "\n", + request.from, request.len, + (uint64_t)exp->size, exp->dev_offset); + LOG("requested operation past EOF--bad client?"); + goto invalid_request; + } + + switch (request.type & NBD_CMD_MASK_COMMAND) { case NBD_CMD_READ: TRACE("Request type is READ"); - if (bdrv_read(bs, (request.from + dev_offset) / 512, - data + NBD_REPLY_SIZE, - request.len / 512) == -1) { + ret = bdrv_read(exp->bs, (request.from + exp->dev_offset) / 512, + req->data, request.len / 512); + if (ret < 0) { LOG("reading from file failed"); - errno = EINVAL; - return -1; + reply.error = -ret; + goto error_reply; } - *offset += request.len; TRACE("Read %u byte(s)", request.len); - - /* Reply - [ 0 .. 3] magic (NBD_REPLY_MAGIC) - [ 4 .. 7] error (0 == no error) - [ 7 .. 15] handle - */ - - cpu_to_be32w((uint32_t*)data, NBD_REPLY_MAGIC); - cpu_to_be32w((uint32_t*)(data + 4), reply.error); - cpu_to_be64w((uint64_t*)(data + 8), reply.handle); - - TRACE("Sending data to client"); - - if (write_sync(csock, data, - request.len + NBD_REPLY_SIZE) != - request.len + NBD_REPLY_SIZE) { - LOG("writing to socket failed"); - errno = EINVAL; - return -1; - } + if (nbd_co_send_reply(req, &reply, request.len) < 0) + goto out; break; case NBD_CMD_WRITE: TRACE("Request type is WRITE"); - TRACE("Reading %u byte(s)", request.len); - - if (read_sync(csock, data, request.len) != request.len) { - LOG("reading from socket failed"); - errno = EINVAL; - return -1; + if (exp->nbdflags & NBD_FLAG_READ_ONLY) { + TRACE("Server is read-only, return error"); + reply.error = EROFS; + goto error_reply; } - if (nbdflags & NBD_FLAG_READ_ONLY) { - TRACE("Server is read-only, return error"); - reply.error = 1; - } else { - TRACE("Writing to device"); + TRACE("Writing to device"); - if (bdrv_write(bs, (request.from + dev_offset) / 512, - data, request.len / 512) == -1) { - LOG("writing to file failed"); - errno = EINVAL; - return -1; - } + ret = bdrv_write(exp->bs, (request.from + exp->dev_offset) / 512, + req->data, request.len / 512); + if (ret < 0) { + LOG("writing to file failed"); + reply.error = -ret; + goto error_reply; + } - *offset += request.len; + 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; + } } - if (nbd_send_reply(csock, &reply) == -1) - return -1; + if (nbd_co_send_reply(req, &reply, 0) < 0) + goto out; break; case NBD_CMD_DISC: TRACE("Request type is DISCONNECT"); errno = 0; - return 1; + goto out; + case NBD_CMD_FLUSH: + TRACE("Request type is FLUSH"); + + ret = bdrv_co_flush(exp->bs); + if (ret < 0) { + LOG("flush failed"); + reply.error = -ret; + } + + if (nbd_co_send_reply(req, &reply, 0) < 0) + goto out; + break; + case NBD_CMD_TRIM: + TRACE("Request type is TRIM"); + ret = bdrv_co_discard(exp->bs, (request.from + exp->dev_offset) / 512, + request.len / 512); + if (ret < 0) { + LOG("discard failed"); + reply.error = -ret; + } + if (nbd_co_send_reply(req, &reply, 0) < 0) + goto out; + break; default: LOG("invalid request type (%u) received", request.type); - errno = EINVAL; - return -1; + invalid_request: + reply.error = -EINVAL; + error_reply: + if (nbd_co_send_reply(req, &reply, 0) == -1) + goto out; + break; } TRACE("Request/Reply complete"); - return 0; + nbd_request_put(req); + return; + +out: + nbd_request_put(req); + nbd_client_close(client); +} + +static int nbd_can_read(void *opaque) +{ + NBDClient *client = opaque; + + return client->recv_coroutine || client->nb_requests < MAX_NBD_REQUESTS; +} + +static void nbd_read(void *opaque) +{ + NBDClient *client = opaque; + + if (client->recv_coroutine) { + qemu_coroutine_enter(client->recv_coroutine, NULL); + } else { + qemu_coroutine_enter(qemu_coroutine_create(nbd_trip), client); + } +} + +static void nbd_restart_write(void *opaque) +{ + NBDClient *client = opaque; + + qemu_coroutine_enter(client->send_coroutine, NULL); +} + +NBDClient *nbd_client_new(NBDExport *exp, int csock, + void (*close)(NBDClient *)) +{ + NBDClient *client; + if (nbd_send_negotiate(csock, exp->size, exp->nbdflags) == -1) { + return NULL; + } + client = g_malloc0(sizeof(NBDClient)); + client->refcount = 1; + client->exp = exp; + client->sock = csock; + client->close = close; + qemu_co_mutex_init(&client->send_lock); + qemu_set_fd_handler2(csock, nbd_can_read, nbd_read, NULL, client); + return client; } @@ -57,6 +57,8 @@ enum { #define NBD_DEFAULT_PORT 10809 +#define NBD_BUFFER_SIZE (1024*1024) + size_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); @@ -65,15 +67,21 @@ int tcp_socket_incoming_spec(const char *address_and_port); int unix_socket_outgoing(const char *path); int unix_socket_incoming(const char *path); -int nbd_negotiate(int csock, off_t size, uint32_t flags); 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); -int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset, - off_t *offset, uint32_t nbdflags, uint8_t *data, int data_size); int nbd_client(int fd); int nbd_disconnect(int fd); +typedef struct NBDExport NBDExport; +typedef struct NBDClient NBDClient; + +NBDExport *nbd_export_new(BlockDriverState *bs, off_t dev_offset, + off_t size, uint32_t nbdflags); +void nbd_export_close(NBDExport *exp); +NBDClient *nbd_client_new(NBDExport *exp, int csock, + void (*close)(NBDClient *)); + #endif diff --git a/net/dump.c b/net/dump.c index 0d0cbb2591..4b48d48408 100644 --- a/net/dump.c +++ b/net/dump.c @@ -30,6 +30,7 @@ typedef struct DumpState { VLANClientState nc; + int64_t start_ts; int fd; int pcap_caplen; } DumpState; @@ -70,7 +71,7 @@ static ssize_t dump_receive(VLANClientState *nc, const uint8_t *buf, size_t size ts = muldiv64(qemu_get_clock_ns(vm_clock), 1000000, get_ticks_per_sec()); caplen = size > s->pcap_caplen ? s->pcap_caplen : size; - hdr.ts.tv_sec = ts / 1000000; + hdr.ts.tv_sec = ts / 1000000 + s->start_ts; hdr.ts.tv_usec = ts % 1000000; hdr.caplen = caplen; hdr.len = size; @@ -104,9 +105,10 @@ static int net_dump_init(VLANState *vlan, const char *device, struct pcap_file_hdr hdr; VLANClientState *nc; DumpState *s; + struct tm tm; int fd; - fd = open(filename, O_CREAT | O_WRONLY | O_BINARY, 0644); + fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644); if (fd < 0) { error_report("-net dump: can't open %s", filename); return -1; @@ -136,6 +138,9 @@ static int net_dump_init(VLANState *vlan, const char *device, s->fd = fd; s->pcap_caplen = len; + qemu_get_timedate(&tm, 0); + s->start_ts = mktime(&tm); + return 0; } diff --git a/os-posix.c b/os-posix.c index dc4a6bb3ff..5c437ca12c 100644 --- a/os-posix.c +++ b/os-posix.c @@ -42,11 +42,6 @@ #ifdef CONFIG_LINUX #include <sys/prctl.h> -#include <sys/syscall.h> -#endif - -#ifdef CONFIG_EVENTFD -#include <sys/eventfd.h> #endif static struct passwd *user_pwd; @@ -333,34 +328,6 @@ void os_set_line_buffering(void) setvbuf(stdout, NULL, _IOLBF, 0); } -/* - * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set. - */ -int qemu_eventfd(int fds[2]) -{ -#ifdef CONFIG_EVENTFD - int ret; - - ret = eventfd(0, 0); - if (ret >= 0) { - fds[0] = ret; - qemu_set_cloexec(ret); - if ((fds[1] = dup(ret)) == -1) { - close(ret); - return -1; - } - qemu_set_cloexec(fds[1]); - return 0; - } - - if (errno != ENOSYS) { - return -1; - } -#endif - - return qemu_pipe(fds); -} - int qemu_create_pidfile(const char *filename) { char buffer[128]; @@ -384,12 +351,3 @@ int qemu_create_pidfile(const char *filename) close(fd); return 0; } - -int qemu_get_thread_id(void) -{ -#if defined (__linux__) - return syscall(SYS_gettid); -#else - return getpid(); -#endif -} diff --git a/os-win32.c b/os-win32.c index 8523d8d0c4..ad76370c7c 100644 --- a/os-win32.c +++ b/os-win32.c @@ -151,8 +151,3 @@ int qemu_create_pidfile(const char *filename) } return 0; } - -int qemu_get_thread_id(void) -{ - return GetCurrentThreadId(); -} @@ -48,6 +48,15 @@ extern int madvise(caddr_t, size_t, int); #include "trace.h" #include "qemu_socket.h" +int socket_set_cork(int fd, int v) +{ +#if defined(SOL_TCP) && defined(TCP_CORK) + return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v)); +#else + return 0; +#endif +} + int qemu_madvise(void *addr, size_t len, int advice) { if (advice == QEMU_MADV_INVALID) { @@ -166,3 +175,70 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen) return ret; } + +/* + * A variant of send(2) which handles partial write. + * + * Return the number of bytes transferred, which is only + * smaller than `count' if there is an error. + * + * This function won't work with non-blocking fd's. + * Any of the possibilities with non-bloking fd's is bad: + * - return a short write (then name is wrong) + * - busy wait adding (errno == EAGAIN) to the loop + */ +ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags) +{ + ssize_t ret = 0; + ssize_t total = 0; + + while (count) { + ret = send(fd, buf, count, flags); + if (ret < 0) { + if (errno == EINTR) { + continue; + } + break; + } + + count -= ret; + buf += ret; + total += ret; + } + + return total; +} + +/* + * A variant of recv(2) which handles partial write. + * + * Return the number of bytes transferred, which is only + * smaller than `count' if there is an error. + * + * This function won't work with non-blocking fd's. + * Any of the possibilities with non-bloking fd's is bad: + * - return a short write (then name is wrong) + * - busy wait adding (errno == EAGAIN) to the loop + */ +ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags) +{ + ssize_t ret = 0; + ssize_t total = 0; + + while (count) { + ret = qemu_recv(fd, buf, count, flags); + if (ret <= 0) { + if (ret < 0 && errno == EINTR) { + continue; + } + break; + } + + count -= ret; + buf += ret; + total += ret; + } + + return total; +} + diff --git a/oslib-posix.c b/oslib-posix.c index ce755496b5..b6a3c7fc55 100644 --- a/oslib-posix.c +++ b/oslib-posix.c @@ -55,6 +55,21 @@ static int running_on_valgrind = -1; #else # define running_on_valgrind 0 #endif +#ifdef CONFIG_LINUX +#include <sys/syscall.h> +#endif +#ifdef CONFIG_EVENTFD +#include <sys/eventfd.h> +#endif + +int qemu_get_thread_id(void) +{ +#if defined(__linux__) + return syscall(SYS_gettid); +#else + return getpid(); +#endif +} int qemu_daemon(int nochdir, int noclose) { @@ -162,6 +177,34 @@ int qemu_pipe(int pipefd[2]) return ret; } +/* + * Creates an eventfd that looks like a pipe and has EFD_CLOEXEC set. + */ +int qemu_eventfd(int fds[2]) +{ +#ifdef CONFIG_EVENTFD + int ret; + + ret = eventfd(0, 0); + if (ret >= 0) { + fds[0] = ret; + fds[1] = dup(ret); + if (fds[1] == -1) { + close(ret); + return -1; + } + qemu_set_cloexec(ret); + qemu_set_cloexec(fds[1]); + return 0; + } + if (errno != ENOSYS) { + return -1; + } +#endif + + return qemu_pipe(fds); +} + int qemu_utimens(const char *path, const struct timespec *times) { struct timeval tv[2], tv_now; diff --git a/oslib-win32.c b/oslib-win32.c index 5e3de7dc8a..ce3021e6c7 100644 --- a/oslib-win32.c +++ b/oslib-win32.c @@ -118,3 +118,8 @@ int qemu_gettimeofday(qemu_timeval *tp) Do not set errno on error. */ return 0; } + +int qemu_get_thread_id(void) +{ + return GetCurrentThreadId(); +} diff --git a/qemu-common.h b/qemu-common.h index 44870fe523..6ab7dfb1b9 100644 --- a/qemu-common.h +++ b/qemu-common.h @@ -173,6 +173,10 @@ void *qemu_oom_check(void *ptr); int qemu_open(const char *name, int flags, ...); ssize_t qemu_write_full(int fd, const void *buf, size_t count) QEMU_WARN_UNUSED_RESULT; +ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags) + QEMU_WARN_UNUSED_RESULT; +ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags) + QEMU_WARN_UNUSED_RESULT; void qemu_set_cloexec(int fd); #ifndef _WIN32 @@ -186,6 +190,9 @@ int qemu_pipe(int pipefd[2]); #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags) #endif +int qemu_recvv(int sockfd, struct iovec *iov, int len, int iov_offset); +int qemu_sendv(int sockfd, struct iovec *iov, int len, int iov_offset); + /* Error handling. */ void QEMU_NORETURN hw_error(const char *fmt, ...) GCC_FMT_ATTR(1, 2); @@ -217,6 +224,7 @@ typedef struct VLANState VLANState; typedef struct VLANClientState VLANClientState; typedef struct i2c_bus i2c_bus; typedef struct i2c_slave i2c_slave; +typedef struct ISABus ISABus; typedef struct SMBusDevice SMBusDevice; typedef struct PCIHostState PCIHostState; typedef struct PCIExpressHost PCIExpressHost; @@ -271,6 +279,33 @@ struct qemu_work_item { void qemu_init_vcpu(void *env); #endif +/** + * Sends an iovec (or optionally a part of it) down a socket, yielding + * when the socket is full. + */ +int qemu_co_sendv(int sockfd, struct iovec *iov, + int len, int iov_offset); + +/** + * Receives data into an iovec (or optionally into a part of it) from + * a socket, yielding when there is no data in the socket. + */ +int qemu_co_recvv(int sockfd, struct iovec *iov, + int len, int iov_offset); + + +/** + * Sends a buffer down a socket, yielding when the socket is full. + */ +int qemu_co_send(int sockfd, void *buf, int len); + +/** + * Receives data into a buffer from a socket, yielding when there + * is no data in the socket. + */ +int qemu_co_recv(int sockfd, void *buf, int len); + + typedef struct QEMUIOVector { struct iovec *iov; int niov; diff --git a/qemu-coroutine-io.c b/qemu-coroutine-io.c new file mode 100644 index 0000000000..40fd514395 --- /dev/null +++ b/qemu-coroutine-io.c @@ -0,0 +1,96 @@ +/* + * Coroutine-aware I/O functions + * + * Copyright (C) 2009-2010 Nippon Telegraph and Telephone Corporation. + * Copyright (c) 2011, Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "qemu-common.h" +#include "qemu_socket.h" +#include "qemu-coroutine.h" + +int coroutine_fn qemu_co_recvv(int sockfd, struct iovec *iov, + int len, int iov_offset) +{ + int total = 0; + int ret; + while (len) { + ret = qemu_recvv(sockfd, iov, len, iov_offset + total); + if (ret < 0) { + if (errno == EAGAIN) { + qemu_coroutine_yield(); + continue; + } + if (total == 0) { + total = -1; + } + break; + } + if (ret == 0) { + break; + } + total += ret, len -= ret; + } + + return total; +} + +int coroutine_fn qemu_co_sendv(int sockfd, struct iovec *iov, + int len, int iov_offset) +{ + int total = 0; + int ret; + while (len) { + ret = qemu_sendv(sockfd, iov, len, iov_offset + total); + if (ret < 0) { + if (errno == EAGAIN) { + qemu_coroutine_yield(); + continue; + } + if (total == 0) { + total = -1; + } + break; + } + total += ret, len -= ret; + } + + return total; +} + +int coroutine_fn qemu_co_recv(int sockfd, void *buf, int len) +{ + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = len; + + return qemu_co_recvv(sockfd, &iov, len, 0); +} + +int coroutine_fn qemu_co_send(int sockfd, void *buf, int len) +{ + struct iovec iov; + + iov.iov_base = buf; + iov.iov_len = len; + + return qemu_co_sendv(sockfd, &iov, len, 0); +} diff --git a/qemu-nbd.c b/qemu-nbd.c index 291cba2eaa..155b05840b 100644 --- a/qemu-nbd.c +++ b/qemu-nbd.c @@ -35,13 +35,15 @@ #define SOCKET_PATH "/var/lock/qemu-nbd-%s" -#define NBD_BUFFER_SIZE (1024*1024) - -static int sigterm_wfd; +static NBDExport *exp; static int verbose; static char *device; static char *srcpath; static char *sockpath; +static bool sigterm_reported; +static bool nbd_started; +static int shared = 1; +static int nb_fds; static void usage(const char *name) { @@ -170,10 +172,8 @@ static int find_partition(BlockDriverState *bs, int partition, static void termsig_handler(int signum) { - static int sigterm_reported; - if (!sigterm_reported) { - sigterm_reported = (write(sigterm_wfd, "", 1) == 1); - } + sigterm_reported = true; + qemu_notify_event(); } static void *show_parts(void *arg) @@ -244,17 +244,38 @@ out: return (void *) EXIT_FAILURE; } +static int nbd_can_accept(void *opaque) +{ + return nb_fds < shared; +} + +static void nbd_client_closed(NBDClient *client) +{ + nb_fds--; + qemu_notify_event(); +} + +static void nbd_accept(void *opaque) +{ + int server_fd = (uintptr_t) opaque; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + + int fd = accept(server_fd, (struct sockaddr *)&addr, &addr_len); + nbd_started = true; + if (fd != -1 && nbd_client_new(exp, fd, nbd_client_closed)) { + nb_fds++; + } +} + int main(int argc, char **argv) { BlockDriverState *bs; off_t dev_offset = 0; - off_t offset = 0; uint32_t nbdflags = 0; bool disconnect = false; const char *bindto = "0.0.0.0"; int port = NBD_DEFAULT_PORT; - struct sockaddr_in addr; - socklen_t addr_len = sizeof(addr); off_t fd_size; const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t"; struct option lopt[] = { @@ -282,14 +303,7 @@ int main(int argc, char **argv) int flags = BDRV_O_RDWR; int partition = -1; int ret; - int shared = 1; - uint8_t *data; - fd_set fds; - int *sharing_fds; int fd; - int i; - int nb_fds = 0; - int max_fd; int persistent = 0; pthread_t client_thread; @@ -297,12 +311,6 @@ int main(int argc, char **argv) * handler ensures that "qemu-nbd -v -c" exits with a nice status code. */ struct sigaction sa_sigterm; - int sigterm_fd[2]; - if (qemu_pipe(sigterm_fd) == -1) { - err(EXIT_FAILURE, "Error setting up communication pipe"); - } - - sigterm_wfd = sigterm_fd[1]; memset(&sa_sigterm, 0, sizeof(sa_sigterm)); sa_sigterm.sa_handler = termsig_handler; sigaction(SIGTERM, &sa_sigterm, NULL); @@ -492,16 +500,17 @@ int main(int argc, char **argv) err(EXIT_FAILURE, "Could not find partition %d", partition); } - sharing_fds = g_malloc((shared + 1) * sizeof(int)); + exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags); if (sockpath) { - sharing_fds[0] = unix_socket_incoming(sockpath); + fd = unix_socket_incoming(sockpath); } else { - sharing_fds[0] = tcp_socket_incoming(bindto, port); + fd = tcp_socket_incoming(bindto, port); } - if (sharing_fds[0] == -1) + if (fd == -1) { return 1; + } if (device) { int ret; @@ -516,60 +525,15 @@ int main(int argc, char **argv) memset(&client_thread, 0, sizeof(client_thread)); } - max_fd = sharing_fds[0]; - nb_fds++; - - data = qemu_blockalign(bs, NBD_BUFFER_SIZE); - if (data == NULL) { - errx(EXIT_FAILURE, "Cannot allocate data buffer"); - } + qemu_init_main_loop(); + qemu_set_fd_handler2(fd, nbd_can_accept, nbd_accept, NULL, + (void *)(uintptr_t)fd); do { - FD_ZERO(&fds); - FD_SET(sigterm_fd[0], &fds); - for (i = 0; i < nb_fds; i++) - FD_SET(sharing_fds[i], &fds); - - do { - ret = select(max_fd + 1, &fds, NULL, NULL, NULL); - } while (ret == -1 && errno == EINTR); - if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) { - break; - } - - if (FD_ISSET(sharing_fds[0], &fds)) - ret--; - for (i = 1; i < nb_fds && ret; i++) { - if (FD_ISSET(sharing_fds[i], &fds)) { - if (nbd_trip(bs, sharing_fds[i], fd_size, dev_offset, - &offset, nbdflags, data, NBD_BUFFER_SIZE) != 0) { - close(sharing_fds[i]); - nb_fds--; - sharing_fds[i] = sharing_fds[nb_fds]; - i--; - } - ret--; - } - } - /* new connection ? */ - if (FD_ISSET(sharing_fds[0], &fds)) { - if (nb_fds < shared + 1) { - sharing_fds[nb_fds] = accept(sharing_fds[0], - (struct sockaddr *)&addr, - &addr_len); - if (sharing_fds[nb_fds] != -1 && - nbd_negotiate(sharing_fds[nb_fds], fd_size, nbdflags) != -1) { - if (sharing_fds[nb_fds] > max_fd) - max_fd = sharing_fds[nb_fds]; - nb_fds++; - } - } - } - } while (persistent || nb_fds > 1); - qemu_vfree(data); + main_loop_wait(false); + } while (!sigterm_reported && (persistent || !nbd_started || nb_fds > 0)); - close(sharing_fds[0]); - g_free(sharing_fds); + nbd_export_close(exp); if (sockpath) { unlink(sockpath); } diff --git a/qemu-tool.c b/qemu-tool.c index 5df7279745..226b6e890e 100644 --- a/qemu-tool.c +++ b/qemu-tool.c @@ -16,12 +16,12 @@ #include "qemu-timer.h" #include "qemu-log.h" #include "migration.h" +#include "main-loop.h" +#include "qemu_socket.h" +#include "slirp/libslirp.h" #include <sys/time.h> -QEMUClock *rt_clock; -QEMUClock *vm_clock; - FILE *logfile; struct QEMUBH @@ -57,41 +57,45 @@ void monitor_protocol_event(MonitorEvent event, QObject *data) { } -int qemu_set_fd_handler2(int fd, - IOCanReadHandler *fd_read_poll, - IOHandler *fd_read, - IOHandler *fd_write, - void *opaque) +int64 cpu_get_clock(void) { - return 0; + abort(); } -void qemu_notify_event(void) +int64 cpu_get_icount(void) { + abort(); } -QEMUTimer *qemu_new_timer(QEMUClock *clock, int scale, - QEMUTimerCB *cb, void *opaque) +void qemu_mutex_lock_iothread(void) { - return g_malloc(1); } -void qemu_free_timer(QEMUTimer *ts) +void qemu_mutex_unlock_iothread(void) { - g_free(ts); } -void qemu_del_timer(QEMUTimer *ts) +int use_icount; + +void qemu_clock_warp(QEMUClock *clock) { } -void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time) +static void __attribute__((constructor)) init_main_loop(void) { + init_clocks(); + init_timer_alarm(); + qemu_clock_enable(vm_clock, false); } -int64_t qemu_get_clock_ns(QEMUClock *clock) +void slirp_select_fill(int *pnfds, fd_set *readfds, + fd_set *writefds, fd_set *xfds) +{ +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, + fd_set *xfds, int select_error) { - return 0; } void migrate_add_blocker(Error *reason) diff --git a/qemu_socket.h b/qemu_socket.h index 9e32fac651..fe4cf6ca61 100644 --- a/qemu_socket.h +++ b/qemu_socket.h @@ -35,6 +35,7 @@ int inet_aton(const char *cp, struct in_addr *ia); /* misc helpers */ int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int socket_set_cork(int fd, int v); void socket_set_block(int fd); void socket_set_nonblock(int fd); int send_all(int fd, const void *buf, int len1); diff --git a/scripts/analyse-9p-simpletrace.py b/scripts/analyse-9p-simpletrace.py index b6d58fde96..3c3dee4337 100755 --- a/scripts/analyse-9p-simpletrace.py +++ b/scripts/analyse-9p-simpletrace.py @@ -3,15 +3,86 @@ # Usage: ./analyse-9p-simpletrace <trace-events> <trace-pid> # # Author: Harsh Prateek Bora - +import os import simpletrace +symbol_9p = { + 6 : 'TLERROR', + 7 : 'RLERROR', + 8 : 'TSTATFS', + 9 : 'RSTATFS', + 12 : 'TLOPEN', + 13 : 'RLOPEN', + 14 : 'TLCREATE', + 15 : 'RLCREATE', + 16 : 'TSYMLINK', + 17 : 'RSYMLINK', + 18 : 'TMKNOD', + 19 : 'RMKNOD', + 20 : 'TRENAME', + 21 : 'RRENAME', + 22 : 'TREADLINK', + 23 : 'RREADLINK', + 24 : 'TGETATTR', + 25 : 'RGETATTR', + 26 : 'TSETATTR', + 27 : 'RSETATTR', + 30 : 'TXATTRWALK', + 31 : 'RXATTRWALK', + 32 : 'TXATTRCREATE', + 33 : 'RXATTRCREATE', + 40 : 'TREADDIR', + 41 : 'RREADDIR', + 50 : 'TFSYNC', + 51 : 'RFSYNC', + 52 : 'TLOCK', + 53 : 'RLOCK', + 54 : 'TGETLOCK', + 55 : 'RGETLOCK', + 70 : 'TLINK', + 71 : 'RLINK', + 72 : 'TMKDIR', + 73 : 'RMKDIR', + 74 : 'TRENAMEAT', + 75 : 'RRENAMEAT', + 76 : 'TUNLINKAT', + 77 : 'RUNLINKAT', + 100 : 'TVERSION', + 101 : 'RVERSION', + 102 : 'TAUTH', + 103 : 'RAUTH', + 104 : 'TATTACH', + 105 : 'RATTACH', + 106 : 'TERROR', + 107 : 'RERROR', + 108 : 'TFLUSH', + 109 : 'RFLUSH', + 110 : 'TWALK', + 111 : 'RWALK', + 112 : 'TOPEN', + 113 : 'ROPEN', + 114 : 'TCREATE', + 115 : 'RCREATE', + 116 : 'TREAD', + 117 : 'RREAD', + 118 : 'TWRITE', + 119 : 'RWRITE', + 120 : 'TCLUNK', + 121 : 'RCLUNK', + 122 : 'TREMOVE', + 123 : 'RREMOVE', + 124 : 'TSTAT', + 125 : 'RSTAT', + 126 : 'TWSTAT', + 127 : 'RWSTAT' +} + class VirtFSRequestTracker(simpletrace.Analyzer): def begin(self): print "Pretty printing 9p simpletrace log ..." def v9fs_rerror(self, tag, id, err): - print "RERROR (tag =", tag, ", id =", id, ",err =", err, ")" + print "RERROR (tag =", tag, ", id =", symbol_9p[id], ", err = \"", os.strerror(err), "\")" def v9fs_version(self, tag, id, msize, version): print "TVERSION (tag =", tag, ", msize =", msize, ", version =", version, ")" diff --git a/scripts/qapi-commands.py b/scripts/qapi-commands.py index 54d1f5d659..bd7b207122 100644 --- a/scripts/qapi-commands.py +++ b/scripts/qapi-commands.py @@ -372,7 +372,9 @@ def gen_command_def_prologue(prefix="", proxy=False): try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:m", ["prefix=", "output-dir=", "type=", "middle"]) + opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:m", + ["source", "header", "prefix=", + "output-dir=", "type=", "middle"]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -384,6 +386,9 @@ c_file = 'qmp-marshal.c' h_file = 'qmp-commands.h' middle_mode = False +do_c = False +do_h = False + for o, a in opts: if o in ("-p", "--prefix"): prefix = a @@ -393,10 +398,29 @@ for o, a in opts: dispatch_type = a elif o in ("-m", "--middle"): middle_mode = True + elif o in ("-c", "--source"): + do_h = True + elif o in ("-h", "--header"): + do_c = True + +if not do_c and not do_h: + do_c = True + do_h = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file +def maybe_open(really, name, opt): + class Null(object): + def write(self, str): + pass + def read(self): + return '' + if really: + return open(name, opt) + else: + return Null() + try: os.makedirs(output_dir) except os.error, e: @@ -408,8 +432,8 @@ commands = filter(lambda expr: expr.has_key('command'), exprs) commands = filter(lambda expr: not expr.has_key('gen'), commands) if dispatch_type == "sync": - fdecl = open(h_file, 'w') - fdef = open(c_file, 'w') + fdecl = maybe_open(do_h, h_file, 'w') + fdef = maybe_open(do_c, c_file, 'w') ret = gen_command_decl_prologue(header=basename(h_file), guard=guardname(h_file), prefix=prefix) fdecl.write(ret) ret = gen_command_def_prologue(prefix=prefix) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 267cb49b13..ae644bc06f 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -163,7 +163,8 @@ void qapi_free_%(type)s(%(c_type)s obj) try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="]) + opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", + ["source", "header", "prefix=", "output-dir="]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -173,11 +174,22 @@ prefix = "" c_file = 'qapi-types.c' h_file = 'qapi-types.h' +do_c = False +do_h = False + for o, a in opts: if o in ("-p", "--prefix"): prefix = a elif o in ("-o", "--output-dir"): output_dir = a + "/" + elif o in ("-c", "--source"): + do_h = True + elif o in ("-h", "--header"): + do_c = True + +if not do_c and not do_h: + do_c = True + do_h = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file @@ -188,8 +200,17 @@ except os.error, e: if e.errno != errno.EEXIST: raise -fdef = open(c_file, 'w') -fdecl = open(h_file, 'w') +def maybe_open(really, name, opt): + class Null(object): + def write(self, str): + pass + def read(self): + return '' + if really: + return open(name, opt) + +fdef = maybe_open(do_c, c_file, 'w') +fdecl = maybe_open(do_h, h_file, 'w') fdef.write(mcgen(''' /* AUTOMATICALLY GENERATED, DO NOT MODIFY */ diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 62de83d0f0..e9d0584c78 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -139,7 +139,8 @@ void visit_type_%(name)s(Visitor *m, %(name)s * obj, const char *name, Error **e name=name) try: - opts, args = getopt.gnu_getopt(sys.argv[1:], "p:o:", ["prefix=", "output-dir="]) + opts, args = getopt.gnu_getopt(sys.argv[1:], "chp:o:", + ["source", "header", "prefix=", "output-dir="]) except getopt.GetoptError, err: print str(err) sys.exit(1) @@ -149,11 +150,22 @@ prefix = "" c_file = 'qapi-visit.c' h_file = 'qapi-visit.h' +do_c = False +do_h = False + for o, a in opts: if o in ("-p", "--prefix"): prefix = a elif o in ("-o", "--output-dir"): output_dir = a + "/" + elif o in ("-c", "--source"): + do_h = True + elif o in ("-h", "--header"): + do_c = True + +if not do_c and not do_h: + do_c = True + do_h = True c_file = output_dir + prefix + c_file h_file = output_dir + prefix + h_file @@ -164,8 +176,17 @@ except os.error, e: if e.errno != errno.EEXIST: raise -fdef = open(c_file, 'w') -fdecl = open(h_file, 'w') +def maybe_open(really, name, opt): + class Null(object): + def write(self, str): + pass + def read(self): + return '' + if really: + return open(name, opt) + +fdef = maybe_open(do_c, c_file, 'w') +fdecl = maybe_open(do_h, h_file, 'w') fdef.write(mcgen(''' /* THIS FILE IS AUTOMATICALLY GENERATED, DO NOT MODIFY */ diff --git a/target-i386/cpu.h b/target-i386/cpu.h index a08ce9d873..37dde79581 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -751,7 +751,8 @@ typedef struct CPUX86State { uint32_t cpuid_svm_features; bool tsc_valid; int tsc_khz; - + void *kvm_xsave_buf; + /* in order to simplify APIC support, we leave this pointer to the user */ struct DeviceState *apic_state; diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c index 0b3af9060c..91a104ba0b 100644 --- a/target-i386/cpuid.c +++ b/target-i386/cpuid.c @@ -1180,10 +1180,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, break; case 0xA: /* Architectural Performance Monitoring Leaf */ - *eax = 0; - *ebx = 0; - *ecx = 0; - *edx = 0; + if (kvm_enabled()) { + KVMState *s = env->kvm_state; + + *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); + *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); + *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); + *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); + } else { + *eax = 0; + *ebx = 0; + *ecx = 0; + *edx = 0; + } break; case 0xD: /* Processor Extended State */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 74d81efbd1..04e65c5ea1 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -515,6 +515,10 @@ int kvm_arch_init_vcpu(CPUState *env) } } + if (kvm_has_xsave()) { + env->kvm_xsave_buf = qemu_memalign(4096, sizeof(struct kvm_xsave)); + } + return 0; } @@ -758,6 +762,8 @@ static int kvm_put_fpu(CPUState *env) return kvm_vcpu_ioctl(env, KVM_SET_FPU, &fpu); } +#define XSAVE_FCW_FSW 0 +#define XSAVE_FTW_FOP 1 #define XSAVE_CWD_RIP 2 #define XSAVE_CWD_RDP 4 #define XSAVE_MXCSR 6 @@ -768,15 +774,14 @@ static int kvm_put_fpu(CPUState *env) static int kvm_put_xsave(CPUState *env) { - int i, r; - struct kvm_xsave* xsave; + struct kvm_xsave* xsave = env->kvm_xsave_buf; uint16_t cwd, swd, twd; + int i, r; if (!kvm_has_xsave()) { return kvm_put_fpu(env); } - xsave = qemu_memalign(4096, sizeof(struct kvm_xsave)); memset(xsave, 0, sizeof(struct kvm_xsave)); twd = 0; swd = env->fpus & ~(7 << 11); @@ -785,8 +790,8 @@ static int kvm_put_xsave(CPUState *env) for (i = 0; i < 8; ++i) { twd |= (!env->fptags[i]) << i; } - xsave->region[0] = (uint32_t)(swd << 16) + cwd; - xsave->region[1] = (uint32_t)(env->fpop << 16) + twd; + xsave->region[XSAVE_FCW_FSW] = (uint32_t)(swd << 16) + cwd; + xsave->region[XSAVE_FTW_FOP] = (uint32_t)(env->fpop << 16) + twd; memcpy(&xsave->region[XSAVE_CWD_RIP], &env->fpip, sizeof(env->fpip)); memcpy(&xsave->region[XSAVE_CWD_RDP], &env->fpdp, sizeof(env->fpdp)); memcpy(&xsave->region[XSAVE_ST_SPACE], env->fpregs, @@ -798,7 +803,6 @@ static int kvm_put_xsave(CPUState *env) memcpy(&xsave->region[XSAVE_YMMH_SPACE], env->ymmh_regs, sizeof env->ymmh_regs); r = kvm_vcpu_ioctl(env, KVM_SET_XSAVE, xsave); - g_free(xsave); return r; } @@ -975,7 +979,7 @@ static int kvm_get_fpu(CPUState *env) static int kvm_get_xsave(CPUState *env) { - struct kvm_xsave* xsave; + struct kvm_xsave* xsave = env->kvm_xsave_buf; int ret, i; uint16_t cwd, swd, twd; @@ -983,17 +987,15 @@ static int kvm_get_xsave(CPUState *env) return kvm_get_fpu(env); } - xsave = qemu_memalign(4096, sizeof(struct kvm_xsave)); ret = kvm_vcpu_ioctl(env, KVM_GET_XSAVE, xsave); if (ret < 0) { - g_free(xsave); return ret; } - cwd = (uint16_t)xsave->region[0]; - swd = (uint16_t)(xsave->region[0] >> 16); - twd = (uint16_t)xsave->region[1]; - env->fpop = (uint16_t)(xsave->region[1] >> 16); + cwd = (uint16_t)xsave->region[XSAVE_FCW_FSW]; + swd = (uint16_t)(xsave->region[XSAVE_FCW_FSW] >> 16); + twd = (uint16_t)xsave->region[XSAVE_FTW_FOP]; + env->fpop = (uint16_t)(xsave->region[XSAVE_FTW_FOP] >> 16); env->fpstt = (swd >> 11) & 7; env->fpus = swd; env->fpuc = cwd; @@ -1010,7 +1012,6 @@ static int kvm_get_xsave(CPUState *env) env->xstate_bv = *(uint64_t *)&xsave->region[XSAVE_XSTATE_BV]; memcpy(env->ymmh_regs, &xsave->region[XSAVE_YMMH_SPACE], sizeof env->ymmh_regs); - g_free(xsave); return 0; } @@ -1080,10 +1081,9 @@ static int kvm_get_sregs(CPUState *env) env->cr[3] = sregs.cr3; env->cr[4] = sregs.cr4; - cpu_set_apic_base(env->apic_state, sregs.apic_base); - env->efer = sregs.efer; - //cpu_set_apic_tpr(env->apic_state, sregs.cr8); + + /* changes to apic base and cr8/tpr are read back via kvm_arch_post_run */ #define HFLAG_COPY_MASK \ ~( HF_CPL_MASK | HF_PE_MASK | HF_MP_MASK | HF_EM_MASK | \ diff --git a/trace-events b/trace-events index 5781a69b0b..c18435bbe1 100644 --- a/trace-events +++ b/trace-events @@ -578,11 +578,11 @@ v9fs_lcreate(uint16_t tag, uint8_t id, int32_t dfid, int32_t flags, int32_t mode v9fs_lcreate_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int32_t iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" v9fs_fsync(uint16_t tag, uint8_t id, int32_t fid, int datasync) "tag %d id %d fid %d datasync %d" v9fs_clunk(uint16_t tag, uint8_t id, int32_t fid) "tag %d id %d fid %d" -v9fs_read(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t max_count) "tag %d id %d fid %d off %"PRId64" max_count %d" +v9fs_read(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t max_count) "tag %d id %d fid %d off %"PRIu64" max_count %u" v9fs_read_return(uint16_t tag, uint8_t id, int32_t count, ssize_t err) "tag %d id %d count %d err %zd" -v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, int64_t offset, int32_t max_count) "tag %d id %d fid %d offset %"PRId64" max_count %d" -v9fs_readdir_return(uint16_t tag, uint8_t id, int32_t count, ssize_t retval) "tag %d id %d count %d retval %zd" -v9fs_write(uint16_t tag, uint8_t id, int32_t fid, int64_t off, int32_t count, int cnt) "tag %d id %d fid %d off %"PRId64" count %d cnt %d" +v9fs_readdir(uint16_t tag, uint8_t id, int32_t fid, uint64_t offset, uint32_t max_count) "tag %d id %d fid %d offset %"PRIu64" max_count %u" +v9fs_readdir_return(uint16_t tag, uint8_t id, uint32_t count, ssize_t retval) "tag %d id %d count %u retval %zd" +v9fs_write(uint16_t tag, uint8_t id, int32_t fid, uint64_t off, uint32_t count, int cnt) "tag %d id %d fid %d off %"PRIu64" count %u cnt %d" v9fs_write_return(uint16_t tag, uint8_t id, int32_t total, ssize_t err) "tag %d id %d total %d err %zd" v9fs_create(uint16_t tag, uint8_t id, int32_t fid, char* name, int32_t perm, int8_t mode) "tag %d id %d fid %d name %s perm %d mode %d" v9fs_create_return(uint16_t tag, uint8_t id, int8_t type, int32_t version, int64_t path, int iounit) "tag %d id %d qid={type %d version %d path %"PRId64"} iounit %d" diff --git a/trace/simple.c b/trace/simple.c index 6339152d27..bbc99302b9 100644 --- a/trace/simple.c +++ b/trace/simple.c @@ -376,7 +376,12 @@ bool trace_backend_init(const char *events, const char *file) GThread *thread; if (!g_thread_supported()) { +#if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); +#else + fprintf(stderr, "glib threading failed to initialize.\n"); + exit(1); +#endif } trace_available_cond = g_cond_new(); @@ -2176,7 +2176,12 @@ int main(int argc, char **argv, char **envp) g_mem_set_vtable(&mem_trace); if (!g_thread_supported()) { +#if !GLIB_CHECK_VERSION(2, 31, 0) g_thread_init(NULL); +#else + fprintf(stderr, "glib threading failed to initialize.\n"); + exit(1); +#endif } runstate_init(); @@ -3300,7 +3305,7 @@ int main(int argc, char **argv, char **envp) * real machines which also use this scheme. */ if (i == nb_numa_nodes) { - for (i = 0; i < smp_cpus; i++) { + for (i = 0; i < max_cpus; i++) { node_cpumask[i % nb_numa_nodes] |= 1 << i; } } @@ -3335,6 +3340,8 @@ int main(int argc, char **argv, char **envp) } qemu_add_globals(); + qdev_machine_init(); + machine->init(ram_size, boot_devices, kernel_filename, kernel_cmdline, initrd_filename, cpu_model); |