* Xen fix (Anthony)
* chardev fixes (Anton, Marc-André) * small dead code removal (Zhongyi) * documentation (Dan) * bugfixes (David) * decrease migration downtime (Jay) * improved error output (Laurent) * RTC tests and bugfix (me) * Bluetooth clang analyzer fix (me) * KVM CPU hotplug race (Peng Hao) * Two other patches from Philippe's clang analyzer series -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQEcBAABAgAGBQJZgKSlAAoJEL/70l94x66DTZ0IAKtZ3ASQiVaniYey4DNwq38G 6ivVfOy9ZHvWozN4pVf+CC8o7nGTGcm2zT5wUDs/7OvjZM9Mit7fmLb28DbGjgPk dFNiuA1VSR+7lQ90NNx5iypU760zJfLlmI34YsrrK7msQy7KI7m4QAr1DHhitLN8 LKaq3/Zhb4kB5i/GxcLF+ozh4BZ3v3kJ2KiqQYWxGhWhODnn+ejzWx+Zp+vAK7Nl QoMHKHYt9BlsTDg3zMpMwEfdocy7etXcRllC+jaeNjvboQiiyidUH1PKGOKt3YdL j8aAxZ9rdLvEP9zA572Hh56869FZiljYkhohcKDHx6KrRyWQeoG80GCLgDq+cUs= =4Rey -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging * Xen fix (Anthony) * chardev fixes (Anton, Marc-André) * small dead code removal (Zhongyi) * documentation (Dan) * bugfixes (David) * decrease migration downtime (Jay) * improved error output (Laurent) * RTC tests and bugfix (me) * Bluetooth clang analyzer fix (me) * KVM CPU hotplug race (Peng Hao) * Two other patches from Philippe's clang analyzer series # gpg: Signature made Tue 01 Aug 2017 16:56:21 BST # gpg: using RSA key 0xBFFBD25F78C7AE83 # gpg: Good signature from "Paolo Bonzini <bonzini@gnu.org>" # gpg: aka "Paolo Bonzini <pbonzini@redhat.com>" # Primary key fingerprint: 46F5 9FBD 57D6 12E7 BFD4 E2F7 7E15 100C CD36 69B1 # Subkey fingerprint: F133 3857 4B66 2389 866C 7682 BFFB D25F 78C7 AE83 * remotes/bonzini/tags/for-upstream: mc146818rtc: implement UIP latching as intended mc146818rtc: simplify check_update_timer rtc-test: introduce more update tests rtc-test: cleanup register_b_set_flag test hw/scsi/vmw_pvscsi: Convert to realize hw/scsi/vmw_pvscsi: Remove the dead error handling migration: optimize the downtime qemu-options: document existance of versioned machine types bt: stop the sdp memory allocation craziness exec: Add lock parameter to qemu_ram_ptr_length target-i386: kvm_get/put_vcpu_events don't handle sipi_vector docs: document deprecation policy & deprecated features in appendix char: don't exit on hmp 'chardev-add help' char-fd: remove useless chr pointer accel: cleanup error output cpu_physical_memory_sync_dirty_bitmap: Fix alignment check vl.c/exit: pause cpus before closing block devices Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
82d3d409b8
|
@ -33,6 +33,7 @@
|
|||
#include "sysemu/qtest.h"
|
||||
#include "hw/xen/xen.h"
|
||||
#include "qom/object.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
static const TypeInfo accel_type = {
|
||||
.name = TYPE_ACCEL,
|
||||
|
@ -69,19 +70,20 @@ static int accel_init_machine(AccelClass *acc, MachineState *ms)
|
|||
|
||||
void configure_accelerator(MachineState *ms)
|
||||
{
|
||||
const char *p;
|
||||
const char *accel, *p;
|
||||
char buf[10];
|
||||
int ret;
|
||||
bool accel_initialised = false;
|
||||
bool init_failed = false;
|
||||
AccelClass *acc = NULL;
|
||||
|
||||
p = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (p == NULL) {
|
||||
accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
|
||||
if (accel == NULL) {
|
||||
/* Use the default "accelerator", tcg */
|
||||
p = "tcg";
|
||||
accel = "tcg";
|
||||
}
|
||||
|
||||
p = accel;
|
||||
while (!accel_initialised && *p != '\0') {
|
||||
if (*p == ':') {
|
||||
p++;
|
||||
|
@ -89,7 +91,6 @@ void configure_accelerator(MachineState *ms)
|
|||
p = get_opt_name(buf, sizeof(buf), p, ':');
|
||||
acc = accel_find(buf);
|
||||
if (!acc) {
|
||||
fprintf(stderr, "\"%s\" accelerator not found.\n", buf);
|
||||
continue;
|
||||
}
|
||||
if (acc->available && !acc->available()) {
|
||||
|
@ -100,9 +101,8 @@ void configure_accelerator(MachineState *ms)
|
|||
ret = accel_init_machine(acc, ms);
|
||||
if (ret < 0) {
|
||||
init_failed = true;
|
||||
fprintf(stderr, "failed to initialize %s: %s\n",
|
||||
acc->name,
|
||||
strerror(-ret));
|
||||
error_report("failed to initialize %s: %s",
|
||||
acc->name, strerror(-ret));
|
||||
} else {
|
||||
accel_initialised = true;
|
||||
}
|
||||
|
@ -110,13 +110,13 @@ void configure_accelerator(MachineState *ms)
|
|||
|
||||
if (!accel_initialised) {
|
||||
if (!init_failed) {
|
||||
fprintf(stderr, "No accelerator found!\n");
|
||||
error_report("-machine accel=%s: No accelerator found", accel);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (init_failed) {
|
||||
fprintf(stderr, "Back to %s accelerator.\n", acc->name);
|
||||
error_report("Back to %s accelerator", acc->name);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -141,7 +141,6 @@ void qemu_chr_open_fd(Chardev *chr,
|
|||
qio_channel_set_name(QIO_CHANNEL(s->ioc_out), name);
|
||||
g_free(name);
|
||||
qemu_set_nonblock(fd_out);
|
||||
s->chr = chr;
|
||||
}
|
||||
|
||||
static void char_fd_class_init(ObjectClass *oc, void *data)
|
||||
|
|
|
@ -620,7 +620,7 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts, Error **errp)
|
|||
|
||||
error_report("Available chardev backend types: %s", str->str);
|
||||
g_string_free(str, true);
|
||||
exit(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (id == NULL) {
|
||||
|
|
12
exec.c
12
exec.c
|
@ -2203,7 +2203,7 @@ void *qemu_map_ram_ptr(RAMBlock *ram_block, ram_addr_t addr)
|
|||
* Called within RCU critical section.
|
||||
*/
|
||||
static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
|
||||
hwaddr *size)
|
||||
hwaddr *size, bool lock)
|
||||
{
|
||||
RAMBlock *block = ram_block;
|
||||
if (*size == 0) {
|
||||
|
@ -2222,10 +2222,10 @@ static void *qemu_ram_ptr_length(RAMBlock *ram_block, ram_addr_t addr,
|
|||
* In that case just map the requested area.
|
||||
*/
|
||||
if (block->offset == 0) {
|
||||
return xen_map_cache(addr, *size, 1, true);
|
||||
return xen_map_cache(addr, *size, lock, lock);
|
||||
}
|
||||
|
||||
block->host = xen_map_cache(block->offset, block->max_length, 1, true);
|
||||
block->host = xen_map_cache(block->offset, block->max_length, 1, lock);
|
||||
}
|
||||
|
||||
return ramblock_ptr(block, addr);
|
||||
|
@ -2947,7 +2947,7 @@ static MemTxResult address_space_write_continue(AddressSpace *as, hwaddr addr,
|
|||
}
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
|
||||
memcpy(ptr, buf, l);
|
||||
invalidate_and_set_dirty(mr, addr1, l);
|
||||
}
|
||||
|
@ -3038,7 +3038,7 @@ MemTxResult address_space_read_continue(AddressSpace *as, hwaddr addr,
|
|||
}
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
|
||||
memcpy(buf, ptr, l);
|
||||
}
|
||||
|
||||
|
@ -3349,7 +3349,7 @@ void *address_space_map(AddressSpace *as,
|
|||
|
||||
memory_region_ref(mr);
|
||||
*plen = address_space_extend_translation(as, addr, len, mr, xlat, l, is_write);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen);
|
||||
ptr = qemu_ram_ptr_length(mr->ram_block, xlat, plen, true);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ptr;
|
||||
|
|
17
hw/bt/sdp.c
17
hw/bt/sdp.c
|
@ -580,7 +580,7 @@ static void bt_l2cap_sdp_close_ch(void *opaque)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < sdp->services; i ++) {
|
||||
g_free(sdp->service_list[i].attribute_list->pair);
|
||||
g_free(sdp->service_list[i].attribute_list[0].pair);
|
||||
g_free(sdp->service_list[i].attribute_list);
|
||||
g_free(sdp->service_list[i].uuid);
|
||||
}
|
||||
|
@ -720,6 +720,8 @@ static void sdp_service_record_build(struct sdp_service_record_s *record,
|
|||
len += sdp_attr_max_size(&def->attributes[record->attributes ++].data,
|
||||
&record->uuids);
|
||||
}
|
||||
|
||||
assert(len > 0);
|
||||
record->uuids = pow2ceil(record->uuids);
|
||||
record->attribute_list =
|
||||
g_malloc0(record->attributes * sizeof(*record->attribute_list));
|
||||
|
@ -730,12 +732,14 @@ static void sdp_service_record_build(struct sdp_service_record_s *record,
|
|||
record->attributes = 0;
|
||||
uuid = record->uuid;
|
||||
while (def->attributes[record->attributes].data.type) {
|
||||
int attribute_id = def->attributes[record->attributes].id;
|
||||
record->attribute_list[record->attributes].pair = data;
|
||||
record->attribute_list[record->attributes].attribute_id = attribute_id;
|
||||
|
||||
len = 0;
|
||||
data[len ++] = SDP_DTYPE_UINT | SDP_DSIZE_2;
|
||||
data[len ++] = def->attributes[record->attributes].id >> 8;
|
||||
data[len ++] = def->attributes[record->attributes].id & 0xff;
|
||||
data[len ++] = attribute_id >> 8;
|
||||
data[len ++] = attribute_id & 0xff;
|
||||
len += sdp_attr_write(data + len,
|
||||
&def->attributes[record->attributes].data, &uuid);
|
||||
|
||||
|
@ -749,10 +753,15 @@ static void sdp_service_record_build(struct sdp_service_record_s *record,
|
|||
data += len;
|
||||
}
|
||||
|
||||
/* Sort the attribute list by the AttributeID */
|
||||
/* Sort the attribute list by the AttributeID. The first must be
|
||||
* SDP_ATTR_RECORD_HANDLE so that bt_l2cap_sdp_close_ch can free
|
||||
* the buffer.
|
||||
*/
|
||||
qsort(record->attribute_list, record->attributes,
|
||||
sizeof(*record->attribute_list),
|
||||
(void *) sdp_attributeid_compare);
|
||||
assert(record->attribute_list[0].pair == data);
|
||||
|
||||
/* Sort the searchable UUIDs list for bisection */
|
||||
qsort(record->uuid, record->uuids,
|
||||
sizeof(*record->uuid),
|
||||
|
|
|
@ -1103,8 +1103,8 @@ static const struct SCSIBusInfo pvscsi_scsi_info = {
|
|||
.cancel = pvscsi_request_cancelled,
|
||||
};
|
||||
|
||||
static int
|
||||
pvscsi_init(PCIDevice *pci_dev)
|
||||
static void
|
||||
pvscsi_realizefn(PCIDevice *pci_dev, Error **errp)
|
||||
{
|
||||
PVSCSIState *s = PVSCSI(pci_dev);
|
||||
|
||||
|
@ -1138,18 +1138,12 @@ pvscsi_init(PCIDevice *pci_dev)
|
|||
}
|
||||
|
||||
s->completion_worker = qemu_bh_new(pvscsi_process_completion_queue, s);
|
||||
if (!s->completion_worker) {
|
||||
pvscsi_cleanup_msi(s);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(pci_dev),
|
||||
&pvscsi_scsi_info, NULL);
|
||||
/* override default SCSI bus hotplug-handler, with pvscsi's one */
|
||||
qbus_set_hotplug_handler(BUS(&s->bus), DEVICE(s), &error_abort);
|
||||
pvscsi_reset_state(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1282,7 +1276,7 @@ static void pvscsi_class_init(ObjectClass *klass, void *data)
|
|||
PVSCSIClass *pvs_k = PVSCSI_DEVICE_CLASS(klass);
|
||||
HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass);
|
||||
|
||||
k->init = pvscsi_init;
|
||||
k->realize = pvscsi_realizefn;
|
||||
k->exit = pvscsi_uninit;
|
||||
k->vendor_id = PCI_VENDOR_ID_VMWARE;
|
||||
k->device_id = PCI_DEVICE_ID_VMWARE_PVSCSI;
|
||||
|
|
|
@ -291,26 +291,15 @@ static void check_update_timer(RTCState *s)
|
|||
|
||||
/* From the data sheet: "Holding the dividers in reset prevents
|
||||
* interrupts from operating, while setting the SET bit allows"
|
||||
* them to occur. However, it will prevent an alarm interrupt
|
||||
* from occurring, because the time of day is not updated.
|
||||
* them to occur.
|
||||
*/
|
||||
if ((s->cmos_data[RTC_REG_A] & 0x60) == 0x60) {
|
||||
timer_del(s->update_timer);
|
||||
return;
|
||||
}
|
||||
if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
|
||||
(s->cmos_data[RTC_REG_B] & REG_B_SET)) {
|
||||
timer_del(s->update_timer);
|
||||
return;
|
||||
}
|
||||
if ((s->cmos_data[RTC_REG_C] & REG_C_UF) &&
|
||||
(s->cmos_data[RTC_REG_C] & REG_C_AF)) {
|
||||
assert((s->cmos_data[RTC_REG_A] & REG_A_UIP) == 0);
|
||||
timer_del(s->update_timer);
|
||||
return;
|
||||
}
|
||||
|
||||
guest_nsec = get_guest_rtc_ns(s) % NANOSECONDS_PER_SECOND;
|
||||
/* if UF is clear, reprogram to next second */
|
||||
next_update_time = qemu_clock_get_ns(rtc_clock)
|
||||
+ NANOSECONDS_PER_SECOND - guest_nsec;
|
||||
|
||||
|
@ -321,7 +310,21 @@ static void check_update_timer(RTCState *s)
|
|||
s->next_alarm_time = next_update_time +
|
||||
(next_alarm_sec - 1) * NANOSECONDS_PER_SECOND;
|
||||
|
||||
if (s->cmos_data[RTC_REG_C] & REG_C_UF) {
|
||||
/* If update_in_progress latched the UIP bit, we must keep the timer
|
||||
* programmed to the next second, so that UIP is cleared. Otherwise,
|
||||
* if UF is already set, we might be able to optimize.
|
||||
*/
|
||||
if (!(s->cmos_data[RTC_REG_A] & REG_A_UIP) &&
|
||||
(s->cmos_data[RTC_REG_C] & REG_C_UF)) {
|
||||
/* If AF cannot change (i.e. either it is set already, or
|
||||
* SET=1 and then the time is not updated), nothing to do.
|
||||
*/
|
||||
if ((s->cmos_data[RTC_REG_B] & REG_B_SET) ||
|
||||
(s->cmos_data[RTC_REG_C] & REG_C_AF)) {
|
||||
timer_del(s->update_timer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* UF is set, but AF is clear. Program the timer to target
|
||||
* the alarm time. */
|
||||
next_update_time = s->next_alarm_time;
|
||||
|
@ -727,12 +730,10 @@ static uint64_t cmos_ioport_read(void *opaque, hwaddr addr,
|
|||
ret = s->cmos_data[s->cmos_index];
|
||||
break;
|
||||
case RTC_REG_A:
|
||||
if (update_in_progress(s)) {
|
||||
s->cmos_data[s->cmos_index] |= REG_A_UIP;
|
||||
} else {
|
||||
s->cmos_data[s->cmos_index] &= ~REG_A_UIP;
|
||||
}
|
||||
ret = s->cmos_data[s->cmos_index];
|
||||
if (update_in_progress(s)) {
|
||||
ret |= REG_A_UIP;
|
||||
}
|
||||
break;
|
||||
case RTC_REG_C:
|
||||
ret = s->cmos_data[s->cmos_index];
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
typedef struct FDChardev {
|
||||
Chardev parent;
|
||||
Chardev *chr;
|
||||
|
||||
QIOChannel *ioc_in, *ioc_out;
|
||||
int max_size;
|
||||
} FDChardev;
|
||||
|
|
|
@ -65,7 +65,9 @@ struct Chardev {
|
|||
*
|
||||
* @opts see qemu-config.c for a list of valid options
|
||||
*
|
||||
* Returns: a new character backend
|
||||
* Returns: on success: a new character backend
|
||||
* otherwise: NULL; @errp specifies the error
|
||||
* or left untouched in case of help option
|
||||
*/
|
||||
Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
|
||||
Error **errp);
|
||||
|
|
|
@ -377,19 +377,20 @@ uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
|
|||
uint64_t *real_dirty_pages)
|
||||
{
|
||||
ram_addr_t addr;
|
||||
unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
|
||||
unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS);
|
||||
uint64_t num_dirty = 0;
|
||||
unsigned long *dest = rb->bmap;
|
||||
|
||||
/* start address is aligned at the start of a word? */
|
||||
if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
|
||||
if (((word * BITS_PER_LONG) << TARGET_PAGE_BITS) ==
|
||||
(start + rb->offset)) {
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(length >> TARGET_PAGE_BITS);
|
||||
unsigned long * const *src;
|
||||
unsigned long word = BIT_WORD((start + rb->offset) >> TARGET_PAGE_BITS);
|
||||
unsigned long idx = (word * BITS_PER_LONG) / DIRTY_MEMORY_BLOCK_SIZE;
|
||||
unsigned long offset = BIT_WORD((word * BITS_PER_LONG) %
|
||||
DIRTY_MEMORY_BLOCK_SIZE);
|
||||
unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
|
|
36
memory.c
36
memory.c
|
@ -2357,8 +2357,15 @@ void memory_global_dirty_log_sync(void)
|
|||
}
|
||||
}
|
||||
|
||||
static VMChangeStateEntry *vmstate_change;
|
||||
|
||||
void memory_global_dirty_log_start(void)
|
||||
{
|
||||
if (vmstate_change) {
|
||||
qemu_del_vm_change_state_handler(vmstate_change);
|
||||
vmstate_change = NULL;
|
||||
}
|
||||
|
||||
global_dirty_log = true;
|
||||
|
||||
MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward);
|
||||
|
@ -2369,7 +2376,7 @@ void memory_global_dirty_log_start(void)
|
|||
memory_region_transaction_commit();
|
||||
}
|
||||
|
||||
void memory_global_dirty_log_stop(void)
|
||||
static void memory_global_dirty_log_do_stop(void)
|
||||
{
|
||||
global_dirty_log = false;
|
||||
|
||||
|
@ -2381,6 +2388,33 @@ void memory_global_dirty_log_stop(void)
|
|||
MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse);
|
||||
}
|
||||
|
||||
static void memory_vm_change_state_handler(void *opaque, int running,
|
||||
RunState state)
|
||||
{
|
||||
if (running) {
|
||||
memory_global_dirty_log_do_stop();
|
||||
|
||||
if (vmstate_change) {
|
||||
qemu_del_vm_change_state_handler(vmstate_change);
|
||||
vmstate_change = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void memory_global_dirty_log_stop(void)
|
||||
{
|
||||
if (!runstate_is_running()) {
|
||||
if (vmstate_change) {
|
||||
return;
|
||||
}
|
||||
vmstate_change = qemu_add_vm_change_state_handler(
|
||||
memory_vm_change_state_handler, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
memory_global_dirty_log_do_stop();
|
||||
}
|
||||
|
||||
static void listener_add_address_space(MemoryListener *listener,
|
||||
AddressSpace *as)
|
||||
{
|
||||
|
|
175
qemu-doc.texi
175
qemu-doc.texi
|
@ -38,6 +38,7 @@
|
|||
* QEMU Guest Agent::
|
||||
* QEMU User space emulator::
|
||||
* Implementation notes::
|
||||
* Deprecated features::
|
||||
* License::
|
||||
* Index::
|
||||
@end menu
|
||||
|
@ -3128,6 +3129,180 @@ Run the emulation in single step mode.
|
|||
|
||||
@include qemu-tech.texi
|
||||
|
||||
@node Deprecated features
|
||||
@appendix Deprecated features
|
||||
|
||||
In general features are intended to be supported indefinitely once
|
||||
introduced into QEMU. In the event that a feature needs to be removed,
|
||||
it will be listed in this appendix. The feature will remain functional
|
||||
for 2 releases prior to actual removal. Deprecated features may also
|
||||
generate warnings on the console when QEMU starts up, or if activated
|
||||
via a monitor command, however, this is not a mandatory requirement.
|
||||
|
||||
Prior to the 2.10.0 release there was no official policy on how
|
||||
long features would be deprecated prior to their removal, nor
|
||||
any documented list of which features were deprecated. Thus
|
||||
any features deprecated prior to 2.10.0 will be treated as if
|
||||
they were first deprecated in the 2.10.0 release.
|
||||
|
||||
What follows is a list of all features currently marked as
|
||||
deprecated.
|
||||
|
||||
@section System emulator command line arguments
|
||||
|
||||
@subsection -drive boot=on|off (since 1.3.0)
|
||||
|
||||
The ``boot=on|off'' option to the ``-drive'' argument is
|
||||
ignored. Applications should use the ``bootindex=N'' parameter
|
||||
to set an absolute ordering between devices instead.
|
||||
|
||||
@subsection -tdf (since 1.3.0)
|
||||
|
||||
The ``-tdf'' argument is ignored. The behaviour implemented
|
||||
by this argument is now the default when using the KVM PIT,
|
||||
but can be requested explicitly using
|
||||
``-global kvm-pit.lost_tick_policy=slew''.
|
||||
|
||||
@subsection -no-kvm-pit-reinjection (since 1.3.0)
|
||||
|
||||
The ``-no-kvm-pit-reinjection'' argument is now a
|
||||
synonym for setting ``-global kvm-pit.lost_tick_policy=discard''.
|
||||
|
||||
@subsection -no-kvm-irqchip (since 1.3.0)
|
||||
|
||||
The ``-no-kvm-irqchip'' argument is now a synonym for
|
||||
setting ``-machine kernel_irqchip=off''.
|
||||
|
||||
@subsection -no-kvm-pit (since 1.3.0)
|
||||
|
||||
The ``-no-kvm-pit'' argument is ignored. It is no longer
|
||||
possible to disable the KVM PIT directly.
|
||||
|
||||
@subsection -no-kvm (since 1.3.0)
|
||||
|
||||
The ``-no-kvm'' argument is now a synonym for setting
|
||||
``-machine accel=tcg''.
|
||||
|
||||
@subsection -mon default=on (since 2.4.0)
|
||||
|
||||
The ``default'' option to the ``-mon'' argument is
|
||||
now ignored. When multiple monitors were enabled, it
|
||||
indicated which monitor would receive log messages
|
||||
from the various subsystems. This feature is no longer
|
||||
required as messages are now only sent to the monitor
|
||||
in response to explicitly monitor commands.
|
||||
|
||||
@subsection -vnc tls (since 2.5.0)
|
||||
|
||||
The ``-vnc tls'' argument is now a synonym for setting
|
||||
``-object tls-creds-anon,id=tls0'' combined with
|
||||
``-vnc tls-creds=tls0'
|
||||
|
||||
@subsection -vnc x509 (since 2.5.0)
|
||||
|
||||
The ``-vnc x509=/path/to/certs'' argument is now a
|
||||
synonym for setting
|
||||
``-object tls-creds-x509,dir=/path/to/certs,id=tls0,verify-peer=no''
|
||||
combined with ``-vnc tls-creds=tls0'
|
||||
|
||||
@subsection -vnc x509verify (since 2.5.0)
|
||||
|
||||
The ``-vnc x509verify=/path/to/certs'' argument is now a
|
||||
synonym for setting
|
||||
``-object tls-creds-x509,dir=/path/to/certs,id=tls0,verify-peer=yes''
|
||||
combined with ``-vnc tls-creds=tls0'
|
||||
|
||||
@subsection -tftp (since 2.6.0)
|
||||
|
||||
The ``-tftp /some/dir'' argument is now a synonym for setting
|
||||
the ``-netdev user,tftp=/some/dir' argument. The new syntax
|
||||
allows different settings to be provided per NIC.
|
||||
|
||||
@subsection -bootp (since 2.6.0)
|
||||
|
||||
The ``-bootp /some/file'' argument is now a synonym for setting
|
||||
the ``-netdev user,bootp=/some/file' argument. The new syntax
|
||||
allows different settings to be provided per NIC.
|
||||
|
||||
@subsection -redir (since 2.6.0)
|
||||
|
||||
The ``-redir ARGS'' argument is now a synonym for setting
|
||||
the ``-netdev user,hostfwd=ARGS'' argument instead. The new
|
||||
syntax allows different settings to be provided per NIC.
|
||||
|
||||
@subsection -smb (since 2.6.0)
|
||||
|
||||
The ``-smb /some/dir'' argument is now a synonym for setting
|
||||
the ``-netdev user,smb=/some/dir'' argument instead. The new
|
||||
syntax allows different settings to be provided per NIC.
|
||||
|
||||
@subsection -net channel (since 2.6.0)
|
||||
|
||||
The ``--net channel,ARGS'' argument is now a synonym for setting
|
||||
the ``-netdev user,guestfwd=ARGS'' argument instead.
|
||||
|
||||
@subsection -net vlan (since 2.9.0)
|
||||
|
||||
The ``-net van=NN'' argument is partially replaced with the
|
||||
new ``-netdev'' argument. The remaining use cases will no
|
||||
longer be directly supported in QEMU.
|
||||
|
||||
@subsection -drive if=scsi (since 2.9.0)
|
||||
|
||||
The ``-drive if=scsi'' argument is replaced by the the
|
||||
``-device BUS-TYPE'' argument combined with ``-drive if=none''.
|
||||
|
||||
@subsection -net dump (since 2.10.0)
|
||||
|
||||
The ``--net dump'' argument is now replaced with the
|
||||
``-object filter-dump'' argument which works in combination
|
||||
with the modern ``-netdev`` backends instead.
|
||||
|
||||
@subsection -hdachs (since 2.10.0)
|
||||
|
||||
The ``-hdachs'' argument is now a synonym for setting
|
||||
the ``cyls'', ``heads'', ``secs'', and ``trans'' properties
|
||||
on the ``ide-hd'' device using the ``-device'' argument.
|
||||
The new syntax allows different settings to be provided
|
||||
per disk.
|
||||
|
||||
@subsection -usbdevice (since 2.10.0)
|
||||
|
||||
The ``-usbdevice DEV'' argument is now a synonym for setting
|
||||
the ``-device usb-DEV'' argument instead. The deprecated syntax
|
||||
would automatically enable USB support on the machine type.
|
||||
If using the new syntax, USB support must be explicitly
|
||||
enabled via the ``-machine usb=on'' argument.
|
||||
|
||||
@section qemu-img command line arguments
|
||||
|
||||
@subsection convert -s (since 2.0.0)
|
||||
|
||||
The ``convert -s snapshot_id_or_name'' argument is obsoleted
|
||||
by the ``convert -l snapshot_param'' argument instead.
|
||||
|
||||
@section System emulator human monitor commands
|
||||
|
||||
@subsection usb_add (since 2.10.0)
|
||||
|
||||
The ``usb_add'' command is replaced by the ``device_add'' command.
|
||||
|
||||
@subsection usb_del (since 2.10.0)
|
||||
|
||||
The ``usb_del'' command is replaced by the ``device_del'' command.
|
||||
|
||||
@section System emulator devices
|
||||
|
||||
@subsection ivshmem (since 2.6.0)
|
||||
|
||||
The ``ivshmem'' device type is replaced by either the ``ivshmem-plain''
|
||||
or ``ivshmem-doorbell`` device types.
|
||||
|
||||
@subsection spapr-pci-vfio-host-bridge (since 2.6.0)
|
||||
|
||||
The ``spapr-pci-vfio-host-bridge'' device type is replaced by
|
||||
the ``spapr-pci-host-bridge'' device type.
|
||||
|
||||
@node License
|
||||
@appendix License
|
||||
|
||||
|
|
|
@ -49,7 +49,20 @@ STEXI
|
|||
@item -machine [type=]@var{name}[,prop=@var{value}[,...]]
|
||||
@findex -machine
|
||||
Select the emulated machine by @var{name}. Use @code{-machine help} to list
|
||||
available machines. Supported machine properties are:
|
||||
available machines.
|
||||
|
||||
For architectures which aim to support live migration compatibility
|
||||
across releases, each release will introduce a new versioned machine
|
||||
type. For example, the 2.8.0 release introduced machine types
|
||||
``pc-i440fx-2.8'' and ``pc-q35-2.8'' for the x86_64/i686 architectures.
|
||||
|
||||
To allow live migration of guests from QEMU version 2.8.0, to QEMU
|
||||
version 2.9.0, the 2.9.0 version must support the ``pc-i440fx-2.8''
|
||||
and ``pc-q35-2.8'' machines too. To allow users live migrating VMs
|
||||
to skip multiple intermediate releases when upgrading, new releases
|
||||
of QEMU will support machine types from many previous versions.
|
||||
|
||||
Supported machine properties are:
|
||||
@table @option
|
||||
@item accel=@var{accels1}[:@var{accels2}[:...]]
|
||||
This is used to enable an accelerator. Depending on the target architecture,
|
||||
|
|
|
@ -2444,8 +2444,10 @@ static int kvm_put_vcpu_events(X86CPU *cpu, int level)
|
|||
}
|
||||
|
||||
if (level >= KVM_PUT_RESET_STATE) {
|
||||
events.flags |=
|
||||
KVM_VCPUEVENT_VALID_NMI_PENDING | KVM_VCPUEVENT_VALID_SIPI_VECTOR;
|
||||
events.flags |= KVM_VCPUEVENT_VALID_NMI_PENDING;
|
||||
if (env->mp_state == KVM_MP_STATE_SIPI_RECEIVED) {
|
||||
events.flags |= KVM_VCPUEVENT_VALID_SIPI_VECTOR;
|
||||
}
|
||||
}
|
||||
|
||||
return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_VCPU_EVENTS, &events);
|
||||
|
@ -2633,6 +2635,10 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
|
|||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = kvm_put_vcpu_events(x86_cpu, level);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
if (level >= KVM_PUT_RESET_STATE) {
|
||||
ret = kvm_put_mp_state(x86_cpu);
|
||||
if (ret < 0) {
|
||||
|
@ -2644,11 +2650,6 @@ int kvm_arch_put_registers(CPUState *cpu, int level)
|
|||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = kvm_put_vcpu_events(x86_cpu, level);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
ret = kvm_put_debugregs(x86_cpu);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
|
@ -2668,6 +2669,18 @@ int kvm_arch_get_registers(CPUState *cs)
|
|||
|
||||
assert(cpu_is_stopped(cs) || qemu_cpu_is_self(cs));
|
||||
|
||||
ret = kvm_get_vcpu_events(cpu);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* KVM_GET_MPSTATE can modify CS and RIP, call it before
|
||||
* KVM_GET_REGS and KVM_GET_SREGS.
|
||||
*/
|
||||
ret = kvm_get_mp_state(cpu);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_getput_regs(cpu, 0);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
|
@ -2688,18 +2701,10 @@ int kvm_arch_get_registers(CPUState *cs)
|
|||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_mp_state(cpu);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_apic(cpu);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_vcpu_events(cpu);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
}
|
||||
ret = kvm_get_debugregs(cpu);
|
||||
if (ret < 0) {
|
||||
goto out;
|
||||
|
|
160
tests/rtc-test.c
160
tests/rtc-test.c
|
@ -17,6 +17,8 @@
|
|||
#include "qemu/timer.h"
|
||||
#include "hw/timer/mc146818rtc_regs.h"
|
||||
|
||||
#define UIP_HOLD_LENGTH (8 * NANOSECONDS_PER_SECOND / 32768)
|
||||
|
||||
static uint8_t base = 0x70;
|
||||
|
||||
static int bcd2dec(int value)
|
||||
|
@ -297,15 +299,53 @@ static void alarm_time(void)
|
|||
g_assert(cmos_read(RTC_REG_C) == 0);
|
||||
}
|
||||
|
||||
static void set_time(int mode, int h, int m, int s)
|
||||
static void set_time_regs(int h, int m, int s)
|
||||
{
|
||||
/* set BCD 12 hour mode */
|
||||
cmos_write(RTC_REG_B, mode);
|
||||
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
cmos_write(RTC_HOURS, h);
|
||||
cmos_write(RTC_MINUTES, m);
|
||||
cmos_write(RTC_SECONDS, s);
|
||||
}
|
||||
|
||||
static void set_time(int mode, int h, int m, int s)
|
||||
{
|
||||
cmos_write(RTC_REG_B, mode);
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
set_time_regs(h, m, s);
|
||||
cmos_write(RTC_REG_A, 0x26);
|
||||
}
|
||||
|
||||
static void set_datetime_bcd(int h, int min, int s, int d, int m, int y)
|
||||
{
|
||||
cmos_write(RTC_HOURS, h);
|
||||
cmos_write(RTC_MINUTES, min);
|
||||
cmos_write(RTC_SECONDS, s);
|
||||
cmos_write(RTC_YEAR, y & 0xFF);
|
||||
cmos_write(RTC_CENTURY, y >> 8);
|
||||
cmos_write(RTC_MONTH, m);
|
||||
cmos_write(RTC_DAY_OF_MONTH, d);
|
||||
}
|
||||
|
||||
static void set_datetime_dec(int h, int min, int s, int d, int m, int y)
|
||||
{
|
||||
cmos_write(RTC_HOURS, h);
|
||||
cmos_write(RTC_MINUTES, min);
|
||||
cmos_write(RTC_SECONDS, s);
|
||||
cmos_write(RTC_YEAR, y % 100);
|
||||
cmos_write(RTC_CENTURY, y / 100);
|
||||
cmos_write(RTC_MONTH, m);
|
||||
cmos_write(RTC_DAY_OF_MONTH, d);
|
||||
}
|
||||
|
||||
static void set_datetime(int mode, int h, int min, int s, int d, int m, int y)
|
||||
{
|
||||
cmos_write(RTC_REG_B, mode);
|
||||
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
if (mode & REG_B_DM) {
|
||||
set_datetime_dec(h, min, s, d, m, y);
|
||||
} else {
|
||||
set_datetime_bcd(h, min, s, d, m, y);
|
||||
}
|
||||
cmos_write(RTC_REG_A, 0x26);
|
||||
}
|
||||
|
||||
|
@ -316,6 +356,17 @@ static void set_time(int mode, int h, int m, int s)
|
|||
g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
|
||||
} while(0)
|
||||
|
||||
#define assert_datetime_bcd(h, min, s, d, m, y) \
|
||||
do { \
|
||||
g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
|
||||
g_assert_cmpint(cmos_read(RTC_MINUTES), ==, min); \
|
||||
g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
|
||||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, d); \
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, m); \
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, (y & 0xFF)); \
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, (y >> 8)); \
|
||||
} while(0)
|
||||
|
||||
static void basic_12h_bcd(void)
|
||||
{
|
||||
/* set BCD 12 hour mode */
|
||||
|
@ -506,41 +557,84 @@ static void fuzz_registers(void)
|
|||
|
||||
static void register_b_set_flag(void)
|
||||
{
|
||||
if (cmos_read(RTC_REG_A) & REG_A_UIP) {
|
||||
clock_step(UIP_HOLD_LENGTH + NANOSECONDS_PER_SECOND / 5);
|
||||
}
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
|
||||
|
||||
/* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/
|
||||
cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET);
|
||||
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
cmos_write(RTC_YEAR, 0x11);
|
||||
cmos_write(RTC_CENTURY, 0x20);
|
||||
cmos_write(RTC_MONTH, 0x02);
|
||||
cmos_write(RTC_DAY_OF_MONTH, 0x02);
|
||||
cmos_write(RTC_HOURS, 0x02);
|
||||
cmos_write(RTC_MINUTES, 0x04);
|
||||
cmos_write(RTC_SECONDS, 0x58);
|
||||
cmos_write(RTC_REG_A, 0x26);
|
||||
set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* Since SET flag is still enabled, these are equality checks. */
|
||||
g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
|
||||
g_assert_cmpint(cmos_read(RTC_SECONDS), ==, 0x58);
|
||||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* Since SET flag is still enabled, time does not advance. */
|
||||
clock_step(1000000000LL);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* Disable SET flag in Register B */
|
||||
cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_SET);
|
||||
|
||||
g_assert_cmpint(cmos_read(RTC_HOURS), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MINUTES), ==, 0x04);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* Since SET flag is disabled, this is an inequality check.
|
||||
* We (reasonably) assume that no (sexagesimal) overflow occurs. */
|
||||
g_assert_cmpint(cmos_read(RTC_SECONDS), >=, 0x58);
|
||||
g_assert_cmpint(cmos_read(RTC_DAY_OF_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_MONTH), ==, 0x02);
|
||||
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
|
||||
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
|
||||
/* Since SET flag is disabled, the clock now advances. */
|
||||
clock_step(1000000000LL);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
|
||||
}
|
||||
|
||||
static void divider_reset(void)
|
||||
{
|
||||
/* Enable binary-coded decimal (BCD) mode in Register B*/
|
||||
cmos_write(RTC_REG_B, REG_B_24H);
|
||||
|
||||
/* Enter divider reset */
|
||||
cmos_write(RTC_REG_A, 0x76);
|
||||
set_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* Since divider reset flag is still enabled, these are equality checks. */
|
||||
clock_step(1000000000LL);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* The first update ends 500 ms after divider reset */
|
||||
cmos_write(RTC_REG_A, 0x26);
|
||||
clock_step(500000000LL - UIP_HOLD_LENGTH - 1);
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
clock_step(1);
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0);
|
||||
clock_step(UIP_HOLD_LENGTH);
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
|
||||
|
||||
assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
|
||||
}
|
||||
|
||||
static void uip_stuck(void)
|
||||
{
|
||||
set_datetime(REG_B_24H, 0x02, 0x04, 0x58, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* The first update ends 500 ms after divider reset */
|
||||
(void)cmos_read(RTC_REG_C);
|
||||
clock_step(500000000LL);
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
|
||||
assert_datetime_bcd(0x02, 0x04, 0x59, 0x02, 0x02, 0x2011);
|
||||
|
||||
/* UF is now set. */
|
||||
cmos_write(RTC_HOURS_ALARM, 0x02);
|
||||
cmos_write(RTC_MINUTES_ALARM, 0xC0);
|
||||
cmos_write(RTC_SECONDS_ALARM, 0xC0);
|
||||
|
||||
/* Because the alarm will fire soon, reading register A will latch UIP. */
|
||||
clock_step(1000000000LL - UIP_HOLD_LENGTH / 2);
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, !=, 0);
|
||||
|
||||
/* Move the alarm far away. This must not cause UIP to remain stuck! */
|
||||
cmos_write(RTC_HOURS_ALARM, 0x03);
|
||||
clock_step(UIP_HOLD_LENGTH);
|
||||
g_assert_cmpint(cmos_read(RTC_REG_A) & REG_A_UIP, ==, 0);
|
||||
}
|
||||
|
||||
#define RTC_PERIOD_CODE1 13 /* 8 Hz */
|
||||
|
@ -609,7 +703,9 @@ int main(int argc, char **argv)
|
|||
qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
|
||||
qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
|
||||
qtest_add_func("/rtc/set-year/1980", set_year_1980);
|
||||
qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag);
|
||||
qtest_add_func("/rtc/update/register_b_set_flag", register_b_set_flag);
|
||||
qtest_add_func("/rtc/update/divider-reset", divider_reset);
|
||||
qtest_add_func("/rtc/update/uip-stuck", uip_stuck);
|
||||
qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
|
||||
qtest_add_func("/rtc/periodic/interrupt", periodic_timer);
|
||||
|
||||
|
|
12
vl.c
12
vl.c
|
@ -2344,10 +2344,12 @@ static int chardev_init_func(void *opaque, QemuOpts *opts, Error **errp)
|
|||
{
|
||||
Error *local_err = NULL;
|
||||
|
||||
qemu_chr_new_from_opts(opts, &local_err);
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return -1;
|
||||
if (!qemu_chr_new_from_opts(opts, &local_err)) {
|
||||
if (local_err) {
|
||||
error_report_err(local_err);
|
||||
return -1;
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -4787,8 +4789,8 @@ int main(int argc, char **argv, char **envp)
|
|||
replay_disable_events();
|
||||
iothread_stop_all();
|
||||
|
||||
bdrv_close_all();
|
||||
pause_all_vcpus();
|
||||
bdrv_close_all();
|
||||
res_free();
|
||||
|
||||
/* vhost-user must be cleaned up before chardevs. */
|
||||
|
|
Loading…
Reference in a new issue