Compare commits
168 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
78260a5f08 | ||
|
b3dbb9546a | ||
|
272d28ecf2 | ||
|
6f12926142 | ||
|
d6111501c1 | ||
|
eba25057b9 | ||
|
e78bd5ab07 | ||
|
1643f2b232 | ||
|
1352672860 | ||
|
9e2fa418fb | ||
|
eecae14724 | ||
|
a6de8ed80e | ||
|
9c3a596a03 | ||
|
8294a64d7f | ||
|
1c4ad9d2b4 | ||
|
60b46aa2f3 | ||
|
f283edc482 | ||
|
dd86df756e | ||
|
422831fc81 | ||
|
306761537f | ||
|
7943df571a | ||
|
d501f8478a | ||
|
917cfc1f26 | ||
|
9b24d8e987 | ||
|
f4dfa67f04 | ||
|
6bcd1346bb | ||
|
dbfff6d776 | ||
|
c7b4a95202 | ||
|
c9b9f6824f | ||
|
e20e48a802 | ||
|
24f50d7ea5 | ||
|
7cd331617a | ||
|
cfb08fbafc | ||
|
9ecd394753 | ||
|
b84762e245 | ||
|
df02179189 | ||
|
b6fc8245e9 | ||
|
cb595887cc | ||
|
622b6057be | ||
|
9fda6ab1d9 | ||
|
b6c147622d | ||
|
12badfc238 | ||
|
2c02cbf6e9 | ||
|
8ab1bf120d | ||
|
aeb29b6459 | ||
|
f8687bab91 | ||
|
c48b0c80fc | ||
|
4accd107d0 | ||
|
a340046614 | ||
|
2a633c461e | ||
|
a6c5c84ae2 | ||
|
12c5674b84 | ||
|
0e47931b88 | ||
|
f34e73cd69 | ||
|
80a2ba3d3c | ||
|
b4f1a7ca72 | ||
|
fba0c40bb7 | ||
|
fd4567d9a6 | ||
|
d7f66b52de | ||
|
77a8f1a512 | ||
|
4636b9d146 | ||
|
5f2bf0fe55 | ||
|
a28853871d | ||
|
ace2e4dad7 | ||
|
180640ea07 | ||
|
a4f1a7589a | ||
|
ed54776643 | ||
|
c6961b7d38 | ||
|
ba1dffed63 | ||
|
95d5d75ede | ||
|
c2d8d311c1 | ||
|
8efacc43ae | ||
|
6c615ec57e | ||
|
3674838cd0 | ||
|
d5dd3498eb | ||
|
dc8764f061 | ||
|
226a48949c | ||
|
04b4e75f33 | ||
|
d9fcd2a1c8 | ||
|
432d29db0d | ||
|
c6fcc10ab3 | ||
|
8926817219 | ||
|
ce8c8b7bd8 | ||
|
d34b867d81 | ||
|
76ee152a86 | ||
|
f4f7d01a3a | ||
|
c82e5848e2 | ||
|
9cc31772bf | ||
|
981b1628b3 | ||
|
8592d5259a | ||
|
7a85d1cf1c | ||
|
caa3d6d37b | ||
|
82ac96a72b | ||
|
90ca64a970 | ||
|
fa170c148b | ||
|
c44bfe4637 | ||
|
99b5beba2f | ||
|
77f4c9a68a | ||
|
1ee518760a | ||
|
a2498f76b8 | ||
|
3f6297b922 | ||
|
b65ee4fa29 | ||
|
3804da9dbe | ||
|
8bd383b41a | ||
|
2ae4748f4c | ||
|
a31f053129 | ||
|
52ef651f56 | ||
|
0c9dfe460d | ||
|
c115cd6578 | ||
|
f3be016d03 | ||
|
8185bfc146 | ||
|
7a05995361 | ||
|
0466e458de | ||
|
bed38e425f | ||
|
94d1991445 | ||
|
d1d80055ba | ||
|
00b2ace509 | ||
|
22036a49dd | ||
|
7f1b17f297 | ||
|
56eb21e158 | ||
|
d5c5dacc70 | ||
|
029409e5a9 | ||
|
a6ba35b3be | ||
|
aed3d11df6 | ||
|
e2d87bff12 | ||
|
f29a56147b | ||
|
3ed2d9ee1f | ||
|
756557de64 | ||
|
c8262a4767 | ||
|
b5a8fe5e8a | ||
|
04120e3bb0 | ||
|
a7aae221b0 | ||
|
2e1201d09b | ||
|
b3d6ca770d | ||
|
b3def7f5ff | ||
|
ad37ad5b25 | ||
|
7e598de023 | ||
|
3145fcb605 | ||
|
2084a8e330 | ||
|
6c806637fa | ||
|
efcc7a2324 | ||
|
b21d677ee9 | ||
|
c6db23958b | ||
|
f6133def92 | ||
|
6e34360973 | ||
|
863a5d042f | ||
|
cc785c349d | ||
|
8655d2de0a | ||
|
dc5a137125 | ||
|
6405875cdd | ||
|
947995c09e | ||
|
f53f4da9c6 | ||
|
fa4478d5c8 | ||
|
4513eafe92 | ||
|
0ac9377d04 | ||
|
a275fa42fa | ||
|
3a389e7926 | ||
|
e023b2e244 | ||
|
93e9eb6808 | ||
|
a3ca163cb5 | ||
|
c68b039aa9 | ||
|
71df14fcbe | ||
|
63090dac3a | ||
|
469ef350e1 | ||
|
5f3777945d | ||
|
e86fe18ac9 | ||
|
31155b9b3c | ||
|
4c355d53c6 |
@@ -447,7 +447,7 @@ version 0.5.0:
|
||||
- multi-target build
|
||||
- fixed: no error code in hardware interrupts
|
||||
- fixed: pop ss, mov ss, x and sti disable hardware irqs for the next insn
|
||||
- correct single stepping thru string operations
|
||||
- correct single stepping through string operations
|
||||
- preliminary SPARC target support (Thomas M. Ogrisegg)
|
||||
- tun-fd option (Rusty Russell)
|
||||
- automatic IDE geometry detection
|
||||
|
16
Makefile
16
Makefile
@@ -281,11 +281,18 @@ ifdef CONFIG_VIRTFS
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
|
||||
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
|
||||
endif
|
||||
install-sysconfig:
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
|
||||
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
|
||||
|
||||
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig
|
||||
install-datadir:
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
|
||||
|
||||
install-confdir:
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_confdir)"
|
||||
|
||||
install-sysconfig: install-datadir install-confdir
|
||||
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/target-x86_64.conf "$(DESTDIR)$(qemu_confdir)"
|
||||
$(INSTALL_DATA) $(SRC_PATH)/sysconfigs/target/cpus-x86_64.conf "$(DESTDIR)$(qemu_datadir)"
|
||||
|
||||
install: all $(if $(BUILD_DOCS),install-doc) install-sysconfig install-datadir
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(bindir)"
|
||||
ifneq ($(TOOLS),)
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(TOOLS) "$(DESTDIR)$(bindir)"
|
||||
@@ -295,7 +302,6 @@ ifneq ($(HELPERS-y),)
|
||||
$(INSTALL_PROG) $(STRIP_OPT) $(HELPERS-y) "$(DESTDIR)$(libexecdir)"
|
||||
endif
|
||||
ifneq ($(BLOBS),)
|
||||
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
|
||||
set -e; for x in $(BLOBS); do \
|
||||
$(INSTALL_DATA) $(SRC_PATH)/pc-bios/$$x "$(DESTDIR)$(qemu_datadir)"; \
|
||||
done
|
||||
|
36
arch_init.c
36
arch_init.c
@@ -54,7 +54,6 @@ int graphic_height = 600;
|
||||
int graphic_depth = 15;
|
||||
#endif
|
||||
|
||||
const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf";
|
||||
|
||||
#if defined(TARGET_ALPHA)
|
||||
#define QEMU_ARCH QEMU_ARCH_ALPHA
|
||||
@@ -101,6 +100,10 @@ const uint32_t arch_type = QEMU_ARCH;
|
||||
#define VECTYPE vector unsigned char
|
||||
#define SPLAT(p) vec_splat(vec_ld(0, p), 0)
|
||||
#define ALL_EQ(v1, v2) vec_all_eq(v1, v2)
|
||||
/* altivec.h may redefine the bool macro as vector type.
|
||||
* Reset it to POSIX semantics. */
|
||||
#undef bool
|
||||
#define bool _Bool
|
||||
#elif defined __SSE2__
|
||||
#include <emmintrin.h>
|
||||
#define VECTYPE __m128i
|
||||
@@ -112,6 +115,37 @@ const uint32_t arch_type = QEMU_ARCH;
|
||||
#define ALL_EQ(v1, v2) ((v1) == (v2))
|
||||
#endif
|
||||
|
||||
|
||||
static struct defconfig_file {
|
||||
const char *filename;
|
||||
/* Indicates it is an user config file (disabled by -no-user-config) */
|
||||
bool userconfig;
|
||||
} default_config_files[] = {
|
||||
{ CONFIG_QEMU_DATADIR "/cpus-" TARGET_ARCH ".conf", false },
|
||||
{ CONFIG_QEMU_CONFDIR "/qemu.conf", true },
|
||||
{ CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf", true },
|
||||
{ NULL }, /* end of list */
|
||||
};
|
||||
|
||||
|
||||
int qemu_read_default_config_files(bool userconfig)
|
||||
{
|
||||
int ret;
|
||||
struct defconfig_file *f;
|
||||
|
||||
for (f = default_config_files; f->filename; f++) {
|
||||
if (!userconfig && f->userconfig) {
|
||||
continue;
|
||||
}
|
||||
ret = qemu_read_config_file(f->filename);
|
||||
if (ret < 0 && ret != -ENOENT) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_dup_page(uint8_t *page)
|
||||
{
|
||||
VECTYPE *p = (VECTYPE *)page;
|
||||
|
@@ -1,8 +1,6 @@
|
||||
#ifndef QEMU_ARCH_INIT_H
|
||||
#define QEMU_ARCH_INIT_H
|
||||
|
||||
extern const char arch_config_name[];
|
||||
|
||||
enum {
|
||||
QEMU_ARCH_ALL = -1,
|
||||
QEMU_ARCH_ALPHA = 1,
|
||||
|
@@ -1775,10 +1775,12 @@ static void audio_atexit (void)
|
||||
HWVoiceOut *hwo = NULL;
|
||||
HWVoiceIn *hwi = NULL;
|
||||
|
||||
while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) {
|
||||
while ((hwo = audio_pcm_hw_find_any_out (hwo))) {
|
||||
SWVoiceCap *sc;
|
||||
|
||||
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
|
||||
if (hwo->enabled) {
|
||||
hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE);
|
||||
}
|
||||
hwo->pcm_ops->fini_out (hwo);
|
||||
|
||||
for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) {
|
||||
@@ -1791,8 +1793,10 @@ static void audio_atexit (void)
|
||||
}
|
||||
}
|
||||
|
||||
while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) {
|
||||
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
||||
while ((hwi = audio_pcm_hw_find_any_in (hwi))) {
|
||||
if (hwi->enabled) {
|
||||
hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE);
|
||||
}
|
||||
hwi->pcm_ops->fini_in (hwi);
|
||||
}
|
||||
|
||||
|
@@ -33,7 +33,8 @@
|
||||
#define ENDIAN_CONVERT(v) (v)
|
||||
|
||||
/* Signed 8 bit */
|
||||
#define IN_T int8_t
|
||||
#define BSIZE 8
|
||||
#define ITYPE int
|
||||
#define IN_MIN SCHAR_MIN
|
||||
#define IN_MAX SCHAR_MAX
|
||||
#define SIGNED
|
||||
@@ -42,25 +43,29 @@
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 8 bit */
|
||||
#define IN_T uint8_t
|
||||
#define BSIZE 8
|
||||
#define ITYPE uint
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX UCHAR_MAX
|
||||
#define SHIFT 8
|
||||
#include "mixeng_template.h"
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
#undef ENDIAN_CONVERT
|
||||
#undef ENDIAN_CONVERSION
|
||||
|
||||
/* Signed 16 bit */
|
||||
#define IN_T int16_t
|
||||
#define BSIZE 16
|
||||
#define ITYPE int
|
||||
#define IN_MIN SHRT_MIN
|
||||
#define IN_MAX SHRT_MAX
|
||||
#define SIGNED
|
||||
@@ -78,11 +83,13 @@
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 16 bit */
|
||||
#define IN_T uint16_t
|
||||
#define BSIZE 16
|
||||
#define ITYPE uint
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX USHRT_MAX
|
||||
#define SHIFT 16
|
||||
@@ -98,11 +105,13 @@
|
||||
#undef ENDIAN_CONVERSION
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Signed 32 bit */
|
||||
#define IN_T int32_t
|
||||
#define BSIZE 32
|
||||
#define ITYPE int
|
||||
#define IN_MIN INT32_MIN
|
||||
#define IN_MAX INT32_MAX
|
||||
#define SIGNED
|
||||
@@ -120,11 +129,13 @@
|
||||
#undef SIGNED
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
/* Unsigned 32 bit */
|
||||
#define IN_T uint32_t
|
||||
#define BSIZE 32
|
||||
#define ITYPE uint
|
||||
#define IN_MIN 0
|
||||
#define IN_MAX UINT32_MAX
|
||||
#define SHIFT 32
|
||||
@@ -140,7 +151,8 @@
|
||||
#undef ENDIAN_CONVERSION
|
||||
#undef IN_MAX
|
||||
#undef IN_MIN
|
||||
#undef IN_T
|
||||
#undef BSIZE
|
||||
#undef ITYPE
|
||||
#undef SHIFT
|
||||
|
||||
t_sample *mixeng_conv[2][2][2][3] = {
|
||||
|
@@ -31,7 +31,8 @@
|
||||
#define HALF (IN_MAX >> 1)
|
||||
#endif
|
||||
|
||||
#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T))
|
||||
#define ET glue (ENDIAN_CONVERSION, glue (glue (glue (_, ITYPE), BSIZE), _t))
|
||||
#define IN_T glue (glue (ITYPE, BSIZE), _t)
|
||||
|
||||
#ifdef FLOAT_MIXENG
|
||||
static mixeng_real inline glue (conv_, ET) (IN_T v)
|
||||
@@ -150,3 +151,4 @@ static void glue (glue (clip_, ET), _from_mono)
|
||||
|
||||
#undef ET
|
||||
#undef HALF
|
||||
#undef IN_T
|
||||
|
213
block.c
213
block.c
@@ -198,33 +198,31 @@ static void bdrv_io_limits_intercept(BlockDriverState *bs,
|
||||
/* check if the path starts with "<protocol>:" */
|
||||
static int path_has_protocol(const char *path)
|
||||
{
|
||||
const char *p;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (is_windows_drive(path) ||
|
||||
is_windows_drive_prefix(path)) {
|
||||
return 0;
|
||||
}
|
||||
p = path + strcspn(path, ":/\\");
|
||||
#else
|
||||
p = path + strcspn(path, ":/");
|
||||
#endif
|
||||
|
||||
return strchr(path, ':') != NULL;
|
||||
return *p == ':';
|
||||
}
|
||||
|
||||
int path_is_absolute(const char *path)
|
||||
{
|
||||
const char *p;
|
||||
#ifdef _WIN32
|
||||
/* specific case for names like: "\\.\d:" */
|
||||
if (*path == '/' || *path == '\\')
|
||||
if (is_windows_drive(path) || is_windows_drive_prefix(path)) {
|
||||
return 1;
|
||||
#endif
|
||||
p = strchr(path, ':');
|
||||
if (p)
|
||||
p++;
|
||||
else
|
||||
p = path;
|
||||
#ifdef _WIN32
|
||||
return (*p == '/' || *p == '\\');
|
||||
}
|
||||
return (*path == '/' || *path == '\\');
|
||||
#else
|
||||
return (*p == '/');
|
||||
return (*path == '/');
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -272,6 +270,15 @@ void path_combine(char *dest, int dest_size,
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz)
|
||||
{
|
||||
if (bs->backing_file[0] == '\0' || path_has_protocol(bs->backing_file)) {
|
||||
pstrcpy(dest, sz, bs->backing_file);
|
||||
} else {
|
||||
path_combine(dest, sz, bs->filename, bs->backing_file);
|
||||
}
|
||||
}
|
||||
|
||||
void bdrv_register(BlockDriver *bdrv)
|
||||
{
|
||||
/* Block drivers without coroutine functions need emulation */
|
||||
@@ -402,28 +409,36 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
|
||||
return bdrv_create(drv, filename, options);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a uniquely-named empty temporary file.
|
||||
* Return 0 upon success, otherwise a negative errno value.
|
||||
*/
|
||||
int get_tmp_filename(char *filename, int size)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
void get_tmp_filename(char *filename, int size)
|
||||
{
|
||||
char temp_dir[MAX_PATH];
|
||||
|
||||
GetTempPath(MAX_PATH, temp_dir);
|
||||
GetTempFileName(temp_dir, "qem", 0, filename);
|
||||
}
|
||||
/* GetTempFileName requires that its output buffer (4th param)
|
||||
have length MAX_PATH or greater. */
|
||||
assert(size >= MAX_PATH);
|
||||
return (GetTempPath(MAX_PATH, temp_dir)
|
||||
&& GetTempFileName(temp_dir, "qem", 0, filename)
|
||||
? 0 : -GetLastError());
|
||||
#else
|
||||
void get_tmp_filename(char *filename, int size)
|
||||
{
|
||||
int fd;
|
||||
const char *tmpdir;
|
||||
/* XXX: race condition possible */
|
||||
tmpdir = getenv("TMPDIR");
|
||||
if (!tmpdir)
|
||||
tmpdir = "/tmp";
|
||||
snprintf(filename, size, "%s/vl.XXXXXX", tmpdir);
|
||||
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
|
||||
return -EOVERFLOW;
|
||||
}
|
||||
fd = mkstemp(filename);
|
||||
close(fd);
|
||||
}
|
||||
if (fd < 0 || close(fd)) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect host devices. By convention, /dev/cdrom[N] is always
|
||||
@@ -612,16 +627,11 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
||||
int ret, open_flags;
|
||||
|
||||
assert(drv != NULL);
|
||||
assert(bs->file == NULL);
|
||||
|
||||
trace_bdrv_open_common(bs, filename, flags, drv->format_name);
|
||||
|
||||
bs->file = NULL;
|
||||
bs->total_sectors = 0;
|
||||
bs->encrypted = 0;
|
||||
bs->valid_key = 0;
|
||||
bs->sg = 0;
|
||||
bs->open_flags = flags;
|
||||
bs->growable = 0;
|
||||
bs->buffer_alignment = 512;
|
||||
|
||||
assert(bs->copy_on_read == 0); /* bdrv_new() and bdrv_close() make it so */
|
||||
@@ -630,7 +640,6 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
||||
}
|
||||
|
||||
pstrcpy(bs->filename, sizeof(bs->filename), filename);
|
||||
bs->backing_file[0] = '\0';
|
||||
|
||||
if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) {
|
||||
return -ENOTSUP;
|
||||
@@ -752,7 +761,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||
|
||||
bdrv_delete(bs1);
|
||||
|
||||
get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename));
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Real path is meaningless for protocols */
|
||||
if (is_protocol)
|
||||
@@ -804,14 +816,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
||||
BlockDriver *back_drv = NULL;
|
||||
|
||||
bs->backing_hd = bdrv_new("");
|
||||
|
||||
if (path_has_protocol(bs->backing_file)) {
|
||||
pstrcpy(backing_filename, sizeof(backing_filename),
|
||||
bs->backing_file);
|
||||
} else {
|
||||
path_combine(backing_filename, sizeof(backing_filename),
|
||||
filename, bs->backing_file);
|
||||
}
|
||||
bdrv_get_full_backing_filename(bs, backing_filename,
|
||||
sizeof(backing_filename));
|
||||
|
||||
if (bs->backing_format[0] != '\0') {
|
||||
back_drv = bdrv_find_format(bs->backing_format);
|
||||
@@ -878,9 +884,17 @@ void bdrv_close(BlockDriverState *bs)
|
||||
bs->opaque = NULL;
|
||||
bs->drv = NULL;
|
||||
bs->copy_on_read = 0;
|
||||
bs->backing_file[0] = '\0';
|
||||
bs->backing_format[0] = '\0';
|
||||
bs->total_sectors = 0;
|
||||
bs->encrypted = 0;
|
||||
bs->valid_key = 0;
|
||||
bs->sg = 0;
|
||||
bs->growable = 0;
|
||||
|
||||
if (bs->file != NULL) {
|
||||
bdrv_close(bs->file);
|
||||
bdrv_delete(bs->file);
|
||||
bs->file = NULL;
|
||||
}
|
||||
|
||||
bdrv_dev_change_media_cb(bs, false);
|
||||
@@ -906,12 +920,31 @@ void bdrv_close_all(void)
|
||||
*
|
||||
* This function does not flush data to disk, use bdrv_flush_all() for that
|
||||
* after calling this function.
|
||||
*
|
||||
* Note that completion of an asynchronous I/O operation can trigger any
|
||||
* number of other I/O operations on other devices---for example a coroutine
|
||||
* can be arbitrarily complex and a constant flow of I/O can come until the
|
||||
* coroutine is complete. Because of this, it is not possible to have a
|
||||
* function to drain a single device's I/O queue.
|
||||
*/
|
||||
void bdrv_drain_all(void)
|
||||
{
|
||||
BlockDriverState *bs;
|
||||
bool busy;
|
||||
|
||||
qemu_aio_flush();
|
||||
do {
|
||||
busy = qemu_aio_wait();
|
||||
|
||||
/* FIXME: We do not have timer support here, so this is effectively
|
||||
* a busy wait.
|
||||
*/
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||
if (!qemu_co_queue_empty(&bs->throttled_reqs)) {
|
||||
qemu_co_queue_restart_all(&bs->throttled_reqs);
|
||||
busy = true;
|
||||
}
|
||||
}
|
||||
} while (busy);
|
||||
|
||||
/* If requests are still pending there is a bug somewhere */
|
||||
QTAILQ_FOREACH(bs, &bdrv_states, list) {
|
||||
@@ -930,6 +963,13 @@ void bdrv_make_anon(BlockDriverState *bs)
|
||||
bs->device_name[0] = '\0';
|
||||
}
|
||||
|
||||
static void bdrv_rebind(BlockDriverState *bs)
|
||||
{
|
||||
if (bs->drv && bs->drv->bdrv_rebind) {
|
||||
bs->drv->bdrv_rebind(bs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add new bs contents at the top of an image chain while the chain is
|
||||
* live, while keeping required fields on the top layer.
|
||||
@@ -951,6 +991,7 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
|
||||
tmp = *bs_new;
|
||||
|
||||
/* there are some fields that need to stay on the top layer: */
|
||||
tmp.open_flags = bs_top->open_flags;
|
||||
|
||||
/* dev info */
|
||||
tmp.dev_ops = bs_top->dev_ops;
|
||||
@@ -1018,6 +1059,9 @@ void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top)
|
||||
bs_new->slice_time = 0;
|
||||
bs_new->slice_start = 0;
|
||||
bs_new->slice_end = 0;
|
||||
|
||||
bdrv_rebind(bs_new);
|
||||
bdrv_rebind(bs_top);
|
||||
}
|
||||
|
||||
void bdrv_delete(BlockDriverState *bs)
|
||||
@@ -1030,9 +1074,6 @@ void bdrv_delete(BlockDriverState *bs)
|
||||
bdrv_make_anon(bs);
|
||||
|
||||
bdrv_close(bs);
|
||||
if (bs->file != NULL) {
|
||||
bdrv_delete(bs->file);
|
||||
}
|
||||
|
||||
assert(bs != bs_snapshots);
|
||||
g_free(bs);
|
||||
@@ -1440,12 +1481,24 @@ int bdrv_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt)
|
||||
{
|
||||
BlockDriver *drv = bs->drv;
|
||||
int ret;
|
||||
|
||||
/* Backing file format doesn't make sense without a backing file */
|
||||
if (backing_fmt && !backing_file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (drv->bdrv_change_backing_file != NULL) {
|
||||
return drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
|
||||
ret = drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
|
||||
} else {
|
||||
return -ENOTSUP;
|
||||
ret = -ENOTSUP;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
|
||||
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bdrv_check_byte_request(BlockDriverState *bs, int64_t offset,
|
||||
@@ -1553,6 +1606,8 @@ int bdrv_read(BlockDriverState *bs, int64_t sector_num,
|
||||
return bdrv_rw_co(bs, sector_num, buf, nb_sectors, false);
|
||||
}
|
||||
|
||||
#define BITS_PER_LONG (sizeof(unsigned long) * 8)
|
||||
|
||||
static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
|
||||
int nb_sectors, int dirty)
|
||||
{
|
||||
@@ -1563,8 +1618,8 @@ static void set_dirty_bitmap(BlockDriverState *bs, int64_t sector_num,
|
||||
end = (sector_num + nb_sectors - 1) / BDRV_SECTORS_PER_DIRTY_CHUNK;
|
||||
|
||||
for (; start <= end; start++) {
|
||||
idx = start / (sizeof(unsigned long) * 8);
|
||||
bit = start % (sizeof(unsigned long) * 8);
|
||||
idx = start / BITS_PER_LONG;
|
||||
bit = start % BITS_PER_LONG;
|
||||
val = bs->dirty_bitmap[idx];
|
||||
if (dirty) {
|
||||
if (!(val & (1UL << bit))) {
|
||||
@@ -3869,10 +3924,10 @@ void bdrv_set_dirty_tracking(BlockDriverState *bs, int enable)
|
||||
if (enable) {
|
||||
if (!bs->dirty_bitmap) {
|
||||
bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
|
||||
BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
|
||||
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
|
||||
BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG - 1;
|
||||
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * BITS_PER_LONG;
|
||||
|
||||
bs->dirty_bitmap = g_malloc0(bitmap_size);
|
||||
bs->dirty_bitmap = g_new0(unsigned long, bitmap_size);
|
||||
}
|
||||
} else {
|
||||
if (bs->dirty_bitmap) {
|
||||
@@ -4072,10 +4127,15 @@ int bdrv_img_create(const char *filename, const char *fmt,
|
||||
if (backing_file && backing_file->value.s) {
|
||||
uint64_t size;
|
||||
char buf[32];
|
||||
int back_flags;
|
||||
|
||||
/* backing files always opened read-only */
|
||||
back_flags =
|
||||
flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING);
|
||||
|
||||
bs = bdrv_new("");
|
||||
|
||||
ret = bdrv_open(bs, backing_file->value.s, flags, backing_drv);
|
||||
ret = bdrv_open(bs, backing_file->value.s, back_flags, backing_drv);
|
||||
if (ret < 0) {
|
||||
error_report("Could not open '%s'", backing_file->value.s);
|
||||
goto out;
|
||||
@@ -4139,6 +4199,7 @@ void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
|
||||
job->bs = bs;
|
||||
job->cb = cb;
|
||||
job->opaque = opaque;
|
||||
job->busy = true;
|
||||
bs->job = job;
|
||||
|
||||
/* Only set speed when necessary to avoid NotSupported error */
|
||||
@@ -4188,6 +4249,9 @@ void block_job_set_speed(BlockJob *job, int64_t speed, Error **errp)
|
||||
void block_job_cancel(BlockJob *job)
|
||||
{
|
||||
job->cancelled = true;
|
||||
if (job->co && !job->busy) {
|
||||
qemu_coroutine_enter(job->co, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
bool block_job_is_cancelled(BlockJob *job)
|
||||
@@ -4195,13 +4259,52 @@ bool block_job_is_cancelled(BlockJob *job)
|
||||
return job->cancelled;
|
||||
}
|
||||
|
||||
void block_job_cancel_sync(BlockJob *job)
|
||||
struct BlockCancelData {
|
||||
BlockJob *job;
|
||||
BlockDriverCompletionFunc *cb;
|
||||
void *opaque;
|
||||
bool cancelled;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void block_job_cancel_cb(void *opaque, int ret)
|
||||
{
|
||||
struct BlockCancelData *data = opaque;
|
||||
|
||||
data->cancelled = block_job_is_cancelled(data->job);
|
||||
data->ret = ret;
|
||||
data->cb(data->opaque, ret);
|
||||
}
|
||||
|
||||
int block_job_cancel_sync(BlockJob *job)
|
||||
{
|
||||
struct BlockCancelData data;
|
||||
BlockDriverState *bs = job->bs;
|
||||
|
||||
assert(bs->job == job);
|
||||
|
||||
/* Set up our own callback to store the result and chain to
|
||||
* the original callback.
|
||||
*/
|
||||
data.job = job;
|
||||
data.cb = job->cb;
|
||||
data.opaque = job->opaque;
|
||||
data.ret = -EINPROGRESS;
|
||||
job->cb = block_job_cancel_cb;
|
||||
job->opaque = &data;
|
||||
block_job_cancel(job);
|
||||
while (bs->job != NULL && bs->job->busy) {
|
||||
while (data.ret == -EINPROGRESS) {
|
||||
qemu_aio_wait();
|
||||
}
|
||||
return (data.cancelled && data.ret == 0) ? -ECANCELED : data.ret;
|
||||
}
|
||||
|
||||
void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns)
|
||||
{
|
||||
/* Check cancellation *before* setting busy = false, too! */
|
||||
if (!block_job_is_cancelled(job)) {
|
||||
job->busy = false;
|
||||
co_sleep_ns(clock, ns);
|
||||
job->busy = true;
|
||||
}
|
||||
}
|
||||
|
2
block.h
2
block.h
@@ -303,6 +303,8 @@ int bdrv_get_info(BlockDriverState *bs, BlockDriverInfo *bdi);
|
||||
const char *bdrv_get_encrypted_filename(BlockDriverState *bs);
|
||||
void bdrv_get_backing_filename(BlockDriverState *bs,
|
||||
char *filename, int filename_size);
|
||||
void bdrv_get_full_backing_filename(BlockDriverState *bs,
|
||||
char *dest, size_t sz);
|
||||
int bdrv_can_snapshot(BlockDriverState *bs);
|
||||
int bdrv_is_snapshot(BlockDriverState *bs);
|
||||
BlockDriverState *bdrv_snapshots(void);
|
||||
|
240
block/iscsi.c
240
block/iscsi.c
@@ -25,10 +25,12 @@
|
||||
#include "config-host.h"
|
||||
|
||||
#include <poll.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "qemu-common.h"
|
||||
#include "qemu-error.h"
|
||||
#include "block_int.h"
|
||||
#include "trace.h"
|
||||
#include "hw/scsi-defs.h"
|
||||
|
||||
#include <iscsi/iscsi.h>
|
||||
#include <iscsi/scsi-lowlevel.h>
|
||||
@@ -37,8 +39,10 @@
|
||||
typedef struct IscsiLun {
|
||||
struct iscsi_context *iscsi;
|
||||
int lun;
|
||||
enum scsi_inquiry_peripheral_device_type type;
|
||||
int block_size;
|
||||
unsigned long num_blocks;
|
||||
uint64_t num_blocks;
|
||||
int events;
|
||||
} IscsiLun;
|
||||
|
||||
typedef struct IscsiAIOCB {
|
||||
@@ -104,11 +108,27 @@ static void
|
||||
iscsi_set_events(IscsiLun *iscsilun)
|
||||
{
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
int ev;
|
||||
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi), iscsi_process_read,
|
||||
(iscsi_which_events(iscsi) & POLLOUT)
|
||||
? iscsi_process_write : NULL,
|
||||
iscsi_process_flush, iscsilun);
|
||||
/* We always register a read handler. */
|
||||
ev = POLLIN;
|
||||
ev |= iscsi_which_events(iscsi);
|
||||
if (ev != iscsilun->events) {
|
||||
qemu_aio_set_fd_handler(iscsi_get_fd(iscsi),
|
||||
iscsi_process_read,
|
||||
(ev & POLLOUT) ? iscsi_process_write : NULL,
|
||||
iscsi_process_flush,
|
||||
iscsilun);
|
||||
|
||||
}
|
||||
|
||||
/* If we just added an event, the callback might be delayed
|
||||
* unless we call qemu_notify_event().
|
||||
*/
|
||||
if (ev & ~iscsilun->events) {
|
||||
qemu_notify_event();
|
||||
}
|
||||
iscsilun->events = ev;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -161,12 +181,12 @@ iscsi_readv_writev_bh_cb(void *p)
|
||||
|
||||
|
||||
static void
|
||||
iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi_aio_write16_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
IscsiAIOCB *acb = opaque;
|
||||
|
||||
trace_iscsi_aio_write10_cb(iscsi, status, acb, acb->canceled);
|
||||
trace_iscsi_aio_write16_cb(iscsi, status, acb, acb->canceled);
|
||||
|
||||
g_free(acb->buf);
|
||||
|
||||
@@ -179,7 +199,7 @@ iscsi_aio_write10_cb(struct iscsi_context *iscsi, int status,
|
||||
|
||||
acb->status = 0;
|
||||
if (status < 0) {
|
||||
error_report("Failed to write10 data to iSCSI lun. %s",
|
||||
error_report("Failed to write16 data to iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
acb->status = -EIO;
|
||||
}
|
||||
@@ -204,12 +224,9 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
IscsiAIOCB *acb;
|
||||
size_t size;
|
||||
int fua = 0;
|
||||
|
||||
/* set FUA on writes when cache mode is write through */
|
||||
if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
|
||||
fua = 1;
|
||||
}
|
||||
uint32_t num_sectors;
|
||||
uint64_t lba;
|
||||
struct iscsi_data data;
|
||||
|
||||
acb = qemu_aio_get(&iscsi_aio_pool, bs, cb, opaque);
|
||||
trace_iscsi_aio_writev(iscsi, sector_num, nb_sectors, opaque, acb);
|
||||
@@ -219,18 +236,44 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
acb->canceled = 0;
|
||||
|
||||
/* XXX we should pass the iovec to write10 to avoid the extra copy */
|
||||
/* XXX we should pass the iovec to write16 to avoid the extra copy */
|
||||
/* this will allow us to get rid of 'buf' completely */
|
||||
size = nb_sectors * BDRV_SECTOR_SIZE;
|
||||
acb->buf = g_malloc(size);
|
||||
qemu_iovec_to_buffer(acb->qiov, acb->buf);
|
||||
acb->task = iscsi_write10_task(iscsi, iscsilun->lun, acb->buf, size,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
fua, 0, iscsilun->block_size,
|
||||
iscsi_aio_write10_cb, acb);
|
||||
|
||||
|
||||
acb->task = malloc(sizeof(struct scsi_task));
|
||||
if (acb->task == NULL) {
|
||||
error_report("iSCSI: Failed to send write10 command. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
error_report("iSCSI: Failed to allocate task for scsi WRITE16 "
|
||||
"command. %s", iscsi_get_error(iscsi));
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||
|
||||
acb->task->xfer_dir = SCSI_XFER_WRITE;
|
||||
acb->task->cdb_size = 16;
|
||||
acb->task->cdb[0] = 0x8a;
|
||||
if (!(bs->open_flags & BDRV_O_CACHE_WB)) {
|
||||
/* set FUA on writes when cache mode is write through */
|
||||
acb->task->cdb[1] |= 0x04;
|
||||
}
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
|
||||
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
|
||||
num_sectors = size / iscsilun->block_size;
|
||||
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
||||
acb->task->expxferlen = size;
|
||||
|
||||
data.data = acb->buf;
|
||||
data.size = size;
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||
iscsi_aio_write16_cb,
|
||||
&data,
|
||||
acb) != 0) {
|
||||
scsi_free_scsi_task(acb->task);
|
||||
g_free(acb->buf);
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
@@ -242,12 +285,12 @@ iscsi_aio_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
|
||||
iscsi_aio_read16_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
IscsiAIOCB *acb = opaque;
|
||||
|
||||
trace_iscsi_aio_read10_cb(iscsi, status, acb, acb->canceled);
|
||||
trace_iscsi_aio_read16_cb(iscsi, status, acb, acb->canceled);
|
||||
|
||||
if (acb->canceled != 0) {
|
||||
qemu_aio_release(acb);
|
||||
@@ -258,7 +301,7 @@ iscsi_aio_read10_cb(struct iscsi_context *iscsi, int status,
|
||||
|
||||
acb->status = 0;
|
||||
if (status != 0) {
|
||||
error_report("Failed to read10 data from iSCSI lun. %s",
|
||||
error_report("Failed to read16 data from iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
acb->status = -EIO;
|
||||
}
|
||||
@@ -277,8 +320,10 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
IscsiLun *iscsilun = bs->opaque;
|
||||
struct iscsi_context *iscsi = iscsilun->iscsi;
|
||||
IscsiAIOCB *acb;
|
||||
size_t qemu_read_size, lun_read_size;
|
||||
size_t qemu_read_size;
|
||||
int i;
|
||||
uint64_t lba;
|
||||
uint32_t num_sectors;
|
||||
|
||||
qemu_read_size = BDRV_SECTOR_SIZE * (size_t)nb_sectors;
|
||||
|
||||
@@ -303,16 +348,44 @@ iscsi_aio_readv(BlockDriverState *bs, int64_t sector_num,
|
||||
acb->read_offset = bdrv_offset % iscsilun->block_size;
|
||||
}
|
||||
|
||||
lun_read_size = (qemu_read_size + iscsilun->block_size
|
||||
+ acb->read_offset - 1)
|
||||
/ iscsilun->block_size * iscsilun->block_size;
|
||||
acb->task = iscsi_read10_task(iscsi, iscsilun->lun,
|
||||
sector_qemu2lun(sector_num, iscsilun),
|
||||
lun_read_size, iscsilun->block_size,
|
||||
iscsi_aio_read10_cb, acb);
|
||||
num_sectors = (qemu_read_size + iscsilun->block_size
|
||||
+ acb->read_offset - 1)
|
||||
/ iscsilun->block_size;
|
||||
|
||||
acb->task = malloc(sizeof(struct scsi_task));
|
||||
if (acb->task == NULL) {
|
||||
error_report("iSCSI: Failed to send read10 command. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
error_report("iSCSI: Failed to allocate task for scsi READ16 "
|
||||
"command. %s", iscsi_get_error(iscsi));
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
memset(acb->task, 0, sizeof(struct scsi_task));
|
||||
|
||||
acb->task->xfer_dir = SCSI_XFER_READ;
|
||||
lba = sector_qemu2lun(sector_num, iscsilun);
|
||||
acb->task->expxferlen = qemu_read_size;
|
||||
|
||||
switch (iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
acb->task->cdb_size = 16;
|
||||
acb->task->cdb[0] = 0x88;
|
||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba >> 32);
|
||||
*(uint32_t *)&acb->task->cdb[6] = htonl(lba & 0xffffffff);
|
||||
*(uint32_t *)&acb->task->cdb[10] = htonl(num_sectors);
|
||||
break;
|
||||
default:
|
||||
acb->task->cdb_size = 10;
|
||||
acb->task->cdb[0] = 0x28;
|
||||
*(uint32_t *)&acb->task->cdb[2] = htonl(lba);
|
||||
*(uint16_t *)&acb->task->cdb[7] = htons(num_sectors);
|
||||
break;
|
||||
}
|
||||
|
||||
if (iscsi_scsi_command_async(iscsi, iscsilun->lun, acb->task,
|
||||
iscsi_aio_read16_cb,
|
||||
NULL,
|
||||
acb) != 0) {
|
||||
scsi_free_scsi_task(acb->task);
|
||||
qemu_aio_release(acb);
|
||||
return NULL;
|
||||
}
|
||||
@@ -490,6 +563,98 @@ iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
|
||||
void *command_data, void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_readcapacity10 *rc10;
|
||||
struct scsi_task *task = command_data;
|
||||
|
||||
if (status != 0) {
|
||||
error_report("iSCSI: Failed to read capacity of iSCSI lun. %s",
|
||||
iscsi_get_error(iscsi));
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
rc10 = scsi_datain_unmarshall(task);
|
||||
if (rc10 == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall readcapacity10 data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->block_size = rc10->block_size;
|
||||
itask->iscsilun->num_blocks = rc10->lba + 1;
|
||||
itask->bs->total_sectors = itask->iscsilun->num_blocks *
|
||||
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
|
||||
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_inquiry_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *opaque)
|
||||
{
|
||||
struct IscsiTask *itask = opaque;
|
||||
struct scsi_task *task = command_data;
|
||||
struct scsi_inquiry_standard *inq;
|
||||
|
||||
if (status != 0) {
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
inq = scsi_datain_unmarshall(task);
|
||||
if (inq == NULL) {
|
||||
error_report("iSCSI: Failed to unmarshall inquiry data.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
scsi_free_scsi_task(task);
|
||||
return;
|
||||
}
|
||||
|
||||
itask->iscsilun->type = inq->periperal_device_type;
|
||||
|
||||
scsi_free_scsi_task(task);
|
||||
|
||||
switch (itask->iscsilun->type) {
|
||||
case TYPE_DISK:
|
||||
task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
||||
iscsi_readcapacity16_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case TYPE_ROM:
|
||||
task = iscsi_readcapacity10_task(iscsi, itask->iscsilun->lun,
|
||||
0, 0,
|
||||
iscsi_readcapacity10_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
itask->status = 0;
|
||||
itask->complete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
void *opaque)
|
||||
@@ -503,10 +668,11 @@ iscsi_connect_cb(struct iscsi_context *iscsi, int status, void *command_data,
|
||||
return;
|
||||
}
|
||||
|
||||
task = iscsi_readcapacity16_task(iscsi, itask->iscsilun->lun,
|
||||
iscsi_readcapacity16_cb, opaque);
|
||||
task = iscsi_inquiry_task(iscsi, itask->iscsilun->lun,
|
||||
0, 0, 36,
|
||||
iscsi_inquiry_cb, opaque);
|
||||
if (task == NULL) {
|
||||
error_report("iSCSI: failed to send readcapacity16 command.");
|
||||
error_report("iSCSI: failed to send inquiry command.");
|
||||
itask->status = 1;
|
||||
itask->complete = 1;
|
||||
return;
|
||||
|
@@ -762,7 +762,6 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
uint64_t *host_offset, unsigned int *nb_clusters)
|
||||
{
|
||||
BDRVQcowState *s = bs->opaque;
|
||||
int64_t cluster_offset;
|
||||
QCowL2Meta *old_alloc;
|
||||
|
||||
trace_qcow2_do_alloc_clusters_offset(qemu_coroutine_self(), guest_offset,
|
||||
@@ -808,17 +807,21 @@ static int do_alloc_cluster_offset(BlockDriverState *bs, uint64_t guest_offset,
|
||||
/* Allocate new clusters */
|
||||
trace_qcow2_cluster_alloc_phys(qemu_coroutine_self());
|
||||
if (*host_offset == 0) {
|
||||
cluster_offset = qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size);
|
||||
int64_t cluster_offset =
|
||||
qcow2_alloc_clusters(bs, *nb_clusters * s->cluster_size);
|
||||
if (cluster_offset < 0) {
|
||||
return cluster_offset;
|
||||
}
|
||||
*host_offset = cluster_offset;
|
||||
return 0;
|
||||
} else {
|
||||
cluster_offset = *host_offset;
|
||||
*nb_clusters = qcow2_alloc_clusters_at(bs, cluster_offset, *nb_clusters);
|
||||
int ret = qcow2_alloc_clusters_at(bs, *host_offset, *nb_clusters);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
*nb_clusters = ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (cluster_offset < 0) {
|
||||
return cluster_offset;
|
||||
}
|
||||
*host_offset = cluster_offset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -300,7 +300,10 @@ static int qcow2_open(BlockDriverState *bs, int flags)
|
||||
|
||||
if (!bs->read_only && s->autoclear_features != 0) {
|
||||
s->autoclear_features = 0;
|
||||
qcow2_update_header(bs);
|
||||
ret = qcow2_update_header(bs);
|
||||
if (ret < 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check support for various header values */
|
||||
@@ -916,7 +919,8 @@ int qcow2_update_header(BlockDriverState *bs)
|
||||
ret = sizeof(*header);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
buf += ret;
|
||||
@@ -1011,11 +1015,6 @@ fail:
|
||||
static int qcow2_change_backing_file(BlockDriverState *bs,
|
||||
const char *backing_file, const char *backing_fmt)
|
||||
{
|
||||
/* Backing file format doesn't make sense without a backing file */
|
||||
if (backing_fmt && !backing_file) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pstrcpy(bs->backing_file, sizeof(bs->backing_file), backing_file ?: "");
|
||||
pstrcpy(bs->backing_format, sizeof(bs->backing_format), backing_fmt ?: "");
|
||||
|
||||
|
@@ -367,6 +367,12 @@ static void qed_cancel_need_check_timer(BDRVQEDState *s)
|
||||
qemu_del_timer(s->need_check_timer);
|
||||
}
|
||||
|
||||
static void bdrv_qed_rebind(BlockDriverState *bs)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
s->bs = bs;
|
||||
}
|
||||
|
||||
static int bdrv_qed_open(BlockDriverState *bs, int flags)
|
||||
{
|
||||
BDRVQEDState *s = bs->opaque;
|
||||
@@ -1550,6 +1556,7 @@ static BlockDriver bdrv_qed = {
|
||||
.create_options = qed_create_options,
|
||||
|
||||
.bdrv_probe = bdrv_qed_probe,
|
||||
.bdrv_rebind = bdrv_qed_rebind,
|
||||
.bdrv_open = bdrv_qed_open,
|
||||
.bdrv_close = bdrv_qed_close,
|
||||
.bdrv_create = bdrv_qed_create,
|
||||
|
113
block/sheepdog.c
113
block/sheepdog.c
@@ -468,7 +468,7 @@ static int connect_to_sdog(const char *addr, const char *port)
|
||||
if (ret) {
|
||||
error_report("unable to get address info %s, %s",
|
||||
addr, strerror(errno));
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
for (res = res0; res; res = res->ai_next) {
|
||||
@@ -495,7 +495,7 @@ static int connect_to_sdog(const char *addr, const char *port)
|
||||
dprintf("connected to %s:%s\n", addr, port);
|
||||
goto success;
|
||||
}
|
||||
fd = -1;
|
||||
fd = -errno;
|
||||
error_report("failed connect to %s:%s", addr, port);
|
||||
success:
|
||||
freeaddrinfo(res0);
|
||||
@@ -510,12 +510,13 @@ static int send_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_send_full(sockfd, hdr, sizeof(*hdr), 0);
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
return ret;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ret = qemu_send_full(sockfd, data, *wlen, 0);
|
||||
if (ret < *wlen) {
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -553,6 +554,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_recv_full(sockfd, hdr, sizeof(*hdr), 0);
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to get a rsp, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -564,6 +566,7 @@ static int do_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_recv_full(sockfd, data, *rlen, 0);
|
||||
if (ret < *rlen) {
|
||||
error_report("failed to get the data, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -587,6 +590,7 @@ static int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_co_recv(sockfd, hdr, sizeof(*hdr));
|
||||
if (ret < sizeof(*hdr)) {
|
||||
error_report("failed to get a rsp, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -598,6 +602,7 @@ static int do_co_req(int sockfd, SheepdogReq *hdr, void *data,
|
||||
ret = qemu_co_recv(sockfd, data, *rlen);
|
||||
if (ret < *rlen) {
|
||||
error_report("failed to get the data, %s", strerror(errno));
|
||||
ret = -errno;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
@@ -787,7 +792,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("%s", strerror(errno));
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
socket_set_nonblock(fd);
|
||||
@@ -796,7 +801,7 @@ static int get_sheep_fd(BDRVSheepdogState *s)
|
||||
if (ret) {
|
||||
error_report("%s", strerror(errno));
|
||||
closesocket(fd);
|
||||
return -1;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
qemu_aio_set_fd_handler(fd, co_read_response, NULL, aio_flush_request, s);
|
||||
@@ -883,7 +888,7 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
return fd;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@@ -904,14 +909,17 @@ static int find_vdi_name(BDRVSheepdogState *s, char *filename, uint32_t snapid,
|
||||
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
error_report("cannot get vdi info, %s, %s %d %s",
|
||||
sd_strerror(rsp->result), filename, snapid, tag);
|
||||
ret = -1;
|
||||
if (rsp->result == SD_RES_NO_VDI) {
|
||||
ret = -ENOENT;
|
||||
} else {
|
||||
ret = -EIO;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
*vid = rsp->vdi_id;
|
||||
@@ -980,7 +988,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
if (ret < 0) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
error_report("failed to send a req, %s", strerror(errno));
|
||||
return -EIO;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (wlen) {
|
||||
@@ -988,7 +996,7 @@ static int coroutine_fn add_aio_request(BDRVSheepdogState *s, AIOReq *aio_req,
|
||||
if (ret < 0) {
|
||||
qemu_co_mutex_unlock(&s->lock);
|
||||
error_report("failed to send a data, %s", strerror(errno));
|
||||
return -EIO;
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1038,7 +1046,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
|
||||
ret = do_req(fd, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
|
||||
if (ret) {
|
||||
error_report("failed to send a request to the sheep");
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
switch (rsp->result) {
|
||||
@@ -1046,7 +1054,7 @@ static int read_write_object(int fd, char *buf, uint64_t oid, int copies,
|
||||
return 0;
|
||||
default:
|
||||
error_report("%s", sd_strerror(rsp->result));
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1082,10 +1090,12 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
memset(tag, 0, sizeof(tag));
|
||||
if (parse_vdiname(s, filename, vdi, &snapid, tag) < 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
s->fd = get_sheep_fd(s);
|
||||
if (s->fd < 0) {
|
||||
ret = s->fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1099,11 +1109,12 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
s->flush_fd = connect_to_sdog(s->addr, s->port);
|
||||
if (s->flush_fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = s->flush_fd;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (snapid) {
|
||||
if (snapid || tag[0] != '\0') {
|
||||
dprintf("%" PRIx32 " snapshot inode was open.\n", vid);
|
||||
s->is_snapshot = 1;
|
||||
}
|
||||
@@ -1111,6 +1122,7 @@ static int sd_open(BlockDriverState *bs, const char *filename, int flags)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1139,7 +1151,7 @@ out:
|
||||
closesocket(s->fd);
|
||||
}
|
||||
g_free(buf);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int do_sd_create(char *filename, int64_t vdi_size,
|
||||
@@ -1154,7 +1166,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
|
||||
|
||||
fd = connect_to_sdog(addr, port);
|
||||
if (fd < 0) {
|
||||
return -EIO;
|
||||
return fd;
|
||||
}
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@@ -1177,7 +1189,7 @@ static int do_sd_create(char *filename, int64_t vdi_size,
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
return -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rsp->result != SD_RES_SUCCESS) {
|
||||
@@ -1237,24 +1249,26 @@ out:
|
||||
|
||||
static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
uint32_t vid = 0, base_vid = 0;
|
||||
int64_t vdi_size = 0;
|
||||
char *backing_file = NULL;
|
||||
BDRVSheepdogState s;
|
||||
BDRVSheepdogState *s;
|
||||
char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
|
||||
uint32_t snapid;
|
||||
int prealloc = 0;
|
||||
const char *vdiname;
|
||||
|
||||
s = g_malloc0(sizeof(BDRVSheepdogState));
|
||||
|
||||
strstart(filename, "sheepdog:", &vdiname);
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
memset(vdi, 0, sizeof(vdi));
|
||||
memset(tag, 0, sizeof(tag));
|
||||
if (parse_vdiname(&s, vdiname, vdi, &snapid, tag) < 0) {
|
||||
if (parse_vdiname(s, vdiname, vdi, &snapid, tag) < 0) {
|
||||
error_report("invalid filename");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
while (options && options->name) {
|
||||
@@ -1270,7 +1284,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
} else {
|
||||
error_report("Invalid preallocation mode: '%s'",
|
||||
options->value.s);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
options++;
|
||||
@@ -1278,7 +1293,8 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
|
||||
if (vdi_size > SD_MAX_VDI_SIZE) {
|
||||
error_report("too big image size");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (backing_file) {
|
||||
@@ -1290,31 +1306,37 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
|
||||
drv = bdrv_find_protocol(backing_file);
|
||||
if (!drv || strcmp(drv->protocol_name, "sheepdog") != 0) {
|
||||
error_report("backing_file must be a sheepdog image");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = bdrv_file_open(&bs, backing_file, 0);
|
||||
if (ret < 0)
|
||||
return -EIO;
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
s = bs->opaque;
|
||||
|
||||
if (!is_snapshot(&s->inode)) {
|
||||
error_report("cannot clone from a non snapshot vdi");
|
||||
bdrv_delete(bs);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
base_vid = s->inode.vdi_id;
|
||||
bdrv_delete(bs);
|
||||
}
|
||||
|
||||
ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s.addr, s.port);
|
||||
ret = do_sd_create(vdi, vdi_size, base_vid, &vid, 0, s->addr, s->port);
|
||||
if (!prealloc || ret) {
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
return sd_prealloc(filename);
|
||||
ret = sd_prealloc(filename);
|
||||
out:
|
||||
g_free(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sd_close(BlockDriverState *bs)
|
||||
@@ -1379,7 +1401,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
return -EIO;
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* we don't need to update entire object */
|
||||
@@ -1391,10 +1413,9 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to update an inode.");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1464,6 +1485,7 @@ static int sd_create_branch(BDRVSheepdogState *s)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1606,8 +1628,9 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
|
||||
|
||||
if (bs->growable && sector_num + nb_sectors > bs->total_sectors) {
|
||||
/* TODO: shouldn't block here */
|
||||
if (sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE) < 0) {
|
||||
return -EIO;
|
||||
ret = sd_truncate(bs, (sector_num + nb_sectors) * SECTOR_SIZE);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
bs->total_sectors = sector_num + nb_sectors;
|
||||
}
|
||||
@@ -1724,7 +1747,7 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
/* refresh inode. */
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
ret = -EIO;
|
||||
ret = fd;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1732,7 +1755,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
s->inode.nr_copies, datalen, 0, 0, s->cache_enabled);
|
||||
if (ret < 0) {
|
||||
error_report("failed to write snapshot's inode.");
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1741,7 +1763,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
if (ret < 0) {
|
||||
error_report("failed to create inode for snapshot. %s",
|
||||
strerror(errno));
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1752,7 +1773,6 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to read new inode info. %s", strerror(errno));
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
@@ -1773,7 +1793,7 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
char *buf = NULL;
|
||||
uint32_t vid;
|
||||
uint32_t snapid = 0;
|
||||
int ret = -ENOENT, fd;
|
||||
int ret = 0, fd;
|
||||
|
||||
old_s = g_malloc(sizeof(BDRVSheepdogState));
|
||||
|
||||
@@ -1791,13 +1811,13 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
ret = find_vdi_name(s, vdi, snapid, tag, &vid, 1);
|
||||
if (ret) {
|
||||
error_report("Failed to find_vdi_name");
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1808,7 +1828,6 @@ static int sd_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
|
||||
closesocket(fd);
|
||||
|
||||
if (ret) {
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1861,6 +1880,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1888,6 +1908,7 @@ static int sd_snapshot_list(BlockDriverState *bs, QEMUSnapshotInfo **psn_tab)
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
error_report("failed to connect");
|
||||
ret = fd;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1925,6 +1946,10 @@ out:
|
||||
|
||||
g_free(vdi_inuse);
|
||||
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -1940,8 +1965,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
|
||||
fd = connect_to_sdog(s->addr, s->port);
|
||||
if (fd < 0) {
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
return fd;
|
||||
}
|
||||
|
||||
while (size) {
|
||||
@@ -1965,7 +1989,6 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
|
||||
|
||||
if (ret < 0) {
|
||||
error_report("failed to save vmstate %s", strerror(errno));
|
||||
ret = -EIO;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@@ -33,19 +33,19 @@ typedef struct {
|
||||
|
||||
static int64_t ratelimit_calculate_delay(RateLimit *limit, uint64_t n)
|
||||
{
|
||||
int64_t delay_ns = 0;
|
||||
int64_t now = qemu_get_clock_ns(rt_clock);
|
||||
|
||||
if (limit->next_slice_time < now) {
|
||||
limit->next_slice_time = now + SLICE_TIME;
|
||||
limit->dispatched = 0;
|
||||
}
|
||||
if (limit->dispatched + n > limit->slice_quota) {
|
||||
delay_ns = limit->next_slice_time - now;
|
||||
} else {
|
||||
if (limit->dispatched == 0 || limit->dispatched + n <= limit->slice_quota) {
|
||||
limit->dispatched += n;
|
||||
return 0;
|
||||
} else {
|
||||
limit->dispatched = n;
|
||||
return limit->next_slice_time - now;
|
||||
}
|
||||
return delay_ns;
|
||||
}
|
||||
|
||||
static void ratelimit_set_speed(RateLimit *limit, uint64_t speed)
|
||||
@@ -96,17 +96,6 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
|
||||
bdrv_delete(unused);
|
||||
}
|
||||
top->backing_hd = base;
|
||||
|
||||
pstrcpy(top->backing_file, sizeof(top->backing_file), "");
|
||||
pstrcpy(top->backing_format, sizeof(top->backing_format), "");
|
||||
if (base_id) {
|
||||
pstrcpy(top->backing_file, sizeof(top->backing_file), base_id);
|
||||
if (base->drv) {
|
||||
pstrcpy(top->backing_format, sizeof(top->backing_format),
|
||||
base->drv->format_name);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -141,14 +130,9 @@ static int coroutine_fn is_allocated_base(BlockDriverState *top,
|
||||
*/
|
||||
intermediate = top->backing_hd;
|
||||
|
||||
while (intermediate) {
|
||||
while (intermediate != base) {
|
||||
int pnum_inter;
|
||||
|
||||
/* reached base */
|
||||
if (intermediate == base) {
|
||||
*pnum = n;
|
||||
return 1;
|
||||
}
|
||||
ret = bdrv_co_is_allocated(intermediate, sector_num, nb_sectors,
|
||||
&pnum_inter);
|
||||
if (ret < 0) {
|
||||
@@ -171,6 +155,7 @@ static int coroutine_fn is_allocated_base(BlockDriverState *top,
|
||||
intermediate = intermediate->backing_hd;
|
||||
}
|
||||
|
||||
*pnum = n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -181,7 +166,7 @@ static void coroutine_fn stream_run(void *opaque)
|
||||
BlockDriverState *base = s->base;
|
||||
int64_t sector_num, end;
|
||||
int ret = 0;
|
||||
int n;
|
||||
int n = 0;
|
||||
void *buf;
|
||||
|
||||
s->common.len = bdrv_getlength(bs);
|
||||
@@ -203,30 +188,25 @@ static void coroutine_fn stream_run(void *opaque)
|
||||
}
|
||||
|
||||
for (sector_num = 0; sector_num < end; sector_num += n) {
|
||||
retry:
|
||||
uint64_t delay_ns = 0;
|
||||
|
||||
wait:
|
||||
/* Note that even when no rate limit is applied we need to yield
|
||||
* with no pending I/O here so that qemu_aio_flush() returns.
|
||||
*/
|
||||
block_job_sleep_ns(&s->common, rt_clock, delay_ns);
|
||||
if (block_job_is_cancelled(&s->common)) {
|
||||
break;
|
||||
}
|
||||
|
||||
s->common.busy = true;
|
||||
if (base) {
|
||||
ret = is_allocated_base(bs, base, sector_num,
|
||||
STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
|
||||
} else {
|
||||
ret = bdrv_co_is_allocated(bs, sector_num,
|
||||
STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE,
|
||||
&n);
|
||||
}
|
||||
ret = is_allocated_base(bs, base, sector_num,
|
||||
STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n);
|
||||
trace_stream_one_iteration(s, sector_num, n, ret);
|
||||
if (ret == 0) {
|
||||
if (s->common.speed) {
|
||||
uint64_t delay_ns = ratelimit_calculate_delay(&s->limit, n);
|
||||
delay_ns = ratelimit_calculate_delay(&s->limit, n);
|
||||
if (delay_ns > 0) {
|
||||
s->common.busy = false;
|
||||
co_sleep_ns(rt_clock, delay_ns);
|
||||
|
||||
/* Recheck cancellation and that sectors are unallocated */
|
||||
goto retry;
|
||||
goto wait;
|
||||
}
|
||||
}
|
||||
ret = stream_populate(bs, sector_num, n, buf);
|
||||
@@ -238,12 +218,6 @@ retry:
|
||||
|
||||
/* Publish progress */
|
||||
s->common.offset += n * BDRV_SECTOR_SIZE;
|
||||
|
||||
/* Note that even when no rate limit is applied we need to yield
|
||||
* with no pending I/O here so that qemu_aio_flush() returns.
|
||||
*/
|
||||
s->common.busy = false;
|
||||
co_sleep_ns(rt_clock, 0);
|
||||
}
|
||||
|
||||
if (!base) {
|
||||
@@ -251,11 +225,14 @@ retry:
|
||||
}
|
||||
|
||||
if (!block_job_is_cancelled(&s->common) && sector_num == end && ret == 0) {
|
||||
const char *base_id = NULL;
|
||||
const char *base_id = NULL, *base_fmt = NULL;
|
||||
if (base) {
|
||||
base_id = s->backing_file_id;
|
||||
if (base->drv) {
|
||||
base_fmt = base->drv->format_name;
|
||||
}
|
||||
}
|
||||
ret = bdrv_change_backing_file(bs, base_id, NULL);
|
||||
ret = bdrv_change_backing_file(bs, base_id, base_fmt);
|
||||
close_unused_images(bs, base, base_id);
|
||||
}
|
||||
|
||||
@@ -286,7 +263,6 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
StreamBlockJob *s;
|
||||
Coroutine *co;
|
||||
|
||||
s = block_job_create(&stream_job_type, bs, speed, cb, opaque, errp);
|
||||
if (!s) {
|
||||
@@ -298,7 +274,7 @@ void stream_start(BlockDriverState *bs, BlockDriverState *base,
|
||||
pstrcpy(s->backing_file_id, sizeof(s->backing_file_id), base_id);
|
||||
}
|
||||
|
||||
co = qemu_coroutine_create(stream_run);
|
||||
trace_stream_start(bs, base, s, co, opaque);
|
||||
qemu_coroutine_enter(co, s);
|
||||
s->common.co = qemu_coroutine_create(stream_run);
|
||||
trace_stream_start(bs, base, s, s->common.co, opaque);
|
||||
qemu_coroutine_enter(s->common.co, s);
|
||||
}
|
||||
|
@@ -982,6 +982,12 @@ static BDRVVVFATState *vvv = NULL;
|
||||
static int enable_write_target(BDRVVVFATState *s);
|
||||
static int is_consistent(BDRVVVFATState *s);
|
||||
|
||||
static void vvfat_rebind(BlockDriverState *bs)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
s->bs = bs;
|
||||
}
|
||||
|
||||
static int vvfat_open(BlockDriverState *bs, const char* dirname, int flags)
|
||||
{
|
||||
BDRVVVFATState *s = bs->opaque;
|
||||
@@ -2802,7 +2808,12 @@ static int enable_write_target(BDRVVVFATState *s)
|
||||
array_init(&(s->commits), sizeof(commit_t));
|
||||
|
||||
s->qcow_filename = g_malloc(1024);
|
||||
get_tmp_filename(s->qcow_filename, 1024);
|
||||
ret = get_tmp_filename(s->qcow_filename, 1024);
|
||||
if (ret < 0) {
|
||||
g_free(s->qcow_filename);
|
||||
s->qcow_filename = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
bdrv_qcow = bdrv_find_format("qcow");
|
||||
options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
|
||||
@@ -2855,6 +2866,7 @@ static BlockDriver bdrv_vvfat = {
|
||||
.format_name = "vvfat",
|
||||
.instance_size = sizeof(BDRVVVFATState),
|
||||
.bdrv_file_open = vvfat_open,
|
||||
.bdrv_rebind = vvfat_rebind,
|
||||
.bdrv_read = vvfat_co_read,
|
||||
.bdrv_write = vvfat_co_write,
|
||||
.bdrv_close = vvfat_close,
|
||||
|
36
block_int.h
36
block_int.h
@@ -94,21 +94,24 @@ struct BlockJob {
|
||||
/** The block device on which the job is operating. */
|
||||
BlockDriverState *bs;
|
||||
|
||||
/**
|
||||
* The coroutine that executes the job. If not NULL, it is
|
||||
* reentered when busy is false and the job is cancelled.
|
||||
*/
|
||||
Coroutine *co;
|
||||
|
||||
/**
|
||||
* Set to true if the job should cancel itself. The flag must
|
||||
* always be tested just before toggling the busy flag from false
|
||||
* to true. After a job has detected that the cancelled flag is
|
||||
* true, it should not anymore issue any I/O operation to the
|
||||
* block device.
|
||||
* to true. After a job has been cancelled, it should only yield
|
||||
* if #qemu_aio_wait will ("sooner or later") reenter the coroutine.
|
||||
*/
|
||||
bool cancelled;
|
||||
|
||||
/**
|
||||
* Set to false by the job while it is in a quiescent state, where
|
||||
* no I/O is pending and cancellation can be processed without
|
||||
* issuing new I/O. The busy flag must be set to false when the
|
||||
* job goes to sleep on any condition that is not detected by
|
||||
* #qemu_aio_wait, such as a timer.
|
||||
* no I/O is pending and the job has yielded on any condition
|
||||
* that is not detected by #qemu_aio_wait, such as a timer.
|
||||
*/
|
||||
bool busy;
|
||||
|
||||
@@ -140,6 +143,7 @@ struct BlockDriver {
|
||||
int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num,
|
||||
const uint8_t *buf, int nb_sectors);
|
||||
void (*bdrv_close)(BlockDriverState *bs);
|
||||
void (*bdrv_rebind)(BlockDriverState *bs);
|
||||
int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
|
||||
int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
|
||||
int (*bdrv_make_empty)(BlockDriverState *bs);
|
||||
@@ -331,7 +335,7 @@ struct BlockDriverState {
|
||||
BlockJob *job;
|
||||
};
|
||||
|
||||
void get_tmp_filename(char *filename, int size);
|
||||
int get_tmp_filename(char *filename, int size);
|
||||
|
||||
void bdrv_set_io_limits(BlockDriverState *bs,
|
||||
BlockIOLimit *io_limits);
|
||||
@@ -362,6 +366,17 @@ void *block_job_create(const BlockJobType *job_type, BlockDriverState *bs,
|
||||
int64_t speed, BlockDriverCompletionFunc *cb,
|
||||
void *opaque, Error **errp);
|
||||
|
||||
/**
|
||||
* block_job_sleep_ns:
|
||||
* @job: The job that calls the function.
|
||||
* @clock: The clock to sleep on.
|
||||
* @ns: How many nanoseconds to stop for.
|
||||
*
|
||||
* Put the job to sleep (assuming that it wasn't canceled) for @ns
|
||||
* nanoseconds. Canceling the job will interrupt the wait immediately.
|
||||
*/
|
||||
void block_job_sleep_ns(BlockJob *job, QEMUClock *clock, int64_t ns);
|
||||
|
||||
/**
|
||||
* block_job_complete:
|
||||
* @job: The job being completed.
|
||||
@@ -409,8 +424,11 @@ bool block_job_is_cancelled(BlockJob *job);
|
||||
* immediately after #block_job_cancel_sync. Users of block jobs
|
||||
* will usually protect the BlockDriverState objects with a reference
|
||||
* count, should this be a concern.
|
||||
*
|
||||
* Returns the return value from the job if the job actually completed
|
||||
* during the call, or -ECANCELED if it was canceled.
|
||||
*/
|
||||
void block_job_cancel_sync(BlockJob *job);
|
||||
int block_job_cancel_sync(BlockJob *job);
|
||||
|
||||
/**
|
||||
* stream_start:
|
||||
|
@@ -756,14 +756,17 @@ void qmp_transaction(BlockdevActionList *dev_list, Error **errp)
|
||||
goto delete_and_fail;
|
||||
}
|
||||
|
||||
if (!bdrv_is_inserted(states->old_bs)) {
|
||||
error_set(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
|
||||
goto delete_and_fail;
|
||||
}
|
||||
|
||||
if (bdrv_in_use(states->old_bs)) {
|
||||
error_set(errp, QERR_DEVICE_IN_USE, device);
|
||||
goto delete_and_fail;
|
||||
}
|
||||
|
||||
if (!bdrv_is_read_only(states->old_bs) &&
|
||||
bdrv_is_inserted(states->old_bs)) {
|
||||
|
||||
if (!bdrv_is_read_only(states->old_bs)) {
|
||||
if (bdrv_flush(states->old_bs)) {
|
||||
error_set(errp, QERR_IO_ERROR);
|
||||
goto delete_and_fail;
|
||||
|
40
cmd.c
40
cmd.c
@@ -418,31 +418,37 @@ cvtstr(
|
||||
char *str,
|
||||
size_t size)
|
||||
{
|
||||
const char *fmt;
|
||||
int precise;
|
||||
|
||||
precise = ((double)value * 1000 == (double)(int)value * 1000);
|
||||
char *trim;
|
||||
const char *suffix;
|
||||
|
||||
if (value >= EXABYTES(1)) {
|
||||
fmt = precise ? "%.f EiB" : "%.3f EiB";
|
||||
snprintf(str, size, fmt, TO_EXABYTES(value));
|
||||
suffix = " EiB";
|
||||
snprintf(str, size - 4, "%.3f", TO_EXABYTES(value));
|
||||
} else if (value >= PETABYTES(1)) {
|
||||
fmt = precise ? "%.f PiB" : "%.3f PiB";
|
||||
snprintf(str, size, fmt, TO_PETABYTES(value));
|
||||
suffix = " PiB";
|
||||
snprintf(str, size - 4, "%.3f", TO_PETABYTES(value));
|
||||
} else if (value >= TERABYTES(1)) {
|
||||
fmt = precise ? "%.f TiB" : "%.3f TiB";
|
||||
snprintf(str, size, fmt, TO_TERABYTES(value));
|
||||
suffix = " TiB";
|
||||
snprintf(str, size - 4, "%.3f", TO_TERABYTES(value));
|
||||
} else if (value >= GIGABYTES(1)) {
|
||||
fmt = precise ? "%.f GiB" : "%.3f GiB";
|
||||
snprintf(str, size, fmt, TO_GIGABYTES(value));
|
||||
suffix = " GiB";
|
||||
snprintf(str, size - 4, "%.3f", TO_GIGABYTES(value));
|
||||
} else if (value >= MEGABYTES(1)) {
|
||||
fmt = precise ? "%.f MiB" : "%.3f MiB";
|
||||
snprintf(str, size, fmt, TO_MEGABYTES(value));
|
||||
suffix = " MiB";
|
||||
snprintf(str, size - 4, "%.3f", TO_MEGABYTES(value));
|
||||
} else if (value >= KILOBYTES(1)) {
|
||||
fmt = precise ? "%.f KiB" : "%.3f KiB";
|
||||
snprintf(str, size, fmt, TO_KILOBYTES(value));
|
||||
suffix = " KiB";
|
||||
snprintf(str, size - 4, "%.3f", TO_KILOBYTES(value));
|
||||
} else {
|
||||
snprintf(str, size, "%f bytes", value);
|
||||
suffix = " bytes";
|
||||
snprintf(str, size - 6, "%f", value);
|
||||
}
|
||||
|
||||
trim = strstr(str, ".000");
|
||||
if (trim) {
|
||||
strcpy(trim, suffix);
|
||||
} else {
|
||||
strcat(str, suffix);
|
||||
}
|
||||
}
|
||||
|
||||
|
21
configure
vendored
21
configure
vendored
@@ -1006,7 +1006,7 @@ echo " --datadir=PATH install firmware in PATH$confsuffix"
|
||||
echo " --docdir=PATH install documentation in PATH$confsuffix"
|
||||
echo " --bindir=PATH install binaries in PATH"
|
||||
echo " --sysconfdir=PATH install config in PATH$confsuffix"
|
||||
echo " --with-confsuffix=SUFFIX suffix for Qemu data inside datadir and sysconfdir [$confsuffix]"
|
||||
echo " --with-confsuffix=SUFFIX suffix for QEMU data inside datadir and sysconfdir [$confsuffix]"
|
||||
echo " --enable-debug-tcg enable TCG debugging"
|
||||
echo " --disable-debug-tcg disable TCG debugging (default)"
|
||||
echo " --enable-debug enable common debug build options"
|
||||
@@ -2831,6 +2831,21 @@ if compile_prog "" "" ; then
|
||||
linux_magic_h=yes
|
||||
fi
|
||||
|
||||
########################################
|
||||
# check if environ is declared
|
||||
|
||||
has_environ=no
|
||||
cat > $TMPC << EOF
|
||||
#include <unistd.h>
|
||||
int main(void) {
|
||||
environ = environ;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
if compile_prog "" "" ; then
|
||||
has_environ=yes
|
||||
fi
|
||||
|
||||
##########################################
|
||||
# End of CC checks
|
||||
# After here, no more $cc or $ld runs
|
||||
@@ -3342,6 +3357,10 @@ if test "$linux_magic_h" = "yes" ; then
|
||||
echo "CONFIG_LINUX_MAGIC_H=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
if test "$has_environ" = "yes" ; then
|
||||
echo "CONFIG_HAS_ENVIRON=y" >> $config_host_mak
|
||||
fi
|
||||
|
||||
# USB host support
|
||||
case "$usb" in
|
||||
linux)
|
||||
|
@@ -226,7 +226,7 @@ static Coroutine *coroutine_new(void)
|
||||
* called.
|
||||
*/
|
||||
coTS->tr_called = 0;
|
||||
kill(getpid(), SIGUSR2);
|
||||
pthread_kill(pthread_self(), SIGUSR2);
|
||||
sigfillset(&sigs);
|
||||
sigdelset(&sigs, SIGUSR2);
|
||||
while (!coTS->tr_called) {
|
||||
@@ -257,7 +257,7 @@ static Coroutine *coroutine_new(void)
|
||||
/*
|
||||
* Now enter the trampoline again, but this time not as a signal
|
||||
* handler. Instead we jump into it directly. The functionally
|
||||
* redundant ping-pong pointer arithmentic is neccessary to avoid
|
||||
* redundant ping-pong pointer arithmetic is necessary to avoid
|
||||
* type-conversion warnings related to the `volatile' qualifier and
|
||||
* the fact that `jmp_buf' usually is an array type.
|
||||
*/
|
||||
|
4
cputlb.c
4
cputlb.c
@@ -272,10 +272,10 @@ void tlb_set_page(CPUArchState *env, target_ulong vaddr,
|
||||
} else {
|
||||
addend = 0;
|
||||
}
|
||||
iotlb = memory_region_section_get_iotlb(env, section, vaddr, paddr, prot,
|
||||
&address);
|
||||
|
||||
code_address = address;
|
||||
iotlb = memory_region_section_get_iotlb(env, section, vaddr, paddr, prot,
|
||||
&address);
|
||||
|
||||
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
env->iotlb[mmu_idx][index] = iotlb - vaddr;
|
||||
|
2
disas.c
2
disas.c
@@ -51,7 +51,7 @@ perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
|
||||
"Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
|
||||
}
|
||||
|
||||
/* This could be in a separate file, to save miniscule amounts of space
|
||||
/* This could be in a separate file, to save minuscule amounts of space
|
||||
in statically linked executables. */
|
||||
|
||||
/* Just print the address is hex. This is included for completeness even
|
||||
|
@@ -55,6 +55,21 @@ try ...
|
||||
... then use "bus=ehci.0" to assign your usb devices to that bus.
|
||||
|
||||
|
||||
xhci controller support
|
||||
-----------------------
|
||||
|
||||
There also is xhci host controller support available. It got alot
|
||||
less testing than ehci and there are a bunch of known limitations, so
|
||||
ehci may work better for you. On the other hand the xhci hardware
|
||||
design is much more virtualization-friendly, thus xhci emulation uses
|
||||
less ressources (especially cpu). If you wanna give xhci a try
|
||||
use this to add the host controller ...
|
||||
|
||||
qemu -device nec-usb-xhci,id=xhci
|
||||
|
||||
... then use "bus=xhci.0" when assigning usb devices.
|
||||
|
||||
|
||||
More USB tips & tricks
|
||||
======================
|
||||
|
||||
|
@@ -96,6 +96,8 @@ void QEMU_NORETURN cpu_loop_exit(CPUArchState *env1);
|
||||
int page_unprotect(target_ulong address, uintptr_t pc, void *puc);
|
||||
void tb_invalidate_phys_page_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access);
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
/* cputlb.c */
|
||||
void tlb_flush_page(CPUArchState *env, target_ulong addr);
|
||||
|
17
exec.c
17
exec.c
@@ -1075,6 +1075,23 @@ TranslationBlock *tb_gen_code(CPUArchState *env,
|
||||
return tb;
|
||||
}
|
||||
|
||||
/*
|
||||
* invalidate all TBs which intersect with the target physical pages
|
||||
* starting in range [start;end[. NOTE: start and end may refer to
|
||||
* different physical pages. 'is_cpu_write_access' should be true if called
|
||||
* from a real cpu write access: the virtual CPU will exit the current
|
||||
* TB if code is modified inside this TB.
|
||||
*/
|
||||
void tb_invalidate_phys_range(tb_page_addr_t start, tb_page_addr_t end,
|
||||
int is_cpu_write_access)
|
||||
{
|
||||
while (start < end) {
|
||||
tb_invalidate_phys_page_range(start, end, is_cpu_write_access);
|
||||
start &= TARGET_PAGE_MASK;
|
||||
start += TARGET_PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
/* invalidate all TBs which intersect with the target physical page
|
||||
starting in range [start;end[. NOTE: start and end must refer to
|
||||
the same physical page. 'is_cpu_write_access' should be true if called
|
||||
|
2
hmp.c
2
hmp.c
@@ -849,7 +849,7 @@ void hmp_block_job_set_speed(Monitor *mon, const QDict *qdict)
|
||||
{
|
||||
Error *error = NULL;
|
||||
const char *device = qdict_get_str(qdict, "device");
|
||||
int64_t value = qdict_get_int(qdict, "value");
|
||||
int64_t value = qdict_get_int(qdict, "speed");
|
||||
|
||||
qmp_block_job_set_speed(device, value, &error);
|
||||
|
||||
|
@@ -299,6 +299,7 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
|
||||
if (pc->no_hotplug) {
|
||||
slot_free = false;
|
||||
} else {
|
||||
object_unparent(OBJECT(dev));
|
||||
qdev_free(qdev);
|
||||
}
|
||||
}
|
||||
|
18
hw/apb_pci.c
18
hw/apb_pci.c
@@ -85,6 +85,8 @@ typedef struct APBState {
|
||||
unsigned int nr_resets;
|
||||
} APBState;
|
||||
|
||||
static void pci_apb_set_irq(void *opaque, int irq_num, int level);
|
||||
|
||||
static void apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
uint64_t val, unsigned size)
|
||||
{
|
||||
@@ -113,6 +115,16 @@ static void apb_config_writel (void *opaque, target_phys_addr_t addr,
|
||||
s->obio_irq_map[(addr & 0xff) >> 3] |= val & ~PBM_PCI_IMR_MASK;
|
||||
}
|
||||
break;
|
||||
case 0x1400 ... 0x143f: /* PCI interrupt clear */
|
||||
if (addr & 4) {
|
||||
pci_apb_set_irq(s, (addr & 0x3f) >> 3, 0);
|
||||
}
|
||||
break;
|
||||
case 0x1800 ... 0x1860: /* OBIO interrupt clear */
|
||||
if (addr & 4) {
|
||||
pci_apb_set_irq(s, 0x20 | ((addr & 0xff) >> 3), 0);
|
||||
}
|
||||
break;
|
||||
case 0x2000 ... 0x202f: /* PCI control */
|
||||
s->pci_control[(addr & 0x3f) >> 2] = val;
|
||||
break;
|
||||
@@ -404,6 +416,9 @@ static void pci_pbm_reset(DeviceState *d)
|
||||
for (i = 0; i < 8; i++) {
|
||||
s->pci_irq_map[i] &= PBM_PCI_IMR_MASK;
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
s->obio_irq_map[i] &= PBM_PCI_IMR_MASK;
|
||||
}
|
||||
|
||||
if (s->nr_resets++ == 0) {
|
||||
/* Power on reset */
|
||||
@@ -426,6 +441,9 @@ static int pci_pbm_init_device(SysBusDevice *dev)
|
||||
for (i = 0; i < 8; i++) {
|
||||
s->pci_irq_map[i] = (0x1f << 6) | (i << 2);
|
||||
}
|
||||
for (i = 0; i < 32; i++) {
|
||||
s->obio_irq_map[i] = ((0x1f << 6) | 0x20) + i;
|
||||
}
|
||||
s->pbm_irqs = qemu_allocate_irqs(pci_apb_set_irq, s, MAX_IVEC);
|
||||
|
||||
/* apb_config */
|
||||
|
11
hw/es1370.c
11
hw/es1370.c
@@ -410,7 +410,7 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl)
|
||||
|
||||
if ((old_fmt != new_fmt) || (old_freq != new_freq)) {
|
||||
d->shift = (new_fmt & 1) + (new_fmt >> 1);
|
||||
ldebug ("channel %d, freq = %d, nchannels %d, fmt %d, shift %d\n",
|
||||
ldebug ("channel %zu, freq = %d, nchannels %d, fmt %d, shift %d\n",
|
||||
i,
|
||||
new_freq,
|
||||
1 << (new_fmt & 1),
|
||||
@@ -578,7 +578,7 @@ IO_WRITE_PROTO (es1370_writel)
|
||||
d++;
|
||||
case ES1370_REG_DAC1_SCOUNT:
|
||||
d->scount = (val & 0xffff) | (d->scount & ~0xffff);
|
||||
ldebug ("chan %d CURR_SAMP_CT %d, SAMP_CT %d\n",
|
||||
ldebug ("chan %td CURR_SAMP_CT %d, SAMP_CT %d\n",
|
||||
d - &s->chan[0], val >> 16, (val & 0xffff));
|
||||
break;
|
||||
|
||||
@@ -588,7 +588,7 @@ IO_WRITE_PROTO (es1370_writel)
|
||||
d++;
|
||||
case ES1370_REG_DAC1_FRAMEADR:
|
||||
d->frame_addr = val;
|
||||
ldebug ("chan %d frame address %#x\n", d - &s->chan[0], val);
|
||||
ldebug ("chan %td frame address %#x\n", d - &s->chan[0], val);
|
||||
break;
|
||||
|
||||
case ES1370_REG_PHANTOM_FRAMECNT:
|
||||
@@ -605,7 +605,7 @@ IO_WRITE_PROTO (es1370_writel)
|
||||
case ES1370_REG_DAC1_FRAMECNT:
|
||||
d->frame_cnt = val;
|
||||
d->leftover = 0;
|
||||
ldebug ("chan %d frame count %d, buffer size %d\n",
|
||||
ldebug ("chan %td frame count %d, buffer size %d\n",
|
||||
d - &s->chan[0], val >> 16, val & 0xffff);
|
||||
break;
|
||||
|
||||
@@ -745,9 +745,10 @@ IO_READ_PROTO (es1370_readl)
|
||||
{
|
||||
uint32_t size = ((d->frame_cnt & 0xffff) + 1) << 2;
|
||||
uint32_t curr = ((d->frame_cnt >> 16) + 1) << 2;
|
||||
if (curr > size)
|
||||
if (curr > size) {
|
||||
dolog ("read framecnt curr %d, size %d %d\n", curr, size,
|
||||
curr > size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
|
14
hw/fdc.c
14
hw/fdc.c
@@ -179,12 +179,14 @@ static void fd_revalidate(FDrive *drv)
|
||||
FDriveRate rate;
|
||||
|
||||
FLOPPY_DPRINTF("revalidate\n");
|
||||
if (drv->bs != NULL && bdrv_is_inserted(drv->bs)) {
|
||||
if (drv->bs != NULL) {
|
||||
ro = bdrv_is_read_only(drv->bs);
|
||||
bdrv_get_floppy_geometry_hint(drv->bs, &nb_heads, &max_track,
|
||||
&last_sect, drv->drive, &drive, &rate);
|
||||
if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
|
||||
FLOPPY_DPRINTF("User defined disk (%d %d %d)",
|
||||
if (!bdrv_is_inserted(drv->bs)) {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
} else if (nb_heads != 0 && max_track != 0 && last_sect != 0) {
|
||||
FLOPPY_DPRINTF("User defined disk (%d %d %d)\n",
|
||||
nb_heads - 1, max_track, last_sect);
|
||||
} else {
|
||||
FLOPPY_DPRINTF("Floppy disk (%d h %d t %d s) %s\n", nb_heads,
|
||||
@@ -201,7 +203,7 @@ static void fd_revalidate(FDrive *drv)
|
||||
drv->drive = drive;
|
||||
drv->media_rate = rate;
|
||||
} else {
|
||||
FLOPPY_DPRINTF("No disk in drive\n");
|
||||
FLOPPY_DPRINTF("No drive connected\n");
|
||||
drv->last_sect = 0;
|
||||
drv->max_track = 0;
|
||||
drv->flags &= ~FDISK_DBL_SIDES;
|
||||
@@ -709,7 +711,7 @@ static void fdctrl_raise_irq(FDCtrl *fdctrl, uint8_t status0)
|
||||
FDrive *cur_drv;
|
||||
/* A seek clears the disk change line (if a disk is inserted) */
|
||||
cur_drv = get_cur_drv(fdctrl);
|
||||
if (cur_drv->max_track) {
|
||||
if (cur_drv->bs != NULL && bdrv_is_inserted(cur_drv->bs)) {
|
||||
cur_drv->media_changed = 0;
|
||||
}
|
||||
}
|
||||
@@ -1878,7 +1880,7 @@ static int fdctrl_connect_drives(FDCtrl *fdctrl)
|
||||
}
|
||||
|
||||
fd_init(drive);
|
||||
fd_revalidate(drive);
|
||||
fdctrl_change_cb(drive, 0);
|
||||
if (drive->bs) {
|
||||
bdrv_set_dev_ops(drive->bs, &fdctrl_block_ops, drive);
|
||||
}
|
||||
|
@@ -103,7 +103,7 @@ ssize_t read_targphys(const char *name,
|
||||
|
||||
/* return the size or -1 if error */
|
||||
int load_image_targphys(const char *filename,
|
||||
target_phys_addr_t addr, int max_sz)
|
||||
target_phys_addr_t addr, uint64_t max_sz)
|
||||
{
|
||||
int size;
|
||||
|
||||
|
@@ -4,7 +4,8 @@
|
||||
/* loader.c */
|
||||
int get_image_size(const char *filename);
|
||||
int load_image(const char *filename, uint8_t *addr); /* deprecated */
|
||||
int load_image_targphys(const char *filename, target_phys_addr_t, int max_sz);
|
||||
int load_image_targphys(const char *filename, target_phys_addr_t,
|
||||
uint64_t max_sz);
|
||||
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
||||
uint64_t *highaddr, int big_endian, int elf_machine,
|
||||
|
@@ -284,7 +284,6 @@ static void mips_fulong2e_init(ram_addr_t ram_size, const char *boot_device,
|
||||
exit(1);
|
||||
}
|
||||
|
||||
register_savevm(NULL, "cpu", 0, 3, cpu_save, cpu_load, env);
|
||||
qemu_register_reset(main_cpu_reset, env);
|
||||
|
||||
/* fulong 2e has 256M ram. */
|
||||
|
@@ -202,10 +202,16 @@ int load_multiboot(void *fw_cfg,
|
||||
uint32_t mh_bss_end_addr = ldl_p(header+i+24);
|
||||
mh_load_addr = ldl_p(header+i+16);
|
||||
uint32_t mb_kernel_text_offset = i - (mh_header_addr - mh_load_addr);
|
||||
uint32_t mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
|
||||
uint32_t mb_load_size = 0;
|
||||
mh_entry_addr = ldl_p(header+i+28);
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
|
||||
if (mh_load_end_addr) {
|
||||
mb_kernel_size = mh_bss_end_addr - mh_load_addr;
|
||||
mb_load_size = mh_load_end_addr - mh_load_addr;
|
||||
} else {
|
||||
mb_kernel_size = kernel_file_size - mb_kernel_text_offset;
|
||||
mb_load_size = mb_kernel_size;
|
||||
}
|
||||
|
||||
/* Valid if mh_flags sets MULTIBOOT_HEADER_HAS_VBE.
|
||||
uint32_t mh_mode_type = ldl_p(header+i+32);
|
||||
|
25
hw/pc.c
25
hw/pc.c
@@ -47,6 +47,7 @@
|
||||
#include "ui/qemu-spice.h"
|
||||
#include "memory.h"
|
||||
#include "exec-memory.h"
|
||||
#include "arch_init.h"
|
||||
|
||||
/* output Bochs bios info messages */
|
||||
//#define DEBUG_BIOS
|
||||
@@ -382,7 +383,7 @@ void pc_cmos_init(ram_addr_t ram_size, ram_addr_t above_4g_mem_size,
|
||||
if (floppy) {
|
||||
fdc_get_bs(fd, floppy);
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (fd[i] && bdrv_is_inserted(fd[i])) {
|
||||
if (fd[i]) {
|
||||
bdrv_get_floppy_geometry_hint(fd[i], &nb_heads, &max_track,
|
||||
&last_sect, FDRIVE_DRV_NONE,
|
||||
&fd_type[i], &rate);
|
||||
@@ -1097,7 +1098,7 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
qemu_irq pit_alt_irq = NULL;
|
||||
qemu_irq rtc_irq = NULL;
|
||||
qemu_irq *a20_line;
|
||||
ISADevice *i8042, *port92, *vmmouse, *pit;
|
||||
ISADevice *i8042, *port92, *vmmouse, *pit = NULL;
|
||||
qemu_irq *cpu_exit_irq;
|
||||
|
||||
register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
|
||||
@@ -1126,16 +1127,18 @@ void pc_basic_device_init(ISABus *isa_bus, qemu_irq *gsi,
|
||||
|
||||
qemu_register_boot_set(pc_boot_set, *rtc_state);
|
||||
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
pit = kvm_pit_init(isa_bus, 0x40);
|
||||
} else {
|
||||
pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
|
||||
if (!xen_enabled()) {
|
||||
if (kvm_irqchip_in_kernel()) {
|
||||
pit = kvm_pit_init(isa_bus, 0x40);
|
||||
} else {
|
||||
pit = pit_init(isa_bus, 0x40, pit_isa_irq, pit_alt_irq);
|
||||
}
|
||||
if (hpet) {
|
||||
/* connect PIT to output control line of the HPET */
|
||||
qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
|
||||
}
|
||||
pcspk_init(isa_bus, pit);
|
||||
}
|
||||
if (hpet) {
|
||||
/* connect PIT to output control line of the HPET */
|
||||
qdev_connect_gpio_out(hpet, 0, qdev_get_gpio_in(&pit->qdev, 0));
|
||||
}
|
||||
pcspk_init(isa_bus, pit);
|
||||
|
||||
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
|
||||
if (serial_hds[i]) {
|
||||
|
@@ -522,6 +522,10 @@ static QEMUMachine pc_machine_v0_12 = {
|
||||
.driver = "virtio-blk-pci",\
|
||||
.property = "vectors",\
|
||||
.value = stringify(0),\
|
||||
},{\
|
||||
.driver = "PCI",\
|
||||
.property = "rombar",\
|
||||
.value = stringify(0),\
|
||||
}
|
||||
|
||||
static QEMUMachine pc_machine_v0_11 = {
|
||||
|
1
hw/pci.c
1
hw/pci.c
@@ -1527,7 +1527,6 @@ static int pci_unplug_device(DeviceState *qdev)
|
||||
qerror_report(QERR_DEVICE_NO_HOTPLUG, object_get_typename(OBJECT(dev)));
|
||||
return -1;
|
||||
}
|
||||
object_unparent(OBJECT(dev));
|
||||
return dev->bus->hotplug(dev->bus->hotplug_qdev, dev,
|
||||
PCI_HOTPLUG_DISABLED);
|
||||
}
|
||||
|
@@ -158,7 +158,7 @@ int qdev_device_help(QemuOpts *opts)
|
||||
* for removal. This conditional should be removed along with
|
||||
* it.
|
||||
*/
|
||||
if (!prop->info->parse) {
|
||||
if (!prop->info->set) {
|
||||
continue; /* no way to set it, don't show */
|
||||
}
|
||||
error_printf("%s.%s=%s\n", driver, prop->name,
|
||||
@@ -166,7 +166,7 @@ int qdev_device_help(QemuOpts *opts)
|
||||
}
|
||||
if (info->bus_info) {
|
||||
for (prop = info->bus_info->props; prop && prop->name; prop++) {
|
||||
if (!prop->info->parse) {
|
||||
if (!prop->info->set) {
|
||||
continue; /* no way to set it, don't show */
|
||||
}
|
||||
error_printf("%s.%s=%s\n", driver, prop->name,
|
||||
@@ -493,7 +493,7 @@ static void qdev_print_props(Monitor *mon, DeviceState *dev, Property *props,
|
||||
if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
|
||||
value = object_property_get_str(OBJECT(dev), legacy_name, &err);
|
||||
} else {
|
||||
value = object_property_get_str(OBJECT(dev), props->name, &err);
|
||||
value = object_property_print(OBJECT(dev), props->name, &err);
|
||||
}
|
||||
g_free(legacy_name);
|
||||
|
||||
|
@@ -753,10 +753,12 @@ static void set_mac(Object *obj, Visitor *v, void *opaque,
|
||||
}
|
||||
mac->a[i] = strtol(str+pos, &p, 16);
|
||||
}
|
||||
g_free(str);
|
||||
return;
|
||||
|
||||
inval:
|
||||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
PropertyInfo qdev_prop_macaddr = {
|
||||
@@ -825,7 +827,7 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
|
||||
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
|
||||
unsigned int slot, fn, n;
|
||||
Error *local_err = NULL;
|
||||
char *str = (char *)"";
|
||||
char *str;
|
||||
|
||||
if (dev->state != DEV_STATE_CREATED) {
|
||||
error_set(errp, QERR_PERMISSION_DENIED);
|
||||
@@ -848,10 +850,12 @@ static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
|
||||
goto invalid;
|
||||
}
|
||||
*ptr = slot << 3 | fn;
|
||||
g_free(str);
|
||||
return;
|
||||
|
||||
invalid:
|
||||
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
||||
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len)
|
||||
|
@@ -576,9 +576,12 @@ void qdev_property_add_legacy(DeviceState *dev, Property *prop,
|
||||
{
|
||||
gchar *name, *type;
|
||||
|
||||
if (!prop->info->print && !prop->info->parse) {
|
||||
/* Register pointer properties as legacy properties */
|
||||
if (!prop->info->print && !prop->info->parse &&
|
||||
(prop->info->set || prop->info->get)) {
|
||||
return;
|
||||
}
|
||||
|
||||
name = g_strdup_printf("legacy-%s", prop->name);
|
||||
type = g_strdup_printf("legacy<%s>",
|
||||
prop->info->legacy_name ?: prop->info->name);
|
||||
|
8
hw/qxl.c
8
hw/qxl.c
@@ -1746,13 +1746,16 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
switch (qxl->revision) {
|
||||
case 1: /* spice 0.4 -- qxl-1 */
|
||||
pci_device_rev = QXL_REVISION_STABLE_V04;
|
||||
io_size = 8;
|
||||
break;
|
||||
case 2: /* spice 0.6 -- qxl-2 */
|
||||
pci_device_rev = QXL_REVISION_STABLE_V06;
|
||||
io_size = 16;
|
||||
break;
|
||||
case 3: /* qxl-3 */
|
||||
default:
|
||||
pci_device_rev = QXL_DEFAULT_REVISION;
|
||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1770,11 +1773,6 @@ static int qxl_init_common(PCIQXLDevice *qxl)
|
||||
memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar,
|
||||
0, qxl->vram32_size);
|
||||
|
||||
io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1);
|
||||
if (qxl->revision == 1) {
|
||||
io_size = 8;
|
||||
}
|
||||
|
||||
memory_region_init_io(&qxl->io_bar, &qxl_io_ops, qxl,
|
||||
"qxl-ioports", io_size);
|
||||
if (qxl->id == 0) {
|
||||
|
@@ -163,8 +163,7 @@ static int s390_virtio_blk_init(VirtIOS390Device *dev)
|
||||
{
|
||||
VirtIODevice *vdev;
|
||||
|
||||
vdev = virtio_blk_init((DeviceState *)dev, &dev->block,
|
||||
&dev->block_serial);
|
||||
vdev = virtio_blk_init((DeviceState *)dev, &dev->blk);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
@@ -400,8 +399,11 @@ static TypeInfo s390_virtio_net = {
|
||||
};
|
||||
|
||||
static Property s390_virtio_blk_properties[] = {
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, block),
|
||||
DEFINE_PROP_STRING("serial", VirtIOS390Device, block_serial),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOS390Device, blk.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOS390Device, blk.serial),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOS390Device, blk.scsi, 0, true),
|
||||
#endif
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "virtio-blk.h"
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
@@ -64,8 +65,7 @@ struct VirtIOS390Device {
|
||||
ram_addr_t feat_offs;
|
||||
uint8_t feat_len;
|
||||
VirtIODevice *vdev;
|
||||
BlockConf block;
|
||||
char *block_serial;
|
||||
VirtIOBlkConf blk;
|
||||
NICConf nic;
|
||||
uint32_t host_features;
|
||||
virtio_serial_conf serial;
|
||||
|
@@ -1561,7 +1561,7 @@ static int get_scsi_requests(QEMUFile *f, void *pv, size_t size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
const VMStateInfo vmstate_info_scsi_requests = {
|
||||
static const VMStateInfo vmstate_info_scsi_requests = {
|
||||
.name = "scsi-requests",
|
||||
.get = get_scsi_requests,
|
||||
.put = put_scsi_requests,
|
||||
|
56
hw/sun4u.c
56
hw/sun4u.c
@@ -67,7 +67,6 @@
|
||||
|
||||
#define KERNEL_LOAD_ADDR 0x00404000
|
||||
#define CMDLINE_ADDR 0x003ff000
|
||||
#define INITRD_LOAD_ADDR 0x00300000
|
||||
#define PROM_SIZE_MAX (4 * 1024 * 1024)
|
||||
#define PROM_VADDR 0x000ffd00000ULL
|
||||
#define APB_SPECIAL_BASE 0x1fe00000000ULL
|
||||
@@ -181,14 +180,18 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
|
||||
|
||||
return 0;
|
||||
}
|
||||
static unsigned long sun4u_load_kernel(const char *kernel_filename,
|
||||
const char *initrd_filename,
|
||||
ram_addr_t RAM_size, long *initrd_size)
|
||||
|
||||
static uint64_t sun4u_load_kernel(const char *kernel_filename,
|
||||
const char *initrd_filename,
|
||||
ram_addr_t RAM_size, uint64_t *initrd_size,
|
||||
uint64_t *initrd_addr, uint64_t *kernel_addr,
|
||||
uint64_t *kernel_entry)
|
||||
{
|
||||
int linux_boot;
|
||||
unsigned int i;
|
||||
long kernel_size;
|
||||
uint8_t *ptr;
|
||||
uint64_t kernel_top;
|
||||
|
||||
linux_boot = (kernel_filename != NULL);
|
||||
|
||||
@@ -201,29 +204,34 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename,
|
||||
#else
|
||||
bswap_needed = 0;
|
||||
#endif
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
|
||||
NULL, NULL, 1, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
|
||||
kernel_addr, &kernel_top, 1, ELF_MACHINE, 0);
|
||||
if (kernel_size < 0) {
|
||||
*kernel_addr = KERNEL_LOAD_ADDR;
|
||||
*kernel_entry = KERNEL_LOAD_ADDR;
|
||||
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
|
||||
RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
|
||||
TARGET_PAGE_SIZE);
|
||||
if (kernel_size < 0)
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(kernel_filename,
|
||||
KERNEL_LOAD_ADDR,
|
||||
RAM_size - KERNEL_LOAD_ADDR);
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* load initrd */
|
||||
/* load initrd above kernel */
|
||||
*initrd_size = 0;
|
||||
if (initrd_filename) {
|
||||
*initrd_addr = TARGET_PAGE_ALIGN(kernel_top);
|
||||
|
||||
*initrd_size = load_image_targphys(initrd_filename,
|
||||
INITRD_LOAD_ADDR,
|
||||
RAM_size - INITRD_LOAD_ADDR);
|
||||
if (*initrd_size < 0) {
|
||||
*initrd_addr,
|
||||
RAM_size - *initrd_addr);
|
||||
if ((int)*initrd_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
|
||||
initrd_filename);
|
||||
exit(1);
|
||||
@@ -231,9 +239,9 @@ static unsigned long sun4u_load_kernel(const char *kernel_filename,
|
||||
}
|
||||
if (*initrd_size > 0) {
|
||||
for (i = 0; i < 64 * TARGET_PAGE_SIZE; i += TARGET_PAGE_SIZE) {
|
||||
ptr = rom_ptr(KERNEL_LOAD_ADDR + i);
|
||||
ptr = rom_ptr(*kernel_addr + i);
|
||||
if (ldl_p(ptr + 8) == 0x48647253) { /* HdrS */
|
||||
stl_p(ptr + 24, INITRD_LOAD_ADDR + KERNEL_LOAD_ADDR - 0x4000);
|
||||
stl_p(ptr + 24, *initrd_addr + *kernel_addr);
|
||||
stl_p(ptr + 28, *initrd_size);
|
||||
break;
|
||||
}
|
||||
@@ -788,7 +796,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
CPUSPARCState *env;
|
||||
M48t59State *nvram;
|
||||
unsigned int i;
|
||||
long initrd_size, kernel_size;
|
||||
uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
|
||||
PCIBus *pci_bus, *pci_bus2, *pci_bus3;
|
||||
ISABus *isa_bus;
|
||||
qemu_irq *ivec_irqs, *pbm_irqs;
|
||||
@@ -845,13 +853,15 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
|
||||
|
||||
initrd_size = 0;
|
||||
initrd_addr = 0;
|
||||
kernel_size = sun4u_load_kernel(kernel_filename, initrd_filename,
|
||||
ram_size, &initrd_size);
|
||||
ram_size, &initrd_size, &initrd_addr,
|
||||
&kernel_addr, &kernel_entry);
|
||||
|
||||
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", RAM_size, boot_devices,
|
||||
KERNEL_LOAD_ADDR, kernel_size,
|
||||
kernel_addr, kernel_size,
|
||||
kernel_cmdline,
|
||||
INITRD_LOAD_ADDR, initrd_size,
|
||||
initrd_addr, initrd_size,
|
||||
/* XXX: need an option to load a NVRAM image */
|
||||
0,
|
||||
graphic_width, graphic_height, graphic_depth,
|
||||
@@ -861,8 +871,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_ADDR, KERNEL_LOAD_ADDR);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_ADDR, kernel_entry);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_KERNEL_SIZE, kernel_size);
|
||||
if (kernel_cmdline) {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE,
|
||||
strlen(kernel_cmdline) + 1);
|
||||
@@ -872,8 +882,8 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
|
||||
} else {
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_CMDLINE_SIZE, 0);
|
||||
}
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_ADDR, INITRD_LOAD_ADDR);
|
||||
fw_cfg_add_i32(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_ADDR, initrd_addr);
|
||||
fw_cfg_add_i64(fw_cfg, FW_CFG_INITRD_SIZE, initrd_size);
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, boot_devices[0]);
|
||||
|
||||
fw_cfg_add_i16(fw_cfg, FW_CFG_SPARC64_WIDTH, graphic_width);
|
||||
|
@@ -1091,8 +1091,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val)
|
||||
break;
|
||||
|
||||
case USBSTS:
|
||||
val &= USBSTS_RO_MASK; // bits 6 thru 31 are RO
|
||||
ehci_clear_usbsts(s, val); // bits 0 thru 5 are R/WC
|
||||
val &= USBSTS_RO_MASK; // bits 6 through 31 are RO
|
||||
ehci_clear_usbsts(s, val); // bits 0 through 5 are R/WC
|
||||
val = s->usbsts;
|
||||
ehci_set_interrupt(s, 0);
|
||||
break;
|
||||
|
@@ -1058,6 +1058,15 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p,
|
||||
ret = usb_host_set_interface(s, index, value);
|
||||
trace_usb_host_req_emulated(s->bus_num, s->addr, p, ret);
|
||||
return ret;
|
||||
|
||||
case EndpointOutRequest | USB_REQ_CLEAR_FEATURE:
|
||||
if (value == 0) { /* clear halt */
|
||||
int pid = (index & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT;
|
||||
ioctl(s->fd, USBDEVFS_CLEAR_HALT, &index);
|
||||
clear_halt(s, pid, index & 0x0f);
|
||||
trace_usb_host_req_emulated(s->bus_num, s->addr, p, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* The rest are asynchronous */
|
||||
|
7
hw/vga.c
7
hw/vga.c
@@ -2357,10 +2357,15 @@ void vga_init(VGACommonState *s, MemoryRegion *address_space,
|
||||
void vga_init_vbe(VGACommonState *s, MemoryRegion *system_memory)
|
||||
{
|
||||
#ifdef CONFIG_BOCHS_VBE
|
||||
/* With pc-0.12 and below we map both the PCI BAR and the fixed VBE region,
|
||||
* so use an alias to avoid double-mapping the same region.
|
||||
*/
|
||||
memory_region_init_alias(&s->vram_vbe, "vram.vbe",
|
||||
&s->vram, 0, memory_region_size(&s->vram));
|
||||
/* XXX: use optimized standard vga accesses */
|
||||
memory_region_add_subregion(system_memory,
|
||||
VBE_DISPI_LFB_PHYSICAL_ADDRESS,
|
||||
&s->vram);
|
||||
&s->vram_vbe);
|
||||
s->vbe_mapped = 1;
|
||||
#endif
|
||||
}
|
||||
|
@@ -105,6 +105,7 @@ typedef struct VGACommonState {
|
||||
MemoryRegion *legacy_address_space;
|
||||
uint8_t *vram_ptr;
|
||||
MemoryRegion vram;
|
||||
MemoryRegion vram_vbe;
|
||||
uint32_t vram_size;
|
||||
uint32_t latch;
|
||||
MemoryRegion *chain4_alias;
|
||||
|
@@ -211,11 +211,15 @@ static void virtio_balloon_save(QEMUFile *f, void *opaque)
|
||||
static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOBalloon *s = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id != 1)
|
||||
return -EINVAL;
|
||||
|
||||
virtio_load(&s->vdev, f);
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->num_pages = qemu_get_be32(f);
|
||||
s->actual = qemu_get_be32(f);
|
||||
|
@@ -29,7 +29,7 @@ typedef struct VirtIOBlock
|
||||
void *rq;
|
||||
QEMUBH *bh;
|
||||
BlockConf *conf;
|
||||
char *serial;
|
||||
VirtIOBlkConf *blk;
|
||||
unsigned short sector_mask;
|
||||
DeviceState *qdev;
|
||||
} VirtIOBlock;
|
||||
@@ -145,20 +145,12 @@ static VirtIOBlockReq *virtio_blk_get_request(VirtIOBlock *s)
|
||||
return req;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
{
|
||||
struct sg_io_hdr hdr;
|
||||
int ret;
|
||||
int status;
|
||||
int status = VIRTIO_BLK_S_OK;
|
||||
int i;
|
||||
|
||||
if ((req->dev->vdev.guest_features & (1 << VIRTIO_BLK_F_SCSI)) == 0) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
g_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We require at least one output segment each for the virtio_blk_outhdr
|
||||
* and the SCSI command block.
|
||||
@@ -172,21 +164,27 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* No support for bidirection commands yet.
|
||||
*/
|
||||
if (req->elem.out_num > 2 && req->elem.in_num > 3) {
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
g_free(req);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* The scsi inhdr is placed in the second-to-last input segment, just
|
||||
* before the regular inhdr.
|
||||
*/
|
||||
req->scsi = (void *)req->elem.in_sg[req->elem.in_num - 2].iov_base;
|
||||
|
||||
if (!req->dev->blk->scsi) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
* No support for bidirection commands yet.
|
||||
*/
|
||||
if (req->elem.out_num > 2 && req->elem.in_num > 3) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
struct sg_io_hdr hdr;
|
||||
memset(&hdr, 0, sizeof(struct sg_io_hdr));
|
||||
hdr.interface_id = 'S';
|
||||
hdr.cmd_len = req->elem.out_sg[1].iov_len;
|
||||
@@ -230,12 +228,7 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
ret = bdrv_ioctl(req->dev->bs, SG_IO, &hdr);
|
||||
if (ret) {
|
||||
status = VIRTIO_BLK_S_UNSUPP;
|
||||
hdr.status = ret;
|
||||
hdr.resid = hdr.dxfer_len;
|
||||
} else if (hdr.status) {
|
||||
status = VIRTIO_BLK_S_IOERR;
|
||||
} else {
|
||||
status = VIRTIO_BLK_S_OK;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -258,14 +251,16 @@ static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
|
||||
virtio_blk_req_complete(req, status);
|
||||
g_free(req);
|
||||
}
|
||||
#else
|
||||
static void virtio_blk_handle_scsi(VirtIOBlockReq *req)
|
||||
{
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
|
||||
abort();
|
||||
#endif
|
||||
|
||||
fail:
|
||||
/* Just put anything nonzero so that the ioctl fails in the guest. */
|
||||
stl_p(&req->scsi->errors, 255);
|
||||
virtio_blk_req_complete(req, status);
|
||||
g_free(req);
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
typedef struct MultiReqBuffer {
|
||||
BlockRequest blkreq[32];
|
||||
@@ -394,7 +389,7 @@ static void virtio_blk_handle_request(VirtIOBlockReq *req,
|
||||
* terminated by '\0' only when shorter than buffer.
|
||||
*/
|
||||
strncpy(req->elem.in_sg[0].iov_base,
|
||||
s->serial ? s->serial : "",
|
||||
s->blk->serial ? s->blk->serial : "",
|
||||
MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
|
||||
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
|
||||
g_free(req);
|
||||
@@ -509,6 +504,7 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev, uint32_t features)
|
||||
features |= (1 << VIRTIO_BLK_F_GEOMETRY);
|
||||
features |= (1 << VIRTIO_BLK_F_TOPOLOGY);
|
||||
features |= (1 << VIRTIO_BLK_F_BLK_SIZE);
|
||||
features |= (1 << VIRTIO_BLK_F_SCSI);
|
||||
|
||||
if (bdrv_enable_write_cache(s->bs))
|
||||
features |= (1 << VIRTIO_BLK_F_WCACHE);
|
||||
@@ -537,11 +533,16 @@ static void virtio_blk_save(QEMUFile *f, void *opaque)
|
||||
static int virtio_blk_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOBlock *s = opaque;
|
||||
int ret;
|
||||
|
||||
if (version_id != 2)
|
||||
return -EINVAL;
|
||||
|
||||
virtio_load(&s->vdev, f);
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
while (qemu_get_sbyte(f)) {
|
||||
VirtIOBlockReq *req = virtio_blk_alloc_request(s);
|
||||
qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem));
|
||||
@@ -568,28 +569,27 @@ static const BlockDevOps virtio_block_ops = {
|
||||
.resize_cb = virtio_blk_resize,
|
||||
};
|
||||
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
char **serial)
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk)
|
||||
{
|
||||
VirtIOBlock *s;
|
||||
int cylinders, heads, secs;
|
||||
static int virtio_blk_id;
|
||||
DriveInfo *dinfo;
|
||||
|
||||
if (!conf->bs) {
|
||||
if (!blk->conf.bs) {
|
||||
error_report("drive property not set");
|
||||
return NULL;
|
||||
}
|
||||
if (!bdrv_is_inserted(conf->bs)) {
|
||||
if (!bdrv_is_inserted(blk->conf.bs)) {
|
||||
error_report("Device needs media, but drive is empty");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!*serial) {
|
||||
if (!blk->serial) {
|
||||
/* try to fall back to value set with legacy -drive serial=... */
|
||||
dinfo = drive_get_by_blockdev(conf->bs);
|
||||
dinfo = drive_get_by_blockdev(blk->conf.bs);
|
||||
if (*dinfo->serial) {
|
||||
*serial = strdup(dinfo->serial);
|
||||
blk->serial = strdup(dinfo->serial);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -600,9 +600,9 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
s->vdev.get_config = virtio_blk_update_config;
|
||||
s->vdev.get_features = virtio_blk_get_features;
|
||||
s->vdev.reset = virtio_blk_reset;
|
||||
s->bs = conf->bs;
|
||||
s->conf = conf;
|
||||
s->serial = *serial;
|
||||
s->bs = blk->conf.bs;
|
||||
s->conf = &blk->conf;
|
||||
s->blk = blk;
|
||||
s->rq = NULL;
|
||||
s->sector_mask = (s->conf->logical_block_size / BDRV_SECTOR_SIZE) - 1;
|
||||
bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
|
||||
@@ -614,10 +614,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
register_savevm(dev, "virtio-blk", virtio_blk_id++, 2,
|
||||
virtio_blk_save, virtio_blk_load, s);
|
||||
bdrv_set_dev_ops(s->bs, &virtio_block_ops, s);
|
||||
bdrv_set_buffer_alignment(s->bs, conf->logical_block_size);
|
||||
bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size);
|
||||
|
||||
bdrv_iostatus_enable(s->bs);
|
||||
add_boot_device_path(conf->bootindex, dev, "/disk@0,0");
|
||||
add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0");
|
||||
|
||||
return &s->vdev;
|
||||
}
|
||||
@@ -626,5 +626,6 @@ void virtio_blk_exit(VirtIODevice *vdev)
|
||||
{
|
||||
VirtIOBlock *s = to_virtio_blk(vdev);
|
||||
unregister_savevm(s->qdev, "virtio-blk", s);
|
||||
blockdev_mark_auto_del(s->bs);
|
||||
virtio_cleanup(vdev);
|
||||
}
|
||||
|
@@ -97,12 +97,14 @@ struct virtio_scsi_inhdr
|
||||
uint32_t residual;
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field), \
|
||||
DEFINE_PROP_BIT("scsi", _state, _field, VIRTIO_BLK_F_SCSI, true)
|
||||
#else
|
||||
struct VirtIOBlkConf
|
||||
{
|
||||
BlockConf conf;
|
||||
char *serial;
|
||||
uint32_t scsi;
|
||||
};
|
||||
|
||||
#define DEFINE_VIRTIO_BLK_FEATURES(_state, _field) \
|
||||
DEFINE_VIRTIO_COMMON_FEATURES(_state, _field)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@@ -891,11 +891,15 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIONet *n = opaque;
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (version_id < 2 || version_id > VIRTIO_NET_VM_VERSION)
|
||||
return -EINVAL;
|
||||
|
||||
virtio_load(&n->vdev, f);
|
||||
ret = virtio_load(&n->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
qemu_get_buffer(f, n->mac, ETH_ALEN);
|
||||
n->tx_waiting = qemu_get_be32(f);
|
||||
|
@@ -491,7 +491,7 @@ static void virtio_pci_config_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
virtio_config_writel(proxy->vdev, addr, val);
|
||||
}
|
||||
|
||||
const MemoryRegionPortio virtio_portio[] = {
|
||||
static const MemoryRegionPortio virtio_portio[] = {
|
||||
{ 0, 0x10000, 1, .write = virtio_pci_config_writeb, },
|
||||
{ 0, 0x10000, 2, .write = virtio_pci_config_writew, },
|
||||
{ 0, 0x10000, 4, .write = virtio_pci_config_writel, },
|
||||
@@ -697,8 +697,7 @@ static int virtio_blk_init_pci(PCIDevice *pci_dev)
|
||||
proxy->class_code != PCI_CLASS_STORAGE_OTHER)
|
||||
proxy->class_code = PCI_CLASS_STORAGE_SCSI;
|
||||
|
||||
vdev = virtio_blk_init(&pci_dev->qdev, &proxy->block,
|
||||
&proxy->block_serial);
|
||||
vdev = virtio_blk_init(&pci_dev->qdev, &proxy->blk);
|
||||
if (!vdev) {
|
||||
return -1;
|
||||
}
|
||||
@@ -726,7 +725,6 @@ static int virtio_blk_exit_pci(PCIDevice *pci_dev)
|
||||
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
virtio_blk_exit(proxy->vdev);
|
||||
blockdev_mark_auto_del(proxy->block.bs);
|
||||
return virtio_exit_pci(pci_dev);
|
||||
}
|
||||
|
||||
@@ -814,8 +812,11 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev)
|
||||
|
||||
static Property virtio_blk_properties[] = {
|
||||
DEFINE_PROP_HEX32("class", VirtIOPCIProxy, class_code, 0),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, block),
|
||||
DEFINE_PROP_STRING("serial", VirtIOPCIProxy, block_serial),
|
||||
DEFINE_BLOCK_PROPERTIES(VirtIOPCIProxy, blk.conf),
|
||||
DEFINE_PROP_STRING("serial", VirtIOPCIProxy, blk.serial),
|
||||
#ifdef __linux__
|
||||
DEFINE_PROP_BIT("scsi", VirtIOPCIProxy, blk.scsi, 0, true),
|
||||
#endif
|
||||
DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
|
||||
DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2),
|
||||
DEFINE_VIRTIO_BLK_FEATURES(VirtIOPCIProxy, host_features),
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#ifndef QEMU_VIRTIO_PCI_H
|
||||
#define QEMU_VIRTIO_PCI_H
|
||||
|
||||
#include "virtio-blk.h"
|
||||
#include "virtio-net.h"
|
||||
#include "virtio-serial.h"
|
||||
#include "virtio-scsi.h"
|
||||
@@ -32,8 +33,7 @@ typedef struct {
|
||||
uint32_t flags;
|
||||
uint32_t class_code;
|
||||
uint32_t nvectors;
|
||||
BlockConf block;
|
||||
char *block_serial;
|
||||
VirtIOBlkConf blk;
|
||||
NICConf nic;
|
||||
uint32_t host_features;
|
||||
#ifdef CONFIG_LINUX
|
||||
|
@@ -564,7 +564,12 @@ static void virtio_scsi_save(QEMUFile *f, void *opaque)
|
||||
static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id)
|
||||
{
|
||||
VirtIOSCSI *s = opaque;
|
||||
virtio_load(&s->vdev, f);
|
||||
int ret;
|
||||
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -637,13 +637,17 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
|
||||
VirtIOSerialPort *port;
|
||||
uint32_t max_nr_ports, nr_active_ports, ports_map;
|
||||
unsigned int i;
|
||||
int ret;
|
||||
|
||||
if (version_id > 3) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* The virtio device */
|
||||
virtio_load(&s->vdev, f);
|
||||
ret = virtio_load(&s->vdev, f);
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (version_id < 2) {
|
||||
return 0;
|
||||
|
@@ -191,8 +191,8 @@ void virtio_bind_device(VirtIODevice *vdev, const VirtIOBindings *binding,
|
||||
void *opaque);
|
||||
|
||||
/* Base devices. */
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, BlockConf *conf,
|
||||
char **serial);
|
||||
typedef struct VirtIOBlkConf VirtIOBlkConf;
|
||||
VirtIODevice *virtio_blk_init(DeviceState *dev, VirtIOBlkConf *blk);
|
||||
struct virtio_net_conf;
|
||||
VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
|
||||
struct virtio_net_conf *net);
|
||||
|
@@ -148,6 +148,6 @@ static inline int xen_xc_hvm_inject_msi(XenXC xen_xc, domid_t dom,
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy_hvm_domain(void);
|
||||
void destroy_hvm_domain(bool reboot);
|
||||
|
||||
#endif /* QEMU_HW_XEN_COMMON_H */
|
||||
|
@@ -48,7 +48,6 @@
|
||||
|
||||
/* ------------------------------------------------------------- */
|
||||
|
||||
static int syncwrite = 0;
|
||||
static int batch_maps = 0;
|
||||
|
||||
static int max_requests = 32;
|
||||
@@ -67,6 +66,7 @@ struct ioreq {
|
||||
QEMUIOVector v;
|
||||
int presync;
|
||||
int postsync;
|
||||
uint8_t mapped;
|
||||
|
||||
/* grant mapping */
|
||||
uint32_t domids[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
@@ -154,7 +154,7 @@ static void ioreq_finish(struct ioreq *ioreq)
|
||||
blkdev->requests_finished++;
|
||||
}
|
||||
|
||||
static void ioreq_release(struct ioreq *ioreq)
|
||||
static void ioreq_release(struct ioreq *ioreq, bool finish)
|
||||
{
|
||||
struct XenBlkDev *blkdev = ioreq->blkdev;
|
||||
|
||||
@@ -162,7 +162,11 @@ static void ioreq_release(struct ioreq *ioreq)
|
||||
memset(ioreq, 0, sizeof(*ioreq));
|
||||
ioreq->blkdev = blkdev;
|
||||
QLIST_INSERT_HEAD(&blkdev->freelist, ioreq, list);
|
||||
blkdev->requests_finished--;
|
||||
if (finish) {
|
||||
blkdev->requests_finished--;
|
||||
} else {
|
||||
blkdev->requests_inflight--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -189,15 +193,10 @@ static int ioreq_parse(struct ioreq *ioreq)
|
||||
ioreq->presync = 1;
|
||||
return 0;
|
||||
}
|
||||
if (!syncwrite) {
|
||||
ioreq->presync = ioreq->postsync = 1;
|
||||
}
|
||||
ioreq->presync = ioreq->postsync = 1;
|
||||
/* fall through */
|
||||
case BLKIF_OP_WRITE:
|
||||
ioreq->prot = PROT_READ; /* from memory */
|
||||
if (syncwrite) {
|
||||
ioreq->postsync = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
xen_be_printf(&blkdev->xendev, 0, "error: unknown operation (%d)\n",
|
||||
@@ -248,7 +247,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
|
||||
XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
|
||||
int i;
|
||||
|
||||
if (ioreq->v.niov == 0) {
|
||||
if (ioreq->v.niov == 0 || ioreq->mapped == 0) {
|
||||
return;
|
||||
}
|
||||
if (batch_maps) {
|
||||
@@ -274,6 +273,7 @@ static void ioreq_unmap(struct ioreq *ioreq)
|
||||
ioreq->page[i] = NULL;
|
||||
}
|
||||
}
|
||||
ioreq->mapped = 0;
|
||||
}
|
||||
|
||||
static int ioreq_map(struct ioreq *ioreq)
|
||||
@@ -281,7 +281,7 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
XenGnttab gnt = ioreq->blkdev->xendev.gnttabdev;
|
||||
int i;
|
||||
|
||||
if (ioreq->v.niov == 0) {
|
||||
if (ioreq->v.niov == 0 || ioreq->mapped == 1) {
|
||||
return 0;
|
||||
}
|
||||
if (batch_maps) {
|
||||
@@ -313,9 +313,12 @@ static int ioreq_map(struct ioreq *ioreq)
|
||||
ioreq->blkdev->cnt_map++;
|
||||
}
|
||||
}
|
||||
ioreq->mapped = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ioreq_runio_qemu_aio(struct ioreq *ioreq);
|
||||
|
||||
static void qemu_aio_complete(void *opaque, int ret)
|
||||
{
|
||||
struct ioreq *ioreq = opaque;
|
||||
@@ -327,11 +330,19 @@ static void qemu_aio_complete(void *opaque, int ret)
|
||||
}
|
||||
|
||||
ioreq->aio_inflight--;
|
||||
if (ioreq->presync) {
|
||||
ioreq->presync = 0;
|
||||
ioreq_runio_qemu_aio(ioreq);
|
||||
return;
|
||||
}
|
||||
if (ioreq->aio_inflight > 0) {
|
||||
return;
|
||||
}
|
||||
if (ioreq->postsync) {
|
||||
bdrv_flush(ioreq->blkdev->bs);
|
||||
ioreq->postsync = 0;
|
||||
ioreq->aio_inflight++;
|
||||
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
|
||||
return;
|
||||
}
|
||||
|
||||
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
|
||||
@@ -351,7 +362,8 @@ static int ioreq_runio_qemu_aio(struct ioreq *ioreq)
|
||||
|
||||
ioreq->aio_inflight++;
|
||||
if (ioreq->presync) {
|
||||
bdrv_flush(blkdev->bs); /* FIXME: aio_flush() ??? */
|
||||
bdrv_aio_flush(ioreq->blkdev->bs, qemu_aio_complete, ioreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ioreq->req.operation) {
|
||||
@@ -449,7 +461,7 @@ static void blk_send_response_all(struct XenBlkDev *blkdev)
|
||||
while (!QLIST_EMPTY(&blkdev->finished)) {
|
||||
ioreq = QLIST_FIRST(&blkdev->finished);
|
||||
send_notify += blk_send_response_one(ioreq);
|
||||
ioreq_release(ioreq);
|
||||
ioreq_release(ioreq, true);
|
||||
}
|
||||
if (send_notify) {
|
||||
xen_be_send_notify(&blkdev->xendev);
|
||||
@@ -505,7 +517,7 @@ static void blk_handle_requests(struct XenBlkDev *blkdev)
|
||||
if (blk_send_response_one(ioreq)) {
|
||||
xen_be_send_notify(&blkdev->xendev);
|
||||
}
|
||||
ioreq_release(ioreq);
|
||||
ioreq_release(ioreq, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -87,7 +87,10 @@ static void unplug_nic(PCIBus *b, PCIDevice *d)
|
||||
{
|
||||
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
|
||||
PCI_CLASS_NETWORK_ETHERNET) {
|
||||
qdev_unplug(&(d->qdev), NULL);
|
||||
/* Until qdev_free includes a call to object_unparent, we call it here
|
||||
*/
|
||||
object_unparent(&d->qdev.parent_obj);
|
||||
qdev_free(&d->qdev);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -555,6 +555,12 @@ ObjectClass *object_class_dynamic_cast(ObjectClass *klass,
|
||||
*/
|
||||
const char *object_class_get_name(ObjectClass *klass);
|
||||
|
||||
/**
|
||||
* object_class_by_name:
|
||||
* @typename: The QOM typename to obtain the class for.
|
||||
*
|
||||
* Returns: The class for @typename or %NULL if not found.
|
||||
*/
|
||||
ObjectClass *object_class_by_name(const char *typename);
|
||||
|
||||
void object_class_foreach(void (*fn)(ObjectClass *klass, void *opaque),
|
||||
|
14
kvm-all.c
14
kvm-all.c
@@ -348,6 +348,7 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
|
||||
unsigned long page_number, c;
|
||||
target_phys_addr_t addr, addr1;
|
||||
unsigned int len = ((section->size / TARGET_PAGE_SIZE) + HOST_LONG_BITS - 1) / HOST_LONG_BITS;
|
||||
unsigned long hpratio = getpagesize() / TARGET_PAGE_SIZE;
|
||||
|
||||
/*
|
||||
* bitmap-traveling is faster than memory-traveling (for addr...)
|
||||
@@ -359,10 +360,11 @@ static int kvm_get_dirty_pages_log_range(MemoryRegionSection *section,
|
||||
do {
|
||||
j = ffsl(c) - 1;
|
||||
c &= ~(1ul << j);
|
||||
page_number = i * HOST_LONG_BITS + j;
|
||||
page_number = (i * HOST_LONG_BITS + j) * hpratio;
|
||||
addr1 = page_number * TARGET_PAGE_SIZE;
|
||||
addr = section->offset_within_region + addr1;
|
||||
memory_region_set_dirty(section->mr, addr, TARGET_PAGE_SIZE);
|
||||
memory_region_set_dirty(section->mr, addr,
|
||||
TARGET_PAGE_SIZE * hpratio);
|
||||
} while (c != 0);
|
||||
}
|
||||
}
|
||||
@@ -980,6 +982,14 @@ int kvm_init(void)
|
||||
|
||||
s = g_malloc0(sizeof(KVMState));
|
||||
|
||||
/*
|
||||
* On systems where the kernel can support different base page
|
||||
* sizes, host page size may be different from TARGET_PAGE_SIZE,
|
||||
* even with KVM. TARGET_PAGE_SIZE is assumed to be the minimum
|
||||
* page size for the system though.
|
||||
*/
|
||||
assert(TARGET_PAGE_SIZE <= getpagesize());
|
||||
|
||||
#ifdef KVM_CAP_SET_GUEST_DEBUG
|
||||
QTAILQ_INIT(&s->kvm_sw_breakpoints);
|
||||
#endif
|
||||
|
@@ -573,6 +573,7 @@ abi_long target_mmap(abi_ulong start, abi_ulong len, int prot,
|
||||
page_dump(stdout);
|
||||
printf("\n");
|
||||
#endif
|
||||
tb_invalidate_phys_range(start, start + len, 0);
|
||||
mmap_unlock();
|
||||
return start;
|
||||
fail:
|
||||
@@ -675,8 +676,10 @@ int target_munmap(abi_ulong start, abi_ulong len)
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
if (ret == 0) {
|
||||
page_set_flags(start, start + len, 0);
|
||||
tb_invalidate_phys_range(start, start + len, 0);
|
||||
}
|
||||
mmap_unlock();
|
||||
return ret;
|
||||
}
|
||||
@@ -754,6 +757,7 @@ abi_long target_mremap(abi_ulong old_addr, abi_ulong old_size,
|
||||
page_set_flags(old_addr, old_addr + old_size, 0);
|
||||
page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
|
||||
}
|
||||
tb_invalidate_phys_range(new_addr, new_addr + new_size, 0);
|
||||
mmap_unlock();
|
||||
return new_addr;
|
||||
}
|
||||
|
@@ -25,11 +25,7 @@
|
||||
#ifndef QEMU_MAIN_LOOP_H
|
||||
#define QEMU_MAIN_LOOP_H 1
|
||||
|
||||
#ifdef SIGRTMIN
|
||||
#define SIG_IPI (SIGRTMIN+4)
|
||||
#else
|
||||
#define SIG_IPI SIGUSR1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* qemu_init_main_loop: Set up the process so that it can run the main loop.
|
||||
|
@@ -79,45 +79,32 @@ static void tcp_wait_for_connect(void *opaque)
|
||||
}
|
||||
}
|
||||
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port)
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
|
||||
Error **errp)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int ret;
|
||||
|
||||
ret = parse_host_port(&addr, host_port);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
s->get_error = socket_errno;
|
||||
s->write = socket_write;
|
||||
s->close = tcp_close;
|
||||
|
||||
s->fd = qemu_socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (s->fd == -1) {
|
||||
DPRINTF("Unable to open socket");
|
||||
return -socket_error();
|
||||
}
|
||||
s->fd = inet_connect(host_port, false, errp);
|
||||
|
||||
socket_set_nonblock(s->fd);
|
||||
|
||||
do {
|
||||
ret = connect(s->fd, (struct sockaddr *)&addr, sizeof(addr));
|
||||
if (ret == -1) {
|
||||
ret = -socket_error();
|
||||
}
|
||||
if (ret == -EINPROGRESS || ret == -EWOULDBLOCK) {
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
|
||||
return 0;
|
||||
}
|
||||
} while (ret == -EINTR);
|
||||
|
||||
if (ret < 0) {
|
||||
if (!error_is_set(errp)) {
|
||||
migrate_fd_connect(s);
|
||||
} else if (error_is_type(*errp, QERR_SOCKET_CONNECT_IN_PROGRESS)) {
|
||||
DPRINTF("connect in progress\n");
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s);
|
||||
} else if (error_is_type(*errp, QERR_SOCKET_CREATE_FAILED)) {
|
||||
DPRINTF("connect failed\n");
|
||||
return -1;
|
||||
} else if (error_is_type(*errp, QERR_SOCKET_CONNECT_FAILED)) {
|
||||
DPRINTF("connect failed\n");
|
||||
migrate_fd_error(s);
|
||||
return ret;
|
||||
return -1;
|
||||
} else {
|
||||
DPRINTF("unknown error\n");
|
||||
return -1;
|
||||
}
|
||||
migrate_fd_connect(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -155,40 +142,18 @@ out2:
|
||||
close(s);
|
||||
}
|
||||
|
||||
int tcp_start_incoming_migration(const char *host_port)
|
||||
int tcp_start_incoming_migration(const char *host_port, Error **errp)
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
int val;
|
||||
int s;
|
||||
|
||||
DPRINTF("Attempting to start an incoming migration\n");
|
||||
s = inet_listen(host_port, NULL, 256, SOCK_STREAM, 0, errp);
|
||||
|
||||
if (parse_host_port(&addr, host_port) < 0) {
|
||||
fprintf(stderr, "invalid host/port combination: %s\n", host_port);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
s = qemu_socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (s == -1) {
|
||||
return -socket_error();
|
||||
}
|
||||
|
||||
val = 1;
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
|
||||
|
||||
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
goto err;
|
||||
}
|
||||
if (listen(s, 1) == -1) {
|
||||
goto err;
|
||||
if (s < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
qemu_set_fd_handler2(s, NULL, tcp_accept_incoming_migration, NULL,
|
||||
(void *)(intptr_t)s);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
close(s);
|
||||
return -socket_error();
|
||||
}
|
||||
|
14
migration.c
14
migration.c
@@ -60,13 +60,13 @@ static MigrationState *migrate_get_current(void)
|
||||
return ¤t_migration;
|
||||
}
|
||||
|
||||
int qemu_start_incoming_migration(const char *uri)
|
||||
int qemu_start_incoming_migration(const char *uri, Error **errp)
|
||||
{
|
||||
const char *p;
|
||||
int ret;
|
||||
|
||||
if (strstart(uri, "tcp:", &p))
|
||||
ret = tcp_start_incoming_migration(p);
|
||||
ret = tcp_start_incoming_migration(p, errp);
|
||||
#if !defined(WIN32)
|
||||
else if (strstart(uri, "exec:", &p))
|
||||
ret = exec_start_incoming_migration(p);
|
||||
@@ -414,7 +414,7 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
|
||||
s = migrate_init(blk, inc);
|
||||
|
||||
if (strstart(uri, "tcp:", &p)) {
|
||||
ret = tcp_start_outgoing_migration(s, p);
|
||||
ret = tcp_start_outgoing_migration(s, p, errp);
|
||||
#if !defined(WIN32)
|
||||
} else if (strstart(uri, "exec:", &p)) {
|
||||
ret = exec_start_outgoing_migration(s, p);
|
||||
@@ -429,9 +429,11 @@ void qmp_migrate(const char *uri, bool has_blk, bool blk,
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
DPRINTF("migration failed: %s\n", strerror(-ret));
|
||||
/* FIXME: we should return meaningful errors */
|
||||
error_set(errp, QERR_UNDEFINED_ERROR);
|
||||
if (!error_is_set(errp)) {
|
||||
DPRINTF("migration failed: %s\n", strerror(-ret));
|
||||
/* FIXME: we should return meaningful errors */
|
||||
error_set(errp, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -37,7 +37,7 @@ struct MigrationState
|
||||
|
||||
void process_incoming_migration(QEMUFile *f);
|
||||
|
||||
int qemu_start_incoming_migration(const char *uri);
|
||||
int qemu_start_incoming_migration(const char *uri, Error **errp);
|
||||
|
||||
uint64_t migrate_max_downtime(void);
|
||||
|
||||
@@ -49,9 +49,10 @@ int exec_start_incoming_migration(const char *host_port);
|
||||
|
||||
int exec_start_outgoing_migration(MigrationState *s, const char *host_port);
|
||||
|
||||
int tcp_start_incoming_migration(const char *host_port);
|
||||
int tcp_start_incoming_migration(const char *host_port, Error **errp);
|
||||
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port);
|
||||
int tcp_start_outgoing_migration(MigrationState *s, const char *host_port,
|
||||
Error **errp);
|
||||
|
||||
int unix_start_incoming_migration(const char *path);
|
||||
|
||||
|
4
nbd.c
4
nbd.c
@@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port)
|
||||
|
||||
int tcp_socket_outgoing_spec(const char *address_and_port)
|
||||
{
|
||||
return inet_connect(address_and_port, SOCK_STREAM);
|
||||
return inet_connect(address_and_port, true, NULL);
|
||||
}
|
||||
|
||||
int tcp_socket_incoming(const char *address, uint16_t port)
|
||||
@@ -176,7 +176,7 @@ int tcp_socket_incoming_spec(const char *address_and_port)
|
||||
{
|
||||
char *ostr = NULL;
|
||||
int olen = 0;
|
||||
return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0);
|
||||
return inet_listen(address_and_port, ostr, olen, SOCK_STREAM, 0, NULL);
|
||||
}
|
||||
|
||||
int unix_socket_incoming(const char *path)
|
||||
|
@@ -12,7 +12,7 @@
|
||||
1275-1994 (referred to as Open Firmware) compliant firmware.
|
||||
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
|
||||
Sparc32 and Sparc64 are built from OpenBIOS SVN revision
|
||||
1056.
|
||||
1060.
|
||||
|
||||
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
|
||||
implementation for certain IBM POWER hardware. The sources are at
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -18,7 +18,7 @@
|
||||
# lexer/tokenizer/parser state should be flushed/reset in
|
||||
# preparation for reliably receiving the subsequent response. As
|
||||
# an optimization, clients may opt to ignore all data until a
|
||||
# sentinel value is receiving to avoid unecessary processing of
|
||||
# sentinel value is receiving to avoid unnecessary processing of
|
||||
# stale data.
|
||||
#
|
||||
# Similarly, clients should also precede this *request*
|
||||
@@ -126,16 +126,19 @@
|
||||
# @guest-shutdown:
|
||||
#
|
||||
# Initiate guest-activated shutdown. Note: this is an asynchronous
|
||||
# shutdown request, with no guaruntee of successful shutdown. Errors
|
||||
# will be logged to guest's syslog.
|
||||
# shutdown request, with no guarantee of successful shutdown.
|
||||
#
|
||||
# @mode: #optional "halt", "powerdown" (default), or "reboot"
|
||||
#
|
||||
# Returns: Nothing on success
|
||||
# This command does NOT return a response on success. Success condition
|
||||
# is indicated by the VM exiting with a zero exit status or, when
|
||||
# running with --no-shutdown, by issuing the query-status QMP command
|
||||
# to confirm the VM status is "shutdown".
|
||||
#
|
||||
# Since: 0.15.0
|
||||
##
|
||||
{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' } }
|
||||
{ 'command': 'guest-shutdown', 'data': { '*mode': 'str' },
|
||||
'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @guest-file-open:
|
||||
@@ -359,17 +362,21 @@
|
||||
# For the best results it's strongly recommended to have the pm-utils
|
||||
# package installed in the guest.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# This command does NOT return a response on success. There is a high chance
|
||||
# the command succeeded if the VM exits with a zero exit status or, when
|
||||
# running with --no-shutdown, by issuing the query-status QMP command to
|
||||
# to confirm the VM status is "shutdown". However, the VM could also exit
|
||||
# (or set its status to "shutdown") due to other reasons.
|
||||
#
|
||||
# The following errors may be returned:
|
||||
# If suspend to disk is not supported, Unsupported
|
||||
#
|
||||
# Notes: o This is an asynchronous request. There's no guarantee a response
|
||||
# will be sent
|
||||
# o It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
# Notes: It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-suspend-disk' }
|
||||
{ 'command': 'guest-suspend-disk', 'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @guest-suspend-ram
|
||||
@@ -387,17 +394,21 @@
|
||||
# command. Thus, it's *required* to query QEMU for the presence of the
|
||||
# 'system_wakeup' command before issuing guest-suspend-ram.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# This command does NOT return a response on success. There are two options
|
||||
# to check for success:
|
||||
# 1. Wait for the SUSPEND QMP event from QEMU
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# The following errors may be returned:
|
||||
# If suspend to ram is not supported, Unsupported
|
||||
#
|
||||
# Notes: o This is an asynchronous request. There's no guarantee a response
|
||||
# will be sent
|
||||
# o It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
# Notes: It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-suspend-ram' }
|
||||
{ 'command': 'guest-suspend-ram', 'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @guest-suspend-hybrid
|
||||
@@ -410,17 +421,21 @@
|
||||
# command. Thus, it's *required* to query QEMU for the presence of the
|
||||
# 'system_wakeup' command before issuing guest-suspend-hybrid.
|
||||
#
|
||||
# Returns: nothing on success
|
||||
# This command does NOT return a response on success. There are two options
|
||||
# to check for success:
|
||||
# 1. Wait for the SUSPEND QMP event from QEMU
|
||||
# 2. Issue the query-status QMP command to confirm the VM status is
|
||||
# "suspended"
|
||||
#
|
||||
# The following errors may be returned:
|
||||
# If hybrid suspend is not supported, Unsupported
|
||||
#
|
||||
# Notes: o This is an asynchronous request. There's no guarantee a response
|
||||
# will be sent
|
||||
# o It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
# Notes: It's strongly recommended to issue the guest-sync command before
|
||||
# sending commands when the guest resumes
|
||||
#
|
||||
# Since: 1.1
|
||||
##
|
||||
{ 'command': 'guest-suspend-hybrid' }
|
||||
{ 'command': 'guest-suspend-hybrid', 'success-response': 'no' }
|
||||
|
||||
##
|
||||
# @GuestIpAddressType:
|
||||
|
@@ -25,16 +25,24 @@ typedef enum QmpCommandType
|
||||
QCT_NORMAL,
|
||||
} QmpCommandType;
|
||||
|
||||
typedef enum QmpCommandOptions
|
||||
{
|
||||
QCO_NO_OPTIONS = 0x0,
|
||||
QCO_NO_SUCCESS_RESP = 0x1,
|
||||
} QmpCommandOptions;
|
||||
|
||||
typedef struct QmpCommand
|
||||
{
|
||||
const char *name;
|
||||
QmpCommandType type;
|
||||
QmpCommandFunc *fn;
|
||||
QmpCommandOptions options;
|
||||
QTAILQ_ENTRY(QmpCommand) node;
|
||||
bool enabled;
|
||||
} QmpCommand;
|
||||
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn);
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn,
|
||||
QmpCommandOptions options);
|
||||
QmpCommand *qmp_find_command(const char *name);
|
||||
QObject *qmp_dispatch(QObject *request);
|
||||
void qmp_disable_command(const char *name);
|
||||
|
@@ -94,8 +94,12 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
|
||||
switch (cmd->type) {
|
||||
case QCT_NORMAL:
|
||||
cmd->fn(args, &ret, errp);
|
||||
if (!error_is_set(errp) && ret == NULL) {
|
||||
ret = QOBJECT(qdict_new());
|
||||
if (!error_is_set(errp)) {
|
||||
if (cmd->options & QCO_NO_SUCCESS_RESP) {
|
||||
g_assert(!ret);
|
||||
} else if (!ret) {
|
||||
ret = QOBJECT(qdict_new());
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@@ -246,13 +246,18 @@ static void qmp_input_type_number(Visitor *v, double *obj, const char *name,
|
||||
QmpInputVisitor *qiv = to_qiv(v);
|
||||
QObject *qobj = qmp_input_get_object(qiv, name);
|
||||
|
||||
if (!qobj || qobject_type(qobj) != QTYPE_QFLOAT) {
|
||||
if (!qobj || (qobject_type(qobj) != QTYPE_QFLOAT &&
|
||||
qobject_type(qobj) != QTYPE_QINT)) {
|
||||
error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null",
|
||||
"double");
|
||||
"number");
|
||||
return;
|
||||
}
|
||||
|
||||
*obj = qfloat_get_double(qobject_to_qfloat(qobj));
|
||||
if (qobject_type(qobj) == QTYPE_QINT) {
|
||||
*obj = qint_get_int(qobject_to_qint(qobj));
|
||||
} else {
|
||||
*obj = qfloat_get_double(qobject_to_qfloat(qobj));
|
||||
}
|
||||
}
|
||||
|
||||
static void qmp_input_start_optional(Visitor *v, bool *present,
|
||||
|
@@ -17,7 +17,8 @@
|
||||
static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands =
|
||||
QTAILQ_HEAD_INITIALIZER(qmp_commands);
|
||||
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn)
|
||||
void qmp_register_command(const char *name, QmpCommandFunc *fn,
|
||||
QmpCommandOptions options)
|
||||
{
|
||||
QmpCommand *cmd = g_malloc0(sizeof(*cmd));
|
||||
|
||||
@@ -25,6 +26,7 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn)
|
||||
cmd->type = QCT_NORMAL;
|
||||
cmd->fn = fn;
|
||||
cmd->enabled = true;
|
||||
cmd->options = options;
|
||||
QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
|
||||
}
|
||||
|
||||
|
@@ -2444,9 +2444,9 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
|
||||
}
|
||||
} else {
|
||||
if (is_listen) {
|
||||
fd = inet_listen_opts(opts, 0);
|
||||
fd = inet_listen_opts(opts, 0, NULL);
|
||||
} else {
|
||||
fd = inet_connect_opts(opts);
|
||||
fd = inet_connect_opts(opts, NULL);
|
||||
}
|
||||
}
|
||||
if (fd < 0) {
|
||||
|
@@ -61,6 +61,9 @@ typedef struct Monitor Monitor;
|
||||
#if !defined(ENOTSUP)
|
||||
#define ENOTSUP 4096
|
||||
#endif
|
||||
#if !defined(ECANCELED)
|
||||
#define ECANCELED 4097
|
||||
#endif
|
||||
#ifndef TIME_MAX
|
||||
#define TIME_MAX LONG_MAX
|
||||
#endif
|
||||
|
@@ -16,4 +16,8 @@ int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname);
|
||||
|
||||
int qemu_read_config_file(const char *filename);
|
||||
|
||||
/* Read default Qemu config files
|
||||
*/
|
||||
int qemu_read_default_config_files(bool userconfig);
|
||||
|
||||
#endif /* QEMU_CONFIG_H */
|
||||
|
@@ -227,15 +227,15 @@ QEMU uses GUS emulation (GUSEMU32 @url{http://www.deinmeister.de/gusemu/})
|
||||
by Tibor "TS" Schütz.
|
||||
|
||||
Note that, by default, GUS shares IRQ(7) with parallel ports and so
|
||||
qemu must be told to not have parallel ports to have working GUS
|
||||
QEMU must be told to not have parallel ports to have working GUS.
|
||||
|
||||
@example
|
||||
qemu dos.img -soundhw gus -parallel none
|
||||
qemu-system-i386 dos.img -soundhw gus -parallel none
|
||||
@end example
|
||||
|
||||
Alternatively:
|
||||
@example
|
||||
qemu dos.img -device gus,irq=5
|
||||
qemu-system-i386 dos.img -device gus,irq=5
|
||||
@end example
|
||||
|
||||
Or some other unclaimed IRQ.
|
||||
@@ -251,7 +251,7 @@ CS4231A is the chip used in Windows Sound System and GUSMAX products
|
||||
Download and uncompress the linux image (@file{linux.img}) and type:
|
||||
|
||||
@example
|
||||
qemu linux.img
|
||||
qemu-system-i386 linux.img
|
||||
@end example
|
||||
|
||||
Linux should boot and give you a prompt.
|
||||
@@ -261,7 +261,7 @@ Linux should boot and give you a prompt.
|
||||
|
||||
@example
|
||||
@c man begin SYNOPSIS
|
||||
usage: qemu [options] [@var{disk_image}]
|
||||
usage: qemu-system-i386 [options] [@var{disk_image}]
|
||||
@c man end
|
||||
@end example
|
||||
|
||||
@@ -575,7 +575,7 @@ QEMU can automatically create a virtual FAT disk image from a
|
||||
directory tree. In order to use it, just type:
|
||||
|
||||
@example
|
||||
qemu linux.img -hdb fat:/my_directory
|
||||
qemu-system-i386 linux.img -hdb fat:/my_directory
|
||||
@end example
|
||||
|
||||
Then you access access to all the files in the @file{/my_directory}
|
||||
@@ -585,14 +585,14 @@ them via SAMBA or NFS. The default access is @emph{read-only}.
|
||||
Floppies can be emulated with the @code{:floppy:} option:
|
||||
|
||||
@example
|
||||
qemu linux.img -fda fat:floppy:/my_directory
|
||||
qemu-system-i386 linux.img -fda fat:floppy:/my_directory
|
||||
@end example
|
||||
|
||||
A read/write support is available for testing (beta stage) with the
|
||||
@code{:rw:} option:
|
||||
|
||||
@example
|
||||
qemu linux.img -fda fat:floppy:rw:/my_directory
|
||||
qemu-system-i386 linux.img -fda fat:floppy:rw:/my_directory
|
||||
@end example
|
||||
|
||||
What you should @emph{never} do:
|
||||
@@ -610,14 +610,14 @@ QEMU can access directly to block device exported using the Network Block Device
|
||||
protocol.
|
||||
|
||||
@example
|
||||
qemu linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
|
||||
qemu-system-i386 linux.img -hdb nbd:my_nbd_server.mydomain.org:1024
|
||||
@end example
|
||||
|
||||
If the NBD server is located on the same host, you can use an unix socket instead
|
||||
of an inet socket:
|
||||
|
||||
@example
|
||||
qemu linux.img -hdb nbd:unix:/tmp/my_socket
|
||||
qemu-system-i386 linux.img -hdb nbd:unix:/tmp/my_socket
|
||||
@end example
|
||||
|
||||
In this case, the block device must be exported using qemu-nbd:
|
||||
@@ -633,15 +633,15 @@ qemu-nbd --socket=/tmp/my_socket --share=2 my_disk.qcow2
|
||||
|
||||
and then you can use it with two guests:
|
||||
@example
|
||||
qemu linux1.img -hdb nbd:unix:/tmp/my_socket
|
||||
qemu linux2.img -hdb nbd:unix:/tmp/my_socket
|
||||
qemu-system-i386 linux1.img -hdb nbd:unix:/tmp/my_socket
|
||||
qemu-system-i386 linux2.img -hdb nbd:unix:/tmp/my_socket
|
||||
@end example
|
||||
|
||||
If the nbd-server uses named exports (since NBD 2.9.18), you must use the
|
||||
"exportname" option:
|
||||
@example
|
||||
qemu -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
|
||||
qemu -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
|
||||
qemu-system-i386 -cdrom nbd:localhost:exportname=debian-500-ppc-netinst
|
||||
qemu-system-i386 -cdrom nbd:localhost:exportname=openSUSE-11.1-ppc-netinst
|
||||
@end example
|
||||
|
||||
@node disk_images_sheepdog
|
||||
@@ -666,7 +666,7 @@ qemu-img convert @var{filename} sheepdog:@var{image}
|
||||
|
||||
You can boot from the Sheepdog disk image with the command:
|
||||
@example
|
||||
qemu sheepdog:@var{image}
|
||||
qemu-system-i386 sheepdog:@var{image}
|
||||
@end example
|
||||
|
||||
You can also create a snapshot of the Sheepdog image like qcow2.
|
||||
@@ -678,7 +678,7 @@ where @var{tag} is a tag name of the newly created snapshot.
|
||||
To boot from the Sheepdog snapshot, specify the tag name of the
|
||||
snapshot.
|
||||
@example
|
||||
qemu sheepdog:@var{image}:@var{tag}
|
||||
qemu-system-i386 sheepdog:@var{image}:@var{tag}
|
||||
@end example
|
||||
|
||||
You can create a cloned image from the existing snapshot.
|
||||
@@ -692,7 +692,7 @@ If the Sheepdog daemon doesn't run on the local host, you need to
|
||||
specify one of the Sheepdog servers to connect to.
|
||||
@example
|
||||
qemu-img create sheepdog:@var{hostname}:@var{port}:@var{image} @var{size}
|
||||
qemu sheepdog:@var{hostname}:@var{port}:@var{image}
|
||||
qemu-system-i386 sheepdog:@var{hostname}:@var{port}:@var{image}
|
||||
@end example
|
||||
|
||||
@node disk_images_iscsi
|
||||
@@ -899,7 +899,7 @@ zero-copy communication to the application level of the guests. The basic
|
||||
syntax is:
|
||||
|
||||
@example
|
||||
qemu -device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
|
||||
qemu-system-i386 -device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
|
||||
@end example
|
||||
|
||||
If desired, interrupts can be sent between guest VMs accessing the same shared
|
||||
@@ -909,9 +909,9 @@ is qemu.git/contrib/ivshmem-server. An example syntax when using the shared
|
||||
memory server is:
|
||||
|
||||
@example
|
||||
qemu -device ivshmem,size=<size in format accepted by -m>[,chardev=<id>]
|
||||
[,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
|
||||
qemu -chardev socket,path=<path>,id=<id>
|
||||
qemu-system-i386 -device ivshmem,size=<size in format accepted by -m>[,chardev=<id>]
|
||||
[,msi=on][,ioeventfd=on][,vectors=n][,role=peer|master]
|
||||
qemu-system-i386 -chardev socket,path=<path>,id=<id>
|
||||
@end example
|
||||
|
||||
When using the server, the guest will be assigned a VM ID (>=0) that allows guests
|
||||
@@ -941,7 +941,7 @@ kernel testing.
|
||||
|
||||
The syntax is:
|
||||
@example
|
||||
qemu -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda"
|
||||
qemu-system-i386 -kernel arch/i386/boot/bzImage -hda root-2.4.20.img -append "root=/dev/hda"
|
||||
@end example
|
||||
|
||||
Use @option{-kernel} to provide the Linux kernel image and
|
||||
@@ -956,8 +956,8 @@ If you do not need graphical output, you can disable it and redirect
|
||||
the virtual serial port and the QEMU monitor to the console with the
|
||||
@option{-nographic} option. The typical command line is:
|
||||
@example
|
||||
qemu -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
|
||||
-append "root=/dev/hda console=ttyS0" -nographic
|
||||
qemu-system-i386 -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
|
||||
-append "root=/dev/hda console=ttyS0" -nographic
|
||||
@end example
|
||||
|
||||
Use @key{Ctrl-a c} to switch between the serial console and the
|
||||
@@ -986,7 +986,7 @@ or the @code{usb_add} monitor command. Available devices are:
|
||||
Virtual Mouse. This will override the PS/2 mouse emulation when activated.
|
||||
@item tablet
|
||||
Pointer device that uses absolute coordinates (like a touchscreen).
|
||||
This means qemu is able to report the mouse position without having
|
||||
This means QEMU is able to report the mouse position without having
|
||||
to grab the mouse. Also overrides the PS/2 mouse emulation when activated.
|
||||
@item disk:@var{file}
|
||||
Mass storage device based on @var{file} (@pxref{disk_images})
|
||||
@@ -1020,7 +1020,7 @@ Network adapter that supports CDC ethernet and RNDIS protocols. @var{options}
|
||||
specifies NIC options as with @code{-net nic,}@var{options} (see description).
|
||||
For instance, user-mode networking can be used with
|
||||
@example
|
||||
qemu [...OPTIONS...] -net user,vlan=0 -usbdevice net:vlan=0
|
||||
qemu-system-i386 [...OPTIONS...] -net user,vlan=0 -usbdevice net:vlan=0
|
||||
@end example
|
||||
Currently this cannot be used in machines that support PCI NICs.
|
||||
@item bt[:@var{hci-type}]
|
||||
@@ -1030,7 +1030,7 @@ no type is given, the HCI logic corresponds to @code{-bt hci,vlan=0}.
|
||||
This USB device implements the USB Transport Layer of HCI. Example
|
||||
usage:
|
||||
@example
|
||||
qemu [...OPTIONS...] -usbdevice bt:hci,vlan=3 -bt device:keyboard,vlan=3
|
||||
qemu-system-i386 [...OPTIONS...] -usbdevice bt:hci,vlan=3 -bt device:keyboard,vlan=3
|
||||
@end example
|
||||
@end table
|
||||
|
||||
@@ -1108,7 +1108,7 @@ For this setup it is recommended to restrict it to listen on a UNIX domain
|
||||
socket only. For example
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc
|
||||
qemu-system-i386 [...OPTIONS...] -vnc unix:/home/joebloggs/.qemu-myvm-vnc
|
||||
@end example
|
||||
|
||||
This ensures that only users on local box with read/write access to that
|
||||
@@ -1129,7 +1129,7 @@ option, and then once QEMU is running the password is set with the monitor. Unti
|
||||
the monitor is used to set the password all clients will be rejected.
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc :1,password -monitor stdio
|
||||
qemu-system-i386 [...OPTIONS...] -vnc :1,password -monitor stdio
|
||||
(qemu) change vnc password
|
||||
Password: ********
|
||||
(qemu)
|
||||
@@ -1146,7 +1146,7 @@ support provides a secure session, but no authentication. This allows any
|
||||
client to connect, and provides an encrypted session.
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc :1,tls,x509=/etc/pki/qemu -monitor stdio
|
||||
qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509=/etc/pki/qemu -monitor stdio
|
||||
@end example
|
||||
|
||||
In the above example @code{/etc/pki/qemu} should contain at least three files,
|
||||
@@ -1164,7 +1164,7 @@ then validate against the CA certificate. This is a good choice if deploying
|
||||
in an environment with a private internal certificate authority.
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc :1,tls,x509verify=/etc/pki/qemu -monitor stdio
|
||||
qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509verify=/etc/pki/qemu -monitor stdio
|
||||
@end example
|
||||
|
||||
|
||||
@@ -1175,7 +1175,7 @@ Finally, the previous method can be combined with VNC password authentication
|
||||
to provide two layers of authentication for clients.
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc :1,password,tls,x509verify=/etc/pki/qemu -monitor stdio
|
||||
qemu-system-i386 [...OPTIONS...] -vnc :1,password,tls,x509verify=/etc/pki/qemu -monitor stdio
|
||||
(qemu) change vnc password
|
||||
Password: ********
|
||||
(qemu)
|
||||
@@ -1198,7 +1198,7 @@ used for authentication, but assuming use of one supporting SSF,
|
||||
then QEMU can be launched with:
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc :1,sasl -monitor stdio
|
||||
qemu-system-i386 [...OPTIONS...] -vnc :1,sasl -monitor stdio
|
||||
@end example
|
||||
|
||||
@node vnc_sec_certificate_sasl
|
||||
@@ -1212,7 +1212,7 @@ credentials. This can be enabled, by combining the 'sasl' option
|
||||
with the aforementioned TLS + x509 options:
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio
|
||||
qemu-system-i386 [...OPTIONS...] -vnc :1,tls,x509,sasl -monitor stdio
|
||||
@end example
|
||||
|
||||
|
||||
@@ -1377,11 +1377,11 @@ use TLS and x509 certificates to protect security credentials from snooping.
|
||||
QEMU has a primitive support to work with gdb, so that you can do
|
||||
'Ctrl-C' while the virtual machine is running and inspect its state.
|
||||
|
||||
In order to use gdb, launch qemu with the '-s' option. It will wait for a
|
||||
In order to use gdb, launch QEMU with the '-s' option. It will wait for a
|
||||
gdb connection:
|
||||
@example
|
||||
> qemu -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
|
||||
-append "root=/dev/hda"
|
||||
qemu-system-i386 -s -kernel arch/i386/boot/bzImage -hda root-2.4.20.img \
|
||||
-append "root=/dev/hda"
|
||||
Connected to host network interface: tun0
|
||||
Waiting gdb connection on port 1234
|
||||
@end example
|
||||
@@ -2313,8 +2313,8 @@ qemu-i386 -L / /bin/ls
|
||||
@code{-L /} tells that the x86 dynamic linker must be searched with a
|
||||
@file{/} prefix.
|
||||
|
||||
@item Since QEMU is also a linux process, you can launch qemu with
|
||||
qemu (NOTE: you can only do that if you compiled QEMU from the sources):
|
||||
@item Since QEMU is also a linux process, you can launch QEMU with
|
||||
QEMU (NOTE: you can only do that if you compiled QEMU from the sources):
|
||||
|
||||
@example
|
||||
qemu-i386 -L / qemu-i386 -L / /bin/ls
|
||||
@@ -2669,7 +2669,8 @@ installation directory.
|
||||
|
||||
@end itemize
|
||||
|
||||
Wine can be used to launch the resulting qemu.exe compiled for Win32.
|
||||
Wine can be used to launch the resulting qemu-system-i386.exe
|
||||
and all other qemu-system-@var{target}.exe compiled for Win32.
|
||||
|
||||
@node Mac OS X
|
||||
@section Mac OS X
|
||||
|
51
qemu-ga.c
51
qemu-ga.c
@@ -104,16 +104,9 @@ static void quit_handler(int sig)
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* reap _all_ terminated children */
|
||||
static void child_handler(int sig)
|
||||
{
|
||||
int status;
|
||||
while (waitpid(-1, &status, WNOHANG) > 0) /* NOTHING */;
|
||||
}
|
||||
|
||||
static gboolean register_signal_handlers(void)
|
||||
{
|
||||
struct sigaction sigact, sigact_chld;
|
||||
struct sigaction sigact;
|
||||
int ret;
|
||||
|
||||
memset(&sigact, 0, sizeof(struct sigaction));
|
||||
@@ -130,15 +123,24 @@ static gboolean register_signal_handlers(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&sigact_chld, 0, sizeof(struct sigaction));
|
||||
sigact_chld.sa_handler = child_handler;
|
||||
sigact_chld.sa_flags = SA_NOCLDSTOP;
|
||||
ret = sigaction(SIGCHLD, &sigact_chld, NULL);
|
||||
if (ret == -1) {
|
||||
g_error("error configuring signal handler: %s", strerror(errno));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO: use this in place of all post-fork() fclose(std*) callers */
|
||||
void reopen_fd_to_null(int fd)
|
||||
{
|
||||
int nullfd;
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
if (nullfd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
return true;
|
||||
dup2(nullfd, fd);
|
||||
|
||||
if (nullfd != fd) {
|
||||
close(nullfd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -167,7 +169,7 @@ static void usage(const char *cmd)
|
||||
" -h, --help display this help and exit\n"
|
||||
"\n"
|
||||
"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
|
||||
, cmd, QGA_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT,
|
||||
, cmd, QEMU_VERSION, QGA_VIRTIO_PATH_DEFAULT, QGA_PIDFILE_DEFAULT,
|
||||
QGA_STATEDIR_DEFAULT);
|
||||
}
|
||||
|
||||
@@ -304,7 +306,7 @@ static void ga_disable_non_whitelisted(void)
|
||||
g_free(list_head);
|
||||
}
|
||||
|
||||
/* [re-]enable all commands, except those explictly blacklisted by user */
|
||||
/* [re-]enable all commands, except those explicitly blacklisted by user */
|
||||
static void ga_enable_non_blacklisted(GList *blacklist)
|
||||
{
|
||||
char **list_head, **list;
|
||||
@@ -428,9 +430,9 @@ static void become_daemon(const char *pidfile)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
reopen_fd_to_null(STDIN_FILENO);
|
||||
reopen_fd_to_null(STDOUT_FILENO);
|
||||
reopen_fd_to_null(STDERR_FILENO);
|
||||
return;
|
||||
|
||||
fail:
|
||||
@@ -488,8 +490,6 @@ static void process_command(GAState *s, QDict *req)
|
||||
g_warning("error sending response: %s", strerror(ret));
|
||||
}
|
||||
qobject_decref(rsp);
|
||||
} else {
|
||||
g_warning("error getting response");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -729,7 +729,7 @@ int main(int argc, char **argv)
|
||||
log_level = G_LOG_LEVEL_MASK;
|
||||
break;
|
||||
case 'V':
|
||||
printf("QEMU Guest Agent %s\n", QGA_VERSION);
|
||||
printf("QEMU Guest Agent %s\n", QEMU_VERSION);
|
||||
return 0;
|
||||
case 'd':
|
||||
daemonize = 1;
|
||||
@@ -836,12 +836,13 @@ int main(int argc, char **argv)
|
||||
become_daemon(pid_filepath);
|
||||
}
|
||||
if (log_filepath) {
|
||||
s->log_file = fopen(log_filepath, "a");
|
||||
if (!s->log_file) {
|
||||
FILE *log_file = fopen(log_filepath, "a");
|
||||
if (!log_file) {
|
||||
g_critical("unable to open specified log file: %s",
|
||||
strerror(errno));
|
||||
goto out_bad;
|
||||
}
|
||||
s->log_file = log_file;
|
||||
}
|
||||
}
|
||||
|
||||
|
16
qemu-img.c
16
qemu-img.c
@@ -712,6 +712,9 @@ static int img_convert(int argc, char **argv)
|
||||
|
||||
out_filename = argv[argc - 1];
|
||||
|
||||
/* Initialize before goto out */
|
||||
qemu_progress_init(progress, 2.0);
|
||||
|
||||
if (options && !strcmp(options, "?")) {
|
||||
ret = print_block_option_help(out_filename, out_fmt);
|
||||
goto out;
|
||||
@@ -724,7 +727,6 @@ static int img_convert(int argc, char **argv)
|
||||
goto out;
|
||||
}
|
||||
|
||||
qemu_progress_init(progress, 2.0);
|
||||
qemu_progress_print(0, 100);
|
||||
|
||||
bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
|
||||
@@ -1138,11 +1140,13 @@ static int img_info(int argc, char **argv)
|
||||
}
|
||||
bdrv_get_backing_filename(bs, backing_filename, sizeof(backing_filename));
|
||||
if (backing_filename[0] != '\0') {
|
||||
path_combine(backing_filename2, sizeof(backing_filename2),
|
||||
filename, backing_filename);
|
||||
printf("backing file: %s (actual path: %s)\n",
|
||||
backing_filename,
|
||||
backing_filename2);
|
||||
bdrv_get_full_backing_filename(bs, backing_filename2,
|
||||
sizeof(backing_filename2));
|
||||
printf("backing file: %s", backing_filename);
|
||||
if (strcmp(backing_filename, backing_filename2) != 0) {
|
||||
printf(" (actual path: %s)", backing_filename2);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
dump_snapshots(bs);
|
||||
bdrv_delete(bs);
|
||||
|
@@ -159,6 +159,24 @@ It can be used without an accessible old backing file, i.e. you can use it to
|
||||
fix an image whose backing file has already been moved/renamed.
|
||||
@end table
|
||||
|
||||
You can use @code{rebase} to perform a ``diff'' operation on two
|
||||
disk images. This can be useful when you have copied or cloned
|
||||
a guest, and you want to get back to a thin image on top of a
|
||||
template or base image.
|
||||
|
||||
Say that @code{base.img} has been cloned as @code{modified.img} by
|
||||
copying it, and that the @code{modified.img} guest has run so there
|
||||
are now some changes compared to @code{base.img}. To construct a thin
|
||||
image called @code{diff.qcow2} that contains just the differences, do:
|
||||
|
||||
@example
|
||||
qemu-img create -f qcow2 -b modified.img diff.qcow2
|
||||
qemu-img rebase -b base.img diff.qcow2
|
||||
@end example
|
||||
|
||||
At this point, @code{modified.img} can be discarded, since
|
||||
@code{base.img + diff.qcow2} contains the same information.
|
||||
|
||||
@item resize @var{filename} [+ | -]@var{size}
|
||||
|
||||
Change the disk image as if it had been created with @var{size}.
|
||||
|
10
qemu-io.c
10
qemu-io.c
@@ -1560,7 +1560,7 @@ out:
|
||||
|
||||
static int alloc_f(int argc, char **argv)
|
||||
{
|
||||
int64_t offset;
|
||||
int64_t offset, sector_num;
|
||||
int nb_sectors, remaining;
|
||||
char s1[64];
|
||||
int num, sum_alloc;
|
||||
@@ -1581,12 +1581,18 @@ static int alloc_f(int argc, char **argv)
|
||||
|
||||
remaining = nb_sectors;
|
||||
sum_alloc = 0;
|
||||
sector_num = offset >> 9;
|
||||
while (remaining) {
|
||||
ret = bdrv_is_allocated(bs, offset >> 9, nb_sectors, &num);
|
||||
ret = bdrv_is_allocated(bs, sector_num, remaining, &num);
|
||||
sector_num += num;
|
||||
remaining -= num;
|
||||
if (ret) {
|
||||
sum_alloc += num;
|
||||
}
|
||||
if (num == 0) {
|
||||
nb_sectors -= remaining;
|
||||
remaining = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cvtstr(offset, s1, sizeof(s1));
|
||||
|
171
qemu-options.hx
171
qemu-options.hx
@@ -221,7 +221,7 @@ qcow2. If performance is more important than correctness,
|
||||
@option{cache=writeback} should be used with qcow2.
|
||||
|
||||
In case you don't care about data integrity over host failures, use
|
||||
cache=unsafe. This option tells qemu that it never needs to write any data
|
||||
cache=unsafe. This option tells QEMU that it never needs to write any data
|
||||
to the disk but can instead keeps things in cache. If anything goes wrong,
|
||||
like your host losing power, the disk storage getting disconnected accidentally,
|
||||
etc. you're image will most probably be rendered unusable. When using
|
||||
@@ -233,47 +233,47 @@ is off.
|
||||
|
||||
Instead of @option{-cdrom} you can use:
|
||||
@example
|
||||
qemu -drive file=file,index=2,media=cdrom
|
||||
qemu-system-i386 -drive file=file,index=2,media=cdrom
|
||||
@end example
|
||||
|
||||
Instead of @option{-hda}, @option{-hdb}, @option{-hdc}, @option{-hdd}, you can
|
||||
use:
|
||||
@example
|
||||
qemu -drive file=file,index=0,media=disk
|
||||
qemu -drive file=file,index=1,media=disk
|
||||
qemu -drive file=file,index=2,media=disk
|
||||
qemu -drive file=file,index=3,media=disk
|
||||
qemu-system-i386 -drive file=file,index=0,media=disk
|
||||
qemu-system-i386 -drive file=file,index=1,media=disk
|
||||
qemu-system-i386 -drive file=file,index=2,media=disk
|
||||
qemu-system-i386 -drive file=file,index=3,media=disk
|
||||
@end example
|
||||
|
||||
You can connect a CDROM to the slave of ide0:
|
||||
@example
|
||||
qemu -drive file=file,if=ide,index=1,media=cdrom
|
||||
qemu-system-i386 -drive file=file,if=ide,index=1,media=cdrom
|
||||
@end example
|
||||
|
||||
If you don't specify the "file=" argument, you define an empty drive:
|
||||
@example
|
||||
qemu -drive if=ide,index=1,media=cdrom
|
||||
qemu-system-i386 -drive if=ide,index=1,media=cdrom
|
||||
@end example
|
||||
|
||||
You can connect a SCSI disk with unit ID 6 on the bus #0:
|
||||
@example
|
||||
qemu -drive file=file,if=scsi,bus=0,unit=6
|
||||
qemu-system-i386 -drive file=file,if=scsi,bus=0,unit=6
|
||||
@end example
|
||||
|
||||
Instead of @option{-fda}, @option{-fdb}, you can use:
|
||||
@example
|
||||
qemu -drive file=file,index=0,if=floppy
|
||||
qemu -drive file=file,index=1,if=floppy
|
||||
qemu-system-i386 -drive file=file,index=0,if=floppy
|
||||
qemu-system-i386 -drive file=file,index=1,if=floppy
|
||||
@end example
|
||||
|
||||
By default, @var{interface} is "ide" and @var{index} is automatically
|
||||
incremented:
|
||||
@example
|
||||
qemu -drive file=a -drive file=b"
|
||||
qemu-system-i386 -drive file=a -drive file=b"
|
||||
@end example
|
||||
is interpreted like:
|
||||
@example
|
||||
qemu -hda a -hdb b
|
||||
qemu-system-i386 -hda a -hdb b
|
||||
@end example
|
||||
ETEXI
|
||||
|
||||
@@ -297,7 +297,7 @@ STEXI
|
||||
Set default value of @var{driver}'s property @var{prop} to @var{value}, e.g.:
|
||||
|
||||
@example
|
||||
qemu -global ide-drive.physical_block_size=4096 -drive file=file,if=ide,index=0,media=disk
|
||||
qemu-system-i386 -global ide-drive.physical_block_size=4096 -drive file=file,if=ide,index=0,media=disk
|
||||
@end example
|
||||
|
||||
In particular, you can use this to set driver properties for devices which are
|
||||
@@ -359,11 +359,11 @@ the recommended is 320x240, 640x480, 800x640.
|
||||
|
||||
@example
|
||||
# try to boot from network first, then from hard disk
|
||||
qemu -boot order=nc
|
||||
qemu-system-i386 -boot order=nc
|
||||
# boot from CD-ROM first, switch back to default order after reboot
|
||||
qemu -boot once=d
|
||||
qemu-system-i386 -boot once=d
|
||||
# boot with a splash picture for 5 seconds.
|
||||
qemu -boot menu=on,splash=/root/boot.bmp,splash-time=5000
|
||||
qemu-system-i386 -boot menu=on,splash=/root/boot.bmp,splash-time=5000
|
||||
@end example
|
||||
|
||||
Note: The legacy format '-boot @var{drives}' is still supported but its
|
||||
@@ -454,12 +454,12 @@ Enable audio and selected sound hardware. Use ? to print all
|
||||
available sound hardware.
|
||||
|
||||
@example
|
||||
qemu -soundhw sb16,adlib disk.img
|
||||
qemu -soundhw es1370 disk.img
|
||||
qemu -soundhw ac97 disk.img
|
||||
qemu -soundhw hda disk.img
|
||||
qemu -soundhw all disk.img
|
||||
qemu -soundhw ?
|
||||
qemu-system-i386 -soundhw sb16,adlib disk.img
|
||||
qemu-system-i386 -soundhw es1370 disk.img
|
||||
qemu-system-i386 -soundhw ac97 disk.img
|
||||
qemu-system-i386 -soundhw hda disk.img
|
||||
qemu-system-i386 -soundhw all disk.img
|
||||
qemu-system-i386 -soundhw ?
|
||||
@end example
|
||||
|
||||
Note that Linux's i810_audio OSS kernel (for AC97) module might
|
||||
@@ -515,7 +515,7 @@ Virtual Mouse. This will override the PS/2 mouse emulation when activated.
|
||||
|
||||
@item tablet
|
||||
Pointer device that uses absolute coordinates (like a touchscreen). This
|
||||
means qemu is able to report the mouse position without having to grab the
|
||||
means QEMU is able to report the mouse position without having to grab the
|
||||
mouse. Also overrides the PS/2 mouse emulation when activated.
|
||||
|
||||
@item disk:[format=@var{format}]:@var{file}
|
||||
@@ -587,7 +587,7 @@ this path will be available to the 9p client on the guest.
|
||||
Specifies the security model to be used for this export path.
|
||||
Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none".
|
||||
In "passthrough" security model, files are stored using the same
|
||||
credentials as they are created on the guest. This requires qemu
|
||||
credentials as they are created on the guest. This requires QEMU
|
||||
to run as root. In "mapped-xattr" security model, some of the file
|
||||
attributes like uid, gid, mode bits and link target are stored as
|
||||
file attributes. For "mapped-file" these attributes are stored in the
|
||||
@@ -654,7 +654,7 @@ this path will be available to the 9p client on the guest.
|
||||
Specifies the security model to be used for this export path.
|
||||
Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none".
|
||||
In "passthrough" security model, files are stored using the same
|
||||
credentials as they are created on the guest. This requires qemu
|
||||
credentials as they are created on the guest. This requires QEMU
|
||||
to run as root. In "mapped-xattr" security model, some of the file
|
||||
attributes like uid, gid, mode bits and link target are stored as
|
||||
file attributes. For "mapped-file" these attributes are stored in the
|
||||
@@ -1117,7 +1117,7 @@ disables exclusive client access. Useful for shared desktop sessions,
|
||||
where you don't want someone forgetting specify -shared disconnect
|
||||
everybody else. 'ignore' completely ignores the shared flag and
|
||||
allows everybody connect unconditionally. Doesn't conform to the rfb
|
||||
spec but is traditional qemu behavior.
|
||||
spec but is traditional QEMU behavior.
|
||||
|
||||
@end table
|
||||
ETEXI
|
||||
@@ -1368,7 +1368,7 @@ a guest from a local directory.
|
||||
|
||||
Example (using pxelinux):
|
||||
@example
|
||||
qemu -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0
|
||||
qemu-system-i386 -hda linux.img -boot n -net user,tftp=/path/to/tftp/files,bootfile=/pxelinux.0
|
||||
@end example
|
||||
|
||||
@item smb=@var{dir}[,smbserver=@var{addr}]
|
||||
@@ -1403,7 +1403,7 @@ screen 0, use the following:
|
||||
|
||||
@example
|
||||
# on the host
|
||||
qemu -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...]
|
||||
qemu-system-i386 -net user,hostfwd=tcp:127.0.0.1:6001-:6000 [...]
|
||||
# this host xterm should open in the guest X11 server
|
||||
xterm -display :1
|
||||
@end example
|
||||
@@ -1413,7 +1413,7 @@ the guest, use the following:
|
||||
|
||||
@example
|
||||
# on the host
|
||||
qemu -net user,hostfwd=tcp::5555-:23 [...]
|
||||
qemu-system-i386 -net user,hostfwd=tcp::5555-:23 [...]
|
||||
telnet localhost 5555
|
||||
@end example
|
||||
|
||||
@@ -1452,20 +1452,22 @@ Examples:
|
||||
|
||||
@example
|
||||
#launch a QEMU instance with the default network script
|
||||
qemu linux.img -net nic -net tap
|
||||
qemu-system-i386 linux.img -net nic -net tap
|
||||
@end example
|
||||
|
||||
@example
|
||||
#launch a QEMU instance with two NICs, each one connected
|
||||
#to a TAP device
|
||||
qemu linux.img -net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
|
||||
-net nic,vlan=1 -net tap,vlan=1,ifname=tap1
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,vlan=0 -net tap,vlan=0,ifname=tap0 \
|
||||
-net nic,vlan=1 -net tap,vlan=1,ifname=tap1
|
||||
@end example
|
||||
|
||||
@example
|
||||
#launch a QEMU instance with the default network helper to
|
||||
#connect a TAP device to bridge br0
|
||||
qemu linux.img -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper"
|
||||
@end example
|
||||
|
||||
@item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}]
|
||||
@@ -1481,13 +1483,13 @@ Examples:
|
||||
@example
|
||||
#launch a QEMU instance with the default network helper to
|
||||
#connect a TAP device to bridge br0
|
||||
qemu linux.img -net bridge -net nic,model=virtio
|
||||
qemu-system-i386 linux.img -net bridge -net nic,model=virtio
|
||||
@end example
|
||||
|
||||
@example
|
||||
#launch a QEMU instance with the default network helper to
|
||||
#connect a TAP device to bridge qemubr0
|
||||
qemu linux.img -net bridge,br=qemubr0 -net nic,model=virtio
|
||||
qemu-system-i386 linux.img -net bridge,br=qemubr0 -net nic,model=virtio
|
||||
@end example
|
||||
|
||||
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}]
|
||||
@@ -1502,12 +1504,14 @@ specifies an already opened TCP socket.
|
||||
Example:
|
||||
@example
|
||||
# launch a first QEMU instance
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,listen=:1234
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,listen=:1234
|
||||
# connect the VLAN 0 of this instance to the VLAN 0
|
||||
# of the first instance
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
|
||||
-net socket,connect=127.0.0.1:1234
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:57 \
|
||||
-net socket,connect=127.0.0.1:1234
|
||||
@end example
|
||||
|
||||
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
|
||||
@@ -1530,30 +1534,35 @@ Use @option{fd=h} to specify an already opened UDP multicast socket.
|
||||
Example:
|
||||
@example
|
||||
# launch one QEMU instance
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,mcast=230.0.0.1:1234
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,mcast=230.0.0.1:1234
|
||||
# launch another QEMU instance on same "bus"
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
|
||||
-net socket,mcast=230.0.0.1:1234
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:57 \
|
||||
-net socket,mcast=230.0.0.1:1234
|
||||
# launch yet another QEMU instance on same "bus"
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:58 \
|
||||
-net socket,mcast=230.0.0.1:1234
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:58 \
|
||||
-net socket,mcast=230.0.0.1:1234
|
||||
@end example
|
||||
|
||||
Example (User Mode Linux compat.):
|
||||
@example
|
||||
# launch QEMU instance (note mcast address selected
|
||||
# is UML's default)
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,mcast=239.192.168.1:1102
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,mcast=239.192.168.1:1102
|
||||
# launch UML
|
||||
/path/to/linux ubd0=/path/to/root_fs eth0=mcast
|
||||
@end example
|
||||
|
||||
Example (send packets from host's 1.2.3.4):
|
||||
@example
|
||||
qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
|
||||
qemu-system-i386 linux.img \
|
||||
-net nic,macaddr=52:54:00:12:34:56 \
|
||||
-net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
|
||||
@end example
|
||||
|
||||
@item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
|
||||
@@ -1568,7 +1577,7 @@ Example:
|
||||
# launch vde switch
|
||||
vde_switch -F -sock /tmp/myswitch
|
||||
# launch QEMU instance
|
||||
qemu linux.img -net nic -net vde,sock=/tmp/myswitch
|
||||
qemu-system-i386 linux.img -net nic -net vde,sock=/tmp/myswitch
|
||||
@end example
|
||||
|
||||
@item -net dump[,vlan=@var{n}][,file=@var{file}][,len=@var{len}]
|
||||
@@ -1791,7 +1800,7 @@ not take any options.
|
||||
@option{pty} is not available on Windows hosts.
|
||||
|
||||
@item -chardev stdio ,id=@var{id} [,signal=on|off]
|
||||
Connect to standard input and standard output of the qemu process.
|
||||
Connect to standard input and standard output of the QEMU process.
|
||||
|
||||
@option{signal} controls if signals are enabled on the terminal, that includes
|
||||
exiting QEMU with the key sequence @key{Control-c}. This option is enabled by
|
||||
@@ -1853,21 +1862,21 @@ Syntax for specifying iSCSI LUNs is
|
||||
|
||||
Example (without authentication):
|
||||
@example
|
||||
qemu -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
|
||||
-cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
|
||||
-drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
|
||||
qemu-system-i386 -iscsi initiator-name=iqn.2001-04.com.example:my-initiator \
|
||||
-cdrom iscsi://192.0.2.1/iqn.2001-04.com.example/2 \
|
||||
-drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
|
||||
@end example
|
||||
|
||||
Example (CHAP username/password via URL):
|
||||
@example
|
||||
qemu -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
|
||||
qemu-system-i386 -drive file=iscsi://user%password@@192.0.2.1/iqn.2001-04.com.example/1
|
||||
@end example
|
||||
|
||||
Example (CHAP username/password via environment variables):
|
||||
@example
|
||||
LIBISCSI_CHAP_USERNAME="user" \
|
||||
LIBISCSI_CHAP_PASSWORD="password" \
|
||||
qemu -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
|
||||
qemu-system-i386 -drive file=iscsi://192.0.2.1/iqn.2001-04.com.example/1
|
||||
@end example
|
||||
|
||||
iSCSI support is an optional feature of QEMU and only available when
|
||||
@@ -1893,12 +1902,12 @@ Syntax for specifying a NBD device using Unix Domain Sockets
|
||||
|
||||
Example for TCP
|
||||
@example
|
||||
qemu --drive file=nbd:192.0.2.1:30000
|
||||
qemu-system-i386 --drive file=nbd:192.0.2.1:30000
|
||||
@end example
|
||||
|
||||
Example for Unix Domain Sockets
|
||||
@example
|
||||
qemu --drive file=nbd:unix:/tmp/nbd-socket
|
||||
qemu-system-i386 --drive file=nbd:unix:/tmp/nbd-socket
|
||||
@end example
|
||||
|
||||
@item Sheepdog
|
||||
@@ -1923,7 +1932,7 @@ Syntax for specifying a sheepdog device
|
||||
|
||||
Example
|
||||
@example
|
||||
qemu --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine
|
||||
qemu-system-i386 --drive file=sheepdog:192.0.2.1:30000:MyVirtualMachine
|
||||
@end example
|
||||
|
||||
See also @url{http://http://www.osrg.net/sheepdog/}.
|
||||
@@ -1986,7 +1995,7 @@ and communicate. Requires the Linux @code{vhci} driver installed. Can
|
||||
be used as following:
|
||||
|
||||
@example
|
||||
qemu [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5
|
||||
qemu-system-i386 [...OPTIONS...] -bt hci,vlan=5 -bt vhci,vlan=5
|
||||
@end example
|
||||
|
||||
@item -bt device:@var{dev}[,vlan=@var{n}]
|
||||
@@ -2119,19 +2128,19 @@ they default to @code{0.0.0.0}.
|
||||
When not using a specified @var{src_port} a random port is automatically chosen.
|
||||
|
||||
If you just want a simple readonly console you can use @code{netcat} or
|
||||
@code{nc}, by starting qemu with: @code{-serial udp::4555} and nc as:
|
||||
@code{nc -u -l -p 4555}. Any time qemu writes something to that port it
|
||||
@code{nc}, by starting QEMU with: @code{-serial udp::4555} and nc as:
|
||||
@code{nc -u -l -p 4555}. Any time QEMU writes something to that port it
|
||||
will appear in the netconsole session.
|
||||
|
||||
If you plan to send characters back via netconsole or you want to stop
|
||||
and start qemu a lot of times, you should have qemu use the same
|
||||
and start QEMU a lot of times, you should have QEMU use the same
|
||||
source port each time by using something like @code{-serial
|
||||
udp::4555@@:4556} to qemu. Another approach is to use a patched
|
||||
udp::4555@@:4556} to QEMU. Another approach is to use a patched
|
||||
version of netcat which can listen to a TCP port and send and receive
|
||||
characters via udp. If you have a patched version of netcat which
|
||||
activates telnet remote echo and single char transfer, then you can
|
||||
use the following options to step up a netcat redirector to allow
|
||||
telnet on port 5555 to access the qemu port.
|
||||
telnet on port 5555 to access the QEMU port.
|
||||
@table @code
|
||||
@item QEMU Options:
|
||||
-serial udp::4555@@:4556
|
||||
@@ -2286,10 +2295,10 @@ STEXI
|
||||
@findex -gdb
|
||||
Wait for gdb connection on device @var{dev} (@pxref{gdb_usage}). Typical
|
||||
connections will likely be TCP-based, but also UDP, pseudo TTY, or even
|
||||
stdio are reasonable use case. The latter is allowing to start qemu from
|
||||
stdio are reasonable use case. The latter is allowing to start QEMU from
|
||||
within gdb and establish the connection via a pipe:
|
||||
@example
|
||||
(gdb) target remote | exec qemu -gdb stdio ...
|
||||
(gdb) target remote | exec qemu-system-i386 -gdb stdio ...
|
||||
@end example
|
||||
ETEXI
|
||||
|
||||
@@ -2316,15 +2325,15 @@ DEF("D", HAS_ARG, QEMU_OPTION_D, \
|
||||
"-D logfile output log to logfile (instead of the default /tmp/qemu.log)\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -D
|
||||
@item -D @var{logfile}
|
||||
@findex -D
|
||||
Output log in logfile instead of /tmp/qemu.log
|
||||
Output log in @var{logfile} instead of /tmp/qemu.log
|
||||
ETEXI
|
||||
|
||||
DEF("hdachs", HAS_ARG, QEMU_OPTION_hdachs, \
|
||||
"-hdachs c,h,s[,t]\n" \
|
||||
" force hard disk 0 physical geometry and the optional BIOS\n" \
|
||||
" translation (t=none or lba) (usually qemu can guess them)\n",
|
||||
" translation (t=none or lba) (usually QEMU can guess them)\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -hdachs @var{c},@var{h},@var{s},[,@var{t}]
|
||||
@@ -2370,7 +2379,7 @@ DEF("xen-create", 0, QEMU_OPTION_xen_create,
|
||||
QEMU_ARCH_ALL)
|
||||
DEF("xen-attach", 0, QEMU_OPTION_xen_attach,
|
||||
"-xen-attach attach to existing xen domain\n"
|
||||
" xend will use this when starting qemu\n",
|
||||
" xend will use this when starting QEMU\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -xen-domid @var{id}
|
||||
@@ -2383,7 +2392,7 @@ Warning: should not be used when xend is in use (XEN only).
|
||||
@item -xen-attach
|
||||
@findex -xen-attach
|
||||
Attach to existing xen domain.
|
||||
xend will use this when starting qemu (XEN only).
|
||||
xend will use this when starting QEMU (XEN only).
|
||||
ETEXI
|
||||
|
||||
DEF("no-reboot", 0, QEMU_OPTION_no_reboot, \
|
||||
@@ -2685,9 +2694,19 @@ DEF("nodefconfig", 0, QEMU_OPTION_nodefconfig,
|
||||
STEXI
|
||||
@item -nodefconfig
|
||||
@findex -nodefconfig
|
||||
Normally QEMU loads a configuration file from @var{sysconfdir}/qemu.conf and
|
||||
@var{sysconfdir}/target-@var{ARCH}.conf on startup. The @code{-nodefconfig}
|
||||
option will prevent QEMU from loading these configuration files at startup.
|
||||
Normally QEMU loads configuration files from @var{sysconfdir} and @var{datadir} at startup.
|
||||
The @code{-nodefconfig} option will prevent QEMU from loading any of those config files.
|
||||
ETEXI
|
||||
DEF("no-user-config", 0, QEMU_OPTION_nouserconfig,
|
||||
"-no-user-config\n"
|
||||
" do not load user-provided config files at startup\n",
|
||||
QEMU_ARCH_ALL)
|
||||
STEXI
|
||||
@item -no-user-config
|
||||
@findex -no-user-config
|
||||
The @code{-no-user-config} option makes QEMU not load any of the user-provided
|
||||
config files on @var{sysconfdir}, but won't make it skip the QEMU-provided config
|
||||
files from @var{datadir}.
|
||||
ETEXI
|
||||
DEF("trace", HAS_ARG, QEMU_OPTION_trace,
|
||||
"-trace [events=<file>][,file=<file>]\n"
|
||||
|
@@ -51,6 +51,9 @@ static QemuOptsList dummy_opts = {
|
||||
},{
|
||||
.name = "ipv6",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "block",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{ /* end if list */ }
|
||||
},
|
||||
@@ -100,7 +103,7 @@ const char *inet_strfamily(int family)
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
|
||||
{
|
||||
struct addrinfo ai,*res,*e;
|
||||
const char *addr;
|
||||
@@ -117,6 +120,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
if ((qemu_opt_get(opts, "host") == NULL) ||
|
||||
(qemu_opt_get(opts, "port") == NULL)) {
|
||||
fprintf(stderr, "%s: host and/or port not specified\n", __FUNCTION__);
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
|
||||
@@ -135,6 +139,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
if (rc != 0) {
|
||||
fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
|
||||
gai_strerror(rc));
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -147,6 +152,9 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
if (slisten < 0) {
|
||||
fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__,
|
||||
inet_strfamily(e->ai_family), strerror(errno));
|
||||
if (!e->ai_next) {
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -170,6 +178,9 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
fprintf(stderr,"%s: bind(%s,%s,%d): %s\n", __FUNCTION__,
|
||||
inet_strfamily(e->ai_family), uaddr, inet_getport(e),
|
||||
strerror(errno));
|
||||
if (!e->ai_next) {
|
||||
error_set(errp, QERR_SOCKET_BIND_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
closesocket(slisten);
|
||||
@@ -180,6 +191,7 @@ int inet_listen_opts(QemuOpts *opts, int port_offset)
|
||||
|
||||
listen:
|
||||
if (listen(slisten,1) != 0) {
|
||||
error_set(errp, QERR_SOCKET_LISTEN_FAILED);
|
||||
perror("listen");
|
||||
closesocket(slisten);
|
||||
freeaddrinfo(res);
|
||||
@@ -194,7 +206,7 @@ listen:
|
||||
return slisten;
|
||||
}
|
||||
|
||||
int inet_connect_opts(QemuOpts *opts)
|
||||
int inet_connect_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
struct addrinfo ai,*res,*e;
|
||||
const char *addr;
|
||||
@@ -202,6 +214,7 @@ int inet_connect_opts(QemuOpts *opts)
|
||||
char uaddr[INET6_ADDRSTRLEN+1];
|
||||
char uport[33];
|
||||
int sock,rc;
|
||||
bool block;
|
||||
|
||||
memset(&ai,0, sizeof(ai));
|
||||
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
||||
@@ -210,8 +223,10 @@ int inet_connect_opts(QemuOpts *opts)
|
||||
|
||||
addr = qemu_opt_get(opts, "host");
|
||||
port = qemu_opt_get(opts, "port");
|
||||
block = qemu_opt_get_bool(opts, "block", 0);
|
||||
if (addr == NULL || port == NULL) {
|
||||
fprintf(stderr, "inet_connect: host and/or port not specified\n");
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -224,6 +239,7 @@ int inet_connect_opts(QemuOpts *opts)
|
||||
if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) {
|
||||
fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port,
|
||||
gai_strerror(rc));
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -241,19 +257,37 @@ int inet_connect_opts(QemuOpts *opts)
|
||||
continue;
|
||||
}
|
||||
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
|
||||
|
||||
if (!block) {
|
||||
socket_set_nonblock(sock);
|
||||
}
|
||||
/* connect to peer */
|
||||
if (connect(sock,e->ai_addr,e->ai_addrlen) < 0) {
|
||||
do {
|
||||
rc = 0;
|
||||
if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) {
|
||||
rc = -socket_error();
|
||||
}
|
||||
} while (rc == -EINTR);
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK
|
||||
|| rc == -WSAEALREADY)) {
|
||||
#else
|
||||
if (!block && (rc == -EINPROGRESS)) {
|
||||
#endif
|
||||
error_set(errp, QERR_SOCKET_CONNECT_IN_PROGRESS);
|
||||
} else if (rc < 0) {
|
||||
if (NULL == e->ai_next)
|
||||
fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__,
|
||||
inet_strfamily(e->ai_family),
|
||||
e->ai_canonname, uaddr, uport, strerror(errno));
|
||||
closesocket(sock);
|
||||
sock = -1;
|
||||
continue;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
return sock;
|
||||
}
|
||||
error_set(errp, QERR_SOCKET_CONNECT_FAILED);
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
}
|
||||
@@ -421,7 +455,7 @@ static int inet_parse(QemuOpts *opts, const char *str)
|
||||
}
|
||||
|
||||
int inet_listen(const char *str, char *ostr, int olen,
|
||||
int socktype, int port_offset)
|
||||
int socktype, int port_offset, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
char *optstr;
|
||||
@@ -429,7 +463,7 @@ int inet_listen(const char *str, char *ostr, int olen,
|
||||
|
||||
opts = qemu_opts_create(&dummy_opts, NULL, 0);
|
||||
if (inet_parse(opts, str) == 0) {
|
||||
sock = inet_listen_opts(opts, port_offset);
|
||||
sock = inet_listen_opts(opts, port_offset, errp);
|
||||
if (sock != -1 && ostr) {
|
||||
optstr = strchr(str, ',');
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
|
||||
@@ -444,19 +478,27 @@ int inet_listen(const char *str, char *ostr, int olen,
|
||||
optstr ? optstr : "");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return sock;
|
||||
}
|
||||
|
||||
int inet_connect(const char *str, int socktype)
|
||||
int inet_connect(const char *str, bool block, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock = -1;
|
||||
|
||||
opts = qemu_opts_create(&dummy_opts, NULL, 0);
|
||||
if (inet_parse(opts, str) == 0)
|
||||
sock = inet_connect_opts(opts);
|
||||
if (inet_parse(opts, str) == 0) {
|
||||
if (block) {
|
||||
qemu_opt_set(opts, "block", "on");
|
||||
}
|
||||
sock = inet_connect_opts(opts, errp);
|
||||
} else {
|
||||
error_set(errp, QERR_SOCKET_CREATE_FAILED);
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return sock;
|
||||
}
|
||||
|
@@ -635,8 +635,7 @@ static int mm_start_timer(struct qemu_alarm_timer *t)
|
||||
TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
|
||||
|
||||
if (!mm_timer) {
|
||||
fprintf(stderr, "Failed to initialize win32 alarm timer: %ld\n",
|
||||
GetLastError());
|
||||
fprintf(stderr, "Failed to initialize win32 alarm timer\n");
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
return -1;
|
||||
}
|
||||
@@ -667,9 +666,7 @@ static void mm_rearm_timer(struct qemu_alarm_timer *t, int64_t delta)
|
||||
TIME_ONESHOT | TIME_CALLBACK_FUNCTION);
|
||||
|
||||
if (!mm_timer) {
|
||||
fprintf(stderr, "Failed to re-arm win32 alarm timer %ld\n",
|
||||
GetLastError());
|
||||
|
||||
fprintf(stderr, "Failed to re-arm win32 alarm timer\n");
|
||||
timeEndPeriod(mm_tc.wPeriodMin);
|
||||
exit(1);
|
||||
}
|
||||
|
@@ -27,6 +27,8 @@ int inet_aton(const char *cp, struct in_addr *ia);
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
#include "qemu-option.h"
|
||||
#include "error.h"
|
||||
#include "qerror.h"
|
||||
|
||||
/* misc helpers */
|
||||
int qemu_socket(int domain, int type, int protocol);
|
||||
@@ -37,11 +39,11 @@ void socket_set_nonblock(int fd);
|
||||
int send_all(int fd, const void *buf, int len1);
|
||||
|
||||
/* New, ipv6-ready socket helper functions, see qemu-sockets.c */
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset);
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp);
|
||||
int inet_listen(const char *str, char *ostr, int olen,
|
||||
int socktype, int port_offset);
|
||||
int inet_connect_opts(QemuOpts *opts);
|
||||
int inet_connect(const char *str, int socktype);
|
||||
int socktype, int port_offset, Error **errp);
|
||||
int inet_connect_opts(QemuOpts *opts, Error **errp);
|
||||
int inet_connect(const char *str, bool block, Error **errp);
|
||||
int inet_dgram_opts(QemuOpts *opts);
|
||||
const char *inet_strfamily(int family);
|
||||
|
||||
|
20
qerror.c
20
qerror.c
@@ -304,6 +304,26 @@ static const QErrorStringTable qerror_table[] = {
|
||||
.error_fmt = QERR_VNC_SERVER_FAILED,
|
||||
.desc = "Could not start VNC server on %(target)",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_SOCKET_CONNECT_IN_PROGRESS,
|
||||
.desc = "Connection can not be completed immediately",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_SOCKET_CONNECT_FAILED,
|
||||
.desc = "Failed to connect to socket",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_SOCKET_LISTEN_FAILED,
|
||||
.desc = "Failed to set socket to listening mode",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_SOCKET_BIND_FAILED,
|
||||
.desc = "Failed to bind socket",
|
||||
},
|
||||
{
|
||||
.error_fmt = QERR_SOCKET_CREATE_FAILED,
|
||||
.desc = "Failed to create socket",
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
15
qerror.h
15
qerror.h
@@ -248,4 +248,19 @@ QError *qobject_to_qerror(const QObject *obj);
|
||||
#define QERR_VNC_SERVER_FAILED \
|
||||
"{ 'class': 'VNCServerFailed', 'data': { 'target': %s } }"
|
||||
|
||||
#define QERR_SOCKET_CONNECT_IN_PROGRESS \
|
||||
"{ 'class': 'SockConnectInprogress', 'data': {} }"
|
||||
|
||||
#define QERR_SOCKET_CONNECT_FAILED \
|
||||
"{ 'class': 'SockConnectFailed', 'data': {} }"
|
||||
|
||||
#define QERR_SOCKET_LISTEN_FAILED \
|
||||
"{ 'class': 'SockListenFailed', 'data': {} }"
|
||||
|
||||
#define QERR_SOCKET_BIND_FAILED \
|
||||
"{ 'class': 'SockBindFailed', 'data': {} }"
|
||||
|
||||
#define QERR_SOCKET_CREATE_FAILED \
|
||||
"{ 'class': 'SockCreateFailed', 'data': {} }"
|
||||
|
||||
#endif /* QERROR_H */
|
||||
|
@@ -14,12 +14,22 @@
|
||||
#include <glib.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/wait.h>
|
||||
#include "qga/guest-agent-core.h"
|
||||
#include "qga-qmp-commands.h"
|
||||
#include "qerror.h"
|
||||
#include "qemu-queue.h"
|
||||
#include "host-utils.h"
|
||||
|
||||
#ifndef CONFIG_HAS_ENVIRON
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
extern char **environ;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <mntent.h>
|
||||
#include <linux/fs.h>
|
||||
@@ -27,36 +37,17 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#if defined(__linux__) && defined(FIFREEZE)
|
||||
#define CONFIG_FSFREEZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
/* TODO: use this in place of all post-fork() fclose(std*) callers */
|
||||
static void reopen_fd_to_null(int fd)
|
||||
{
|
||||
int nullfd;
|
||||
|
||||
nullfd = open("/dev/null", O_RDWR);
|
||||
if (nullfd < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
dup2(nullfd, fd);
|
||||
|
||||
if (nullfd != fd) {
|
||||
close(nullfd);
|
||||
}
|
||||
}
|
||||
#endif /* defined(__linux__) */
|
||||
|
||||
void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
||||
{
|
||||
int ret;
|
||||
const char *shutdown_flag;
|
||||
pid_t rpid, pid;
|
||||
int status;
|
||||
|
||||
slog("guest-shutdown called, mode: %s", mode);
|
||||
if (!has_mode || strcmp(mode, "powerdown") == 0) {
|
||||
@@ -71,23 +62,30 @@ void qmp_guest_shutdown(bool has_mode, const char *mode, Error **err)
|
||||
return;
|
||||
}
|
||||
|
||||
ret = fork();
|
||||
if (ret == 0) {
|
||||
pid = fork();
|
||||
if (pid == 0) {
|
||||
/* child, start the shutdown */
|
||||
setsid();
|
||||
fclose(stdin);
|
||||
fclose(stdout);
|
||||
fclose(stderr);
|
||||
reopen_fd_to_null(0);
|
||||
reopen_fd_to_null(1);
|
||||
reopen_fd_to_null(2);
|
||||
|
||||
ret = execl("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
|
||||
"hypervisor initiated shutdown", (char*)NULL);
|
||||
if (ret) {
|
||||
slog("guest-shutdown failed: %s", strerror(errno));
|
||||
}
|
||||
exit(!!ret);
|
||||
} else if (ret < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
execle("/sbin/shutdown", "shutdown", shutdown_flag, "+0",
|
||||
"hypervisor initiated shutdown", (char*)NULL, environ);
|
||||
_exit(EXIT_FAILURE);
|
||||
} else if (pid < 0) {
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
do {
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
} while (rpid == -1 && errno == EINTR);
|
||||
if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
exit_err:
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
|
||||
typedef struct GuestFileHandle {
|
||||
@@ -347,7 +345,7 @@ static int guest_fsfreeze_build_mount_list(GuestFsfreezeMountList *mounts)
|
||||
{
|
||||
struct mntent *ment;
|
||||
GuestFsfreezeMount *mount;
|
||||
char const *mtab = MOUNTED;
|
||||
char const *mtab = "/proc/self/mounts";
|
||||
FILE *fp;
|
||||
|
||||
fp = setmntent(mtab, "r");
|
||||
@@ -487,7 +485,7 @@ int64_t qmp_guest_fsfreeze_thaw(Error **err)
|
||||
* was returned the filesystem was *not* unfrozen by that particular
|
||||
* call.
|
||||
*
|
||||
* since multiple preceeding FIFREEZEs require multiple calls to FITHAW
|
||||
* since multiple preceding FIFREEZEs require multiple calls to FITHAW
|
||||
* to unfreeze, continuing issuing FITHAW until an error is returned,
|
||||
* in which case either the filesystem is in an unfreezable state, or,
|
||||
* more likely, it was thawed previously (and remains so afterward).
|
||||
@@ -531,117 +529,88 @@ static void guest_fsfreeze_cleanup(void)
|
||||
#define SUSPEND_SUPPORTED 0
|
||||
#define SUSPEND_NOT_SUPPORTED 1
|
||||
|
||||
/**
|
||||
* This function forks twice and the information about the mode support
|
||||
* status is passed to the qemu-ga process via a pipe.
|
||||
*
|
||||
* This approach allows us to keep the way we reap terminated children
|
||||
* in qemu-ga quite simple.
|
||||
*/
|
||||
static void bios_supports_mode(const char *pmutils_bin, const char *pmutils_arg,
|
||||
const char *sysfile_str, Error **err)
|
||||
{
|
||||
pid_t pid;
|
||||
ssize_t ret;
|
||||
char *pmutils_path;
|
||||
int status, pipefds[2];
|
||||
|
||||
if (pipe(pipefds) < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
return;
|
||||
}
|
||||
pid_t pid, rpid;
|
||||
int status;
|
||||
|
||||
pmutils_path = g_find_program_in_path(pmutils_bin);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
struct sigaction act;
|
||||
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_handler = SIG_DFL;
|
||||
sigaction(SIGCHLD, &act, NULL);
|
||||
char buf[32]; /* hopefully big enough */
|
||||
ssize_t ret;
|
||||
int fd;
|
||||
|
||||
setsid();
|
||||
close(pipefds[0]);
|
||||
reopen_fd_to_null(0);
|
||||
reopen_fd_to_null(1);
|
||||
reopen_fd_to_null(2);
|
||||
|
||||
pid = fork();
|
||||
if (!pid) {
|
||||
int fd;
|
||||
char buf[32]; /* hopefully big enough */
|
||||
if (pmutils_path) {
|
||||
execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
|
||||
}
|
||||
|
||||
if (pmutils_path) {
|
||||
execle(pmutils_path, pmutils_bin, pmutils_arg, NULL, environ);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get here either pm-utils is not installed or execle() has
|
||||
* failed. Let's try the manual method if the caller wants it.
|
||||
*/
|
||||
|
||||
if (!sysfile_str) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
ret = read(fd, buf, sizeof(buf)-1);
|
||||
if (ret <= 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
buf[ret] = '\0';
|
||||
|
||||
if (strstr(buf, sysfile_str)) {
|
||||
_exit(SUSPEND_SUPPORTED);
|
||||
}
|
||||
/*
|
||||
* If we get here either pm-utils is not installed or execle() has
|
||||
* failed. Let's try the manual method if the caller wants it.
|
||||
*/
|
||||
|
||||
if (!sysfile_str) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
if (pid > 0) {
|
||||
wait(&status);
|
||||
} else {
|
||||
status = SUSPEND_NOT_SUPPORTED;
|
||||
fd = open(LINUX_SYS_STATE_FILE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
ret = write(pipefds[1], &status, sizeof(status));
|
||||
if (ret != sizeof(status)) {
|
||||
_exit(EXIT_FAILURE);
|
||||
ret = read(fd, buf, sizeof(buf)-1);
|
||||
if (ret <= 0) {
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
buf[ret] = '\0';
|
||||
|
||||
if (strstr(buf, sysfile_str)) {
|
||||
_exit(SUSPEND_SUPPORTED);
|
||||
}
|
||||
|
||||
_exit(EXIT_SUCCESS);
|
||||
_exit(SUSPEND_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
close(pipefds[1]);
|
||||
g_free(pmutils_path);
|
||||
|
||||
if (pid < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
goto out;
|
||||
goto undef_err;
|
||||
}
|
||||
|
||||
ret = read(pipefds[0], &status, sizeof(status));
|
||||
if (ret == sizeof(status) && WIFEXITED(status) &&
|
||||
WEXITSTATUS(status) == SUSPEND_SUPPORTED) {
|
||||
goto out;
|
||||
do {
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
} while (rpid == -1 && errno == EINTR);
|
||||
if (rpid == pid && WIFEXITED(status)) {
|
||||
switch (WEXITSTATUS(status)) {
|
||||
case SUSPEND_SUPPORTED:
|
||||
return;
|
||||
case SUSPEND_NOT_SUPPORTED:
|
||||
error_set(err, QERR_UNSUPPORTED);
|
||||
return;
|
||||
default:
|
||||
goto undef_err;
|
||||
}
|
||||
}
|
||||
|
||||
error_set(err, QERR_UNSUPPORTED);
|
||||
|
||||
out:
|
||||
close(pipefds[0]);
|
||||
undef_err:
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
|
||||
static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
|
||||
Error **err)
|
||||
{
|
||||
pid_t pid;
|
||||
char *pmutils_path;
|
||||
pid_t rpid, pid;
|
||||
int status;
|
||||
|
||||
pmutils_path = g_find_program_in_path(pmutils_bin);
|
||||
|
||||
@@ -683,9 +652,18 @@ static void guest_suspend(const char *pmutils_bin, const char *sysfile_str,
|
||||
g_free(pmutils_path);
|
||||
|
||||
if (pid < 0) {
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
goto exit_err;
|
||||
}
|
||||
|
||||
do {
|
||||
rpid = waitpid(pid, &status, 0);
|
||||
} while (rpid == -1 && errno == EINTR);
|
||||
if (rpid == pid && WIFEXITED(status) && !WEXITSTATUS(status)) {
|
||||
return;
|
||||
}
|
||||
|
||||
exit_err:
|
||||
error_set(err, QERR_UNDEFINED_ERROR);
|
||||
}
|
||||
|
||||
void qmp_guest_suspend_disk(Error **err)
|
||||
@@ -789,7 +767,7 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
||||
strncpy(ifr.ifr_name, info->value->name, IF_NAMESIZE);
|
||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
|
||||
snprintf(err_msg, sizeof(err_msg),
|
||||
"failed to get MAC addres of %s: %s",
|
||||
"failed to get MAC address of %s: %s",
|
||||
ifa->ifa_name,
|
||||
strerror(errno));
|
||||
error_set(errp, QERR_QGA_COMMAND_FAILED, err_msg);
|
||||
|
@@ -52,7 +52,7 @@ struct GuestAgentInfo *qmp_guest_info(Error **err)
|
||||
GuestAgentCommandInfoList *cmd_info_list;
|
||||
char **cmd_list_head, **cmd_list;
|
||||
|
||||
info->version = g_strdup(QGA_VERSION);
|
||||
info->version = g_strdup(QEMU_VERSION);
|
||||
|
||||
cmd_list_head = cmd_list = qmp_get_command_list();
|
||||
if (*cmd_list_head == NULL) {
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include "qapi/qmp-core.h"
|
||||
#include "qemu-common.h"
|
||||
|
||||
#define QGA_VERSION "1.0"
|
||||
#define QGA_READ_COUNT_DEFAULT 4096
|
||||
|
||||
typedef struct GAState GAState;
|
||||
@@ -35,3 +34,7 @@ void ga_set_response_delimited(GAState *s);
|
||||
bool ga_is_frozen(GAState *s);
|
||||
void ga_set_frozen(GAState *s);
|
||||
void ga_unset_frozen(GAState *s);
|
||||
|
||||
#ifndef _WIN32
|
||||
void reopen_fd_to_null(int fd);
|
||||
#endif
|
||||
|
@@ -759,7 +759,7 @@ EQMP
|
||||
|
||||
{
|
||||
.name = "blockdev-snapshot-sync",
|
||||
.args_type = "device:B,snapshot-file:s,format:s?",
|
||||
.args_type = "device:B,snapshot-file:s,format:s?,mode:s?",
|
||||
.mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
|
||||
},
|
||||
|
||||
|
@@ -830,7 +830,7 @@ char *object_property_print(Object *obj, const char *name,
|
||||
char *string;
|
||||
|
||||
mo = string_output_visitor_new();
|
||||
object_property_get(obj, string_output_get_visitor(mo), name, NULL);
|
||||
object_property_get(obj, string_output_get_visitor(mo), name, errp);
|
||||
string = string_output_get_string(mo);
|
||||
string_output_visitor_cleanup(mo);
|
||||
return string;
|
||||
|
Submodule roms/openbios updated: ff61d973e5...d1d2787f87
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user