aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--VERSION2
-rw-r--r--audio/fmodaudio.c6
-rw-r--r--block.c30
-rw-r--r--block.h10
-rw-r--r--block/cow.c22
-rw-r--r--block/qcow.c18
-rw-r--r--block/qcow2.c14
-rw-r--r--block/raw-win32.c15
-rw-r--r--block/raw.c8
-rw-r--r--block/rbd.c10
-rw-r--r--block/vdi.c2
-rw-r--r--block/vmdk.c4
-rw-r--r--block/vpc.c14
-rw-r--r--block/vvfat.c44
-rw-r--r--block_int.h14
-rw-r--r--blockdev.c10
-rwxr-xr-xconfigure6
-rw-r--r--hw/arm_sysctl.c27
-rw-r--r--hw/arm_timer.c4
-rw-r--r--hw/ide/atapi.c11
-rw-r--r--hw/ide/core.c13
-rw-r--r--hw/nand.c22
-rw-r--r--hw/omap_gpio.c2
-rw-r--r--hw/omap_intc.c6
-rw-r--r--hw/onenand.c5
-rw-r--r--hw/pc.c4
-rw-r--r--hw/pc_piix.c12
-rw-r--r--hw/pl061.c2
-rw-r--r--hw/pxa2xx.c5
-rw-r--r--hw/scsi-disk.c24
-rw-r--r--hw/tc58128.c6
-rw-r--r--linux-user/elfload.c5
-rw-r--r--linux-user/linuxload.c2
-rw-r--r--memory.c4
-rw-r--r--migration.c12
-rw-r--r--nbd.c7
-rw-r--r--os-posix.c3
-rw-r--r--posix-aio-compat.c1
-rw-r--r--qemu-char.c19
-rw-r--r--qemu-nbd.c298
-rw-r--r--qemu-sockets.c1
-rw-r--r--ui/keymaps.c12
-rw-r--r--vl.c10
43 files changed, 505 insertions, 241 deletions
diff --git a/VERSION b/VERSION
index 4a15714fa3..75a7da4bfe 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.15.91
+0.15.92
diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c
index c34cf53567..fabf84dd3b 100644
--- a/audio/fmodaudio.c
+++ b/audio/fmodaudio.c
@@ -343,7 +343,7 @@ static void fmod_fini_out (HWVoiceOut *hw)
static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
{
- int bits16, mode, channel;
+ int mode, channel;
FMODVoiceOut *fmd = (FMODVoiceOut *) hw;
struct audsettings obt_as = *as;
@@ -374,7 +374,6 @@ static int fmod_init_out (HWVoiceOut *hw, struct audsettings *as)
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
- bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
}
@@ -405,7 +404,7 @@ static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...)
static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
{
- int bits16, mode;
+ int mode;
FMODVoiceIn *fmd = (FMODVoiceIn *) hw;
struct audsettings obt_as = *as;
@@ -432,7 +431,6 @@ static int fmod_init_in (HWVoiceIn *hw, struct audsettings *as)
/* FMOD always operates on little endian frames? */
obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as);
- bits16 = (mode & FSOUND_16BITS) != 0;
hw->samples = conf.nb_samples;
return 0;
}
diff --git a/block.c b/block.c
index 9bb236c989..86910b046c 100644
--- a/block.c
+++ b/block.c
@@ -816,6 +816,13 @@ bool bdrv_dev_has_removable_media(BlockDriverState *bs)
return !bs->dev || (bs->dev_ops && bs->dev_ops->change_media_cb);
}
+void bdrv_dev_eject_request(BlockDriverState *bs, bool force)
+{
+ if (bs->dev_ops && bs->dev_ops->eject_request_cb) {
+ bs->dev_ops->eject_request_cb(bs->dev_opaque, force);
+ }
+}
+
bool bdrv_dev_is_tray_open(BlockDriverState *bs)
{
if (bs->dev_ops && bs->dev_ops->is_tray_open) {
@@ -2782,12 +2789,27 @@ static void coroutine_fn bdrv_flush_co_entry(void *opaque)
int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
{
- if (bs->open_flags & BDRV_O_NO_FLUSH) {
+ int ret;
+
+ if (!bs->drv) {
return 0;
- } else if (!bs->drv) {
+ }
+
+ /* Write back cached data to the OS even with cache=unsafe */
+ if (bs->drv->bdrv_co_flush_to_os) {
+ ret = bs->drv->bdrv_co_flush_to_os(bs);
+ if (ret < 0) {
+ return ret;
+ }
+ }
+
+ /* But don't actually force it to the disk with cache=unsafe */
+ if (bs->open_flags & BDRV_O_NO_FLUSH) {
return 0;
- } else if (bs->drv->bdrv_co_flush) {
- return bs->drv->bdrv_co_flush(bs);
+ }
+
+ if (bs->drv->bdrv_co_flush_to_disk) {
+ return bs->drv->bdrv_co_flush_to_disk(bs);
} else if (bs->drv->bdrv_aio_flush) {
BlockDriverAIOCB *acb;
CoroutineIOCompletion co = {
diff --git a/block.h b/block.h
index 38cd748b60..051a25d8d6 100644
--- a/block.h
+++ b/block.h
@@ -39,6 +39,15 @@ typedef struct BlockDevOps {
*/
void (*change_media_cb)(void *opaque, bool load);
/*
+ * Runs when an eject request is issued from the monitor, the tray
+ * is closed, and the medium is locked.
+ * Device models that do not implement is_medium_locked will not need
+ * this callback. Device models that can lock the medium or tray might
+ * want to implement the callback and unlock the tray when "force" is
+ * true, even if they do not support eject requests.
+ */
+ void (*eject_request_cb)(void *opaque, bool force);
+ /*
* Is the virtual tray open?
* Device models implement this only when the device has a tray.
*/
@@ -111,6 +120,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev);
void *bdrv_get_attached_dev(BlockDriverState *bs);
void bdrv_set_dev_ops(BlockDriverState *bs, const BlockDevOps *ops,
void *opaque);
+void bdrv_dev_eject_request(BlockDriverState *bs, bool force);
bool bdrv_dev_has_removable_media(BlockDriverState *bs);
bool bdrv_dev_is_tray_open(BlockDriverState *bs);
bool bdrv_dev_is_medium_locked(BlockDriverState *bs);
diff --git a/block/cow.c b/block/cow.c
index 707c0aad88..089d395c40 100644
--- a/block/cow.c
+++ b/block/cow.c
@@ -326,16 +326,18 @@ static QEMUOptionParameter cow_create_options[] = {
};
static BlockDriver bdrv_cow = {
- .format_name = "cow",
- .instance_size = sizeof(BDRVCowState),
- .bdrv_probe = cow_probe,
- .bdrv_open = cow_open,
- .bdrv_read = cow_co_read,
- .bdrv_write = cow_co_write,
- .bdrv_close = cow_close,
- .bdrv_create = cow_create,
- .bdrv_co_flush = cow_co_flush,
- .bdrv_is_allocated = cow_is_allocated,
+ .format_name = "cow",
+ .instance_size = sizeof(BDRVCowState),
+
+ .bdrv_probe = cow_probe,
+ .bdrv_open = cow_open,
+ .bdrv_close = cow_close,
+ .bdrv_create = cow_create,
+
+ .bdrv_read = cow_co_read,
+ .bdrv_write = cow_co_write,
+ .bdrv_co_flush_to_disk = cow_co_flush,
+ .bdrv_is_allocated = cow_is_allocated,
.create_options = cow_create_options,
};
diff --git a/block/qcow.c b/block/qcow.c
index 35e21eb6b3..adecee06c9 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -828,14 +828,16 @@ static BlockDriver bdrv_qcow = {
.bdrv_open = qcow_open,
.bdrv_close = qcow_close,
.bdrv_create = qcow_create,
- .bdrv_is_allocated = qcow_is_allocated,
- .bdrv_set_key = qcow_set_key,
- .bdrv_make_empty = qcow_make_empty,
- .bdrv_co_readv = qcow_co_readv,
- .bdrv_co_writev = qcow_co_writev,
- .bdrv_co_flush = qcow_co_flush,
- .bdrv_write_compressed = qcow_write_compressed,
- .bdrv_get_info = qcow_get_info,
+
+ .bdrv_co_readv = qcow_co_readv,
+ .bdrv_co_writev = qcow_co_writev,
+ .bdrv_co_flush_to_disk = qcow_co_flush,
+ .bdrv_is_allocated = qcow_is_allocated,
+
+ .bdrv_set_key = qcow_set_key,
+ .bdrv_make_empty = qcow_make_empty,
+ .bdrv_write_compressed = qcow_write_compressed,
+ .bdrv_get_info = qcow_get_info,
.create_options = qcow_create_options,
};
diff --git a/block/qcow2.c b/block/qcow2.c
index ef057d31e0..5c784eee51 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1105,7 +1105,7 @@ fail:
return ret;
}
-static int qcow2_co_flush(BlockDriverState *bs)
+static int qcow2_co_flush_to_os(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
int ret;
@@ -1124,6 +1124,11 @@ static int qcow2_co_flush(BlockDriverState *bs)
}
qemu_co_mutex_unlock(&s->lock);
+ return 0;
+}
+
+static int qcow2_co_flush_to_disk(BlockDriverState *bs)
+{
return bdrv_co_flush(bs->file);
}
@@ -1243,9 +1248,10 @@ static BlockDriver bdrv_qcow2 = {
.bdrv_set_key = qcow2_set_key,
.bdrv_make_empty = qcow2_make_empty,
- .bdrv_co_readv = qcow2_co_readv,
- .bdrv_co_writev = qcow2_co_writev,
- .bdrv_co_flush = qcow2_co_flush,
+ .bdrv_co_readv = qcow2_co_readv,
+ .bdrv_co_writev = qcow2_co_writev,
+ .bdrv_co_flush_to_os = qcow2_co_flush_to_os,
+ .bdrv_co_flush_to_disk = qcow2_co_flush_to_disk,
.bdrv_co_discard = qcow2_co_discard,
.bdrv_truncate = qcow2_truncate,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index f5f73bcd64..e4b0b75b70 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -281,9 +281,11 @@ static BlockDriver bdrv_file = {
.bdrv_file_open = raw_open,
.bdrv_close = raw_close,
.bdrv_create = raw_create,
- .bdrv_co_flush = raw_flush,
- .bdrv_read = raw_read,
- .bdrv_write = raw_write,
+
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
+ .bdrv_co_flush_to_disk = raw_flush,
+
.bdrv_truncate = raw_truncate,
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
@@ -409,11 +411,12 @@ static BlockDriver bdrv_host_device = {
.bdrv_probe_device = hdev_probe_device,
.bdrv_file_open = hdev_open,
.bdrv_close = raw_close,
- .bdrv_co_flush = raw_flush,
.bdrv_has_zero_init = hdev_has_zero_init,
- .bdrv_read = raw_read,
- .bdrv_write = raw_write,
+ .bdrv_read = raw_read,
+ .bdrv_write = raw_write,
+ .bdrv_co_flush_to_disk = raw_flush,
+
.bdrv_getlength = raw_getlength,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
diff --git a/block/raw.c b/block/raw.c
index 33cc4716d3..6098070d65 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -111,10 +111,10 @@ static BlockDriver bdrv_raw = {
.bdrv_open = raw_open,
.bdrv_close = raw_close,
- .bdrv_co_readv = raw_co_readv,
- .bdrv_co_writev = raw_co_writev,
- .bdrv_co_flush = raw_co_flush,
- .bdrv_co_discard = raw_co_discard,
+ .bdrv_co_readv = raw_co_readv,
+ .bdrv_co_writev = raw_co_writev,
+ .bdrv_co_flush_to_disk = raw_co_flush,
+ .bdrv_co_discard = raw_co_discard,
.bdrv_probe = raw_probe,
.bdrv_getlength = raw_getlength,
diff --git a/block/rbd.c b/block/rbd.c
index c684e0cb0b..9088c52d24 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -851,18 +851,18 @@ static BlockDriver bdrv_rbd = {
.bdrv_file_open = qemu_rbd_open,
.bdrv_close = qemu_rbd_close,
.bdrv_create = qemu_rbd_create,
- .bdrv_co_flush = qemu_rbd_co_flush,
.bdrv_get_info = qemu_rbd_getinfo,
.create_options = qemu_rbd_create_options,
.bdrv_getlength = qemu_rbd_getlength,
.bdrv_truncate = qemu_rbd_truncate,
.protocol_name = "rbd",
- .bdrv_aio_readv = qemu_rbd_aio_readv,
- .bdrv_aio_writev = qemu_rbd_aio_writev,
+ .bdrv_aio_readv = qemu_rbd_aio_readv,
+ .bdrv_aio_writev = qemu_rbd_aio_writev,
+ .bdrv_co_flush_to_disk = qemu_rbd_co_flush,
- .bdrv_snapshot_create = qemu_rbd_snap_create,
- .bdrv_snapshot_list = qemu_rbd_snap_list,
+ .bdrv_snapshot_create = qemu_rbd_snap_create,
+ .bdrv_snapshot_list = qemu_rbd_snap_list,
};
static void bdrv_rbd_init(void)
diff --git a/block/vdi.c b/block/vdi.c
index 523a6409c5..684a4a87b6 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -980,7 +980,7 @@ static BlockDriver bdrv_vdi = {
.bdrv_open = vdi_open,
.bdrv_close = vdi_close,
.bdrv_create = vdi_create,
- .bdrv_co_flush = vdi_co_flush,
+ .bdrv_co_flush_to_disk = vdi_co_flush,
.bdrv_is_allocated = vdi_is_allocated,
.bdrv_make_empty = vdi_make_empty,
diff --git a/block/vmdk.c b/block/vmdk.c
index 985006e203..e53a2f0920 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1581,8 +1581,8 @@ static BlockDriver bdrv_vmdk = {
.bdrv_write = vmdk_co_write,
.bdrv_close = vmdk_close,
.bdrv_create = vmdk_create,
- .bdrv_co_flush = vmdk_co_flush,
- .bdrv_is_allocated = vmdk_is_allocated,
+ .bdrv_co_flush_to_disk = vmdk_co_flush,
+ .bdrv_is_allocated = vmdk_is_allocated,
.bdrv_get_allocated_file_size = vmdk_get_allocated_file_size,
.create_options = vmdk_create_options,
diff --git a/block/vpc.c b/block/vpc.c
index 79be7d051b..39a324705d 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -617,7 +617,11 @@ static int vpc_create(const char *filename, QEMUOptionParameter *options)
memcpy(dyndisk_header->magic, "cxsparse", 8);
- dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFF);
+ /*
+ * Note: The spec is actually wrong here for data_offset, it says
+ * 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
+ */
+ dyndisk_header->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
dyndisk_header->table_offset = be64_to_cpu(3 * 512);
dyndisk_header->version = be32_to_cpu(0x00010000);
dyndisk_header->block_size = be32_to_cpu(block_size);
@@ -661,14 +665,16 @@ static QEMUOptionParameter vpc_create_options[] = {
static BlockDriver bdrv_vpc = {
.format_name = "vpc",
.instance_size = sizeof(BDRVVPCState),
+
.bdrv_probe = vpc_probe,
.bdrv_open = vpc_open,
- .bdrv_read = vpc_co_read,
- .bdrv_write = vpc_co_write,
- .bdrv_co_flush = vpc_co_flush,
.bdrv_close = vpc_close,
.bdrv_create = vpc_create,
+ .bdrv_read = vpc_co_read,
+ .bdrv_write = vpc_co_write,
+ .bdrv_co_flush_to_disk = vpc_co_flush,
+
.create_options = vpc_create_options,
};
diff --git a/block/vvfat.c b/block/vvfat.c
index 8511fe523c..131680f6f4 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -1254,15 +1254,15 @@ static int vvfat_read(BlockDriverState *bs, int64_t sector_num,
return -1;
if (s->qcow) {
int n;
- if (s->qcow->drv->bdrv_is_allocated(s->qcow,
- sector_num, nb_sectors-i, &n)) {
+ if (bdrv_is_allocated(s->qcow, sector_num, nb_sectors-i, &n)) {
DLOG(fprintf(stderr, "sectors %d+%d allocated\n", (int)sector_num, n));
- if (s->qcow->drv->bdrv_read(s->qcow, sector_num, buf+i*0x200, n))
- return -1;
- i += n - 1;
- sector_num += n - 1;
- continue;
- }
+ if (bdrv_read(s->qcow, sector_num, buf + i*0x200, n)) {
+ return -1;
+ }
+ i += n - 1;
+ sector_num += n - 1;
+ continue;
+ }
DLOG(fprintf(stderr, "sector %d not allocated\n", (int)sector_num));
}
if(sector_num<s->faked_sectors) {
@@ -1516,7 +1516,7 @@ static inline int cluster_was_modified(BDRVVVFATState* s, uint32_t cluster_num)
return 0;
for (i = 0; !was_modified && i < s->sectors_per_cluster; i++)
- was_modified = s->qcow->drv->bdrv_is_allocated(s->qcow,
+ was_modified = bdrv_is_allocated(s->qcow,
cluster2sector(s, cluster_num) + i, 1, &dummy);
return was_modified;
@@ -1665,16 +1665,16 @@ static uint32_t get_cluster_count_for_direntry(BDRVVVFATState* s,
int64_t offset = cluster2sector(s, cluster_num);
vvfat_close_current_file(s);
- for (i = 0; i < s->sectors_per_cluster; i++)
- if (!s->qcow->drv->bdrv_is_allocated(s->qcow,
- offset + i, 1, &dummy)) {
- if (vvfat_read(s->bs,
- offset, s->cluster_buffer, 1))
- return -1;
- if (s->qcow->drv->bdrv_write(s->qcow,
- offset, s->cluster_buffer, 1))
- return -2;
- }
+ for (i = 0; i < s->sectors_per_cluster; i++) {
+ if (!bdrv_is_allocated(s->qcow, offset + i, 1, &dummy)) {
+ if (vvfat_read(s->bs, offset, s->cluster_buffer, 1)) {
+ return -1;
+ }
+ if (bdrv_write(s->qcow, offset, s->cluster_buffer, 1)) {
+ return -2;
+ }
+ }
+ }
}
}
@@ -2619,7 +2619,9 @@ static int do_commit(BDRVVVFATState* s)
return ret;
}
- s->qcow->drv->bdrv_make_empty(s->qcow);
+ if (s->qcow->drv->bdrv_make_empty) {
+ s->qcow->drv->bdrv_make_empty(s->qcow);
+ }
memset(s->used_clusters, 0, sector2cluster(s, s->sector_count));
@@ -2714,7 +2716,7 @@ DLOG(checkpoint());
* Use qcow backend. Commit later.
*/
DLOG(fprintf(stderr, "Write to qcow backend: %d + %d\n", (int)sector_num, nb_sectors));
- ret = s->qcow->drv->bdrv_write(s->qcow, sector_num, buf, nb_sectors);
+ ret = bdrv_write(s->qcow, sector_num, buf, nb_sectors);
if (ret < 0) {
fprintf(stderr, "Error writing to qcow backend\n");
return ret;
diff --git a/block_int.h b/block_int.h
index f4547f6d93..1ec4921cc6 100644
--- a/block_int.h
+++ b/block_int.h
@@ -84,10 +84,22 @@ struct BlockDriver {
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
int coroutine_fn (*bdrv_co_writev)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors, QEMUIOVector *qiov);
- int coroutine_fn (*bdrv_co_flush)(BlockDriverState *bs);
int coroutine_fn (*bdrv_co_discard)(BlockDriverState *bs,
int64_t sector_num, int nb_sectors);
+ /*
+ * Flushes all data that was already written to the OS all the way down to
+ * the disk (for example raw-posix calls fsync()).
+ */
+ int coroutine_fn (*bdrv_co_flush_to_disk)(BlockDriverState *bs);
+
+ /*
+ * Flushes all internal caches to the OS. The data may still sit in a
+ * writeback cache of the host OS, but it will survive a crash of the qemu
+ * process.
+ */
+ int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
+
int (*bdrv_aio_multiwrite)(BlockDriverState *bs, BlockRequest *reqs,
int num_reqs);
int (*bdrv_merge_requests)(BlockDriverState *bs, BlockRequest* a,
diff --git a/blockdev.c b/blockdev.c
index 0827bf7743..222818690d 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -635,10 +635,12 @@ static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
qerror_report(QERR_DEVICE_NOT_REMOVABLE, bdrv_get_device_name(bs));
return -1;
}
- if (!force && !bdrv_dev_is_tray_open(bs)
- && bdrv_dev_is_medium_locked(bs)) {
- qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
- return -1;
+ if (bdrv_dev_is_medium_locked(bs) && !bdrv_dev_is_tray_open(bs)) {
+ bdrv_dev_eject_request(bs, force);
+ if (!force) {
+ qerror_report(QERR_DEVICE_LOCKED, bdrv_get_device_name(bs));
+ return -1;
+ }
}
bdrv_close(bs);
return 0;
diff --git a/configure b/configure
index 8d85d232c1..6c77fbb1a5 100755
--- a/configure
+++ b/configure
@@ -1963,13 +1963,17 @@ if test "$attr" != "no" ; then
cat > $TMPC <<EOF
#include <stdio.h>
#include <sys/types.h>
+#ifdef CONFIG_LIBATTR
+#include <attr/xattr.h>
+#else
#include <sys/xattr.h>
+#endif
int main(void) { getxattr(NULL, NULL, NULL, 0); setxattr(NULL, NULL, NULL, 0, 0); return 0; }
EOF
if compile_prog "" "" ; then
attr=yes
# Older distros have <attr/xattr.h>, and need -lattr:
- elif sed -i s,sys/xattr,attr/xattr, $TMPC && compile_prog "" "-lattr" ; then
+ elif compile_prog "-DCONFIG_LIBATTR" "-lattr" ; then
attr=yes
LIBS="-lattr $LIBS"
libattr=yes
diff --git a/hw/arm_sysctl.c b/hw/arm_sysctl.c
index 17cf6f72ad..477fc6fd47 100644
--- a/hw/arm_sysctl.c
+++ b/hw/arm_sysctl.c
@@ -231,15 +231,30 @@ static void arm_sysctl_write(void *opaque, target_phys_addr_t offset,
s->nvflags &= ~val;
break;
case 0x40: /* RESETCTL */
- if (board_id(s) == BOARD_ID_VEXPRESS) {
+ switch (board_id(s)) {
+ case BOARD_ID_PB926:
+ if (s->lockval == LOCK_VALUE) {
+ s->resetlevel = val;
+ if (val & 0x100) {
+ qemu_system_reset_request();
+ }
+ }
+ break;
+ case BOARD_ID_PBX:
+ case BOARD_ID_PBA8:
+ if (s->lockval == LOCK_VALUE) {
+ s->resetlevel = val;
+ if (val & 0x04) {
+ qemu_system_reset_request();
+ }
+ }
+ break;
+ case BOARD_ID_VEXPRESS:
+ case BOARD_ID_EB:
+ default:
/* reserved: RAZ/WI */
break;
}
- if (s->lockval == LOCK_VALUE) {
- s->resetlevel = val;
- if (val & 0x100)
- qemu_system_reset_request ();
- }
break;
case 0x44: /* PCICTL */
/* nothing to do. */
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 09a4b247bd..66db81d5b7 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -269,7 +269,7 @@ static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
/* ??? Don't know the PrimeCell ID for this device. */
n = offset >> 8;
- if (n > 3) {
+ if (n > 2) {
hw_error("sp804_read: Bad timer %d\n", n);
}
@@ -283,7 +283,7 @@ static void icp_pit_write(void *opaque, target_phys_addr_t offset,
int n;
n = offset >> 8;
- if (n > 3) {
+ if (n > 2) {
hw_error("sp804_write: Bad timer %d\n", n);
}
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 90b6729692..1fed359ab1 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -516,9 +516,14 @@ static unsigned int event_status_media(IDEState *s,
/* Event notification descriptor */
event_code = MEC_NO_CHANGE;
- if (media_status != MS_TRAY_OPEN && s->events.new_media) {
- event_code = MEC_NEW_MEDIA;
- s->events.new_media = false;
+ if (media_status != MS_TRAY_OPEN) {
+ if (s->events.new_media) {
+ event_code = MEC_NEW_MEDIA;
+ s->events.new_media = false;
+ } else if (s->events.eject_request) {
+ event_code = MEC_EJECT_REQUESTED;
+ s->events.eject_request = false;
+ }
}
buf[4] = event_code;
diff --git a/hw/ide/core.c b/hw/ide/core.c
index 9a2fd30607..93a1a689c4 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -804,6 +804,18 @@ static void ide_cd_change_cb(void *opaque, bool load)
*/
s->cdrom_changed = 1;
s->events.new_media = true;
+ s->events.eject_request = false;
+ ide_set_irq(s->bus);
+}
+
+static void ide_cd_eject_request_cb(void *opaque, bool force)
+{
+ IDEState *s = opaque;
+
+ s->events.eject_request = true;
+ if (force) {
+ s->tray_locked = false;
+ }
ide_set_irq(s->bus);
}
@@ -1811,6 +1823,7 @@ static bool ide_cd_is_medium_locked(void *opaque)
static const BlockDevOps ide_cd_block_ops = {
.change_media_cb = ide_cd_change_cb,
+ .eject_request_cb = ide_cd_eject_request_cb,
.is_tray_open = ide_cd_is_tray_open,
.is_medium_locked = ide_cd_is_medium_locked,
};
diff --git a/hw/nand.c b/hw/nand.c
index c27783e8ac..7f25814ddd 100644
--- a/hw/nand.c
+++ b/hw/nand.c
@@ -19,6 +19,7 @@
# include "flash.h"
# include "blockdev.h"
# include "sysbus.h"
+#include "qemu-error.h"
# define NAND_CMD_READ0 0x00
# define NAND_CMD_READ1 0x01
@@ -384,18 +385,23 @@ static int nand_device_init(SysBusDevice *dev)
nand_init_2048(s);
break;
default:
- hw_error("%s: Unsupported NAND block size.\n", __func__);
+ error_report("Unsupported NAND block size");
+ return -1;
}
pagesize = 1 << s->oob_shift;
s->mem_oob = 1;
- if (s->bdrv && bdrv_getlength(s->bdrv) >=
- (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
- pagesize = 0;
- s->mem_oob = 0;
- }
-
- if (!s->bdrv) {
+ if (s->bdrv) {
+ if (bdrv_is_read_only(s->bdrv)) {
+ error_report("Can't use a read-only drive");
+ return -1;
+ }
+ if (bdrv_getlength(s->bdrv) >=
+ (s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
+ pagesize = 0;
+ s->mem_oob = 0;
+ }
+ } else {
pagesize += 1 << s->page_shift;
}
if (pagesize) {
diff --git a/hw/omap_gpio.c b/hw/omap_gpio.c
index 42e59c3a53..30630a8aa9 100644
--- a/hw/omap_gpio.c
+++ b/hw/omap_gpio.c
@@ -510,7 +510,7 @@ static void omap2_gpio_module_write(void *opaque, target_phys_addr_t addr,
static uint32_t omap2_gpio_module_readp(void *opaque, target_phys_addr_t addr)
{
- return omap2_gpio_module_readp(opaque, addr) >> ((addr & 3) << 3);
+ return omap2_gpio_module_read(opaque, addr & ~3) >> ((addr & 3) << 3);
}
static void omap2_gpio_module_writep(void *opaque, target_phys_addr_t addr,
diff --git a/hw/omap_intc.c b/hw/omap_intc.c
index 0f7fd9dd4c..45efa25109 100644
--- a/hw/omap_intc.c
+++ b/hw/omap_intc.c
@@ -398,6 +398,9 @@ static uint64_t omap2_inth_read(void *opaque, target_phys_addr_t addr,
if (bank_no < s->nbanks) {
offset &= ~0x60;
bank = &s->bank[bank_no];
+ } else {
+ OMAP_BAD_REG(addr);
+ return 0;
}
}
@@ -476,6 +479,9 @@ static void omap2_inth_write(void *opaque, target_phys_addr_t addr,
if (bank_no < s->nbanks) {
offset &= ~0x60;
bank = &s->bank[bank_no];
+ } else {
+ OMAP_BAD_REG(addr);
+ return;
}
}
diff --git a/hw/onenand.c b/hw/onenand.c
index 6f68f70698..7898da9321 100644
--- a/hw/onenand.c
+++ b/hw/onenand.c
@@ -26,6 +26,7 @@
#include "memory.h"
#include "exec-memory.h"
#include "sysbus.h"
+#include "qemu-error.h"
/* 11 for 2kB-page OneNAND ("2nd generation") and 10 for 1kB-page chips */
#define PAGE_SHIFT 11
@@ -772,6 +773,10 @@ static int onenand_initfn(SysBusDevice *dev)
s->image = memset(g_malloc(size + (size >> 5)),
0xff, size + (size >> 5));
} else {
+ if (bdrv_is_read_only(s->bdrv)) {
+ error_report("Can't use a read-only drive");
+ return -1;
+ }
s->bdrv_cur = s->bdrv;
}
s->otp = memset(g_malloc((64 + 2) << PAGE_SHIFT),
diff --git a/hw/pc.c b/hw/pc.c
index 3015671858..33778fe422 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -335,7 +335,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
ISADevice *s)
{
int val, nb, nb_heads, max_track, last_sect, i;
- FDriveType fd_type[2];
+ FDriveType fd_type[2] = { FDRIVE_DRV_NONE, FDRIVE_DRV_NONE };
BlockDriverState *fd[MAX_FD];
static pc_cmos_init_late_arg arg;
@@ -385,8 +385,6 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
&last_sect, FDRIVE_DRV_NONE,
&fd_type[i]);
- } else {
- fd_type[i] = FDRIVE_DRV_NONE;
}
}
}
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 27ea5707e2..970f43c99c 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -311,6 +311,18 @@ static QEMUMachine pc_machine_v0_14 = {
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
+ .compat_props = (GlobalProperty[]) {
+ {
+ .driver = "qxl",
+ .property = "revision",
+ .value = stringify(2),
+ },{
+ .driver = "qxl-vga",
+ .property = "revision",
+ .value = stringify(2),
+ },
+ { /* end of list */ }
+ },
};
static QEMUMachine pc_machine_v0_13 = {
diff --git a/hw/pl061.c b/hw/pl061.c
index d13746cfe5..cf5adbe1fb 100644
--- a/hw/pl061.c
+++ b/hw/pl061.c
@@ -103,7 +103,7 @@ static void pl061_update(pl061_state *s)
s->old_data = out;
for (i = 0; i < 8; i++) {
mask = 1 << i;
- if ((changed & mask) && s->out) {
+ if (changed & mask) {
DPRINTF("Set output %d = %d\n", i, (out & mask) != 0);
qemu_set_irq(s->out[i], (out & mask) != 0);
}
diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c
index bfc28a999b..e9a507ece5 100644
--- a/hw/pxa2xx.c
+++ b/hw/pxa2xx.c
@@ -114,7 +114,10 @@ static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
switch (addr) {
case PMCR:
- s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
+ /* Clear the write-one-to-clear bits... */
+ s->pm_regs[addr >> 2] &= ~(value & 0x2a);
+ /* ...and set the plain r/w bits */
+ s->pm_regs[addr >> 2] &= ~0x15;
s->pm_regs[addr >> 2] |= value & 0x15;
break;
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 1c04872af7..62f538f4f8 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -65,6 +65,7 @@ struct SCSIDiskState
uint32_t removable;
bool media_changed;
bool media_event;
+ bool eject_request;
QEMUBH *bh;
char *version;
char *serial;
@@ -671,9 +672,14 @@ static int scsi_event_status_media(SCSIDiskState *s, uint8_t *outbuf)
/* Event notification descriptor */
event_code = MEC_NO_CHANGE;
- if (media_status != MS_TRAY_OPEN && s->media_event) {
- event_code = MEC_NEW_MEDIA;
- s->media_event = false;
+ if (media_status != MS_TRAY_OPEN) {
+ if (s->media_event) {
+ event_code = MEC_NEW_MEDIA;
+ s->media_event = false;
+ } else if (s->eject_request) {
+ event_code = MEC_EJECT_REQUESTED;
+ s->eject_request = false;
+ }
}
outbuf[0] = event_code;
@@ -1470,6 +1476,17 @@ static void scsi_cd_change_media_cb(void *opaque, bool load)
s->tray_open = !load;
s->qdev.unit_attention = SENSE_CODE(UNIT_ATTENTION_NO_MEDIUM);
s->media_event = true;
+ s->eject_request = false;
+}
+
+static void scsi_cd_eject_request_cb(void *opaque, bool force)
+{
+ SCSIDiskState *s = opaque;
+
+ s->eject_request = true;
+ if (force) {
+ s->tray_locked = false;
+ }
}
static bool scsi_cd_is_tray_open(void *opaque)
@@ -1484,6 +1501,7 @@ static bool scsi_cd_is_medium_locked(void *opaque)
static const BlockDevOps scsi_cd_block_ops = {
.change_media_cb = scsi_cd_change_media_cb,
+ .eject_request_cb = scsi_cd_eject_request_cb,
.is_tray_open = scsi_cd_is_tray_open,
.is_medium_locked = scsi_cd_is_medium_locked,
};
diff --git a/hw/tc58128.c b/hw/tc58128.c
index ee3ecad51a..4ce80b18f3 100644
--- a/hw/tc58128.c
+++ b/hw/tc58128.c
@@ -30,12 +30,8 @@ static void init_dev(tc58128_dev * dev, const char *filename)
int ret, blocks;
dev->state = WAIT;
- dev->flash_contents = g_malloc0(FLASH_SIZE);
+ dev->flash_contents = g_malloc(FLASH_SIZE);
memset(dev->flash_contents, 0xff, FLASH_SIZE);
- if (!dev->flash_contents) {
- fprintf(stderr, "could not alloc memory for flash\n");
- exit(1);
- }
if (filename) {
/* Load flash image skipping the first block */
ret = load_image(filename, dev->flash_contents + 528 * 32);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index a4139763f4..4635bb2e5d 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1105,8 +1105,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
offset = p % TARGET_PAGE_SIZE;
pag = (char *)page[p/TARGET_PAGE_SIZE];
if (!pag) {
- pag = (char *)malloc(TARGET_PAGE_SIZE);
- memset(pag, 0, TARGET_PAGE_SIZE);
+ pag = g_try_malloc0(TARGET_PAGE_SIZE);
page[p/TARGET_PAGE_SIZE] = pag;
if (!pag)
return 0;
@@ -1164,7 +1163,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
info->rss++;
/* FIXME - check return value of memcpy_to_target() for failure */
memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
- free(bprm->page[i]);
+ g_free(bprm->page[i]);
}
stack_base += TARGET_PAGE_SIZE;
}
diff --git a/linux-user/linuxload.c b/linux-user/linuxload.c
index 62ebc7ed41..b47025f08a 100644
--- a/linux-user/linuxload.c
+++ b/linux-user/linuxload.c
@@ -178,7 +178,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
/* Something went wrong, return the inode and free the argument pages*/
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
- free(bprm->page[i]);
+ g_free(bprm->page[i]);
}
return(retval);
}
diff --git a/memory.c b/memory.c
index c0c1d12d79..7c20a0703f 100644
--- a/memory.c
+++ b/memory.c
@@ -1401,7 +1401,7 @@ static void mtree_print_mr(fprintf_function mon_printf, void *f,
alias_print_queue);
}
- QTAILQ_FOREACH_SAFE(next_ml, &submr_print_queue, queue, ml) {
+ QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, queue, next_ml) {
g_free(ml);
}
}
@@ -1425,7 +1425,7 @@ void mtree_info(fprintf_function mon_printf, void *f)
}
QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) {
- g_free(ml2);
+ g_free(ml);
}
if (address_space_io.root &&
diff --git a/migration.c b/migration.c
index 4b17566857..41c3c24e09 100644
--- a/migration.c
+++ b/migration.c
@@ -155,7 +155,6 @@ MigrationInfo *qmp_query_migrate(Error **errp)
static void migrate_fd_monitor_suspend(MigrationState *s, Monitor *mon)
{
- s->mon = mon;
if (monitor_suspend(mon) == 0) {
DPRINTF("suspending monitor\n");
} else {
@@ -383,7 +382,12 @@ static MigrationState *migrate_init(Monitor *mon, int detach, int blk, int inc)
s->bandwidth_limit = bandwidth_limit;
s->blk = blk;
s->shared = inc;
- s->mon = NULL;
+
+ /* s->mon is used for two things:
+ - pass fd in fd migration
+ - suspend/resume monitor for not detached migration
+ */
+ s->mon = mon;
s->bandwidth_limit = bandwidth_limit;
s->state = MIG_STATE_SETUP;
@@ -435,6 +439,10 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
return ret;
}
+ if (detach) {
+ s->mon = NULL;
+ }
+
notifier_list_notify(&migration_state_notifiers, s);
return 0;
}
diff --git a/nbd.c b/nbd.c
index fb5e424abe..e6c931c5ce 100644
--- a/nbd.c
+++ b/nbd.c
@@ -425,6 +425,13 @@ int nbd_client(int fd)
TRACE("Doing NBD loop");
ret = ioctl(fd, NBD_DO_IT);
+ if (ret == -1 && errno == EPIPE) {
+ /* NBD_DO_IT normally returns EPIPE when someone has disconnected
+ * the socket via NBD_DISCONNECT. We do not want to return 1 in
+ * that case.
+ */
+ ret = 0;
+ }
serrno = errno;
TRACE("NBD loop returned %d: %s", ret, strerror(serrno));
diff --git a/os-posix.c b/os-posix.c
index dbf3b240f7..dc4a6bb3ff 100644
--- a/os-posix.c
+++ b/os-posix.c
@@ -372,13 +372,16 @@ int qemu_create_pidfile(const char *filename)
return -1;
}
if (lockf(fd, F_TLOCK, 0) == -1) {
+ close(fd);
return -1;
}
len = snprintf(buffer, sizeof(buffer), FMT_pid "\n", getpid());
if (write(fd, buffer, len) != len) {
+ close(fd);
return -1;
}
+ close(fd);
return 0;
}
diff --git a/posix-aio-compat.c b/posix-aio-compat.c
index d3c1174ebf..0c0035cb18 100644
--- a/posix-aio-compat.c
+++ b/posix-aio-compat.c
@@ -667,6 +667,7 @@ int paio_init(void)
s->first_aio = NULL;
if (qemu_pipe(fds) == -1) {
fprintf(stderr, "failed to create pipe\n");
+ g_free(s);
return -1;
}
diff --git a/qemu-char.c b/qemu-char.c
index 9fd94d1bb4..b562bf88a7 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -985,7 +985,7 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
CharDriverState *chr;
PtyCharDriver *s;
struct termios tty;
- int slave_fd, len;
+ int master_fd, slave_fd, len;
#if defined(__OpenBSD__) || defined(__DragonFly__)
char pty_name[PATH_MAX];
#define q_ptsname(x) pty_name
@@ -994,10 +994,7 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
#define q_ptsname(x) ptsname(x)
#endif
- chr = g_malloc0(sizeof(CharDriverState));
- s = g_malloc0(sizeof(PtyCharDriver));
-
- if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
+ if (openpty(&master_fd, &slave_fd, pty_name, NULL, NULL) < 0) {
return -errno;
}
@@ -1007,17 +1004,21 @@ static int qemu_chr_open_pty(QemuOpts *opts, CharDriverState **_chr)
tcsetattr(slave_fd, TCSAFLUSH, &tty);
close(slave_fd);
- len = strlen(q_ptsname(s->fd)) + 5;
+ chr = g_malloc0(sizeof(CharDriverState));
+
+ len = strlen(q_ptsname(master_fd)) + 5;
chr->filename = g_malloc(len);
- snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
- qemu_opt_set(opts, "path", q_ptsname(s->fd));
- fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
+ snprintf(chr->filename, len, "pty:%s", q_ptsname(master_fd));
+ qemu_opt_set(opts, "path", q_ptsname(master_fd));
+ fprintf(stderr, "char device redirected to %s\n", q_ptsname(master_fd));
+ s = g_malloc0(sizeof(PtyCharDriver));
chr->opaque = s;
chr->chr_write = pty_chr_write;
chr->chr_update_read_handler = pty_chr_update_read_handler;
chr->chr_close = pty_chr_close;
+ s->fd = master_fd;
s->timer = qemu_new_timer_ms(rt_clock, pty_chr_timer, chr);
*_chr = chr;
diff --git a/qemu-nbd.c b/qemu-nbd.c
index d8d3e15a84..291cba2eaa 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -31,12 +31,17 @@
#include <arpa/inet.h>
#include <signal.h>
#include <libgen.h>
+#include <pthread.h>
#define SOCKET_PATH "/var/lock/qemu-nbd-%s"
#define NBD_BUFFER_SIZE (1024*1024)
+static int sigterm_wfd;
static int verbose;
+static char *device;
+static char *srcpath;
+static char *sockpath;
static void usage(const char *name)
{
@@ -163,21 +168,80 @@ static int find_partition(BlockDriverState *bs, int partition,
return -1;
}
-static void show_parts(const char *device)
+static void termsig_handler(int signum)
{
- if (fork() == 0) {
- int nbd;
+ static int sigterm_reported;
+ if (!sigterm_reported) {
+ sigterm_reported = (write(sigterm_wfd, "", 1) == 1);
+ }
+}
- /* linux just needs an open() to trigger
- * the partition table update
- * but remember to load the module with max_part != 0 :
- * modprobe nbd max_part=63
- */
- nbd = open(device, O_RDWR);
- if (nbd != -1)
- close(nbd);
- exit(0);
+static void *show_parts(void *arg)
+{
+ int nbd;
+
+ /* linux just needs an open() to trigger
+ * the partition table update
+ * but remember to load the module with max_part != 0 :
+ * modprobe nbd max_part=63
+ */
+ nbd = open(device, O_RDWR);
+ if (nbd != -1) {
+ close(nbd);
}
+ return NULL;
+}
+
+static void *nbd_client_thread(void *arg)
+{
+ int fd = *(int *)arg;
+ off_t size;
+ size_t blocksize;
+ uint32_t nbdflags;
+ int sock;
+ int ret;
+ pthread_t show_parts_thread;
+
+ do {
+ sock = unix_socket_outgoing(sockpath);
+ if (sock == -1) {
+ goto out;
+ }
+ } while (sock == -1);
+
+ ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
+ &size, &blocksize);
+ if (ret == -1) {
+ goto out;
+ }
+
+ ret = nbd_init(fd, sock, nbdflags, size, blocksize);
+ if (ret == -1) {
+ goto out;
+ }
+
+ /* update partition table */
+ pthread_create(&show_parts_thread, NULL, show_parts, NULL);
+
+ if (verbose) {
+ fprintf(stderr, "NBD device %s is now connected to %s\n",
+ device, srcpath);
+ } else {
+ /* Close stderr so that the qemu-nbd process exits. */
+ dup2(STDOUT_FILENO, STDERR_FILENO);
+ }
+
+ ret = nbd_client(fd);
+ if (ret) {
+ goto out;
+ }
+ close(fd);
+ kill(getpid(), SIGTERM);
+ return (void *) EXIT_SUCCESS;
+
+out:
+ kill(getpid(), SIGTERM);
+ return (void *) EXIT_FAILURE;
}
int main(int argc, char **argv)
@@ -192,9 +256,6 @@ int main(int argc, char **argv)
struct sockaddr_in addr;
socklen_t addr_len = sizeof(addr);
off_t fd_size;
- char *device = NULL;
- char *socket = NULL;
- char sockpath[128];
const char *sopt = "hVb:o:p:rsnP:c:dvk:e:t";
struct option lopt[] = {
{ "help", 0, NULL, 'h' },
@@ -230,6 +291,21 @@ int main(int argc, char **argv)
int nb_fds = 0;
int max_fd;
int persistent = 0;
+ pthread_t client_thread;
+
+ /* The client thread uses SIGTERM to interrupt the server. A signal
+ * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
+ */
+ struct sigaction sa_sigterm;
+ int sigterm_fd[2];
+ if (qemu_pipe(sigterm_fd) == -1) {
+ err(EXIT_FAILURE, "Error setting up communication pipe");
+ }
+
+ sigterm_wfd = sigterm_fd[1];
+ memset(&sa_sigterm, 0, sizeof(sa_sigterm));
+ sa_sigterm.sa_handler = termsig_handler;
+ sigaction(SIGTERM, &sa_sigterm, NULL);
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
@@ -273,8 +349,8 @@ int main(int argc, char **argv)
errx(EXIT_FAILURE, "Invalid partition %d", partition);
break;
case 'k':
- socket = optarg;
- if (socket[0] != '/')
+ sockpath = optarg;
+ if (sockpath[0] != '/')
errx(EXIT_FAILURE, "socket path must be absolute\n");
break;
case 'd':
@@ -332,130 +408,134 @@ int main(int argc, char **argv)
return 0;
}
- bdrv_init();
-
- bs = bdrv_new("hda");
-
- if ((ret = bdrv_open(bs, argv[optind], flags, NULL)) < 0) {
- errno = -ret;
- err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
- }
-
- fd_size = bs->total_sectors * 512;
-
- if (partition != -1 &&
- find_partition(bs, partition, &dev_offset, &fd_size))
- err(EXIT_FAILURE, "Could not find partition %d", partition);
-
- if (device) {
+ if (device && !verbose) {
+ int stderr_fd[2];
pid_t pid;
- int sock;
+ int ret;
- /* want to fail before daemonizing */
- if (access(device, R_OK|W_OK) == -1) {
- err(EXIT_FAILURE, "Could not access '%s'", device);
+ if (qemu_pipe(stderr_fd) == -1) {
+ err(EXIT_FAILURE, "Error setting up communication pipe");
}
- if (!verbose) {
- /* detach client and server */
- if (qemu_daemon(0, 0) == -1) {
+ /* Now daemonize, but keep a communication channel open to
+ * print errors and exit with the proper status code.
+ */
+ pid = fork();
+ if (pid == 0) {
+ close(stderr_fd[0]);
+ ret = qemu_daemon(0, 0);
+
+ /* Temporarily redirect stderr to the parent's pipe... */
+ dup2(stderr_fd[1], STDERR_FILENO);
+ if (ret == -1) {
err(EXIT_FAILURE, "Failed to daemonize");
}
- }
-
- if (socket == NULL) {
- snprintf(sockpath, sizeof(sockpath), SOCKET_PATH,
- basename(device));
- socket = sockpath;
- }
- pid = fork();
- if (pid < 0)
- return 1;
- if (pid != 0) {
- off_t size;
- size_t blocksize;
-
- ret = 0;
- bdrv_close(bs);
-
- do {
- sock = unix_socket_outgoing(socket);
- if (sock == -1) {
- if (errno != ENOENT && errno != ECONNREFUSED) {
- ret = 1;
- goto out;
- }
- sleep(1); /* wait children */
+ /* ... close the descriptor we inherited and go on. */
+ close(stderr_fd[1]);
+ } else {
+ bool errors = false;
+ char *buf;
+
+ /* In the parent. Print error messages from the child until
+ * it closes the pipe.
+ */
+ close(stderr_fd[1]);
+ buf = g_malloc(1024);
+ while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
+ errors = true;
+ ret = qemu_write_full(STDERR_FILENO, buf, ret);
+ if (ret == -1) {
+ exit(EXIT_FAILURE);
}
- } while (sock == -1);
-
- fd = open(device, O_RDWR);
- if (fd == -1) {
- ret = 1;
- goto out;
}
-
- ret = nbd_receive_negotiate(sock, NULL, &nbdflags,
- &size, &blocksize);
if (ret == -1) {
- ret = 1;
- goto out;
+ err(EXIT_FAILURE, "Cannot read from daemon");
}
- ret = nbd_init(fd, sock, nbdflags, size, blocksize);
- if (ret == -1) {
- ret = 1;
- goto out;
- }
+ /* Usually the daemon should not print any message.
+ * Exit with zero status in that case.
+ */
+ exit(errors);
+ }
+ }
- printf("NBD device %s is now connected to file %s\n",
- device, argv[optind]);
+ if (device) {
+ /* Open before spawning new threads. In the future, we may
+ * drop privileges after opening.
+ */
+ fd = open(device, O_RDWR);
+ if (fd == -1) {
+ err(EXIT_FAILURE, "Failed to open %s", device);
+ }
- /* update partition table */
+ if (sockpath == NULL) {
+ sockpath = g_malloc(128);
+ snprintf(sockpath, 128, SOCKET_PATH, basename(device));
+ }
+ }
- show_parts(device);
+ bdrv_init();
+ atexit(bdrv_close_all);
- ret = nbd_client(fd);
- if (ret) {
- ret = 1;
- }
- close(fd);
- out:
- kill(pid, SIGTERM);
- unlink(socket);
+ bs = bdrv_new("hda");
+ srcpath = argv[optind];
+ if ((ret = bdrv_open(bs, srcpath, flags, NULL)) < 0) {
+ errno = -ret;
+ err(EXIT_FAILURE, "Failed to bdrv_open '%s'", argv[optind]);
+ }
- return ret;
- }
- /* children */
+ fd_size = bs->total_sectors * 512;
+
+ if (partition != -1 &&
+ find_partition(bs, partition, &dev_offset, &fd_size)) {
+ err(EXIT_FAILURE, "Could not find partition %d", partition);
}
sharing_fds = g_malloc((shared + 1) * sizeof(int));
- if (socket) {
- sharing_fds[0] = unix_socket_incoming(socket);
+ if (sockpath) {
+ sharing_fds[0] = unix_socket_incoming(sockpath);
} else {
sharing_fds[0] = tcp_socket_incoming(bindto, port);
}
if (sharing_fds[0] == -1)
return 1;
+
+ if (device) {
+ int ret;
+
+ ret = pthread_create(&client_thread, NULL, nbd_client_thread, &fd);
+ if (ret != 0) {
+ errx(EXIT_FAILURE, "Failed to create client thread: %s",
+ strerror(ret));
+ }
+ } else {
+ /* Shut up GCC warnings. */
+ memset(&client_thread, 0, sizeof(client_thread));
+ }
+
max_fd = sharing_fds[0];
nb_fds++;
data = qemu_blockalign(bs, NBD_BUFFER_SIZE);
- if (data == NULL)
+ if (data == NULL) {
errx(EXIT_FAILURE, "Cannot allocate data buffer");
+ }
do {
-
FD_ZERO(&fds);
+ FD_SET(sigterm_fd[0], &fds);
for (i = 0; i < nb_fds; i++)
FD_SET(sharing_fds[i], &fds);
- ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
- if (ret == -1)
+ do {
+ ret = select(max_fd + 1, &fds, NULL, NULL, NULL);
+ } while (ret == -1 && errno == EINTR);
+ if (ret == -1 || FD_ISSET(sigterm_fd[0], &fds)) {
break;
+ }
if (FD_ISSET(sharing_fds[0], &fds))
ret--;
@@ -489,10 +569,16 @@ int main(int argc, char **argv)
qemu_vfree(data);
close(sharing_fds[0]);
- bdrv_close(bs);
g_free(sharing_fds);
- if (socket)
- unlink(socket);
+ if (sockpath) {
+ unlink(sockpath);
+ }
- return 0;
+ if (device) {
+ void *ret;
+ pthread_join(client_thread, &ret);
+ exit(ret != NULL);
+ } else {
+ exit(EXIT_SUCCESS);
+ }
}
diff --git a/qemu-sockets.c b/qemu-sockets.c
index 183a9cbbd2..61b2247077 100644
--- a/qemu-sockets.c
+++ b/qemu-sockets.c
@@ -572,6 +572,7 @@ int unix_connect_opts(QemuOpts *opts)
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
if (connect(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
fprintf(stderr, "connect(unix:%s): %s\n", path, strerror(errno));
+ close(sock);
return -1;
}
diff --git a/ui/keymaps.c b/ui/keymaps.c
index f54a11437b..f55a2aa464 100644
--- a/ui/keymaps.c
+++ b/ui/keymaps.c
@@ -92,15 +92,17 @@ static kbd_layout_t *parse_keyboard_layout(const name2keysym_t *table,
int len;
filename = qemu_find_file(QEMU_FILE_TYPE_KEYMAP, language);
-
- if (!k)
- k = g_malloc0(sizeof(kbd_layout_t));
- if (!(filename && (f = fopen(filename, "r")))) {
+ f = filename ? fopen(filename, "r") : NULL;
+ g_free(filename);
+ if (!f) {
fprintf(stderr,
"Could not read keymap file: '%s'\n", language);
return NULL;
}
- g_free(filename);
+
+ if (!k)
+ k = g_malloc0(sizeof(kbd_layout_t));
+
for(;;) {
if (fgets(line, 1024, f) == NULL)
break;
diff --git a/vl.c b/vl.c
index f169aac1f9..f5afed4c49 100644
--- a/vl.c
+++ b/vl.c
@@ -3089,6 +3089,11 @@ int main(int argc, char **argv, char **envp)
data_dir = CONFIG_QEMU_DATADIR;
}
+ if (machine == NULL) {
+ fprintf(stderr, "No machine found.\n");
+ exit(1);
+ }
+
/*
* Default to max_cpus = smp_cpus, in case the user doesn't
* specify a max_cpus value.
@@ -3226,6 +3231,11 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "could not initialize alarm timer\n");
exit(1);
}
+
+ if (icount_option && (kvm_enabled() || xen_enabled())) {
+ fprintf(stderr, "-icount is not allowed with kvm or xen\n");
+ exit(1);
+ }
configure_icount(icount_option);
if (net_init_clients() < 0) {