aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2011-04-07 09:56:09 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2011-04-07 09:56:09 -0500
commitf124a410ea12a644c3577c5303846c37baa5e819 (patch)
treeb1deb798b7ff6dc9ea95968f4aa5a96c8358ec61
parente54f17713f638189e79dac5ba0aa0ce606788777 (diff)
parent52c050236eaa4f0b5e1d160cd66dc18106445c4d (diff)
downloadqemu-f124a410ea12a644c3577c5303846c37baa5e819.zip
qemu-f124a410ea12a644c3577c5303846c37baa5e819.tar.gz
qemu-f124a410ea12a644c3577c5303846c37baa5e819.tar.bz2
Merge remote branch 'kwolf/for-anthony' into staging
-rw-r--r--Makefile.objs4
-rw-r--r--block-migration.c2
-rw-r--r--block.c28
-rw-r--r--block.h1
-rw-r--r--block/nbd.c157
-rw-r--r--blockdev.c25
-rw-r--r--hw/fdc.c51
-rw-r--r--hw/ide.h3
-rw-r--r--hw/ide/core.c14
-rw-r--r--hw/mips_fulong2e.c9
-rw-r--r--hw/mips_malta.c10
-rw-r--r--hw/mips_r4k.c10
-rw-r--r--hw/pc_piix.c10
-rw-r--r--hw/ppc_newworld.c11
-rw-r--r--hw/ppc_oldworld.c11
-rw-r--r--hw/ppc_prep.c10
-rw-r--r--hw/sun4u.c9
-rw-r--r--hw/virtio-blk.c8
-rw-r--r--hw/xen_disk.c10
-rw-r--r--nbd.c993
-rw-r--r--nbd.h9
-rw-r--r--qemu-common.h4
-rw-r--r--qemu-img-cmds.hx4
-rw-r--r--qemu-img.c46
-rw-r--r--qemu-progress.c89
-rw-r--r--qemu-sockets.c4
-rw-r--r--trace-events1
-rw-r--r--vl.c4
28 files changed, 825 insertions, 712 deletions
diff --git a/Makefile.objs b/Makefile.objs
index c05f5e5..44ce368 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -14,7 +14,7 @@ oslib-obj-$(CONFIG_POSIX) += oslib-posix.o
# block-obj-y is code used by both qemu system emulation and qemu-img
block-obj-y = cutils.o cache-utils.o qemu-malloc.o qemu-option.o module.o async.o
-block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o
+block-obj-y += nbd.o block.o aio.o aes.o qemu-config.o qemu-progress.o qemu-sockets.o
block-obj-$(CONFIG_POSIX) += posix-aio-compat.o
block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o
@@ -94,7 +94,7 @@ common-obj-$(CONFIG_SSI_SD) += ssi-sd.o
common-obj-$(CONFIG_SD) += sd.o
common-obj-y += bt.o bt-host.o bt-vhci.o bt-l2cap.o bt-sdp.o bt-hci.o bt-hid.o usb-bt.o
common-obj-y += bt-hci-csr.o
-common-obj-y += buffered_file.o migration.o migration-tcp.o qemu-sockets.o
+common-obj-y += buffered_file.o migration.o migration-tcp.o
common-obj-y += qemu-char.o savevm.o #aio.o
common-obj-y += msmouse.o ps2.o
common-obj-y += qdev.o qdev-properties.o
diff --git a/block-migration.c b/block-migration.c
index 8218bac..576e55a 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -140,7 +140,7 @@ static inline void add_avg_read_time(int64_t time)
static inline long double compute_read_bwidth(void)
{
assert(block_mig_state.total_time != 0);
- return (block_mig_state.reads * BLOCK_SIZE)/ block_mig_state.total_time;
+ return (block_mig_state.reads / block_mig_state.total_time) * BLOCK_SIZE;
}
static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
diff --git a/block.c b/block.c
index c8e2f97..f731c7a 100644
--- a/block.c
+++ b/block.c
@@ -697,14 +697,22 @@ void bdrv_close_all(void)
}
}
+/* make a BlockDriverState anonymous by removing from bdrv_state list.
+ Also, NULL terminate the device_name to prevent double remove */
+void bdrv_make_anon(BlockDriverState *bs)
+{
+ if (bs->device_name[0] != '\0') {
+ QTAILQ_REMOVE(&bdrv_states, bs, list);
+ }
+ bs->device_name[0] = '\0';
+}
+
void bdrv_delete(BlockDriverState *bs)
{
assert(!bs->peer);
/* remove from list, if necessary */
- if (bs->device_name[0] != '\0') {
- QTAILQ_REMOVE(&bdrv_states, bs, list);
- }
+ bdrv_make_anon(bs);
bdrv_close(bs);
if (bs->file != NULL) {
@@ -1153,14 +1161,12 @@ int64_t bdrv_getlength(BlockDriverState *bs)
if (!drv)
return -ENOMEDIUM;
- /* Fixed size devices use the total_sectors value for speed instead of
- issuing a length query (like lseek) on each call. Also, legacy block
- drivers don't provide a bdrv_getlength function and must use
- total_sectors. */
- if (!bs->growable || !drv->bdrv_getlength) {
- return bs->total_sectors * BDRV_SECTOR_SIZE;
+ if (bs->growable || bs->removable) {
+ if (drv->bdrv_getlength) {
+ return drv->bdrv_getlength(bs);
+ }
}
- return drv->bdrv_getlength(bs);
+ return bs->total_sectors * BDRV_SECTOR_SIZE;
}
/* return 0 as number of sectors if no device present or error */
@@ -2809,6 +2815,8 @@ void bdrv_set_locked(BlockDriverState *bs, int locked)
{
BlockDriver *drv = bs->drv;
+ trace_bdrv_set_locked(bs, locked);
+
bs->locked = locked;
if (drv && drv->bdrv_set_locked) {
drv->bdrv_set_locked(bs, locked);
diff --git a/block.h b/block.h
index 5d78fc0..52e9cad 100644
--- a/block.h
+++ b/block.h
@@ -66,6 +66,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
QEMUOptionParameter *options);
int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
BlockDriverState *bdrv_new(const char *device_name);
+void bdrv_make_anon(BlockDriverState *bs);
void bdrv_delete(BlockDriverState *bs);
int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags);
int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
diff --git a/block/nbd.c b/block/nbd.c
index c8dc763..1d6b225 100644
--- a/block/nbd.c
+++ b/block/nbd.c
@@ -29,96 +29,152 @@
#include "qemu-common.h"
#include "nbd.h"
#include "module.h"
+#include "qemu_socket.h"
#include <sys/types.h>
#include <unistd.h>
#define EN_OPTSTR ":exportname="
+/* #define DEBUG_NBD */
+
+#if defined(DEBUG_NBD)
+#define logout(fmt, ...) \
+ fprintf(stderr, "nbd\t%-24s" fmt, __func__, ##__VA_ARGS__)
+#else
+#define logout(fmt, ...) ((void)0)
+#endif
+
typedef struct BDRVNBDState {
int sock;
off_t size;
size_t blocksize;
+ char *export_name; /* An NBD server may export several devices */
+
+ /* If it begins with '/', this is a UNIX domain socket. Otherwise,
+ * it's a string of the form <hostname|ip4|\[ip6\]>:port
+ */
+ char *host_spec;
} BDRVNBDState;
-static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+static int nbd_config(BDRVNBDState *s, const char *filename, int flags)
{
- BDRVNBDState *s = bs->opaque;
- uint32_t nbdflags;
-
char *file;
- char *name;
- const char *host;
+ char *export_name;
+ const char *host_spec;
const char *unixpath;
- int sock;
- off_t size;
- size_t blocksize;
- int ret;
int err = -EINVAL;
file = qemu_strdup(filename);
- name = strstr(file, EN_OPTSTR);
- if (name) {
- if (name[strlen(EN_OPTSTR)] == 0) {
+ export_name = strstr(file, EN_OPTSTR);
+ if (export_name) {
+ if (export_name[strlen(EN_OPTSTR)] == 0) {
goto out;
}
- name[0] = 0;
- name += strlen(EN_OPTSTR);
+ export_name[0] = 0; /* truncate 'file' */
+ export_name += strlen(EN_OPTSTR);
+ s->export_name = qemu_strdup(export_name);
}
- if (!strstart(file, "nbd:", &host)) {
+ /* extract the host_spec - fail if it's not nbd:... */
+ if (!strstart(file, "nbd:", &host_spec)) {
goto out;
}
- if (strstart(host, "unix:", &unixpath)) {
-
- if (unixpath[0] != '/') {
+ /* are we a UNIX or TCP socket? */
+ if (strstart(host_spec, "unix:", &unixpath)) {
+ if (unixpath[0] != '/') { /* We demand an absolute path*/
goto out;
}
-
- sock = unix_socket_outgoing(unixpath);
-
+ s->host_spec = qemu_strdup(unixpath);
} else {
- uint16_t port = NBD_DEFAULT_PORT;
- char *p, *r;
- char hostname[128];
+ s->host_spec = qemu_strdup(host_spec);
+ }
- pstrcpy(hostname, 128, host);
+ err = 0;
- p = strchr(hostname, ':');
- if (p != NULL) {
- *p = '\0';
- p++;
+out:
+ qemu_free(file);
+ if (err != 0) {
+ qemu_free(s->export_name);
+ qemu_free(s->host_spec);
+ }
+ return err;
+}
- port = strtol(p, &r, 0);
- if (r == p) {
- goto out;
- }
- }
+static int nbd_establish_connection(BlockDriverState *bs)
+{
+ BDRVNBDState *s = bs->opaque;
+ int sock;
+ int ret;
+ off_t size;
+ size_t blocksize;
+ uint32_t nbdflags;
- sock = tcp_socket_outgoing(hostname, port);
+ if (s->host_spec[0] == '/') {
+ sock = unix_socket_outgoing(s->host_spec);
+ } else {
+ sock = tcp_socket_outgoing_spec(s->host_spec);
}
+ /* Failed to establish connection */
if (sock == -1) {
- err = -errno;
- goto out;
+ logout("Failed to establish connection to NBD server\n");
+ return -errno;
}
- ret = nbd_receive_negotiate(sock, name, &nbdflags, &size, &blocksize);
+ /* NBD handshake */
+ ret = nbd_receive_negotiate(sock, s->export_name, &nbdflags, &size,
+ &blocksize);
if (ret == -1) {
- err = -errno;
- goto out;
+ logout("Failed to negotiate with the NBD server\n");
+ closesocket(sock);
+ return -errno;
}
+ /* Now that we're connected, set the socket to be non-blocking */
+ socket_set_nonblock(sock);
+
s->sock = sock;
s->size = size;
s->blocksize = blocksize;
- err = 0;
-out:
- qemu_free(file);
- return err;
+ logout("Established connection with NBD server\n");
+ return 0;
+}
+
+static void nbd_teardown_connection(BlockDriverState *bs)
+{
+ BDRVNBDState *s = bs->opaque;
+ 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);
+
+ closesocket(s->sock);
+}
+
+static int nbd_open(BlockDriverState *bs, const char* filename, int flags)
+{
+ BDRVNBDState *s = bs->opaque;
+ int result;
+
+ /* Pop the config into our state object. Exit if invalid. */
+ result = nbd_config(s, filename, flags);
+ if (result != 0) {
+ return result;
+ }
+
+ /* establish TCP connection, return error if it fails
+ * TODO: Configurable retry-until-timeout behaviour.
+ */
+ result = nbd_establish_connection(bs);
+
+ return result;
}
static int nbd_read(BlockDriverState *bs, int64_t sector_num,
@@ -183,16 +239,7 @@ static int nbd_write(BlockDriverState *bs, int64_t sector_num,
static void nbd_close(BlockDriverState *bs)
{
- BDRVNBDState *s = bs->opaque;
- 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);
-
- close(s->sock);
+ nbd_teardown_connection(bs);
}
static int64_t nbd_getlength(BlockDriverState *bs)
diff --git a/blockdev.c b/blockdev.c
index bbe92fe..5429621 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -737,8 +737,6 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
{
const char *id = qdict_get_str(qdict, "id");
BlockDriverState *bs;
- BlockDriverState **ptr;
- Property *prop;
bs = bdrv_find(id);
if (!bs) {
@@ -755,24 +753,17 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
bdrv_flush(bs);
bdrv_close(bs);
- /* clean up guest state from pointing to host resource by
- * finding and removing DeviceState "drive" property */
+ /* if we have a device associated with this BlockDriverState (bs->peer)
+ * then we need to make the drive anonymous until the device
+ * can be removed. If this is a drive with no device backing
+ * then we can just get rid of the block driver state right here.
+ */
if (bs->peer) {
- for (prop = bs->peer->info->props; prop && prop->name; prop++) {
- if (prop->info->type == PROP_TYPE_DRIVE) {
- ptr = qdev_get_prop_ptr(bs->peer, prop);
- if (*ptr == bs) {
- bdrv_detach(bs, bs->peer);
- *ptr = NULL;
- break;
- }
- }
- }
+ bdrv_make_anon(bs);
+ } else {
+ drive_uninit(drive_get_by_blockdev(bs));
}
- /* clean up host side */
- drive_uninit(drive_get_by_blockdev(bs));
-
return 0;
}
diff --git a/hw/fdc.c b/hw/fdc.c
index 9fdbc75..edf0360 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -36,6 +36,7 @@
#include "qdev-addr.h"
#include "blockdev.h"
#include "sysemu.h"
+#include "block_int.h"
/********************************************************/
/* debug Floppy devices */
@@ -82,6 +83,7 @@ typedef struct FDrive {
uint8_t max_track; /* Nb of tracks */
uint16_t bps; /* Bytes per sector */
uint8_t ro; /* Is read-only */
+ uint8_t media_changed; /* Is media changed */
} FDrive;
static void fd_init(FDrive *drv)
@@ -533,16 +535,63 @@ static CPUWriteMemoryFunc * const fdctrl_mem_write_strict[3] = {
NULL,
};
+static void fdrive_media_changed_pre_save(void *opaque)
+{
+ FDrive *drive = opaque;
+
+ drive->media_changed = drive->bs->media_changed;
+}
+
+static int fdrive_media_changed_post_load(void *opaque, int version_id)
+{
+ FDrive *drive = opaque;
+
+ if (drive->bs != NULL) {
+ drive->bs->media_changed = drive->media_changed;
+ }
+
+ /* User ejected the floppy when drive->bs == NULL */
+ return 0;
+}
+
+static bool fdrive_media_changed_needed(void *opaque)
+{
+ FDrive *drive = opaque;
+
+ return (drive->bs != NULL && drive->bs->media_changed != 1);
+}
+
+static const VMStateDescription vmstate_fdrive_media_changed = {
+ .name = "fdrive/media_changed",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .pre_save = fdrive_media_changed_pre_save,
+ .post_load = fdrive_media_changed_post_load,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT8(media_changed, FDrive),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_fdrive = {
.name = "fdrive",
.version_id = 1,
.minimum_version_id = 1,
.minimum_version_id_old = 1,
- .fields = (VMStateField []) {
+ .fields = (VMStateField[]) {
VMSTATE_UINT8(head, FDrive),
VMSTATE_UINT8(track, FDrive),
VMSTATE_UINT8(sect, FDrive),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &vmstate_fdrive_media_changed,
+ .needed = &fdrive_media_changed_needed,
+ } , {
+ /* empty */
+ }
}
};
diff --git a/hw/ide.h b/hw/ide.h
index 73fb550..34d9394 100644
--- a/hw/ide.h
+++ b/hw/ide.h
@@ -28,4 +28,7 @@ void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2,
void ide_get_bs(BlockDriverState *bs[], BusState *qbus);
+/* ide/core.c */
+void ide_drive_get(DriveInfo **hd, int max_bus);
+
#endif /* HW_IDE_H */
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 007a4ee..c11d457 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -2826,3 +2826,17 @@ const VMStateDescription vmstate_ide_bus = {
VMSTATE_END_OF_LIST()
}
};
+
+void ide_drive_get(DriveInfo **hd, int max_bus)
+{
+ int i;
+
+ if (drive_get_max_bus(IF_IDE) >= max_bus) {
+ fprintf(stderr, "qemu: too many IDE bus: %d\n", max_bus);
+ exit(1);
+ }
+
+ for(i = 0; i < max_bus * MAX_IDE_DEVS; i++) {
+ hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
+ }
+}
diff --git a/hw/mips_fulong2e.c b/hw/mips_fulong2e.c
index f5ae639..0e90d68 100644
--- a/hw/mips_fulong2e.c
+++ b/hw/mips_fulong2e.c
@@ -338,14 +338,7 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
pci_bus = bonito_init((qemu_irq *)&(env->irq[2]));
/* South bridge */
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
+ ide_drive_get(hd, MAX_IDE_BUS);
via_devfn = vt82c686b_init(pci_bus, PCI_DEVFN(FULONG2E_VIA_SLOT, 0));
if (via_devfn < 0) {
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index d8baa6d..bf0d76d 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -905,15 +905,7 @@ void mips_malta_init (ram_addr_t ram_size,
pci_bus = gt64120_register(i8259);
/* Southbridge */
-
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
+ ide_drive_get(hd, MAX_IDE_BUS);
piix4_devfn = piix4_init(pci_bus, 80);
isa_bus_irqs(i8259);
diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
index 8feb461..2834a46 100644
--- a/hw/mips_r4k.c
+++ b/hw/mips_r4k.c
@@ -287,15 +287,7 @@ void mips_r4k_init (ram_addr_t ram_size,
if (nd_table[0].vlan)
isa_ne2000_init(0x300, 9, &nd_table[0]);
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
-
+ 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],
hd[MAX_IDE_DEVS * i],
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index b3ede89..4d54ca1 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -129,15 +129,7 @@ static void pc_init1(ram_addr_t ram_size,
pci_nic_init_nofail(nd, "e1000", NULL);
}
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
-
+ ide_drive_get(hd, MAX_IDE_BUS);
if (pci_enabled) {
PCIDevice *dev;
dev = pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1);
diff --git a/hw/ppc_newworld.c b/hw/ppc_newworld.c
index b9245f0..86f1cfb 100644
--- a/hw/ppc_newworld.c
+++ b/hw/ppc_newworld.c
@@ -325,20 +325,13 @@ static void ppc_core99_init (ram_addr_t ram_size,
for(i = 0; i < nb_nics; i++)
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
+ ide_drive_get(hd, MAX_IDE_BUS);
dbdma = DBDMA_init(&dbdma_mem_index);
/* We only emulate 2 out of 3 IDE controllers for now */
ide_mem_index[0] = -1;
- hd[0] = drive_get(IF_IDE, 0, 0);
- hd[1] = drive_get(IF_IDE, 0, 1);
ide_mem_index[1] = pmac_ide_init(hd, pic[0x0d], dbdma, 0x16, pic[0x02]);
- hd[0] = drive_get(IF_IDE, 1, 0);
- hd[1] = drive_get(IF_IDE, 1, 1);
- ide_mem_index[2] = pmac_ide_init(hd, pic[0x0e], dbdma, 0x1a, pic[0x02]);
+ ide_mem_index[2] = pmac_ide_init(&hd[MAX_IDE_DEVS], pic[0x0e], dbdma, 0x1a, pic[0x02]);
/* cuda also initialize ADB */
if (machine_arch == ARCH_MAC99_U3) {
diff --git a/hw/ppc_oldworld.c b/hw/ppc_oldworld.c
index 8a4e088..75a3127 100644
--- a/hw/ppc_oldworld.c
+++ b/hw/ppc_oldworld.c
@@ -236,21 +236,16 @@ static void ppc_heathrow_init (ram_addr_t ram_size,
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
+ ide_drive_get(hd, MAX_IDE_BUS);
/* First IDE channel is a MAC IDE on the MacIO bus */
- hd[0] = drive_get(IF_IDE, 0, 0);
- hd[1] = drive_get(IF_IDE, 0, 1);
dbdma = DBDMA_init(&dbdma_mem_index);
ide_mem_index[0] = -1;
ide_mem_index[1] = pmac_ide_init(hd, pic[0x0D], dbdma, 0x16, pic[0x02]);
/* Second IDE channel is a CMD646 on the PCI bus */
- hd[0] = drive_get(IF_IDE, 1, 0);
- hd[1] = drive_get(IF_IDE, 1, 1);
+ hd[0] = hd[MAX_IDE_DEVS];
+ hd[1] = hd[MAX_IDE_DEVS + 1];
hd[3] = hd[2] = NULL;
pci_cmd646_ide_init(pci_bus, hd, 0);
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 5615ef9..0e9cfc2 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -681,15 +681,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
}
}
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
-
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS, i % MAX_IDE_DEVS);
- }
-
+ 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],
hd[2 * i],
diff --git a/hw/sun4u.c b/hw/sun4u.c
index dbb5a15..5eb38cf 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -793,14 +793,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
for(i = 0; i < nb_nics; i++)
pci_nic_init_nofail(&nd_table[i], "ne2k_pci", NULL);
- if (drive_get_max_bus(IF_IDE) >= MAX_IDE_BUS) {
- fprintf(stderr, "qemu: too many IDE bus\n");
- exit(1);
- }
- for(i = 0; i < MAX_IDE_BUS * MAX_IDE_DEVS; i++) {
- hd[i] = drive_get(IF_IDE, i / MAX_IDE_DEVS,
- i % MAX_IDE_DEVS);
- }
+ ide_drive_get(hd, MAX_IDE_BUS);
pci_cmd646_ide_init(pci_bus, hd, 1);
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index b14fb99..91e0394 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -290,6 +290,10 @@ static void virtio_blk_handle_write(VirtIOBlockReq *req, MultiReqBuffer *mrb)
virtio_blk_rw_complete(req, -EIO);
return;
}
+ if (req->qiov.size % req->dev->conf->logical_block_size) {
+ virtio_blk_rw_complete(req, -EIO);
+ return;
+ }
if (mrb->num_writes == 32) {
virtio_submit_multiwrite(req->dev->bs, mrb);
@@ -317,6 +321,10 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
virtio_blk_rw_complete(req, -EIO);
return;
}
+ if (req->qiov.size % req->dev->conf->logical_block_size) {
+ virtio_blk_rw_complete(req, -EIO);
+ return;
+ }
acb = bdrv_aio_readv(req->dev->bs, sector, &req->qiov,
req->qiov.size / BDRV_SECTOR_SIZE,
diff --git a/hw/xen_disk.c b/hw/xen_disk.c
index 445bf03..558bf8a 100644
--- a/hw/xen_disk.c
+++ b/hw/xen_disk.c
@@ -310,7 +310,7 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
off_t pos;
if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
- goto err;
+ goto err_no_map;
if (ioreq->presync)
bdrv_flush(blkdev->bs);
@@ -364,6 +364,9 @@ static int ioreq_runio_qemu_sync(struct ioreq *ioreq)
return 0;
err:
+ ioreq_unmap(ioreq);
+err_no_map:
+ ioreq_finish(ioreq);
ioreq->status = BLKIF_RSP_ERROR;
return -1;
}
@@ -393,7 +396,7 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
struct XenBlkDev *blkdev = ioreq->blkdev;
if (ioreq->req.nr_segments && ioreq_map(ioreq) == -1)
- goto err;
+ goto err_no_map;
ioreq->aio_inflight++;
if (ioreq->presync)
@@ -427,6 +430,9 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
return 0;
err:
+ ioreq_unmap(ioreq);
+err_no_map:
+ ioreq_finish(ioreq);
ioreq->status = BLKIF_RSP_ERROR;
return -1;
}
diff --git a/nbd.c b/nbd.c
index d8ebc42..0dcd86b 100644
--- a/nbd.c
+++ b/nbd.c
@@ -49,7 +49,7 @@
/* This is all part of the "official" NBD API */
-#define NBD_REPLY_SIZE (4 + 4 + 8)
+#define NBD_REPLY_SIZE (4 + 4 + 8)
#define NBD_REQUEST_MAGIC 0x25609513
#define NBD_REPLY_MAGIC 0x67446698
@@ -59,11 +59,11 @@
#define NBD_DO_IT _IO(0xab, 3)
#define NBD_CLEAR_SOCK _IO(0xab, 4)
#define NBD_CLEAR_QUE _IO(0xab, 5)
-#define NBD_PRINT_DEBUG _IO(0xab, 6)
-#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
+#define NBD_PRINT_DEBUG _IO(0xab, 6)
+#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7)
#define NBD_DISCONNECT _IO(0xab, 8)
-#define NBD_OPT_EXPORT_NAME (1 << 0)
+#define NBD_OPT_EXPORT_NAME (1 << 0)
/* That's all folks */
@@ -107,155 +107,55 @@ size_t nbd_wr_sync(int fd, void *buffer, size_t size, bool do_read)
return offset;
}
-int tcp_socket_outgoing(const char *address, uint16_t port)
+static void combine_addr(char *buf, size_t len, const char* address,
+ uint16_t port)
{
- int s;
- struct in_addr in;
- struct sockaddr_in addr;
-
- s = socket(PF_INET, SOCK_STREAM, 0);
- if (s == -1) {
- return -1;
- }
-
- if (inet_aton(address, &in) == 0) {
- struct hostent *ent;
-
- ent = gethostbyname(address);
- if (ent == NULL) {
- goto error;
- }
-
- memcpy(&in, ent->h_addr, sizeof(in));
- }
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
-
- if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- goto error;
+ /* If the address-part contains a colon, it's an IPv6 IP so needs [] */
+ if (strstr(address, ":")) {
+ snprintf(buf, len, "[%s]:%u", address, port);
+ } else {
+ snprintf(buf, len, "%s:%u", address, port);
}
-
- return s;
-error:
- closesocket(s);
- return -1;
}
-int tcp_socket_incoming(const char *address, uint16_t port)
+int tcp_socket_outgoing(const char *address, uint16_t port)
{
- int s;
- struct in_addr in;
- struct sockaddr_in addr;
- int opt;
-
- s = socket(PF_INET, SOCK_STREAM, 0);
- if (s == -1) {
- return -1;
- }
-
- if (inet_aton(address, &in) == 0) {
- struct hostent *ent;
-
- ent = gethostbyname(address);
- if (ent == NULL) {
- goto error;
- }
-
- memcpy(&in, ent->h_addr, sizeof(in));
- }
-
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- memcpy(&addr.sin_addr.s_addr, &in, sizeof(in));
-
- opt = 1;
- if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
- (const void *) &opt, sizeof(opt)) == -1) {
- goto error;
- }
-
- if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- goto error;
- }
-
- if (listen(s, 128) == -1) {
- goto error;
- }
-
- return s;
-error:
- closesocket(s);
- return -1;
+ char address_and_port[128];
+ combine_addr(address_and_port, 128, address, port);
+ return tcp_socket_outgoing_spec(address_and_port);
}
-#ifndef _WIN32
-int unix_socket_incoming(const char *path)
+int tcp_socket_outgoing_spec(const char *address_and_port)
{
- int s;
- struct sockaddr_un addr;
-
- s = socket(PF_UNIX, SOCK_STREAM, 0);
- if (s == -1) {
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
-
- if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- goto error;
- }
-
- if (listen(s, 128) == -1) {
- goto error;
- }
-
- return s;
-error:
- closesocket(s);
- return -1;
+ return inet_connect(address_and_port, SOCK_STREAM);
}
-int unix_socket_outgoing(const char *path)
+int tcp_socket_incoming(const char *address, uint16_t port)
{
- int s;
- struct sockaddr_un addr;
-
- s = socket(PF_UNIX, SOCK_STREAM, 0);
- if (s == -1) {
- return -1;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- pstrcpy(addr.sun_path, sizeof(addr.sun_path), path);
-
- if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
- goto error;
- }
+ char address_and_port[128];
+ combine_addr(address_and_port, 128, address, port);
+ return tcp_socket_incoming_spec(address_and_port);
+}
- return s;
-error:
- closesocket(s);
- return -1;
+int tcp_socket_incoming_spec(const char *address_and_port)
+{
+ char *ostr = NULL;
+ int olen = 0;
+ return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0);
}
-#else
+
int unix_socket_incoming(const char *path)
{
- errno = ENOTSUP;
- return -1;
+ char *ostr = NULL;
+ int olen = 0;
+
+ return unix_listen(path, ostr, olen);
}
int unix_socket_outgoing(const char *path)
{
- errno = ENOTSUP;
- return -1;
+ return unix_connect(path);
}
-#endif
-
/* Basic flow
@@ -273,241 +173,241 @@ int unix_socket_outgoing(const char *path)
int nbd_negotiate(int csock, off_t size)
{
- char buf[8 + 8 + 8 + 128];
-
- /* Negotiate
- [ 0 .. 7] passwd ("NBDMAGIC")
- [ 8 .. 15] magic (0x00420281861253)
- [16 .. 23] size
- [24 .. 151] reserved (0)
- */
-
- TRACE("Beginning negotiation.");
- memcpy(buf, "NBDMAGIC", 8);
- cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
- cpu_to_be64w((uint64_t*)(buf + 16), size);
- memset(buf + 24, 0, 128);
-
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
- LOG("write failed");
- errno = EINVAL;
- return -1;
- }
-
- TRACE("Negotation succeeded.");
-
- return 0;
+ char buf[8 + 8 + 8 + 128];
+
+ /* Negotiate
+ [ 0 .. 7] passwd ("NBDMAGIC")
+ [ 8 .. 15] magic (0x00420281861253)
+ [16 .. 23] size
+ [24 .. 151] reserved (0)
+ */
+
+ TRACE("Beginning negotiation.");
+ memcpy(buf, "NBDMAGIC", 8);
+ cpu_to_be64w((uint64_t*)(buf + 8), 0x00420281861253LL);
+ cpu_to_be64w((uint64_t*)(buf + 16), size);
+ memset(buf + 24, 0, 128);
+
+ if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("write failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ TRACE("Negotation succeeded.");
+
+ return 0;
}
int nbd_receive_negotiate(int csock, const char *name, uint32_t *flags,
off_t *size, size_t *blocksize)
{
- char buf[256];
- uint64_t magic, s;
- uint16_t tmp;
-
- TRACE("Receiving negotation.");
-
- if (read_sync(csock, buf, 8) != 8) {
- LOG("read failed");
- errno = EINVAL;
- return -1;
- }
-
- buf[8] = '\0';
- if (strlen(buf) == 0) {
- LOG("server connection closed");
- errno = EINVAL;
- return -1;
- }
-
- TRACE("Magic is %c%c%c%c%c%c%c%c",
- qemu_isprint(buf[0]) ? buf[0] : '.',
- qemu_isprint(buf[1]) ? buf[1] : '.',
- qemu_isprint(buf[2]) ? buf[2] : '.',
- qemu_isprint(buf[3]) ? buf[3] : '.',
- qemu_isprint(buf[4]) ? buf[4] : '.',
- qemu_isprint(buf[5]) ? buf[5] : '.',
- qemu_isprint(buf[6]) ? buf[6] : '.',
- qemu_isprint(buf[7]) ? buf[7] : '.');
-
- if (memcmp(buf, "NBDMAGIC", 8) != 0) {
- LOG("Invalid magic received");
- errno = EINVAL;
- return -1;
- }
-
- if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
- LOG("read failed");
- errno = EINVAL;
- return -1;
- }
- magic = be64_to_cpu(magic);
- TRACE("Magic is 0x%" PRIx64, magic);
-
- if (name) {
- uint32_t reserved = 0;
- uint32_t opt;
- uint32_t namesize;
-
- TRACE("Checking magic (opts_magic)");
- if (magic != 0x49484156454F5054LL) {
- LOG("Bad magic received");
- errno = EINVAL;
- return -1;
- }
- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- LOG("flags read failed");
- errno = EINVAL;
- return -1;
- }
- *flags = be16_to_cpu(tmp) << 16;
- /* reserved for future use */
- if (write_sync(csock, &reserved, sizeof(reserved)) !=
- sizeof(reserved)) {
- LOG("write failed (reserved)");
- errno = EINVAL;
- return -1;
- }
- /* write the export name */
- magic = cpu_to_be64(magic);
- if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
- LOG("write failed (magic)");
- errno = EINVAL;
- return -1;
- }
- opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
- if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
- LOG("write failed (opt)");
- errno = EINVAL;
- return -1;
- }
- namesize = cpu_to_be32(strlen(name));
- if (write_sync(csock, &namesize, sizeof(namesize)) !=
- sizeof(namesize)) {
- LOG("write failed (namesize)");
- errno = EINVAL;
- return -1;
- }
- if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
- LOG("write failed (name)");
- errno = EINVAL;
- return -1;
- }
- } else {
- TRACE("Checking magic (cli_magic)");
-
- if (magic != 0x00420281861253LL) {
- LOG("Bad magic received");
- errno = EINVAL;
- return -1;
- }
- }
-
- if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
- LOG("read failed");
- errno = EINVAL;
- return -1;
- }
- *size = be64_to_cpu(s);
- *blocksize = 1024;
- TRACE("Size is %" PRIu64, *size);
-
- if (!name) {
- if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
- LOG("read failed (flags)");
- errno = EINVAL;
- return -1;
- }
- *flags = be32_to_cpup(flags);
- } else {
- if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
- LOG("read failed (tmp)");
- errno = EINVAL;
- return -1;
- }
- *flags |= be32_to_cpu(tmp);
- }
- if (read_sync(csock, &buf, 124) != 124) {
- LOG("read failed (buf)");
- errno = EINVAL;
- return -1;
- }
+ char buf[256];
+ uint64_t magic, s;
+ uint16_t tmp;
+
+ TRACE("Receiving negotation.");
+
+ if (read_sync(csock, buf, 8) != 8) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ buf[8] = '\0';
+ if (strlen(buf) == 0) {
+ LOG("server connection closed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ TRACE("Magic is %c%c%c%c%c%c%c%c",
+ qemu_isprint(buf[0]) ? buf[0] : '.',
+ qemu_isprint(buf[1]) ? buf[1] : '.',
+ qemu_isprint(buf[2]) ? buf[2] : '.',
+ qemu_isprint(buf[3]) ? buf[3] : '.',
+ qemu_isprint(buf[4]) ? buf[4] : '.',
+ qemu_isprint(buf[5]) ? buf[5] : '.',
+ qemu_isprint(buf[6]) ? buf[6] : '.',
+ qemu_isprint(buf[7]) ? buf[7] : '.');
+
+ if (memcmp(buf, "NBDMAGIC", 8) != 0) {
+ LOG("Invalid magic received");
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (read_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+ magic = be64_to_cpu(magic);
+ TRACE("Magic is 0x%" PRIx64, magic);
+
+ if (name) {
+ uint32_t reserved = 0;
+ uint32_t opt;
+ uint32_t namesize;
+
+ TRACE("Checking magic (opts_magic)");
+ if (magic != 0x49484156454F5054LL) {
+ LOG("Bad magic received");
+ errno = EINVAL;
+ return -1;
+ }
+ if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ LOG("flags read failed");
+ errno = EINVAL;
+ return -1;
+ }
+ *flags = be16_to_cpu(tmp) << 16;
+ /* reserved for future use */
+ if (write_sync(csock, &reserved, sizeof(reserved)) !=
+ sizeof(reserved)) {
+ LOG("write failed (reserved)");
+ errno = EINVAL;
+ return -1;
+ }
+ /* write the export name */
+ magic = cpu_to_be64(magic);
+ if (write_sync(csock, &magic, sizeof(magic)) != sizeof(magic)) {
+ LOG("write failed (magic)");
+ errno = EINVAL;
+ return -1;
+ }
+ opt = cpu_to_be32(NBD_OPT_EXPORT_NAME);
+ if (write_sync(csock, &opt, sizeof(opt)) != sizeof(opt)) {
+ LOG("write failed (opt)");
+ errno = EINVAL;
+ return -1;
+ }
+ namesize = cpu_to_be32(strlen(name));
+ if (write_sync(csock, &namesize, sizeof(namesize)) !=
+ sizeof(namesize)) {
+ LOG("write failed (namesize)");
+ errno = EINVAL;
+ return -1;
+ }
+ if (write_sync(csock, (char*)name, strlen(name)) != strlen(name)) {
+ LOG("write failed (name)");
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ TRACE("Checking magic (cli_magic)");
+
+ if (magic != 0x00420281861253LL) {
+ LOG("Bad magic received");
+ errno = EINVAL;
+ return -1;
+ }
+ }
+
+ if (read_sync(csock, &s, sizeof(s)) != sizeof(s)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+ *size = be64_to_cpu(s);
+ *blocksize = 1024;
+ TRACE("Size is %" PRIu64, *size);
+
+ if (!name) {
+ if (read_sync(csock, flags, sizeof(*flags)) != sizeof(*flags)) {
+ LOG("read failed (flags)");
+ errno = EINVAL;
+ return -1;
+ }
+ *flags = be32_to_cpup(flags);
+ } else {
+ if (read_sync(csock, &tmp, sizeof(tmp)) != sizeof(tmp)) {
+ LOG("read failed (tmp)");
+ errno = EINVAL;
+ return -1;
+ }
+ *flags |= be32_to_cpu(tmp);
+ }
+ if (read_sync(csock, &buf, 124) != 124) {
+ LOG("read failed (buf)");
+ errno = EINVAL;
+ return -1;
+ }
return 0;
}
#ifndef _WIN32
int nbd_init(int fd, int csock, off_t size, size_t blocksize)
{
- TRACE("Setting block size to %lu", (unsigned long)blocksize);
+ TRACE("Setting block size to %lu", (unsigned long)blocksize);
- if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
- int serrno = errno;
- LOG("Failed setting NBD block size");
- errno = serrno;
- return -1;
- }
+ if (ioctl(fd, NBD_SET_BLKSIZE, blocksize) == -1) {
+ int serrno = errno;
+ LOG("Failed setting NBD block size");
+ errno = serrno;
+ return -1;
+ }
TRACE("Setting size to %zd block(s)", (size_t)(size / blocksize));
- if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
- int serrno = errno;
- LOG("Failed setting size (in blocks)");
- errno = serrno;
- return -1;
- }
+ if (ioctl(fd, NBD_SET_SIZE_BLOCKS, size / blocksize) == -1) {
+ int serrno = errno;
+ LOG("Failed setting size (in blocks)");
+ errno = serrno;
+ return -1;
+ }
- TRACE("Clearing NBD socket");
+ TRACE("Clearing NBD socket");
- if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
- int serrno = errno;
- LOG("Failed clearing NBD socket");
- errno = serrno;
- return -1;
- }
+ if (ioctl(fd, NBD_CLEAR_SOCK) == -1) {
+ int serrno = errno;
+ LOG("Failed clearing NBD socket");
+ errno = serrno;
+ return -1;
+ }
- TRACE("Setting NBD socket");
+ 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;
- }
+ if (ioctl(fd, NBD_SET_SOCK, csock) == -1) {
+ int serrno = errno;
+ LOG("Failed to set NBD socket");
+ errno = serrno;
+ return -1;
+ }
- TRACE("Negotiation ended");
+ TRACE("Negotiation ended");
- return 0;
+ return 0;
}
int nbd_disconnect(int fd)
{
- ioctl(fd, NBD_CLEAR_QUE);
- ioctl(fd, NBD_DISCONNECT);
- ioctl(fd, NBD_CLEAR_SOCK);
- return 0;
+ ioctl(fd, NBD_CLEAR_QUE);
+ ioctl(fd, NBD_DISCONNECT);
+ ioctl(fd, NBD_CLEAR_SOCK);
+ return 0;
}
int nbd_client(int fd)
{
- int ret;
- int serrno;
+ int ret;
+ int serrno;
- TRACE("Doing NBD loop");
+ TRACE("Doing NBD loop");
- ret = ioctl(fd, NBD_DO_IT);
- serrno = errno;
+ ret = ioctl(fd, NBD_DO_IT);
+ serrno = errno;
- TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
+ TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
- TRACE("Clearing NBD queue");
- ioctl(fd, NBD_CLEAR_QUE);
+ TRACE("Clearing NBD queue");
+ ioctl(fd, NBD_CLEAR_QUE);
- TRACE("Clearing NBD socket");
- ioctl(fd, NBD_CLEAR_SOCK);
+ TRACE("Clearing NBD socket");
+ ioctl(fd, NBD_CLEAR_SOCK);
- errno = serrno;
- return ret;
+ errno = serrno;
+ return ret;
}
#else
int nbd_init(int fd, int csock, off_t size, size_t blocksize)
@@ -531,235 +431,236 @@ int nbd_client(int fd)
int nbd_send_request(int csock, struct nbd_request *request)
{
- uint8_t buf[4 + 4 + 8 + 8 + 4];
-
- cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
- cpu_to_be32w((uint32_t*)(buf + 4), request->type);
- cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
- cpu_to_be64w((uint64_t*)(buf + 16), request->from);
- cpu_to_be32w((uint32_t*)(buf + 24), request->len);
-
- TRACE("Sending request to client");
-
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
- LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
- }
- return 0;
-}
+ uint8_t buf[4 + 4 + 8 + 8 + 4];
+ cpu_to_be32w((uint32_t*)buf, NBD_REQUEST_MAGIC);
+ cpu_to_be32w((uint32_t*)(buf + 4), request->type);
+ cpu_to_be64w((uint64_t*)(buf + 8), request->handle);
+ cpu_to_be64w((uint64_t*)(buf + 16), request->from);
+ cpu_to_be32w((uint32_t*)(buf + 24), request->len);
+
+ TRACE("Sending request to client: "
+ "{ .from = %" PRIu64", .len = %u, .handle = %" PRIu64", .type=%i}",
+ request->from, request->len, request->handle, request->type);
+
+ if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("writing to socket failed");
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
static int nbd_receive_request(int csock, struct nbd_request *request)
{
- uint8_t buf[4 + 4 + 8 + 8 + 4];
- uint32_t magic;
-
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
- LOG("read failed");
- errno = EINVAL;
- return -1;
- }
-
- /* Request
- [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
- [ 4 .. 7] type (0 == READ, 1 == WRITE)
- [ 8 .. 15] handle
- [16 .. 23] from
- [24 .. 27] len
- */
-
- magic = be32_to_cpup((uint32_t*)buf);
- request->type = be32_to_cpup((uint32_t*)(buf + 4));
- request->handle = be64_to_cpup((uint64_t*)(buf + 8));
- request->from = be64_to_cpup((uint64_t*)(buf + 16));
- request->len = be32_to_cpup((uint32_t*)(buf + 24));
-
- TRACE("Got request: "
- "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
- magic, request->type, request->from, request->len);
-
- if (magic != NBD_REQUEST_MAGIC) {
- LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
- }
- return 0;
+ uint8_t buf[4 + 4 + 8 + 8 + 4];
+ uint32_t magic;
+
+ if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Request
+ [ 0 .. 3] magic (NBD_REQUEST_MAGIC)
+ [ 4 .. 7] type (0 == READ, 1 == WRITE)
+ [ 8 .. 15] handle
+ [16 .. 23] from
+ [24 .. 27] len
+ */
+
+ magic = be32_to_cpup((uint32_t*)buf);
+ request->type = be32_to_cpup((uint32_t*)(buf + 4));
+ request->handle = be64_to_cpup((uint64_t*)(buf + 8));
+ request->from = be64_to_cpup((uint64_t*)(buf + 16));
+ request->len = be32_to_cpup((uint32_t*)(buf + 24));
+
+ TRACE("Got request: "
+ "{ magic = 0x%x, .type = %d, from = %" PRIu64" , len = %u }",
+ magic, request->type, request->from, request->len);
+
+ if (magic != NBD_REQUEST_MAGIC) {
+ LOG("invalid magic (got 0x%x)", magic);
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
}
int nbd_receive_reply(int csock, struct nbd_reply *reply)
{
- uint8_t buf[NBD_REPLY_SIZE];
- uint32_t magic;
-
- memset(buf, 0xAA, sizeof(buf));
-
- if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
- LOG("read failed");
- errno = EINVAL;
- return -1;
- }
-
- /* Reply
- [ 0 .. 3] magic (NBD_REPLY_MAGIC)
- [ 4 .. 7] error (0 == no error)
- [ 7 .. 15] handle
- */
-
- magic = be32_to_cpup((uint32_t*)buf);
- reply->error = be32_to_cpup((uint32_t*)(buf + 4));
- reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
-
- TRACE("Got reply: "
- "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
- magic, reply->error, reply->handle);
-
- if (magic != NBD_REPLY_MAGIC) {
- LOG("invalid magic (got 0x%x)", magic);
- errno = EINVAL;
- return -1;
- }
- return 0;
+ uint8_t buf[NBD_REPLY_SIZE];
+ uint32_t magic;
+
+ memset(buf, 0xAA, sizeof(buf));
+
+ if (read_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("read failed");
+ errno = EINVAL;
+ return -1;
+ }
+
+ /* Reply
+ [ 0 .. 3] magic (NBD_REPLY_MAGIC)
+ [ 4 .. 7] error (0 == no error)
+ [ 7 .. 15] handle
+ */
+
+ magic = be32_to_cpup((uint32_t*)buf);
+ reply->error = be32_to_cpup((uint32_t*)(buf + 4));
+ reply->handle = be64_to_cpup((uint64_t*)(buf + 8));
+
+ TRACE("Got reply: "
+ "{ magic = 0x%x, .error = %d, handle = %" PRIu64" }",
+ magic, reply->error, reply->handle);
+
+ if (magic != NBD_REPLY_MAGIC) {
+ LOG("invalid magic (got 0x%x)", magic);
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
}
static int nbd_send_reply(int csock, struct nbd_reply *reply)
{
- uint8_t buf[4 + 4 + 8];
-
- /* Reply
- [ 0 .. 3] magic (NBD_REPLY_MAGIC)
- [ 4 .. 7] error (0 == no error)
- [ 7 .. 15] handle
- */
- cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
- cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
- cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
-
- TRACE("Sending response to client");
-
- if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
- LOG("writing to socket failed");
- errno = EINVAL;
- return -1;
- }
- return 0;
+ uint8_t buf[4 + 4 + 8];
+
+ /* Reply
+ [ 0 .. 3] magic (NBD_REPLY_MAGIC)
+ [ 4 .. 7] error (0 == no error)
+ [ 7 .. 15] handle
+ */
+ cpu_to_be32w((uint32_t*)buf, NBD_REPLY_MAGIC);
+ cpu_to_be32w((uint32_t*)(buf + 4), reply->error);
+ cpu_to_be64w((uint64_t*)(buf + 8), reply->handle);
+
+ TRACE("Sending response to client");
+
+ if (write_sync(csock, buf, sizeof(buf)) != sizeof(buf)) {
+ LOG("writing to socket failed");
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
}
int nbd_trip(BlockDriverState *bs, int csock, off_t size, uint64_t dev_offset,
off_t *offset, bool readonly, uint8_t *data, int data_size)
{
- struct nbd_request request;
- struct nbd_reply reply;
-
- TRACE("Reading request.");
-
- if (nbd_receive_request(csock, &request) == -1)
- return -1;
-
- if (request.len + NBD_REPLY_SIZE > data_size) {
- LOG("len (%u) is larger than max len (%u)",
- request.len + NBD_REPLY_SIZE, data_size);
- errno = EINVAL;
- return -1;
- }
-
- if ((request.from + request.len) < request.from) {
- LOG("integer overflow detected! "
- "you're probably being attacked");
- errno = EINVAL;
- return -1;
- }
-
- if ((request.from + request.len) > size) {
- LOG("From: %" PRIu64 ", Len: %u, Size: %" PRIu64
- ", Offset: %" PRIu64 "\n",
+ struct nbd_request request;
+ struct nbd_reply reply;
+
+ TRACE("Reading request.");
+
+ if (nbd_receive_request(csock, &request) == -1)
+ return -1;
+
+ if (request.len + NBD_REPLY_SIZE > data_size) {
+ LOG("len (%u) is larger than max len (%u)",
+ request.len + NBD_REPLY_SIZE, data_size);
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((request.from + request.len) < request.from) {
+ LOG("integer overflow detected! "
+ "you're probably being attacked");
+ errno = EINVAL;
+ return -1;
+ }
+
+ 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");
-
- reply.handle = request.handle;
- reply.error = 0;
-
- switch (request.type) {
- 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) {
- LOG("reading from file failed");
- errno = EINVAL;
- return -1;
- }
- *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;
- }
- 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 (readonly) {
- TRACE("Server is read-only, return error");
- reply.error = 1;
- } else {
- 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;
- }
-
- *offset += request.len;
- }
-
- if (nbd_send_reply(csock, &reply) == -1)
- return -1;
- break;
- case NBD_CMD_DISC:
- TRACE("Request type is DISCONNECT");
- errno = 0;
- return 1;
- default:
- LOG("invalid request type (%u) received", request.type);
- errno = EINVAL;
- return -1;
- }
-
- TRACE("Request/Reply complete");
-
- return 0;
+ LOG("requested operation past EOF--bad client?");
+ errno = EINVAL;
+ return -1;
+ }
+
+ TRACE("Decoding type");
+
+ reply.handle = request.handle;
+ reply.error = 0;
+
+ switch (request.type) {
+ 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) {
+ LOG("reading from file failed");
+ errno = EINVAL;
+ return -1;
+ }
+ *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;
+ }
+ 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 (readonly) {
+ TRACE("Server is read-only, return error");
+ reply.error = 1;
+ } else {
+ 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;
+ }
+
+ *offset += request.len;
+ }
+
+ if (nbd_send_reply(csock, &reply) == -1)
+ return -1;
+ break;
+ case NBD_CMD_DISC:
+ TRACE("Request type is DISCONNECT");
+ errno = 0;
+ return 1;
+ default:
+ LOG("invalid request type (%u) received", request.type);
+ errno = EINVAL;
+ return -1;
+ }
+
+ TRACE("Request/Reply complete");
+
+ return 0;
}
diff --git a/nbd.h b/nbd.h
index fc3a594..b38d0d0 100644
--- a/nbd.h
+++ b/nbd.h
@@ -22,19 +22,22 @@
#include <sys/types.h>
#include <qemu-common.h>
+
#include "block_int.h"
struct nbd_request {
+ uint32_t magic;
uint32_t type;
uint64_t handle;
uint64_t from;
uint32_t len;
-};
+} __attribute__ ((__packed__));
struct nbd_reply {
+ uint32_t magic;
uint32_t error;
uint64_t handle;
-};
+} __attribute__ ((__packed__));
enum {
NBD_CMD_READ = 0,
@@ -47,6 +50,8 @@ enum {
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);
+int tcp_socket_outgoing_spec(const char *address_and_port);
+int tcp_socket_incoming_spec(const char *address_and_port);
int unix_socket_outgoing(const char *path);
int unix_socket_incoming(const char *path);
diff --git a/qemu-common.h b/qemu-common.h
index 8ecb488..82e27c1 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -334,6 +334,10 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
size_t skip);
+void qemu_progress_init(int enabled, float min_skip);
+void qemu_progress_end(void);
+void qemu_progress_print(float percent, int max);
+
/* Convert a byte between binary and BCD. */
static inline uint8_t to_bcd(uint8_t val)
{
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 6c7176f..3072d38 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -28,7 +28,7 @@ STEXI
ETEXI
DEF("convert", img_convert,
- "convert [-c] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
+ "convert [-c] [-p] [-f fmt] [-O output_fmt] [-o options] [-s snapshot_name] filename [filename2 [...]] output_filename")
STEXI
@item convert [-c] [-f @var{fmt}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_name}] @var{filename} [@var{filename2} [...]] @var{output_filename}
ETEXI
@@ -46,7 +46,7 @@ STEXI
ETEXI
DEF("rebase", img_rebase,
- "rebase [-f fmt] [-u] -b backing_file [-F backing_fmt] filename")
+ "rebase [-f fmt] [-p] [-u] -b backing_file [-F backing_fmt] filename")
STEXI
@item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename}
ETEXI
diff --git a/qemu-img.c b/qemu-img.c
index 7e3cc4c..d9c2c12 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -77,6 +77,7 @@ static void help(void)
" match exactly. The image doesn't need a working backing file before\n"
" rebasing in this case (useful for renaming the backing file)\n"
" '-h' with or without a command shows this help and lists the supported formats\n"
+ " '-p' show progress of command (only certain commands)\n"
"\n"
"Parameters to snapshot subcommand:\n"
" 'snapshot' is the name of the snapshot to create, apply or delete\n"
@@ -567,6 +568,7 @@ static int compare_sectors(const uint8_t *buf1, const uint8_t *buf2, int n,
static int img_convert(int argc, char **argv)
{
int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
+ int progress = 0;
const char *fmt, *out_fmt, *out_baseimg, *out_filename;
BlockDriver *drv, *proto_drv;
BlockDriverState **bs = NULL, *out_bs = NULL;
@@ -579,13 +581,14 @@ static int img_convert(int argc, char **argv)
QEMUOptionParameter *out_baseimg_param;
char *options = NULL;
const char *snapshot_name = NULL;
+ float local_progress;
fmt = NULL;
out_fmt = "raw";
out_baseimg = NULL;
compress = 0;
for(;;) {
- c = getopt(argc, argv, "f:O:B:s:hce6o:");
+ c = getopt(argc, argv, "f:O:B:s:hce6o:p");
if (c == -1) {
break;
}
@@ -620,6 +623,9 @@ static int img_convert(int argc, char **argv)
case 's':
snapshot_name = optarg;
break;
+ case 'p':
+ progress = 1;
+ break;
}
}
@@ -642,6 +648,9 @@ static int img_convert(int argc, char **argv)
goto out;
}
+ qemu_progress_init(progress, 2.0);
+ qemu_progress_print(0, 100);
+
bs = qemu_mallocz(bs_n * sizeof(BlockDriverState *));
total_sectors = 0;
@@ -773,6 +782,11 @@ static int img_convert(int argc, char **argv)
}
cluster_sectors = cluster_size >> 9;
sector_num = 0;
+
+ nb_sectors = total_sectors;
+ local_progress = (float)100 /
+ (nb_sectors / MIN(nb_sectors, (cluster_sectors)));
+
for(;;) {
int64_t bs_num;
int remainder;
@@ -832,6 +846,7 @@ static int img_convert(int argc, char **argv)
}
}
sector_num += n;
+ qemu_progress_print(local_progress, 100);
}
/* signal EOF to align */
bdrv_write_compressed(out_bs, 0, NULL, 0);
@@ -839,6 +854,10 @@ static int img_convert(int argc, char **argv)
int has_zero_init = bdrv_has_zero_init(out_bs);
sector_num = 0; // total number of sectors converted so far
+ nb_sectors = total_sectors - sector_num;
+ local_progress = (float)100 /
+ (nb_sectors / MIN(nb_sectors, (IO_BUF_SIZE / 512)));
+
for(;;) {
nb_sectors = total_sectors - sector_num;
if (nb_sectors <= 0) {
@@ -912,9 +931,11 @@ static int img_convert(int argc, char **argv)
n -= n1;
buf1 += n1 * 512;
}
+ qemu_progress_print(local_progress, 100);
}
}
out:
+ qemu_progress_end();
free_option_parameters(create_options);
free_option_parameters(param);
qemu_free(buf);
@@ -1184,6 +1205,7 @@ static int img_rebase(int argc, char **argv)
const char *fmt, *out_basefmt, *out_baseimg;
int c, flags, ret;
int unsafe = 0;
+ int progress = 0;
/* Parse commandline parameters */
fmt = NULL;
@@ -1191,7 +1213,7 @@ static int img_rebase(int argc, char **argv)
out_basefmt = NULL;
for(;;) {
- c = getopt(argc, argv, "uhf:F:b:");
+ c = getopt(argc, argv, "uhf:F:b:p");
if (c == -1) {
break;
}
@@ -1212,6 +1234,9 @@ static int img_rebase(int argc, char **argv)
case 'u':
unsafe = 1;
break;
+ case 'p':
+ progress = 1;
+ break;
}
}
@@ -1220,6 +1245,9 @@ static int img_rebase(int argc, char **argv)
}
filename = argv[optind++];
+ qemu_progress_init(progress, 2.0);
+ qemu_progress_print(0, 100);
+
/*
* Open the images.
*
@@ -1295,12 +1323,15 @@ static int img_rebase(int argc, char **argv)
int n;
uint8_t * buf_old;
uint8_t * buf_new;
+ float local_progress;
buf_old = qemu_malloc(IO_BUF_SIZE);
buf_new = qemu_malloc(IO_BUF_SIZE);
bdrv_get_geometry(bs, &num_sectors);
+ local_progress = (float)100 /
+ (num_sectors / MIN(num_sectors, (IO_BUF_SIZE / 512)));
for (sector = 0; sector < num_sectors; sector += n) {
/* How many sectors can we handle with the next read? */
@@ -1348,6 +1379,7 @@ static int img_rebase(int argc, char **argv)
written += pnum;
}
+ qemu_progress_print(local_progress, 100);
}
qemu_free(buf_old);
@@ -1368,6 +1400,7 @@ static int img_rebase(int argc, char **argv)
out_baseimg, strerror(-ret));
}
+ qemu_progress_print(100, 0);
/*
* TODO At this point it is possible to check if any clusters that are
* allocated in the COW file are the same in the backing file. If so, they
@@ -1375,10 +1408,15 @@ static int img_rebase(int argc, char **argv)
* backing file, in case of a crash this would lead to corruption.
*/
out:
+ qemu_progress_end();
/* Cleanup */
if (!unsafe) {
- bdrv_delete(bs_old_backing);
- bdrv_delete(bs_new_backing);
+ if (bs_old_backing != NULL) {
+ bdrv_delete(bs_old_backing);
+ }
+ if (bs_new_backing != NULL) {
+ bdrv_delete(bs_new_backing);
+ }
}
bdrv_delete(bs);
diff --git a/qemu-progress.c b/qemu-progress.c
new file mode 100644
index 0000000..656e065
--- /dev/null
+++ b/qemu-progress.c
@@ -0,0 +1,89 @@
+/*
+ * QEMU progress printing utility functions
+ *
+ * Copyright (C) 2011 Jes Sorensen <Jes.Sorensen@redhat.com>
+ *
+ * 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 "osdep.h"
+#include "sysemu.h"
+#include <stdio.h>
+
+struct progress_state {
+ int enabled;
+ float current;
+ float last_print;
+ float min_skip;
+};
+
+static struct progress_state state;
+
+/*
+ * Simple progress print function.
+ * @percent relative percent of current operation
+ * @max percent of total operation
+ */
+static void progress_simple_print(void)
+{
+ if (state.enabled) {
+ printf(" (%3.2f/100%%)\r", state.current);
+ fflush(stdout);
+ }
+}
+
+static void progress_simple_end(void)
+{
+ if (state.enabled) {
+ printf("\n");
+ }
+}
+
+void qemu_progress_init(int enabled, float min_skip)
+{
+ state.enabled = enabled;
+ state.min_skip = min_skip;
+}
+
+void qemu_progress_end(void)
+{
+ progress_simple_end();
+}
+
+void qemu_progress_print(float percent, int max)
+{
+ float current;
+
+ if (max == 0) {
+ current = percent;
+ } else {
+ current = state.current + percent / 100 * max;
+ }
+ if (current > 100) {
+ current = 100;
+ }
+ state.current = current;
+
+ if (current > (state.last_print + state.min_skip) ||
+ (current == 100) || (current == 0)) {
+ state.last_print = state.current;
+ progress_simple_print();
+ }
+}
diff --git a/qemu-sockets.c b/qemu-sockets.c
index c526324..eda1850 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -627,24 +627,28 @@ int unix_connect(const char *path)
int unix_listen_opts(QemuOpts *opts)
{
fprintf(stderr, "unix sockets are not available on windows\n");
+ errno = ENOTSUP;
return -1;
}
int unix_connect_opts(QemuOpts *opts)
{
fprintf(stderr, "unix sockets are not available on windows\n");
+ errno = ENOTSUP;
return -1;
}
int unix_listen(const char *path, char *ostr, int olen)
{
fprintf(stderr, "unix sockets are not available on windows\n");
+ errno = ENOTSUP;
return -1;
}
int unix_connect(const char *path)
{
fprintf(stderr, "unix sockets are not available on windows\n");
+ errno = ENOTSUP;
return -1;
}
diff --git a/trace-events b/trace-events
index 06efdb7..703b745 100644
--- a/trace-events
+++ b/trace-events
@@ -54,6 +54,7 @@ disable bdrv_aio_multiwrite_latefail(void *mcb, int i) "mcb %p i %d"
disable bdrv_aio_flush(void *bs, void *opaque) "bs %p opaque %p"
disable bdrv_aio_readv(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
disable bdrv_aio_writev(void *bs, int64_t sector_num, int nb_sectors, void *opaque) "bs %p sector_num %"PRId64" nb_sectors %d opaque %p"
+disable bdrv_set_locked(void *bs, int locked) "bs %p locked %d"
# hw/virtio-blk.c
disable virtio_blk_req_complete(void *req, int status) "req %p status %d"
diff --git a/vl.c b/vl.c
index de232b7..68c3b53 100644
--- a/vl.c
+++ b/vl.c
@@ -2102,7 +2102,9 @@ int main(int argc, char **argv, char **envp)
HD_OPTS);
break;
case QEMU_OPTION_drive:
- drive_def(optarg);
+ if (drive_def(optarg) == NULL) {
+ exit(1);
+ }
break;
case QEMU_OPTION_set:
if (qemu_set_option(optarg) != 0)