aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2011-02-22 15:34:38 +0200
committerAvi Kivity <avi@redhat.com>2011-02-22 15:34:38 +0200
commitbeb62edc0aa0ebbf4796785548464109192722e9 (patch)
tree1d40bcab1eea376bfa8a7a5a1bda836702676051
parent7aa8c46b2d3bc3bebbf87cb68e02baee6338b597 (diff)
parent8d610b6ba2b36bbe0159362556455b61c6566526 (diff)
Merge remote branch 'upstream/stable-0.14' into stable-0.14qemu-kvm-0.14.0
* upstream/stable-0.14: qemu-char: Check for missing backend name Update version for 0.14.0 Update version for 0.14.0-rc2 Fix build from previous commit PATCH] slirp: fix buffer overrun correctly check ppr priority during interrupt injection] qcow2: Fix order in L2 table COW qemu-img: Improve error messages for failed bdrv_open qed: Report error for unsupported features qcow2: Report error for version > 2 qerror: Add QERR_UNKNOWN_BLOCK_FORMAT_FEATURE qcow2: Fix error handling for reading compressed clusters qcow2: Fix error handling for immediate backing file read failure QCOW2: bug fix - read base image beyond its size Change snapshot_blkdev hmp to use correct argument type for device linux-user: Fix possible realloc memory leak linux-user: Fix possible realloc memory leak linux-user: fix for loopmount ioctl blockdev: Plug memory leak in drive_init() error paths blockdev: Plug memory leak in drive_uninit() Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--VERSION2
-rw-r--r--block/qcow2-cluster.c13
-rw-r--r--block/qcow2.c26
-rw-r--r--block/qed.c9
-rw-r--r--blockdev.c12
-rw-r--r--cutils.c31
-rw-r--r--hmp-commands.hx2
-rw-r--r--hw/apic.c42
-rw-r--r--linux-user/elfload.c8
-rw-r--r--linux-user/ioctls.h2
-rw-r--r--qemu-char.c5
-rw-r--r--qemu-common.h2
-rw-r--r--qemu-img.c10
-rw-r--r--qerror.c5
-rw-r--r--qerror.h3
-rw-r--r--slirp/mbuf.c4
16 files changed, 137 insertions, 39 deletions
diff --git a/VERSION b/VERSION
index bdfb04f11..a803cc227 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.13.91
+0.14.0
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 5fb8c6695..750abe37d 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -515,13 +515,16 @@ static int get_cluster_table(BlockDriverState *bs, uint64_t offset,
return ret;
}
} else {
- /* FIXME Order */
- if (l2_offset)
- qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+ /* First allocate a new L2 table (and do COW if needed) */
ret = l2_allocate(bs, l1_index, &l2_table);
if (ret < 0) {
return ret;
}
+
+ /* Then decrease the refcount of the old table */
+ if (l2_offset) {
+ qcow2_free_clusters(bs, l2_offset, s->l2_size * sizeof(uint64_t));
+ }
l2_offset = s->l1_table[l1_index] & ~QCOW_OFLAG_COPIED;
}
@@ -878,11 +881,11 @@ int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset)
BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED);
ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors);
if (ret < 0) {
- return -1;
+ return ret;
}
if (decompress_buffer(s->cluster_cache, s->cluster_size,
s->cluster_data + sector_offset, csize) < 0) {
- return -1;
+ return -EIO;
}
s->cluster_cache_offset = coffset;
}
diff --git a/block/qcow2.c b/block/qcow2.c
index a1773e479..75b8becc0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -28,6 +28,7 @@
#include "aes.h"
#include "block/qcow2.h"
#include "qemu-error.h"
+#include "qerror.h"
/*
Differences with QCOW:
@@ -59,7 +60,7 @@ static int qcow2_probe(const uint8_t *buf, int buf_size, const char *filename)
if (buf_size >= sizeof(QCowHeader) &&
be32_to_cpu(cow_header->magic) == QCOW_MAGIC &&
- be32_to_cpu(cow_header->version) == QCOW_VERSION)
+ be32_to_cpu(cow_header->version) >= QCOW_VERSION)
return 100;
else
return 0;
@@ -163,10 +164,18 @@ static int qcow2_open(BlockDriverState *bs, int flags)
be64_to_cpus(&header.snapshots_offset);
be32_to_cpus(&header.nb_snapshots);
- if (header.magic != QCOW_MAGIC || header.version != QCOW_VERSION) {
+ if (header.magic != QCOW_MAGIC) {
ret = -EINVAL;
goto fail;
}
+ if (header.version != QCOW_VERSION) {
+ char version[64];
+ snprintf(version, sizeof(version), "QCOW version %d", header.version);
+ qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ bs->device_name, "qcow2", version);
+ ret = -ENOTSUP;
+ goto fail;
+ }
if (header.cluster_bits < MIN_CLUSTER_BITS ||
header.cluster_bits > MAX_CLUSTER_BITS) {
ret = -EINVAL;
@@ -355,7 +364,7 @@ int qcow2_backing_read1(BlockDriverState *bs, QEMUIOVector *qiov,
else
n1 = bs->total_sectors - sector_num;
- qemu_iovec_memset(qiov, 0, 512 * (nb_sectors - n1));
+ qemu_iovec_memset_skip(qiov, 0, 512 * (nb_sectors - n1), 512 * n1);
return n1;
}
@@ -478,10 +487,11 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
if (n1 > 0) {
BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);
acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num,
- &acb->hd_qiov, acb->cur_nr_sectors,
- qcow2_aio_read_cb, acb);
- if (acb->hd_aiocb == NULL)
+ &acb->hd_qiov, n1, qcow2_aio_read_cb, acb);
+ if (acb->hd_aiocb == NULL) {
+ ret = -EIO;
goto done;
+ }
} else {
ret = qcow2_schedule_bh(qcow2_aio_read_bh, acb);
if (ret < 0)
@@ -496,8 +506,10 @@ static void qcow2_aio_read_cb(void *opaque, int ret)
}
} else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) {
/* add AIO support for compressed blocks ? */
- if (qcow2_decompress_cluster(bs, acb->cluster_offset) < 0)
+ ret = qcow2_decompress_cluster(bs, acb->cluster_offset);
+ if (ret < 0) {
goto done;
+ }
qemu_iovec_from_buffer(&acb->hd_qiov,
s->cluster_cache + index_in_cluster * 512,
diff --git a/block/qed.c b/block/qed.c
index 32734486c..75ae2440e 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -14,6 +14,7 @@
#include "trace.h"
#include "qed.h"
+#include "qerror.h"
static void qed_aio_cancel(BlockDriverAIOCB *blockacb)
{
@@ -311,7 +312,13 @@ static int bdrv_qed_open(BlockDriverState *bs, int flags)
return -EINVAL;
}
if (s->header.features & ~QED_FEATURE_MASK) {
- return -ENOTSUP; /* image uses unsupported feature bits */
+ /* image uses unsupported feature bits */
+ char buf[64];
+ snprintf(buf, sizeof(buf), "%" PRIx64,
+ s->header.features & ~QED_FEATURE_MASK);
+ qerror_report(QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ bs->device_name, "QED", buf);
+ return -ENOTSUP;
}
if (!qed_is_cluster_size_valid(s->header.cluster_size)) {
return -EINVAL;
diff --git a/blockdev.c b/blockdev.c
index 6399d6658..335a77bab 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -184,6 +184,7 @@ static void drive_uninit(DriveInfo *dinfo)
{
qemu_opts_del(dinfo->opts);
bdrv_delete(dinfo->bdrv);
+ qemu_free(dinfo->id);
QTAILQ_REMOVE(&drives, dinfo, next);
qemu_free(dinfo);
}
@@ -538,7 +539,7 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
} else if (ro == 1) {
if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY && type != IF_NONE) {
error_report("readonly not supported by this bus type");
- return NULL;
+ goto err;
}
}
@@ -548,12 +549,19 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi)
if (ret < 0) {
error_report("could not open disk image %s: %s",
file, strerror(-ret));
- return NULL;
+ goto err;
}
if (bdrv_key_required(dinfo->bdrv))
autostart = 0;
return dinfo;
+
+err:
+ bdrv_delete(dinfo->bdrv);
+ qemu_free(dinfo->id);
+ QTAILQ_REMOVE(&drives, dinfo, next);
+ qemu_free(dinfo);
+ return NULL;
}
void do_commit(Monitor *mon, const QDict *qdict)
diff --git a/cutils.c b/cutils.c
index 3f7973c5e..9de57d945 100644
--- a/cutils.c
+++ b/cutils.c
@@ -272,6 +272,37 @@ 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)
+{
+ int i;
+ size_t done;
+ void *iov_base;
+ uint64_t iov_len;
+
+ done = 0;
+ for (i = 0; (i < qiov->niov) && (done != count); i++) {
+ if (skip >= qiov->iov[i].iov_len) {
+ /* Skip the whole iov */
+ skip -= qiov->iov[i].iov_len;
+ continue;
+ } else {
+ /* Skip only part (or nothing) of the iov */
+ iov_base = (uint8_t*) qiov->iov[i].iov_base + skip;
+ iov_len = qiov->iov[i].iov_len - skip;
+ skip = 0;
+ }
+
+ if (done + iov_len > count) {
+ memset(iov_base, c, count - done);
+ break;
+ } else {
+ memset(iov_base, c, iov_len);
+ }
+ done += iov_len;
+ }
+}
+
#ifndef _WIN32
/* Sets a specific flag */
int fcntl_setfl(int fd, int flag)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 5794800fc..247fdf08f 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -822,7 +822,7 @@ ETEXI
{
.name = "snapshot_blkdev",
- .args_type = "device:s,snapshot_file:s?,format:s?",
+ .args_type = "device:B,snapshot_file:s?,format:s?",
.params = "device [new-image-file] [format]",
.help = "initiates a live snapshot\n\t\t\t"
"of device. If a new image file is specified, the\n\t\t\t"
diff --git a/hw/apic.c b/hw/apic.c
index b4f99d842..00907e070 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -376,19 +376,36 @@ static int apic_get_arb_pri(APICState *s)
return 0;
}
-/* signal the CPU if an irq is pending */
-static void apic_update_irq(APICState *s)
+
+/*
+ * <0 - low prio interrupt,
+ * 0 - no interrupt,
+ * >0 - interrupt number
+ */
+static int apic_irq_pending(APICState *s)
{
int irrv, ppr;
- if (!(s->spurious_vec & APIC_SV_ENABLE))
- return;
irrv = get_highest_priority_int(s->irr);
- if (irrv < 0)
- return;
+ if (irrv < 0) {
+ return 0;
+ }
ppr = apic_get_ppr(s);
- if (ppr && (irrv & 0xf0) <= (ppr & 0xf0))
+ if (ppr && (irrv & 0xf0) <= (ppr & 0xf0)) {
+ return -1;
+ }
+
+ return irrv;
+}
+
+/* signal the CPU if an irq is pending */
+static void apic_update_irq(APICState *s)
+{
+ if (!(s->spurious_vec & APIC_SV_ENABLE)) {
return;
- cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ }
+ if (apic_irq_pending(s) > 0) {
+ cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ }
}
void apic_reset_irq_delivered(void)
@@ -599,12 +616,13 @@ int apic_get_interrupt(DeviceState *d)
if (!(s->spurious_vec & APIC_SV_ENABLE))
return -1;
- /* XXX: spurious IRQ handling */
- intno = get_highest_priority_int(s->irr);
- if (intno < 0)
+ intno = apic_irq_pending(s);
+
+ if (intno == 0) {
return -1;
- if (s->tpr && intno <= s->tpr)
+ } else if (intno < 0) {
return s->spurious_vec & 0xff;
+ }
reset_bit(s->irr, intno);
set_bit(s->isr, intno);
apic_update_irq(s);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 33d776de4..08c44d893 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1481,7 +1481,7 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
struct elf_shdr *shdr;
char *strings;
struct syminfo *s;
- struct elf_sym *syms;
+ struct elf_sym *syms, *new_syms;
shnum = hdr->e_shnum;
i = shnum * sizeof(struct elf_shdr);
@@ -1550,12 +1550,14 @@ static void load_symbols(struct elfhdr *hdr, int fd, abi_ulong load_bias)
that we threw away. Whether or not this has any effect on the
memory allocation depends on the malloc implementation and how
many symbols we managed to discard. */
- syms = realloc(syms, nsyms * sizeof(*syms));
- if (syms == NULL) {
+ new_syms = realloc(syms, nsyms * sizeof(*syms));
+ if (new_syms == NULL) {
free(s);
+ free(syms);
free(strings);
return;
}
+ syms = new_syms;
qsort(syms, nsyms, sizeof(*syms), symcmp);
diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h
index acff78108..526aaa2a7 100644
--- a/linux-user/ioctls.h
+++ b/linux-user/ioctls.h
@@ -312,10 +312,8 @@
IOCTL(LOOP_CLR_FD, 0, TYPE_INT)
IOCTL(LOOP_SET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
IOCTL(LOOP_GET_STATUS, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info)))
-#if 0 /* These have some problems - not fully tested */
IOCTL(LOOP_SET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
IOCTL(LOOP_GET_STATUS64, IOC_W, MK_PTR(MK_STRUCT(STRUCT_loop_info64)))
-#endif
IOCTL(LOOP_CHANGE_FD, 0, TYPE_INT)
IOCTL(MTIOCTOP, IOC_W, MK_PTR(MK_STRUCT(STRUCT_mtop)))
diff --git a/qemu-char.c b/qemu-char.c
index ee4f4cab2..bd4e944e1 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -2506,6 +2506,11 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts,
return NULL;
}
+ if (qemu_opt_get(opts, "backend") == NULL) {
+ fprintf(stderr, "chardev: \"%s\" missing backend\n",
+ qemu_opts_id(opts));
+ return NULL;
+ }
for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
break;
diff --git a/qemu-common.h b/qemu-common.h
index c7ff280b9..cb4b7e0d3 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -322,6 +322,8 @@ void qemu_iovec_reset(QEMUIOVector *qiov);
void qemu_iovec_to_buffer(QEMUIOVector *qiov, void *buf);
void qemu_iovec_from_buffer(QEMUIOVector *qiov, const void *buf, size_t count);
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);
struct Monitor;
typedef struct Monitor Monitor;
diff --git a/qemu-img.c b/qemu-img.c
index 4a3735811..7e3cc4cbd 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -213,8 +213,9 @@ static BlockDriverState *bdrv_new_open(const char *filename,
BlockDriverState *bs;
BlockDriver *drv;
char password[256];
+ int ret;
- bs = bdrv_new("");
+ bs = bdrv_new("image");
if (fmt) {
drv = bdrv_find_format(fmt);
@@ -225,10 +226,13 @@ static BlockDriverState *bdrv_new_open(const char *filename,
} else {
drv = NULL;
}
- if (bdrv_open(bs, filename, flags, drv) < 0) {
- error_report("Could not open '%s'", filename);
+
+ ret = bdrv_open(bs, filename, flags, drv);
+ if (ret < 0) {
+ error_report("Could not open '%s': %s", filename, strerror(-ret));
goto fail;
}
+
if (bdrv_is_encrypted(bs)) {
printf("Disk image '%s' is encrypted.\n", filename);
if (read_password(password, sizeof(password)) < 0) {
diff --git a/qerror.c b/qerror.c
index 9d0cdeb45..485560418 100644
--- a/qerror.c
+++ b/qerror.c
@@ -201,6 +201,11 @@ static const QErrorStringTable qerror_table[] = {
.desc = "An undefined error has ocurred",
},
{
+ .error_fmt = QERR_UNKNOWN_BLOCK_FORMAT_FEATURE,
+ .desc = "'%(device)' uses a %(format) feature which is not "
+ "supported by this qemu version: %(feature)",
+ },
+ {
.error_fmt = QERR_VNC_SERVER_FAILED,
.desc = "Could not start VNC server on %(target)",
},
diff --git a/qerror.h b/qerror.h
index b0f69dabe..f732d45e8 100644
--- a/qerror.h
+++ b/qerror.h
@@ -165,6 +165,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_UNDEFINED_ERROR \
"{ 'class': 'UndefinedError', 'data': {} }"
+#define QERR_UNKNOWN_BLOCK_FORMAT_FEATURE \
+ "{ 'class': 'UnknownBlockFormatFeature', 'data': { 'device': %s, 'format': %s, 'feature': %s } }"
+
#define QERR_VNC_SERVER_FAILED \
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
diff --git a/slirp/mbuf.c b/slirp/mbuf.c
index 87508ba01..ce2eb843f 100644
--- a/slirp/mbuf.c
+++ b/slirp/mbuf.c
@@ -23,7 +23,7 @@
* Find a nice value for msize
* XXX if_maxlinkhdr already in mtu
*/
-#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + sizeof(struct m_hdr ) + 6)
+#define SLIRP_MSIZE (IF_MTU + IF_MAXLINKHDR + offsetof(struct mbuf, m_dat) + 6)
void
m_init(Slirp *slirp)
@@ -65,7 +65,7 @@ m_get(Slirp *slirp)
m->m_flags = (flags | M_USEDLIST);
/* Initialise it */
- m->m_size = SLIRP_MSIZE - sizeof(struct m_hdr);
+ m->m_size = SLIRP_MSIZE - offsetof(struct mbuf, m_dat);
m->m_data = m->m_dat;
m->m_len = 0;
m->m_nextpkt = NULL;