aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2010-02-25 23:34:00 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2010-02-25 23:34:00 -0300
commit69a5ecafa27daeb943dc2ee65b1470844f23f934 (patch)
tree13a30a888ad68d5fb63746ad921bf1afc75c82d2
parent64defc2b52571c5f891b018c8f2b70b10f3bb11c (diff)
parent352de743974a48e282a5d37f053aa664404e311b (diff)
Merge branch 'stable-0.12-merge' into stable-0.12qemu-kvm-0.12.3
* stable-0.12-merge: (52 commits) Update version and change for 0.12.3 release qcow2: Fix access after end of array ide save/restore pio/atapi cmd transfer fields and io buffer net: Monitor command set_link finds only VLAN clients, fix net: info network shows only VLAN clients, fix net: net_check_clients() checks only VLAN clients, fix net: Fix bogus "Warning: vlan 0 with no nics" with -device net: net_check_clients() runs too early to see -device, fix net: Remove unused net_client_uninit() don't dereference NULL after failed strdup virtio-net: fix network stall under load json: fix PRId64 on Win32 fix inet_parse typo iothread: fix vcpu stop with smp tcg segfault due to buffer overrun in usb-serial qcow2: Fix signedness bugs Do not ignore error, if open file failed (-serial /dev/tty) pc-bios: update to newer version of (stable) seabios kvm: Fix eflags corruption in kvm mode target-mips: fix ROTR and DROTR by zero ... Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--Changelog52
-rw-r--r--VERSION2
-rw-r--r--block.c36
-rw-r--r--block/curl.c2
-rw-r--r--block/qcow2-cluster.c107
-rw-r--r--block/qcow2-refcount.c84
-rw-r--r--block/qcow2-snapshot.c11
-rw-r--r--block/qcow2.c41
-rw-r--r--block/qcow2.h10
-rw-r--r--block/raw-posix.c2
-rw-r--r--block/vvfat.c10
-rw-r--r--cpu-exec.c12
-rw-r--r--exec.c2
-rw-r--r--hw/cirrus_vga.c6
-rw-r--r--hw/ide/core.c78
-rw-r--r--hw/ide/internal.h9
-rw-r--r--hw/ide/qdev.c3
-rw-r--r--hw/mc146818rtc.c2
-rw-r--r--hw/musicpal.c9
-rw-r--r--hw/pc.c16
-rw-r--r--hw/scsi-disk.c7
-rw-r--r--hw/usb-net.c2
-rw-r--r--hw/usb-serial.c32
-rw-r--r--hw/virtio-blk.c93
-rw-r--r--hw/virtio-net.c10
-rw-r--r--json-lexer.c16
-rw-r--r--json-parser.c3
-rw-r--r--monitor.c11
-rw-r--r--net.c64
-rw-r--r--net.h3
-rw-r--r--net/slirp.c4
-rw-r--r--net/socket.c4
-rw-r--r--net/tap-win32.c4
-rw-r--r--net/tap.c4
-rw-r--r--net/vde.c4
-rw-r--r--pc-bios/bios.binbin131072 -> 131072 bytes
-rw-r--r--qemu-char.c3
-rw-r--r--qemu-common.h3
-rw-r--r--qemu-nbd.c2
-rw-r--r--qemu-options.hx25
-rw-r--r--qemu-sockets.c8
m---------roms/seabios0
-rw-r--r--savevm.c2
-rw-r--r--sdl.c1
-rw-r--r--slirp/misc.c2
-rw-r--r--target-mips/cpu.h4
-rw-r--r--target-mips/helper.c8
-rw-r--r--target-mips/op_helper.c18
-rw-r--r--target-mips/translate.c6
-rw-r--r--tcg/mips/tcg-target.c4
-rw-r--r--usb-linux.c2
-rw-r--r--vl.c7
-rw-r--r--vnc.c6
53 files changed, 594 insertions, 262 deletions
diff --git a/Changelog b/Changelog
index dede703d3..67d0efd3a 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,55 @@
+version 0.12.3
+ - kvm: Fix eflags corruption in kvm mode (Jan Kiszka)
+ - qcow2: Fix access after end of array (Kevin Wolf)
+ - ide save/restore pio/atapi cmd transfer fields and io buffer (Marcelo Tosatti)
+ - net: Monitor command set_link finds only VLAN clients, fix (Markus Armbruster)
+ - net: info network shows only VLAN clients, fix (Markus Armbruster)
+ - net: net_check_clients() checks only VLAN clients, fix (Markus Armbruster)
+ - net: Fix bogus "Warning: vlan 0 with no nics" with -device (Markus Armbruster)
+ - net: net_check_clients() runs too early to see -device, fix (Markus Armbruster)
+ - net: Remove unused net_client_uninit() (Markus Armbruster)
+ - don't dereference NULL after failed strdup (Jim Meyering)
+ - virtio-net: fix network stall under load (Tom Lendacky)
+ - json: fix PRId64 on Win32 (Roy Tam)
+ - fix inet_parse typo (Marcelo Tosatti)
+ - iothread: fix vcpu stop with smp tcg (Marcelo Tosatti)
+ - segfault due to buffer overrun in usb-serial (David S. Ahern)
+ - qcow2: Fix signedness bugs (Kevin Wolf)
+ - Do not ignore error, if open file failed (-serial /dev/tty) (Evgeniy Dushistov)
+ - pc-bios: update to newer version of (stable) seabios (Anthony Liguori)
+ - target-mips: fix ROTR and DROTR by zero (Aurelien Jarno)
+ - target-mips: fix CpU exception for coprocessor 0 (Nathan Froyd)
+ - tcg/mips: fix crash in tcg_out_qemu_ld() (Aurelien Jarno)
+ - target-mips: don't call cpu_loop_exit() from helper.c (Aurelien Jarno)
+ - virtio-blk: Fix error cases which ignored rerror/werror (Kevin Wolf)
+ - virtio-blk: Fix restart after read error (Kevin Wolf)
+ - virtio_blk: Factor virtio_blk_handle_request out (Kevin Wolf)
+ - cirrus: Properly re-register cirrus_linear_io_addr on vram unmap (Jan Kiszka)
+ - qcow2: Don't ignore qcow2_alloc_clusters return value (Kevin Wolf)
+ - qcow2: Don't ignore update_refcount return value (Kevin Wolf)
+ - qcow2: Allow updating no refcounts (Kevin Wolf)
+ - qcow2: Improve error handling in update_refcount (Kevin Wolf)
+ - qcow2: Fix error handling in grow_refcount_table (Kevin Wolf)
+ - block: Return original error codes in bdrv_pread/write (Kevin Wolf)
+ - qcow2: Return 0/-errno in qcow2_alloc_cluster_offset (Kevin Wolf)
+ - qcow2: Return 0/-errno in get_cluster_table (Kevin Wolf)
+ - qcow2: Fix error handling in qcow_save_vmstate (Kevin Wolf)
+ - qcow2: Fix error handling in qcow2_grow_l1_table (Kevin Wolf)
+ - win32/sdl: Fix toggle full screen (Herve Poussineau)
+ - win32: pair qemu_memalign() with qemu_vfree() (Herve Poussineau)
+ - vnc_refresh: calling vnc_update_client might free vs (Stefano Stabellini)
+ - Musicpal: Fix descriptor walk in eth_send (Jan Kiszka)
+ - Musicpal: Fix wm8750 I2C address (Jan Kiszka)
+ - fix savevm command without id or tag (Marcelo Tosatti)
+ - reduce number of reinjects on ACK (Gleb Natapov)
+ - QMP: Fix asynchronous events delivery (Luiz Capitulino)
+ - Documentation: Add missing documentation for qdev related command line options (Stefan Weil)
+ - pc: add driver version compat properties (Gerd Hoffmann)
+ - scsi: device version property (Gerd Hoffmann)
+ - ide: device version property (Gerd Hoffmann)
+ - QMP: Emit asynchronous events on all QMP monitors (Adam Litke)
+ - Fix QEMU_WARN_UNUSED_RESULT (Kevin Wolf)
+
version 0.12.2:
- Qemu's internal TFTP server breaks lock-step-iness of TFTP (Milan Plzik)
- osdep.c: Fix accept4 fallback (Kevin Wolf)
diff --git a/VERSION b/VERSION
index 26acbf080..aa22d3ce3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.12.2
+0.12.3
diff --git a/block.c b/block.c
index 3f3496ec9..97af3f577 100644
--- a/block.c
+++ b/block.c
@@ -691,6 +691,7 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
+ int ret;
count = count1;
/* first read to align to sector start */
@@ -699,8 +700,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
len = count;
sector_num = offset >> BDRV_SECTOR_BITS;
if (len > 0) {
- if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
- return -EIO;
+ if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+ return ret;
memcpy(buf, tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), len);
count -= len;
if (count == 0)
@@ -712,8 +713,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
/* read the sectors "in place" */
nb_sectors = count >> BDRV_SECTOR_BITS;
if (nb_sectors > 0) {
- if (bdrv_read(bs, sector_num, buf, nb_sectors) < 0)
- return -EIO;
+ if ((ret = bdrv_read(bs, sector_num, buf, nb_sectors)) < 0)
+ return ret;
sector_num += nb_sectors;
len = nb_sectors << BDRV_SECTOR_BITS;
buf += len;
@@ -722,8 +723,8 @@ int bdrv_pread(BlockDriverState *bs, int64_t offset,
/* add data from the last sector */
if (count > 0) {
- if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
- return -EIO;
+ if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+ return ret;
memcpy(buf, tmp_buf, count);
}
return count1;
@@ -735,6 +736,7 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
uint8_t tmp_buf[BDRV_SECTOR_SIZE];
int len, nb_sectors, count;
int64_t sector_num;
+ int ret;
count = count1;
/* first write to align to sector start */
@@ -743,11 +745,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
len = count;
sector_num = offset >> BDRV_SECTOR_BITS;
if (len > 0) {
- if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
- return -EIO;
+ if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+ return ret;
memcpy(tmp_buf + (offset & (BDRV_SECTOR_SIZE - 1)), buf, len);
- if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
- return -EIO;
+ if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
+ return ret;
count -= len;
if (count == 0)
return count1;
@@ -758,8 +760,8 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
/* write the sectors "in place" */
nb_sectors = count >> BDRV_SECTOR_BITS;
if (nb_sectors > 0) {
- if (bdrv_write(bs, sector_num, buf, nb_sectors) < 0)
- return -EIO;
+ if ((ret = bdrv_write(bs, sector_num, buf, nb_sectors)) < 0)
+ return ret;
sector_num += nb_sectors;
len = nb_sectors << BDRV_SECTOR_BITS;
buf += len;
@@ -768,11 +770,11 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset,
/* add data from the last sector */
if (count > 0) {
- if (bdrv_read(bs, sector_num, tmp_buf, 1) < 0)
- return -EIO;
+ if ((ret = bdrv_read(bs, sector_num, tmp_buf, 1)) < 0)
+ return ret;
memcpy(tmp_buf, buf, count);
- if (bdrv_write(bs, sector_num, tmp_buf, 1) < 0)
- return -EIO;
+ if ((ret = bdrv_write(bs, sector_num, tmp_buf, 1)) < 0)
+ return ret;
}
return count1;
}
@@ -1607,7 +1609,7 @@ static void multiwrite_user_cb(MultiwriteCB *mcb)
for (i = 0; i < mcb->num_callbacks; i++) {
mcb->callbacks[i].cb(mcb->callbacks[i].opaque, mcb->error);
qemu_free(mcb->callbacks[i].free_qiov);
- qemu_free(mcb->callbacks[i].free_buf);
+ qemu_vfree(mcb->callbacks[i].free_buf);
}
}
diff --git a/block/curl.c b/block/curl.c
index 5223ce879..c9c457486 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -309,7 +309,7 @@ static int curl_open(BlockDriverState *bs, const char *filename, int flags)
static int inited = 0;
- file = strdup(filename);
+ file = qemu_strdup(filename);
s->readahead_size = READ_AHEAD_SIZE;
/* Parse a trailing ":readahead=#:" param, if present. */
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index f88118cdc..b13b6935f 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -33,7 +33,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
BDRVQcowState *s = bs->opaque;
int new_l1_size, new_l1_size2, ret, i;
uint64_t *new_l1_table;
- uint64_t new_l1_table_offset;
+ int64_t new_l1_table_offset;
uint8_t data[12];
new_l1_size = s->l1_size;
@@ -55,6 +55,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
/* write new table (align to cluster) */
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
+ if (new_l1_table_offset < 0) {
+ qemu_free(new_l1_table);
+ return new_l1_table_offset;
+ }
for(i = 0; i < s->l1_size; i++)
new_l1_table[i] = cpu_to_be64(new_l1_table[i]);
@@ -67,9 +71,10 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
/* set new table */
cpu_to_be32w((uint32_t*)data, new_l1_size);
cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset);
- if (bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,
- sizeof(data)) != sizeof(data))
+ ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data));
+ if (ret != sizeof(data)) {
goto fail;
+ }
qemu_free(s->l1_table);
qcow2_free_clusters(bs, s->l1_table_offset, s->l1_size * sizeof(uint64_t));
s->l1_table_offset = new_l1_table_offset;
@@ -77,8 +82,9 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size)
s->l1_size = new_l1_size;
return 0;
fail:
- qemu_free(s->l1_table);
- return -EIO;
+ qemu_free(new_l1_table);
+ qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2);
+ return ret < 0 ? ret : -EIO;
}
void qcow2_l2_cache_reset(BlockDriverState *bs)
@@ -213,13 +219,17 @@ static uint64_t *l2_allocate(BlockDriverState *bs, int l1_index)
BDRVQcowState *s = bs->opaque;
int min_index;
uint64_t old_l2_offset;
- uint64_t *l2_table, l2_offset;
+ uint64_t *l2_table;
+ int64_t l2_offset;
old_l2_offset = s->l1_table[l1_index];
/* allocate a new l2 entry */
l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
+ if (l2_offset < 0) {
+ return NULL;
+ }
/* update the L1 entry */
@@ -479,8 +489,8 @@ out:
* the l2 table offset in the qcow2 file and the cluster index
* in the l2 table are given to the caller.
*
+ * Returns 0 on success, -errno in failure case
*/
-
static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
uint64_t **new_l2_table,
uint64_t *new_l2_offset,
@@ -496,8 +506,9 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
l1_index = offset >> (s->l2_bits + s->cluster_bits);
if (l1_index >= s->l1_size) {
ret = qcow2_grow_l1_table(bs, l1_index + 1);
- if (ret < 0)
- return 0;
+ if (ret < 0) {
+ return ret;
+ }
}
l2_offset = s->l1_table[l1_index];
@@ -507,14 +518,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
/* load the l2 table in memory */
l2_offset &= ~QCOW_OFLAG_COPIED;
l2_table = l2_load(bs, l2_offset);
- if (l2_table == NULL)
- return 0;
+ if (l2_table == NULL) {
+ return -EIO;
+ }
} else {
if (l2_offset)
qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
l2_table = l2_allocate(bs, l1_index);
- if (l2_table == NULL)
- return 0;
+ if (l2_table == NULL) {
+ return -EIO;
+ }
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
}
@@ -526,7 +539,7 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
*new_l2_offset = l2_offset;
*new_l2_index = l2_index;
- return 1;
+ return 0;
}
/*
@@ -548,12 +561,14 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
- uint64_t l2_offset, *l2_table, cluster_offset;
+ uint64_t l2_offset, *l2_table;
+ int64_t cluster_offset;
int nb_csectors;
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
- if (ret == 0)
+ if (ret < 0) {
return 0;
+ }
cluster_offset = be64_to_cpu(l2_table[l2_index]);
if (cluster_offset & QCOW_OFLAG_COPIED)
@@ -563,6 +578,10 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
qcow2_free_any_clusters(bs, cluster_offset, 1);
cluster_offset = qcow2_alloc_bytes(bs, compressed_size);
+ if (cluster_offset < 0) {
+ return 0;
+ }
+
nb_csectors = ((cluster_offset + compressed_size - 1) >> 9) -
(cluster_offset >> 9);
@@ -605,12 +624,12 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table,
return 0;
}
-int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
- QCowL2Meta *m)
+int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int i, j = 0, l2_index, ret;
uint64_t *old_cluster, start_sect, l2_offset, *l2_table;
+ uint64_t cluster_offset = m->cluster_offset;
if (m->nb_clusters == 0)
return 0;
@@ -633,10 +652,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
goto err;
}
- ret = -EIO;
/* update L2 table */
- if (!get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index))
+ ret = get_cluster_table(bs, m->offset, &l2_table, &l2_offset, &l2_index);
+ if (ret < 0) {
goto err;
+ }
for (i = 0; i < m->nb_clusters; i++) {
/* if two concurrent writes happen to the same unallocated cluster
@@ -670,30 +690,36 @@ err:
/*
* alloc_cluster_offset
*
- * For a given offset of the disk image, return cluster offset in
- * qcow2 file.
- *
+ * For a given offset of the disk image, return cluster offset in qcow2 file.
* If the offset is not found, allocate a new cluster.
*
- * Return the cluster offset if successful,
- * Return 0, otherwise.
+ * If the cluster was already allocated, m->nb_clusters is set to 0,
+ * m->depends_on is set to NULL and the other fields in m are meaningless.
*
+ * If the cluster is newly allocated, m->nb_clusters is set to the number of
+ * contiguous clusters that have been allocated. This may be 0 if the request
+ * conflict with another write request in flight; in this case, m->depends_on
+ * is set and the remaining fields of m are meaningless.
+ *
+ * If m->nb_clusters is non-zero, the other fields of m are valid and contain
+ * information about the first allocated cluster.
+ *
+ * Return 0 on success and -errno in error cases
*/
-
-uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
- uint64_t offset,
- int n_start, int n_end,
- int *num, QCowL2Meta *m)
+int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
+ int n_start, int n_end, int *num, QCowL2Meta *m)
{
BDRVQcowState *s = bs->opaque;
int l2_index, ret;
- uint64_t l2_offset, *l2_table, cluster_offset;
+ uint64_t l2_offset, *l2_table;
+ int64_t cluster_offset;
unsigned int nb_clusters, i = 0;
QCowL2Meta *old_alloc;
ret = get_cluster_table(bs, offset, &l2_table, &l2_offset, &l2_index);
- if (ret == 0)
- return 0;
+ if (ret < 0) {
+ return ret;
+ }
nb_clusters = size_to_clusters(s, n_end << 9);
@@ -709,6 +735,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
cluster_offset &= ~QCOW_OFLAG_COPIED;
m->nb_clusters = 0;
+ m->depends_on = NULL;
goto out;
}
@@ -723,12 +750,15 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
while (i < nb_clusters) {
i += count_contiguous_clusters(nb_clusters - i, s->cluster_size,
&l2_table[l2_index], i, 0);
-
- if(be64_to_cpu(l2_table[l2_index + i]))
+ if ((i >= nb_clusters) || be64_to_cpu(l2_table[l2_index + i])) {
break;
+ }
i += count_contiguous_free_clusters(nb_clusters - i,
&l2_table[l2_index + i]);
+ if (i >= nb_clusters) {
+ break;
+ }
cluster_offset = be64_to_cpu(l2_table[l2_index + i]);
@@ -736,6 +766,7 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
(cluster_offset & QCOW_OFLAG_COMPRESSED))
break;
}
+ assert(i <= nb_clusters);
nb_clusters = i;
/*
@@ -779,6 +810,9 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
/* allocate a new cluster */
cluster_offset = qcow2_alloc_clusters(bs, nb_clusters * s->cluster_size);
+ if (cluster_offset < 0) {
+ return cluster_offset;
+ }
/* save info needed for meta data update */
m->offset = offset;
@@ -787,10 +821,11 @@ uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
out:
m->nb_available = MIN(nb_clusters << (s->cluster_bits - 9), n_end);
+ m->cluster_offset = cluster_offset;
*num = m->nb_available - n_start;
- return cluster_offset;
+ return 0;
}
static int decompress_buffer(uint8_t *out_buf, int out_buf_size,
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 54b19f86d..c2a5c0471 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -168,9 +168,12 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
cpu_to_be64w((uint64_t*)data, table_offset);
cpu_to_be32w((uint32_t*)(data + 8), refcount_table_clusters);
- if (bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
- data, sizeof(data)) != sizeof(data))
+ ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset),
+ data, sizeof(data));
+ if (ret != sizeof(data)) {
goto fail;
+ }
+
qemu_free(s->refcount_table);
old_table_offset = s->refcount_table_offset;
old_table_size = s->refcount_table_size;
@@ -183,7 +186,7 @@ static int grow_refcount_table(BlockDriverState *bs, int min_size)
return 0;
fail:
qemu_free(new_table);
- return -EIO;
+ return ret < 0 ? ret : -EIO;
}
@@ -266,22 +269,26 @@ static int write_refcount_block_entries(BDRVQcowState *s,
}
/* XXX: cache several refcount block clusters ? */
-static int update_refcount(BlockDriverState *bs,
- int64_t offset, int64_t length,
- int addend)
+static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
+ int64_t offset, int64_t length, int addend)
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
int64_t refcount_block_offset = 0;
int64_t table_index = -1, old_table_index;
int first_index = -1, last_index = -1;
+ int ret;
#ifdef DEBUG_ALLOC2
printf("update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
offset, length, addend);
#endif
- if (length <= 0)
+ if (length < 0) {
return -EINVAL;
+ } else if (length == 0) {
+ return 0;
+ }
+
start = offset & ~(s->cluster_size - 1);
last = (offset + length - 1) & ~(s->cluster_size - 1);
for(cluster_offset = start; cluster_offset <= last;
@@ -289,6 +296,7 @@ static int update_refcount(BlockDriverState *bs,
{
int block_index, refcount;
int64_t cluster_index = cluster_offset >> s->cluster_bits;
+ int64_t new_block;
/* Only write refcount block to disk when we are done with it */
old_table_index = table_index;
@@ -306,10 +314,12 @@ static int update_refcount(BlockDriverState *bs,
}
/* Load the refcount block and allocate it if needed */
- refcount_block_offset = alloc_refcount_block(bs, cluster_index);
- if (refcount_block_offset < 0) {
- return refcount_block_offset;
+ new_block = alloc_refcount_block(bs, cluster_index);
+ if (new_block < 0) {
+ ret = new_block;
+ goto fail;
}
+ refcount_block_offset = new_block;
/* we can update the count and save it */
block_index = cluster_index &
@@ -323,24 +333,38 @@ static int update_refcount(BlockDriverState *bs,
refcount = be16_to_cpu(s->refcount_block_cache[block_index]);
refcount += addend;
- if (refcount < 0 || refcount > 0xffff)
- return -EINVAL;
+ if (refcount < 0 || refcount > 0xffff) {
+ ret = -EINVAL;
+ goto fail;
+ }
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
s->refcount_block_cache[block_index] = cpu_to_be16(refcount);
}
+ ret = 0;
+fail:
+
/* Write last changed block to disk */
if (refcount_block_offset != 0) {
if (write_refcount_block_entries(s, refcount_block_offset,
first_index, last_index) < 0)
{
- return -EIO;
+ return ret < 0 ? ret : -EIO;
}
}
- return 0;
+ /*
+ * Try do undo any updates if an error is returned (This may succeed in
+ * some cases like ENOSPC for allocating a new refcount block)
+ */
+ if (ret < 0) {
+ int dummy;
+ dummy = update_refcount(bs, offset, cluster_offset - offset, -addend);
+ }
+
+ return ret;
}
/* addend must be 1 or -1 */
@@ -390,9 +414,13 @@ retry:
int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size)
{
int64_t offset;
+ int ret;
offset = alloc_clusters_noref(bs, size);
- update_refcount(bs, offset, size, 1);
+ ret = update_refcount(bs, offset, size, 1);
+ if (ret < 0) {
+ return ret;
+ }
return offset;
}
@@ -407,6 +435,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
assert(size > 0 && size <= s->cluster_size);
if (s->free_byte_offset == 0) {
s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size);
+ if (s->free_byte_offset < 0) {
+ return s->free_byte_offset;
+ }
}
redo:
free_in_cluster = s->cluster_size -
@@ -422,6 +453,9 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
update_cluster_refcount(bs, offset >> s->cluster_bits, 1);
} else {
offset = qcow2_alloc_clusters(bs, s->cluster_size);
+ if (offset < 0) {
+ return offset;
+ }
cluster_offset = s->free_byte_offset & ~(s->cluster_size - 1);
if ((cluster_offset + s->cluster_size) == offset) {
/* we are lucky: contiguous data */
@@ -439,7 +473,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
void qcow2_free_clusters(BlockDriverState *bs,
int64_t offset, int64_t size)
{
- update_refcount(bs, offset, size, -1);
+ int ret;
+
+ ret = update_refcount(bs, offset, size, -1);
+ if (ret < 0) {
+ fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
+ abort();
+ }
}
/*
@@ -549,9 +589,15 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (offset & QCOW_OFLAG_COMPRESSED) {
nb_csectors = ((offset >> s->csize_shift) &
s->csize_mask) + 1;
- if (addend != 0)
- update_refcount(bs, (offset & s->cluster_offset_mask) & ~511,
- nb_csectors * 512, addend);
+ if (addend != 0) {
+ int ret;
+ ret = update_refcount(bs,
+ (offset & s->cluster_offset_mask) & ~511,
+ nb_csectors * 512, addend);
+ if (ret < 0) {
+ goto fail;
+ }
+ }
/* compressed clusters are never modified */
refcount = 2;
} else {
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index d63c7e17d..8ddaea23b 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -139,6 +139,9 @@ static int qcow_write_snapshots(BlockDriverState *bs)
snapshots_offset = qcow2_alloc_clusters(bs, snapshots_size);
offset = snapshots_offset;
+ if (offset < 0) {
+ return offset;
+ }
for(i = 0; i < s->nb_snapshots; i++) {
sn = s->snapshots + i;
@@ -235,6 +238,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
QCowSnapshot *snapshots1, sn1, *sn = &sn1;
int i, ret;
uint64_t *l1_table = NULL;
+ int64_t l1_table_offset;
memset(sn, 0, sizeof(*sn));
@@ -263,7 +267,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
goto fail;
/* create the L1 table of the snapshot */
- sn->l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
+ l1_table_offset = qcow2_alloc_clusters(bs, s->l1_size * sizeof(uint64_t));
+ if (l1_table_offset < 0) {
+ goto fail;
+ }
+
+ sn->l1_table_offset = l1_table_offset;
sn->l1_size = s->l1_size;
if (s->l1_size != 0) {
diff --git a/block/qcow2.c b/block/qcow2.c
index 984264b3e..4ae8f193d 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -561,7 +561,7 @@ static void qcow_aio_write_cb(void *opaque, int ret)
acb->hd_aiocb = NULL;
if (ret >= 0) {
- ret = qcow2_alloc_cluster_link_l2(bs, acb->cluster_offset, &acb->l2meta);
+ ret = qcow2_alloc_cluster_link_l2(bs, &acb->l2meta);
}
run_dependent_requests(&acb->l2meta);
@@ -585,21 +585,23 @@ static void qcow_aio_write_cb(void *opaque, int ret)
n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors)
n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;
- acb->cluster_offset = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
- index_in_cluster,
- n_end, &acb->n, &acb->l2meta);
+ ret = qcow2_alloc_cluster_offset(bs, acb->sector_num << 9,
+ index_in_cluster, n_end, &acb->n, &acb->l2meta);
+ if (ret < 0) {
+ goto done;
+ }
+
+ acb->cluster_offset = acb->l2meta.cluster_offset;
/* Need to wait for another request? If so, we are done for now. */
- if (!acb->cluster_offset && acb->l2meta.depends_on != NULL) {
+ if (acb->l2meta.nb_clusters == 0 && acb->l2meta.depends_on != NULL) {
QLIST_INSERT_HEAD(&acb->l2meta.depends_on->dependent_requests,
acb, next_depend);
return;
}
- if (!acb->cluster_offset || (acb->cluster_offset & 511) != 0) {
- ret = -EIO;
- goto done;
- }
+ assert((acb->cluster_offset & 511) == 0);
+
if (s->crypt_method) {
if (!acb->cluster_data) {
acb->cluster_data = qemu_mallocz(QCOW_MAX_CRYPT_CLUSTERS *
@@ -683,27 +685,27 @@ static int get_bits_from_size(size_t size)
static int preallocate(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
- uint64_t cluster_offset = 0;
uint64_t nb_sectors;
uint64_t offset;
int num;
+ int ret;
QCowL2Meta meta;
nb_sectors = bdrv_getlength(bs) >> 9;
offset = 0;
QLIST_INIT(&meta.dependent_requests);
+ meta.cluster_offset = 0;
while (nb_sectors) {
num = MIN(nb_sectors, INT_MAX >> 9);
- cluster_offset = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num,
- &meta);
+ ret = qcow2_alloc_cluster_offset(bs, offset, 0, num, &num, &meta);
- if (cluster_offset == 0) {
+ if (ret < 0) {
return -1;
}
- if (qcow2_alloc_cluster_link_l2(bs, cluster_offset, &meta) < 0) {
- qcow2_free_any_clusters(bs, cluster_offset, meta.nb_clusters);
+ if (qcow2_alloc_cluster_link_l2(bs, &meta) < 0) {
+ qcow2_free_any_clusters(bs, meta.cluster_offset, meta.nb_clusters);
return -1;
}
@@ -722,10 +724,10 @@ static int preallocate(BlockDriverState *bs)
* all of the allocated clusters (otherwise we get failing reads after
* EOF). Extend the image to the last allocated sector.
*/
- if (cluster_offset != 0) {
+ if (meta.cluster_offset != 0) {
uint8_t buf[512];
memset(buf, 0, 512);
- bdrv_write(s->hd, (cluster_offset >> 9) + num - 1, buf, 1);
+ bdrv_write(s->hd, (meta.cluster_offset >> 9) + num - 1, buf, 1);
}
return 0;
@@ -1056,12 +1058,13 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf,
{
BDRVQcowState *s = bs->opaque;
int growable = bs->growable;
+ int ret;
bs->growable = 1;
- bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
+ ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size);
bs->growable = growable;
- return size;
+ return ret;
}
static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf,
diff --git a/block/qcow2.h b/block/qcow2.h
index 26ab5d952..de9397a3d 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -135,6 +135,7 @@ struct QCowAIOCB;
typedef struct QCowL2Meta
{
uint64_t offset;
+ uint64_t cluster_offset;
int n_start;
int nb_available;
int nb_clusters;
@@ -191,16 +192,13 @@ void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num,
uint64_t qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
int *num);
-uint64_t qcow2_alloc_cluster_offset(BlockDriverState *bs,
- uint64_t offset,
- int n_start, int n_end,
- int *num, QCowL2Meta *m);
+int qcow2_alloc_cluster_offset(BlockDriverState *bs, uint64_t offset,
+ int n_start, int n_end, int *num, QCowL2Meta *m);
uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs,
uint64_t offset,
int compressed_size);
-int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, uint64_t cluster_offset,
- QCowL2Meta *m);
+int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m);
/* qcow2-snapshot.c functions */
int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info);
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 6dcc65189..c204cf94e 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -597,7 +597,7 @@ static void raw_close(BlockDriverState *bs)
close(s->fd);
s->fd = -1;
if (s->aligned_buf != NULL)
- qemu_free(s->aligned_buf);
+ qemu_vfree(s->aligned_buf);
}
}
diff --git a/block/vvfat.c b/block/vvfat.c
index 063f7318c..c1acb3586 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -882,7 +882,7 @@ static int init_directories(BDRVVVFATState* s,
mapping->dir_index = 0;
mapping->info.dir.parent_mapping_index = -1;
mapping->first_mapping_index = -1;
- mapping->path = strdup(dirname);
+ mapping->path = qemu_strdup(dirname);
i = strlen(mapping->path);
if (i > 0 && mapping->path[i - 1] == '/')
mapping->path[i - 1] = '\0';
@@ -1632,10 +1632,10 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
/* rename */
if (strcmp(basename, basename2))
- schedule_rename(s, cluster_num, strdup(path));
+ schedule_rename(s, cluster_num, qemu_strdup(path));
} else if (is_file(direntry))
/* new file */
- schedule_new_file(s, strdup(path), cluster_num);
+ schedule_new_file(s, qemu_strdup(path), cluster_num);
else {
assert(0);
return 0;
@@ -1752,10 +1752,10 @@ static int check_directory_consistency(BDRVVVFATState *s,
mapping->mode &= ~MODE_DELETED;
if (strcmp(basename, basename2))
- schedule_rename(s, cluster_num, strdup(path));
+ schedule_rename(s, cluster_num, qemu_strdup(path));
} else
/* new directory */
- schedule_mkdir(s, cluster_num, strdup(path));
+ schedule_mkdir(s, cluster_num, qemu_strdup(path));
lfn_init(&lfn);
do {
diff --git a/cpu-exec.c b/cpu-exec.c
index 0f085eab3..040d4741b 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -236,11 +236,13 @@ int cpu_exec(CPUState *env1)
env_to_regs();
#if defined(TARGET_I386)
- /* put eflags in CPU temporary format */
- CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
- DF = 1 - (2 * ((env->eflags >> 10) & 1));
- CC_OP = CC_OP_EFLAGS;
- env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ if (!kvm_enabled()) {
+ /* put eflags in CPU temporary format */
+ CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ DF = 1 - (2 * ((env->eflags >> 10) & 1));
+ CC_OP = CC_OP_EFLAGS;
+ env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
+ }
#elif defined(TARGET_SPARC)
#elif defined(TARGET_M68K)
env->cc_op = CC_OP_FLAGS;
diff --git a/exec.c b/exec.c
index 8f873abab..4bae1d9ef 100644
--- a/exec.c
+++ b/exec.c
@@ -3455,7 +3455,7 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
if (is_write) {
cpu_physical_memory_write(bounce.addr, bounce.buffer, access_len);
}
- qemu_free(bounce.buffer);
+ qemu_vfree(bounce.buffer);
bounce.buffer = NULL;
cpu_notify_map_clients();
}
diff --git a/hw/cirrus_vga.c b/hw/cirrus_vga.c
index 25c68b1d9..571044f64 100644
--- a/hw/cirrus_vga.c
+++ b/hw/cirrus_vga.c
@@ -2595,9 +2595,11 @@ static void map_linear_vram(CirrusVGAState *s)
static void unmap_linear_vram(CirrusVGAState *s)
{
vga_dirty_log_stop(&s->vga);
- if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end)
+ if (s->vga.map_addr && s->vga.lfb_addr && s->vga.lfb_end) {
s->vga.map_addr = s->vga.map_end = 0;
-
+ cpu_register_physical_memory(s->vga.lfb_addr, s->vga.vram_size,
+ s->cirrus_linear_io_addr);
+ }
cpu_register_physical_memory(isa_mem_base + 0xa0000, 0x20000,
s->vga.vga_io_memory);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 76c382080..64aebc276 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -115,7 +115,7 @@ static void ide_identify(IDEState *s)
put_le16(p + 20, 3); /* XXX: retired, remove ? */
put_le16(p + 21, 512); /* cache size in sectors */
put_le16(p + 22, 4); /* ecc bytes */
- padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+ padstr((char *)(p + 23), s->version, 8); /* firmware version */
padstr((char *)(p + 27), "QEMU HARDDISK", 40); /* model */
#if MAX_MULT_SECTORS > 1
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
@@ -186,7 +186,7 @@ static void ide_atapi_identify(IDEState *s)
put_le16(p + 20, 3); /* buffer type */
put_le16(p + 21, 512); /* cache size in sectors */
put_le16(p + 22, 4); /* ecc bytes */
- padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware version */
+ padstr((char *)(p + 23), s->version, 8); /* firmware version */
padstr((char *)(p + 27), "QEMU DVD-ROM", 40); /* model */
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
#ifdef USE_DMA_CDROM
@@ -238,7 +238,7 @@ static void ide_cfata_identify(IDEState *s)
put_le16(p + 8, s->nb_sectors); /* Sectors per card */
padstr((char *)(p + 10), s->drive_serial_str, 20); /* serial number */
put_le16(p + 22, 0x0004); /* ECC bytes */
- padstr((char *) (p + 23), QEMU_VERSION, 8); /* Firmware Revision */
+ padstr((char *) (p + 23), s->version, 8); /* Firmware Revision */
padstr((char *) (p + 27), "QEMU MICRODRIVE", 40);/* Model number */
#if MAX_MULT_SECTORS > 1
put_le16(p + 47, 0x8000 | MAX_MULT_SECTORS);
@@ -1591,7 +1591,7 @@ static void ide_atapi_cmd(IDEState *s)
buf[7] = 0; /* reserved */
padstr8(buf + 8, 8, "QEMU");
padstr8(buf + 16, 16, "QEMU DVD-ROM");
- padstr8(buf + 32, 4, QEMU_VERSION);
+ padstr8(buf + 32, 4, s->version);
ide_atapi_cmd_reply(s, 36, max_len);
break;
case GPCMD_GET_CONFIGURATION:
@@ -2590,7 +2590,7 @@ void ide_bus_reset(IDEBus *bus)
ide_clear_hob(bus);
}
-void ide_init_drive(IDEState *s, DriveInfo *dinfo)
+void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version)
{
int cylinders, heads, secs;
uint64_t nb_sectors;
@@ -2619,6 +2619,11 @@ void ide_init_drive(IDEState *s, DriveInfo *dinfo)
if (strlen(s->drive_serial_str) == 0)
snprintf(s->drive_serial_str, sizeof(s->drive_serial_str),
"QM%05d", s->drive_serial);
+ if (version) {
+ pstrcpy(s->version, sizeof(s->version), version);
+ } else {
+ pstrcpy(s->version, sizeof(s->version), QEMU_VERSION);
+ }
ide_reset(s);
}
@@ -2635,13 +2640,14 @@ void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
s->unit = i;
s->drive_serial = drive_serial++;
s->io_buffer = qemu_blockalign(s->bs, IDE_DMA_BUF_SECTORS*512 + 4);
+ s->io_buffer_total_len = IDE_DMA_BUF_SECTORS*512 + 4;
s->smart_selftest_data = qemu_blockalign(s->bs, 512);
s->sector_write_timer = qemu_new_timer(vm_clock,
ide_sector_write_timer_cb, s);
if (i == 0)
- ide_init_drive(s, hd0);
+ ide_init_drive(s, hd0, NULL);
if (i == 1)
- ide_init_drive(s, hd1);
+ ide_init_drive(s, hd1, NULL);
}
bus->irq = irq;
}
@@ -2669,6 +2675,25 @@ static bool is_identify_set(void *opaque, int version_id)
return s->identify_set != 0;
}
+static EndTransferFunc* transfer_end_table[] = {
+ ide_sector_read,
+ ide_sector_write,
+ ide_transfer_stop,
+ ide_atapi_cmd_reply_end,
+ ide_atapi_cmd,
+};
+
+static int transfer_end_table_idx(EndTransferFunc *fn)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(transfer_end_table); i++)
+ if (transfer_end_table[i] == fn)
+ return i;
+
+ return -1;
+}
+
static int ide_drive_post_load(void *opaque, int version_id)
{
IDEState *s = opaque;
@@ -2679,14 +2704,42 @@ static int ide_drive_post_load(void *opaque, int version_id)
s->cdrom_changed = 1;
}
}
+
+ if (s->cur_io_buffer_len) {
+ s->end_transfer_func = transfer_end_table[s->end_transfer_fn_idx];
+ s->data_ptr = s->io_buffer + s->cur_io_buffer_offset;
+ s->data_end = s->data_ptr + s->cur_io_buffer_len;
+ }
+
return 0;
}
+static void ide_drive_pre_save(void *opaque)
+{
+ IDEState *s = opaque;
+
+ s->cur_io_buffer_len = 0;
+
+ if (!(s->status & DRQ_STAT))
+ return;
+
+ s->cur_io_buffer_offset = s->data_ptr - s->io_buffer;
+ s->cur_io_buffer_len = s->data_end - s->data_ptr;
+
+ s->end_transfer_fn_idx = transfer_end_table_idx(s->end_transfer_func);
+ if (s->end_transfer_fn_idx == -1) {
+ fprintf(stderr, "%s: invalid end_transfer_func for DRQ_STAT\n",
+ __func__);
+ s->end_transfer_fn_idx = 2;
+ }
+}
+
const VMStateDescription vmstate_ide_drive = {
.name = "ide_drive",
- .version_id = 3,
+ .version_id = 4,
.minimum_version_id = 0,
.minimum_version_id_old = 0,
+ .pre_save = ide_drive_pre_save,
.post_load = ide_drive_post_load,
.fields = (VMStateField []) {
VMSTATE_INT32(mult_sectors, IDEState),
@@ -2709,7 +2762,14 @@ const VMStateDescription vmstate_ide_drive = {
VMSTATE_UINT8(sense_key, IDEState),
VMSTATE_UINT8(asc, IDEState),
VMSTATE_UINT8_V(cdrom_changed, IDEState, 3),
- /* XXX: if a transfer is pending, we do not save it yet */
+ VMSTATE_INT32_V(req_nb_sectors, IDEState, 4),
+ VMSTATE_VARRAY_INT32(io_buffer, IDEState, io_buffer_total_len, 4,
+ vmstate_info_uint8, uint8_t),
+ VMSTATE_INT32_V(cur_io_buffer_offset, IDEState, 4),
+ VMSTATE_INT32_V(cur_io_buffer_len, IDEState, 4),
+ VMSTATE_UINT8_V(end_transfer_fn_idx, IDEState, 4),
+ VMSTATE_INT32_V(elementary_transfer_size, IDEState, 4),
+ VMSTATE_INT32_V(packet_transfer_size, IDEState, 4),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index f937daacf..8869a0834 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -397,6 +397,7 @@ struct IDEState {
/* set for lba48 access */
uint8_t lba48;
BlockDriverState *bs;
+ char version[9];
/* ATAPI specific */
uint8_t sense_key;
uint8_t asc;
@@ -416,6 +417,11 @@ struct IDEState {
uint8_t *data_ptr;
uint8_t *data_end;
uint8_t *io_buffer;
+ /* PIO save/restore */
+ int32_t io_buffer_total_len;
+ int cur_io_buffer_offset;
+ int cur_io_buffer_len;
+ uint8_t end_transfer_fn_idx;
QEMUTimer *sector_write_timer; /* only used for win2k install hack */
uint32_t irq_count; /* counts IRQs when using win2k install hack */
/* CF-ATA extended error */
@@ -449,6 +455,7 @@ struct IDEDevice {
DeviceState qdev;
uint32_t unit;
DriveInfo *dinfo;
+ char *version;
};
typedef int (*ide_qdev_initfn)(IDEDevice *dev);
@@ -548,7 +555,7 @@ uint32_t ide_data_readw(void *opaque, uint32_t addr);
void ide_data_writel(void *opaque, uint32_t addr, uint32_t val);
uint32_t ide_data_readl(void *opaque, uint32_t addr);
-void ide_init_drive(IDEState *s, DriveInfo *dinfo);
+void ide_init_drive(IDEState *s, DriveInfo *dinfo, const char *version);
void ide_init2(IDEBus *bus, DriveInfo *hd0, DriveInfo *hd1,
qemu_irq irq);
void ide_init_ioport(IDEBus *bus, int iobase, int iobase2);
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index 81e79950d..0b84a4f1d 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -99,7 +99,7 @@ typedef struct IDEDrive {
static int ide_drive_initfn(IDEDevice *dev)
{
IDEBus *bus = DO_UPCAST(IDEBus, qbus, dev->qdev.parent_bus);
- ide_init_drive(bus->ifs + dev->unit, dev->dinfo);
+ ide_init_drive(bus->ifs + dev->unit, dev->dinfo, dev->version);
return 0;
}
@@ -110,6 +110,7 @@ static IDEDeviceInfo ide_drive_info = {
.qdev.props = (Property[]) {
DEFINE_PROP_UINT32("unit", IDEDrive, dev.unit, -1),
DEFINE_PROP_DRIVE("drive", IDEDrive, dev.dinfo),
+ DEFINE_PROP_STRING("ver", IDEDrive, dev.version),
DEFINE_PROP_END_OF_LIST(),
}
};
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index e4d55c7c7..2616d0d7e 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -30,7 +30,7 @@
//#define DEBUG_CMOS
-#define RTC_REINJECT_ON_ACK_COUNT 1000
+#define RTC_REINJECT_ON_ACK_COUNT 20
#define RTC_SECONDS 0
#define RTC_SECONDS_ALARM 1
diff --git a/hw/musicpal.c b/hw/musicpal.c
index 4a33e28bc..b8af15ed5 100644
--- a/hw/musicpal.c
+++ b/hw/musicpal.c
@@ -67,7 +67,7 @@
#define MP_AUDIO_IRQ 30
/* Wolfson 8750 I2C address */
-#define MP_WM_ADDR 0x34
+#define MP_WM_ADDR 0x1A
/* Ethernet register offsets */
#define MP_ETH_SMIR 0x010
@@ -238,14 +238,13 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
{
uint32_t desc_addr = s->tx_queue[queue_index];
mv88w8618_tx_desc desc;
+ uint32_t next_desc;
uint8_t buf[2048];
int len;
- if (!desc_addr) {
- return;
- }
do {
eth_tx_desc_get(desc_addr, &desc);
+ next_desc = desc.next;
if (desc.cmdstat & MP_ETH_TX_OWN) {
len = desc.bytes;
if (len < 2048) {
@@ -256,7 +255,7 @@ static void eth_send(mv88w8618_eth_state *s, int queue_index)
s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index);
eth_tx_desc_put(desc_addr, &desc);
}
- desc_addr = desc.next;
+ desc_addr = next_desc;
} while (desc_addr != s->tx_queue[queue_index]);
}
diff --git a/hw/pc.c b/hw/pc.c
index 78a07c2fd..632f439cd 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1354,6 +1354,14 @@ static QEMUMachine pc_machine_v0_11 = {
.property = "vectors",
.value = stringify(0),
},{
+ .driver = "ide-drive",
+ .property = "ver",
+ .value = "0.11",
+ },{
+ .driver = "scsi-disk",
+ .property = "ver",
+ .value = "0.11",
+ },{
.driver = "PCI",
.property = "rombar",
.value = stringify(0),
@@ -1385,6 +1393,14 @@ static QEMUMachine pc_machine_v0_10 = {
.property = "vectors",
.value = stringify(0),
},{
+ .driver = "ide-drive",
+ .property = "ver",
+ .value = "0.10",
+ },{
+ .driver = "scsi-disk",
+ .property = "ver",
+ .value = "0.10",
+ },{
.driver = "PCI",
.property = "rombar",
.value = stringify(0),
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index eb5b5a847..b34fbaa67 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,6 +65,7 @@ struct SCSIDiskState
int cluster_size;
uint64_t max_lba;
QEMUBH *bh;
+ char *version;
};
static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
@@ -80,7 +81,7 @@ static SCSIDiskReq *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun)
static void scsi_remove_request(SCSIDiskReq *r)
{
- qemu_free(r->iov.iov_base);
+ qemu_vfree(r->iov.iov_base);
scsi_req_free(&r->req);
}
@@ -315,6 +316,7 @@ static uint8_t *scsi_get_buf(SCSIDevice *d, uint32_t tag)
static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
{
BlockDriverState *bdrv = req->dev->dinfo->bdrv;
+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, req->dev);
int buflen = 0;
if (req->cmd.buf[1] & 0x2) {
@@ -432,7 +434,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf)
memcpy(&outbuf[16], "QEMU HARDDISK ", 16);
}
memcpy(&outbuf[8], "QEMU ", 8);
- memcpy(&outbuf[32], QEMU_VERSION, 4);
+ memcpy(&outbuf[32], s->version ? s->version : QEMU_VERSION, 4);
/* Identify device as SCSI-3 rev 1.
Some later commands are also implemented. */
outbuf[2] = 3;
@@ -1029,6 +1031,7 @@ static SCSIDeviceInfo scsi_disk_info = {
.get_buf = scsi_get_buf,
.qdev.props = (Property[]) {
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.dinfo),
+ DEFINE_PROP_STRING("ver", SCSIDiskState, version),
DEFINE_PROP_END_OF_LIST(),
},
};
diff --git a/hw/usb-net.c b/hw/usb-net.c
index 9744dfa5d..cfd2f62e0 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1492,7 +1492,7 @@ static USBDevice *usb_net_init(const char *cmdline)
dev = usb_create(NULL /* FIXME */, "usb-net");
qdev_set_nic_properties(&dev->qdev, &nd_table[idx]);
- qdev_init(&dev->qdev);
+ qdev_init_nofail(&dev->qdev);
return dev;
}
diff --git a/hw/usb-serial.c b/hw/usb-serial.c
index 2775cf0f0..c3f340137 100644
--- a/hw/usb-serial.c
+++ b/hw/usb-serial.c
@@ -497,12 +497,28 @@ static int usb_serial_can_read(void *opaque)
static void usb_serial_read(void *opaque, const uint8_t *buf, int size)
{
USBSerialState *s = opaque;
- int first_size = RECV_BUF - s->recv_ptr;
- if (first_size > size)
- first_size = size;
- memcpy(s->recv_buf + s->recv_ptr + s->recv_used, buf, first_size);
- if (size > first_size)
- memcpy(s->recv_buf, buf + first_size, size - first_size);
+ int first_size, start;
+
+ /* room in the buffer? */
+ if (size > (RECV_BUF - s->recv_used))
+ size = RECV_BUF - s->recv_used;
+
+ start = s->recv_ptr + s->recv_used;
+ if (start < RECV_BUF) {
+ /* copy data to end of buffer */
+ first_size = RECV_BUF - start;
+ if (first_size > size)
+ first_size = size;
+
+ memcpy(s->recv_buf + start, buf, first_size);
+
+ /* wrap around to front if needed */
+ if (size > first_size)
+ memcpy(s->recv_buf, buf + first_size, size - first_size);
+ } else {
+ start -= RECV_BUF;
+ memcpy(s->recv_buf + start, buf, size);
+ }
s->recv_used += size;
}
@@ -583,7 +599,7 @@ static USBDevice *usb_serial_init(const char *filename)
qdev_prop_set_uint16(&dev->qdev, "vendorid", vendorid);
if (productid)
qdev_prop_set_uint16(&dev->qdev, "productid", productid);
- qdev_init(&dev->qdev);
+ qdev_init_nofail(&dev->qdev);
return dev;
}
@@ -599,7 +615,7 @@ static USBDevice *usb_braille_init(const char *unused)
dev = usb_create(NULL /* FIXME */, "usb-braille");
qdev_prop_set_chr(&dev->qdev, "chardev", cdrv);
- qdev_init(&dev->qdev);
+ qdev_init_nofail(&dev->qdev);
return dev;
}
diff --git a/hw/virtio-blk.c b/hw/virtio-blk.c
index a2f063974..2fd9b3fba 100644
--- a/hw/virtio-blk.c
+++ b/hw/virtio-blk.c
@@ -272,7 +272,7 @@ static void do_multiwrite(BlockDriverState *bs, BlockRequest *blkreq,
if (ret != 0) {
for (i = 0; i < num_writes; i++) {
if (blkreq[i].error) {
- virtio_blk_req_complete(blkreq[i].opaque, VIRTIO_BLK_S_IOERR);
+ virtio_blk_rw_complete(blkreq[i].opaque, -EIO);
}
}
}
@@ -316,7 +316,46 @@ static void virtio_blk_handle_read(VirtIOBlockReq *req)
acb = bdrv_aio_readv(req->dev->bs, req->out->sector, &req->qiov,
req->qiov.size / 512, virtio_blk_rw_complete, req);
if (!acb) {
- virtio_blk_req_complete(req, VIRTIO_BLK_S_IOERR);
+ virtio_blk_rw_complete(req, -EIO);
+ }
+}
+
+typedef struct MultiReqBuffer {
+ BlockRequest blkreq[32];
+ int num_writes;
+ BlockDriverState *old_bs;
+} MultiReqBuffer;
+
+static void virtio_blk_handle_request(VirtIOBlockReq *req,
+ MultiReqBuffer *mrb)
+{
+ if (req->elem.out_num < 1 || req->elem.in_num < 1) {
+ fprintf(stderr, "virtio-blk missing headers\n");
+ exit(1);
+ }
+
+ if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
+ req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
+ fprintf(stderr, "virtio-blk header not in correct element\n");
+ exit(1);
+ }
+
+ req->out = (void *)req->elem.out_sg[0].iov_base;
+ req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
+
+ if (req->out->type & VIRTIO_BLK_T_FLUSH) {
+ virtio_blk_handle_flush(req);
+ } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
+ virtio_blk_handle_scsi(req);
+ } else if (req->out->type & VIRTIO_BLK_T_OUT) {
+ qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
+ req->elem.out_num - 1);
+ virtio_blk_handle_write(mrb->blkreq, &mrb->num_writes,
+ req, &mrb->old_bs);
+ } else {
+ qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
+ req->elem.in_num - 1);
+ virtio_blk_handle_read(req);
}
}
@@ -324,42 +363,17 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOBlock *s = to_virtio_blk(vdev);
VirtIOBlockReq *req;
- BlockRequest blkreq[32];
- int num_writes = 0;
- BlockDriverState *old_bs = NULL;
+ MultiReqBuffer mrb = {
+ .num_writes = 0,
+ .old_bs = NULL,
+ };
while ((req = virtio_blk_get_request(s))) {
- if (req->elem.out_num < 1 || req->elem.in_num < 1) {
- fprintf(stderr, "virtio-blk missing headers\n");
- exit(1);
- }
-
- if (req->elem.out_sg[0].iov_len < sizeof(*req->out) ||
- req->elem.in_sg[req->elem.in_num - 1].iov_len < sizeof(*req->in)) {
- fprintf(stderr, "virtio-blk header not in correct element\n");
- exit(1);
- }
-
- req->out = (void *)req->elem.out_sg[0].iov_base;
- req->in = (void *)req->elem.in_sg[req->elem.in_num - 1].iov_base;
-
- if (req->out->type & VIRTIO_BLK_T_FLUSH) {
- virtio_blk_handle_flush(req);
- } else if (req->out->type & VIRTIO_BLK_T_SCSI_CMD) {
- virtio_blk_handle_scsi(req);
- } else if (req->out->type & VIRTIO_BLK_T_OUT) {
- qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
- req->elem.out_num - 1);
- virtio_blk_handle_write(blkreq, &num_writes, req, &old_bs);
- } else {
- qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
- req->elem.in_num - 1);
- virtio_blk_handle_read(req);
- }
+ virtio_blk_handle_request(req, &mrb);
}
- if (num_writes > 0) {
- do_multiwrite(old_bs, blkreq, num_writes);
+ if (mrb.num_writes > 0) {
+ do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
}
/*
@@ -373,6 +387,10 @@ static void virtio_blk_dma_restart_bh(void *opaque)
{
VirtIOBlock *s = opaque;
VirtIOBlockReq *req = s->rq;
+ MultiReqBuffer mrb = {
+ .num_writes = 0,
+ .old_bs = NULL,
+ };
qemu_bh_delete(s->bh);
s->bh = NULL;
@@ -380,10 +398,13 @@ static void virtio_blk_dma_restart_bh(void *opaque)
s->rq = NULL;
while (req) {
- bdrv_aio_writev(req->dev->bs, req->out->sector, &req->qiov,
- req->qiov.size / 512, virtio_blk_rw_complete, req);
+ virtio_blk_handle_request(req, &mrb);
req = req->next;
}
+
+ if (mrb.num_writes > 0) {
+ do_multiwrite(mrb.old_bs, mrb.blkreq, mrb.num_writes);
+ }
}
static void virtio_blk_dma_restart_cb(void *opaque, int running, int reason)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 2f201ffc7..d8a1629dc 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -384,7 +384,15 @@ static int virtio_net_has_buffers(VirtIONet *n, int bufsize)
(n->mergeable_rx_bufs &&
!virtqueue_avail_bytes(n->rx_vq, bufsize, 0))) {
virtio_queue_set_notification(n->rx_vq, 1);
- return 0;
+
+ /* To avoid a race condition where the guest has made some buffers
+ * available after the above check but before notification was
+ * enabled, check for available buffers again.
+ */
+ if (virtio_queue_empty(n->rx_vq) ||
+ (n->mergeable_rx_bufs &&
+ !virtqueue_avail_bytes(n->rx_vq, bufsize, 0)))
+ return 0;
}
virtio_queue_set_notification(n->rx_vq, 0);
diff --git a/json-lexer.c b/json-lexer.c
index 53697c5ff..9d649205a 100644
--- a/json-lexer.c
+++ b/json-lexer.c
@@ -54,6 +54,9 @@ enum json_lexer_state {
IN_ESCAPE,
IN_ESCAPE_L,
IN_ESCAPE_LL,
+ IN_ESCAPE_I,
+ IN_ESCAPE_I6,
+ IN_ESCAPE_I64,
IN_ESCAPE_DONE,
IN_WHITESPACE,
IN_OPERATOR_DONE,
@@ -223,6 +226,18 @@ static const uint8_t json_lexer[][256] = {
['l'] = IN_ESCAPE_LL,
},
+ [IN_ESCAPE_I64] = {
+ ['d'] = IN_ESCAPE_DONE,
+ },
+
+ [IN_ESCAPE_I6] = {
+ ['4'] = IN_ESCAPE_I64,
+ },
+
+ [IN_ESCAPE_I] = {
+ ['6'] = IN_ESCAPE_I6,
+ },
+
[IN_ESCAPE] = {
['d'] = IN_ESCAPE_DONE,
['i'] = IN_ESCAPE_DONE,
@@ -230,6 +245,7 @@ static const uint8_t json_lexer[][256] = {
['s'] = IN_ESCAPE_DONE,
['f'] = IN_ESCAPE_DONE,
['l'] = IN_ESCAPE_L,
+ ['I'] = IN_ESCAPE_I,
},
/* top level rule */
diff --git a/json-parser.c b/json-parser.c
index 7624c0f9b..2ab6f6c11 100644
--- a/json-parser.c
+++ b/json-parser.c
@@ -476,7 +476,8 @@ static QObject *parse_escape(JSONParserContext *ctxt, QList **tokens, va_list *a
obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
} else if (token_is_escape(token, "%ld")) {
obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
- } else if (token_is_escape(token, "%lld")) {
+ } else if (token_is_escape(token, "%lld") ||
+ token_is_escape(token, "%I64d")) {
obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
} else if (token_is_escape(token, "%s")) {
obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
diff --git a/monitor.c b/monitor.c
index 8c36b1089..613ee9d45 100644
--- a/monitor.c
+++ b/monitor.c
@@ -337,13 +337,10 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
{
QDict *qmp;
const char *event_name;
- Monitor *mon = cur_mon;
+ Monitor *mon;
assert(event < QEVENT_MAX);
- if (!monitor_ctrl_mode(mon))
- return;
-
switch (event) {
case QEVENT_DEBUG:
event_name = "DEBUG";
@@ -373,7 +370,11 @@ void monitor_protocol_event(MonitorEvent event, QObject *data)
qdict_put_obj(qmp, "data", data);
}
- monitor_json_emitter(mon, QOBJECT(qmp));
+ QLIST_FOREACH(mon, &mon_list, entry) {
+ if (monitor_ctrl_mode(mon)) {
+ monitor_json_emitter(mon, QOBJECT(qmp));
+ }
+ }
QDECREF(qmp);
}
diff --git a/net.c b/net.c
index 6ef93e615..029b0d79b 100644
--- a/net.c
+++ b/net.c
@@ -96,7 +96,7 @@ int parse_host_src_port(struct sockaddr_in *haddr,
struct sockaddr_in *saddr,
const char *input_str)
{
- char *str = strdup(input_str);
+ char *str = qemu_strdup(input_str);
char *host_str = str;
char *src_str;
const char *src_str2;
@@ -812,9 +812,6 @@ static int net_init_nic(QemuOpts *opts,
}
nd->used = 1;
- if (vlan) {
- nd->vlan->nb_guest_devs++;
- }
nb_nics++;
return idx;
@@ -1128,20 +1125,6 @@ int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev)
return -1;
}
-void net_client_uninit(NICInfo *nd)
-{
- if (nd->vlan) {
- nd->vlan->nb_guest_devs--;
- }
- nb_nics--;
-
- qemu_free(nd->model);
- qemu_free(nd->name);
- qemu_free(nd->devaddr);
-
- nd->used = 0;
-}
-
static int net_host_check_device(const char *device)
{
int i;
@@ -1227,16 +1210,23 @@ void net_set_boot_mask(int net_boot_mask)
void do_info_network(Monitor *mon)
{
VLANState *vlan;
+ VLANClientState *vc;
QTAILQ_FOREACH(vlan, &vlans, next) {
- VLANClientState *vc;
-
monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
QTAILQ_FOREACH(vc, &vlan->clients, next) {
monitor_printf(mon, " %s: %s\n", vc->name, vc->info_str);
}
}
+ monitor_printf(mon, "Devices not on any VLAN:\n");
+ QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+ monitor_printf(mon, " %s: %s", vc->name, vc->info_str);
+ if (vc->peer) {
+ monitor_printf(mon, " peer=%s", vc->peer->name);
+ }
+ monitor_printf(mon, "\n");
+ }
}
void do_set_link(Monitor *mon, const QDict *qdict)
@@ -1253,6 +1243,7 @@ void do_set_link(Monitor *mon, const QDict *qdict)
}
}
}
+ vc = qemu_find_netdev(name);
done:
if (!vc) {
@@ -1289,20 +1280,41 @@ void net_cleanup(void)
}
}
-static void net_check_clients(void)
+void net_check_clients(void)
{
VLANState *vlan;
+ VLANClientState *vc;
+ int has_nic, has_host_dev;
QTAILQ_FOREACH(vlan, &vlans, next) {
- if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
- continue;
- if (vlan->nb_guest_devs == 0)
+ QTAILQ_FOREACH(vc, &vlan->clients, next) {
+ switch (vc->info->type) {
+ case NET_CLIENT_TYPE_NIC:
+ has_nic = 1;
+ break;
+ case NET_CLIENT_TYPE_SLIRP:
+ case NET_CLIENT_TYPE_TAP:
+ case NET_CLIENT_TYPE_SOCKET:
+ case NET_CLIENT_TYPE_VDE:
+ has_host_dev = 1;
+ break;
+ default: ;
+ }
+ }
+ if (has_host_dev && !has_nic)
fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
- if (vlan->nb_host_devs == 0)
+ if (has_nic && !has_host_dev)
fprintf(stderr,
"Warning: vlan %d is not connected to host network\n",
vlan->id);
}
+ QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+ if (!vc->peer) {
+ fprintf(stderr, "Warning: %s %s has no peer\n",
+ vc->info->type == NET_CLIENT_TYPE_NIC ? "nic" : "netdev",
+ vc->name);
+ }
+ }
}
static int net_init_client(QemuOpts *opts, void *dummy)
@@ -1337,8 +1349,6 @@ int net_init_clients(void)
return -1;
}
- net_check_clients();
-
return 0;
}
diff --git a/net.h b/net.h
index 4971fcbbb..673b3554d 100644
--- a/net.h
+++ b/net.h
@@ -76,7 +76,6 @@ struct VLANState {
int id;
QTAILQ_HEAD(, VLANClientState) clients;
QTAILQ_ENTRY(VLANState) next;
- unsigned int nb_guest_devs, nb_host_devs;
NetQueue *send_queue;
};
@@ -160,9 +159,9 @@ extern const char *legacy_tftp_prefix;
extern const char *legacy_bootp_filename;
int net_client_init(Monitor *mon, QemuOpts *opts, int is_netdev);
-void net_client_uninit(NICInfo *nd);
int net_client_parse(QemuOptsList *opts_list, const char *str);
int net_init_clients(void);
+void net_check_clients(void);
void net_cleanup(void);
void net_set_boot_mask(int boot_mask);
void net_host_device_add(Monitor *mon, const QDict *qdict);
diff --git a/net/slirp.c b/net/slirp.c
index 3f91c4bb3..50ac0b9bb 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -728,10 +728,6 @@ int net_init_slirp(QemuOpts *opts,
qemu_free(config);
}
- if (ret != -1 && vlan) {
- vlan->nb_host_devs++;
- }
-
qemu_free(vnet);
return ret;
diff --git a/net/socket.c b/net/socket.c
index 5533737e4..442a9c790 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -569,9 +569,5 @@ int net_init_socket(QemuOpts *opts,
return -1;
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/net/tap-win32.c b/net/tap-win32.c
index b717c1724..8370c803b 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -714,10 +714,6 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
return -1;
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/net/tap.c b/net/tap.c
index 0d8b42412..adbc97992 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -441,9 +441,5 @@ int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
}
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/net/vde.c b/net/vde.c
index 42b463350..0b46fa640 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -127,9 +127,5 @@ int net_init_vde(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan
return -1;
}
- if (vlan) {
- vlan->nb_host_devs++;
- }
-
return 0;
}
diff --git a/pc-bios/bios.bin b/pc-bios/bios.bin
index 1741eeced..855f46834 100644
--- a/pc-bios/bios.bin
+++ b/pc-bios/bios.bin
Binary files differ
diff --git a/qemu-char.c b/qemu-char.c
index b13f8d4cf..5a1b535bd 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -1180,6 +1180,9 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
int fd;
TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
+ if (fd < 0) {
+ return NULL;
+ }
tty_serial_init(fd, 115200, 'N', 8, 1);
chr = qemu_chr_open_fd(fd, fd);
if (!chr) {
diff --git a/qemu-common.h b/qemu-common.h
index 5fbe0f9db..1c5c0b222 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -2,6 +2,8 @@
#ifndef QEMU_COMMON_H
#define QEMU_COMMON_H
+#include "config-host.h"
+
#define QEMU_NORETURN __attribute__ ((__noreturn__))
#ifdef CONFIG_GCC_ATTRIBUTE_WARN_UNUSED_RESULT
#define QEMU_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
@@ -29,7 +31,6 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <assert.h>
-#include "config-host.h"
#ifndef O_LARGEFILE
#define O_LARGEFILE 0
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 6cdb83473..4ea8c9e45 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -467,7 +467,7 @@ int main(int argc, char **argv)
}
}
} while (persistent || nb_fds > 1);
- qemu_free(data);
+ qemu_vfree(data);
close(sharing_fds[0]);
bdrv_close(bs);
diff --git a/qemu-options.hx b/qemu-options.hx
index ca73ba5db..e2fbebd9b 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -405,6 +405,12 @@ ETEXI
DEF("device", HAS_ARG, QEMU_OPTION_device,
"-device driver[,options] add device\n")
+STEXI
+@item -device @var{driver}[,@var{option}[,...]]
+Add device @var{driver}. Depending on the device type,
+@var{option} (typically @var{key}=@var{value}) may be useful.
+ETEXI
+
DEF("name", HAS_ARG, QEMU_OPTION_name,
"-name string1[,process=string2] set the name of the guest\n"
" string1 sets the window title and string2 the process name (on Linux)\n")
@@ -1894,6 +1900,8 @@ ETEXI
DEF("nodefaults", 0, QEMU_OPTION_nodefaults, \
"-nodefaults don't create default devices.\n")
STEXI
+@item -nodefaults
+Don't create default devices.
ETEXI
#ifndef _WIN32
@@ -1916,10 +1924,6 @@ Immediately before starting guest execution, drop root privileges, switching
to the specified user.
ETEXI
-STEXI
-@end table
-ETEXI
-
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
DEF("prom-env", HAS_ARG, QEMU_OPTION_prom_env,
"-prom-env variable=value\n"
@@ -1935,9 +1939,17 @@ DEF("old-param", 0, QEMU_OPTION_old_param,
#endif
DEF("readconfig", HAS_ARG, QEMU_OPTION_readconfig,
"-readconfig <file>\n")
+STEXI
+@item -readconfig @var{file}
+Read device configuration from @var{file}.
+ETEXI
DEF("writeconfig", HAS_ARG, QEMU_OPTION_writeconfig,
"-writeconfig <file>\n"
" read/write config file\n")
+STEXI
+@item -writeconfig @var{file}
+Write device configuration to @var{file}.
+ETEXI
DEF("no-kvm", 0, QEMU_OPTION_no_kvm,
"-no-kvm disable KVM hardware virtualization\n")
@@ -1969,3 +1981,8 @@ DEF("mem-path", HAS_ARG, QEMU_OPTION_mempath,
DEF("mem-prealloc", 0, QEMU_OPTION_mem_prealloc,
"-mem-prealloc preallocate guest memory (use with -mempath)\n")
#endif
+
+HXCOMM This is the last statement. Insert new options before this line!
+STEXI
+@end table
+ETEXI
diff --git a/qemu-sockets.c b/qemu-sockets.c
index 8850516f2..a88b2a77f 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -424,7 +424,7 @@ static int inet_parse(QemuOpts *opts, const char *str)
__FUNCTION__, str);
return -1;
}
- qemu_opt_set(opts, "ipv6", "yes");
+ qemu_opt_set(opts, "ipv6", "on");
} else if (qemu_isdigit(str[0])) {
/* IPv4 addr */
if (2 != sscanf(str,"%64[0-9.]:%32[^,]%n",addr,port,&pos)) {
@@ -432,7 +432,7 @@ static int inet_parse(QemuOpts *opts, const char *str)
__FUNCTION__, str);
return -1;
}
- qemu_opt_set(opts, "ipv4", "yes");
+ qemu_opt_set(opts, "ipv4", "on");
} else {
/* hostname */
if (2 != sscanf(str,"%64[^:]:%32[^,]%n",addr,port,&pos)) {
@@ -450,9 +450,9 @@ static int inet_parse(QemuOpts *opts, const char *str)
if (h)
qemu_opt_set(opts, "to", h+4);
if (strstr(optstr, ",ipv4"))
- qemu_opt_set(opts, "ipv4", "yes");
+ qemu_opt_set(opts, "ipv4", "on");
if (strstr(optstr, ",ipv6"))
- qemu_opt_set(opts, "ipv6", "yes");
+ qemu_opt_set(opts, "ipv6", "on");
return 0;
}
diff --git a/roms/seabios b/roms/seabios
-Subproject 5da68339ecf44677b8f4f115cdf3cb1da46a9f6
+Subproject 9fb3f4d950744e97cc655b7d7b523d8bf101e4a
diff --git a/savevm.c b/savevm.c
index 3992dfd0b..1c37827ea 100644
--- a/savevm.c
+++ b/savevm.c
@@ -1719,7 +1719,7 @@ void do_savevm(Monitor *mon, const QDict *qdict)
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
/* Delete old snapshots of the same name */
- if (del_existing_snapshots(mon, name) < 0) {
+ if (name && del_existing_snapshots(mon, name) < 0) {
goto the_end;
}
diff --git a/sdl.c b/sdl.c
index 034440f72..7912c9159 100644
--- a/sdl.c
+++ b/sdl.c
@@ -525,6 +525,7 @@ static void sdl_send_mouse_event(int dx, int dy, int dz, int x, int y, int state
static void toggle_full_screen(DisplayState *ds)
{
gui_fullscreen = !gui_fullscreen;
+ do_sdl_resize(real_screen->w, real_screen->h, real_screen->format->BitsPerPixel);
if (gui_fullscreen) {
scaling_active = 0;
gui_saved_grab = gui_grab;
diff --git a/slirp/misc.c b/slirp/misc.c
index c76ad8fef..b68af6d7a 100644
--- a/slirp/misc.c
+++ b/slirp/misc.c
@@ -179,7 +179,7 @@ fork_exec(struct socket *so, const char *ex, int do_pty)
close(s);
i = 0;
- bptr = strdup(ex); /* No need to free() this */
+ bptr = qemu_strdup(ex); /* No need to free() this */
if (do_pty == 1) {
/* Setup "slirp.telnetd -x" */
argv[i++] = "slirp.telnetd";
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 97e106f47..89c28f1bf 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -590,8 +590,8 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
#define cpu_handle_mmu_fault cpu_mips_handle_mmu_fault
void do_interrupt (CPUState *env);
void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra);
-target_phys_addr_t do_translate_address (CPUState *env, target_ulong address,
- int rw);
+target_phys_addr_t cpu_mips_translate_address (CPUState *env, target_ulong address,
+ int rw);
static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
{
diff --git a/target-mips/helper.c b/target-mips/helper.c
index 1e7e01608..ec8711498 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -311,7 +311,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
}
#if !defined(CONFIG_USER_ONLY)
-target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int rw)
+target_phys_addr_t cpu_mips_translate_address(CPUState *env, target_ulong address, int rw)
{
target_phys_addr_t physical;
int prot;
@@ -326,10 +326,10 @@ target_phys_addr_t do_translate_address(CPUState *env, target_ulong address, int
address, rw, access_type);
if (ret != TLBRET_MATCH) {
raise_mmu_exception(env, address, rw, ret);
- cpu_loop_exit();
+ return -1LL;
+ } else {
+ return physical;
}
-
- return physical;
}
#endif
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index be75af5e6..dda9e825e 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -276,10 +276,24 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2)
#endif
#ifndef CONFIG_USER_ONLY
+
+static inline target_phys_addr_t do_translate_address(target_ulong address, int rw)
+{
+ target_phys_addr_t lladdr;
+
+ lladdr = cpu_mips_translate_address(env, address, rw);
+
+ if (lladdr == -1LL) {
+ cpu_loop_exit();
+ } else {
+ return lladdr;
+ }
+}
+
#define HELPER_LD_ATOMIC(name, insn) \
target_ulong helper_##name(target_ulong arg, int mem_idx) \
{ \
- env->lladdr = do_translate_address(env, arg, 0); \
+ env->lladdr = do_translate_address(arg, 0); \
env->llval = do_##insn(arg, mem_idx); \
return env->llval; \
}
@@ -298,7 +312,7 @@ target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \
env->CP0_BadVAddr = arg2; \
helper_raise_exception(EXCP_AdES); \
} \
- if (do_translate_address(env, arg2, 1) == env->lladdr) { \
+ if (do_translate_address(arg2, 1) == env->lladdr) { \
tmp = do_##ld_insn(arg2, mem_idx); \
if (tmp == env->llval) { \
do_##st_insn(arg2, arg1, mem_idx); \
diff --git a/target-mips/translate.c b/target-mips/translate.c
index f756ab9db..f811f50c7 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -821,7 +821,7 @@ static inline void gen_op_addr_add (DisasContext *ctx, TCGv ret, TCGv arg0, TCGv
static inline void check_cp0_enabled(DisasContext *ctx)
{
if (unlikely(!(ctx->hflags & MIPS_HFLAG_CP0)))
- generate_exception_err(ctx, EXCP_CpU, 1);
+ generate_exception_err(ctx, EXCP_CpU, 0);
}
static inline void check_cp1_enabled(DisasContext *ctx)
@@ -1451,6 +1451,8 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
tcg_gen_rotri_i32(t1, t1, uimm);
tcg_gen_ext_i32_tl(cpu_gpr[rt], t1);
tcg_temp_free_i32(t1);
+ } else {
+ tcg_gen_ext32s_tl(cpu_gpr[rt], t0);
}
opn = "rotr";
} else {
@@ -1489,6 +1491,8 @@ static void gen_shift_imm(CPUState *env, DisasContext *ctx, uint32_t opc,
if (env->insn_flags & ISA_MIPS32R2) {
if (uimm != 0) {
tcg_gen_rotri_tl(cpu_gpr[rt], t0, uimm);
+ } else {
+ tcg_gen_mov_tl(cpu_gpr[rt], t0);
}
opn = "drotr";
} else {
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 8fcb5c99c..807b8fdfa 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -731,9 +731,9 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
/* label1: fast path */
reloc_pc16(label1_ptr, (tcg_target_long) s->code_ptr);
- tcg_out_opc_imm(s, OPC_LW, TCG_REG_V0, TCG_REG_A0,
+ tcg_out_opc_imm(s, OPC_LW, TCG_REG_A0, TCG_REG_A0,
offsetof(CPUState, tlb_table[mem_index][0].addend) + addr_meml);
- tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_V0, addr_regl);
+ tcg_out_opc_reg(s, OPC_ADDU, TCG_REG_V0, TCG_REG_A0, addr_regl);
addr_reg1 = TCG_REG_V0;
#endif
diff --git a/usb-linux.c b/usb-linux.c
index 88728e927..5619b3060 100644
--- a/usb-linux.c
+++ b/usb-linux.c
@@ -1036,7 +1036,7 @@ USBDevice *usb_host_device_open(const char *devname)
qdev_prop_set_uint32(&dev->qdev, "hostaddr", filter.addr);
qdev_prop_set_uint32(&dev->qdev, "vendorid", filter.vendor_id);
qdev_prop_set_uint32(&dev->qdev, "productid", filter.product_id);
- qdev_init(&dev->qdev);
+ qdev_init_nofail(&dev->qdev);
return dev;
fail:
diff --git a/vl.c b/vl.c
index c9d46de0c..59f8084fa 100644
--- a/vl.c
+++ b/vl.c
@@ -4094,14 +4094,15 @@ static void tcg_cpu_exec(void)
for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
CPUState *env = cur_cpu = next_cpu;
- if (!vm_running)
- break;
if (timer_alarm_pending) {
timer_alarm_pending = 0;
break;
}
if (cpu_can_run(env))
ret = qemu_cpu_exec(env);
+ else if (env->stop)
+ break;
+
if (ret == EXCP_DEBUG) {
gdb_set_stop_cpu(env);
debug_requested = 1;
@@ -6081,6 +6082,8 @@ int main(int argc, char **argv, char **envp)
if (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0)
exit(1);
+ net_check_clients();
+
if (!display_state)
dumb_display_init();
/* just use the first displaystate for the moment */
diff --git a/vnc.c b/vnc.c
index 58eac73f9..a1f9c9293 100644
--- a/vnc.c
+++ b/vnc.c
@@ -2293,7 +2293,7 @@ static int vnc_refresh_server_surface(VncDisplay *vd)
static void vnc_refresh(void *opaque)
{
VncDisplay *vd = opaque;
- VncState *vs = NULL;
+ VncState *vs = NULL, *vn = NULL;
int has_dirty = 0, rects = 0;
vga_hw_update();
@@ -2302,8 +2302,10 @@ static void vnc_refresh(void *opaque)
vs = vd->clients;
while (vs != NULL) {
+ vn = vs->next;
rects += vnc_update_client(vs, has_dirty);
- vs = vs->next;
+ /* vs might be free()ed here */
+ vs = vn;
}
/* vd->timer could be NULL now if the last client disconnected,
* in this case don't update the timer */