pc, pci, virtio: cleanups, fixes

a bunch of bugfixes and a couple of cleanups
 making these easier and/or making debugging easier
 
 Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQEcBAABAgAGBQJXmslFAAoJECgfDbjSjVRpev0IAMZghEuSeKMB2JR88dErS8P5
 J6y/1W2VFuRa1YBkTz/ecr5r2RwIO5teZUZpUkibM65Zo6bu1liMo6gbzeCg/xOi
 k437pNRl6W9RVWuXQM9VOegNoGYhX3Hrnu3iQeiT8KRY3OMCwG52umUXYVodJh1R
 mlozlEcSyUEDZVdNjhRECuUiw8RRcErEtiKda+zjkf4tPAGkyCItVpLYshE6A2/I
 lfQLkv+EWOyuD4cfEHl+4F9K9wegothFTSd/xBmcqqaWRc+pboMVF2A2yga+GjKm
 Xgb8SzQYkt9Q1nFr9fz89q89CsjhmfrD/ct/vJAcCFnw/dNXnC6mYjr6MDX0Gd0=
 =26Uu
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging

pc, pci, virtio: cleanups, fixes

a bunch of bugfixes and a couple of cleanups
making these easier and/or making debugging easier

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

# gpg: Signature made Fri 29 Jul 2016 04:11:01 BST
# gpg:                using RSA key 0x281F0DB8D28D5469
# gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>"
# gpg:                 aka "Michael S. Tsirkin <mst@redhat.com>"
# Primary key fingerprint: 0270 606B 6F3C DF3D 0B17  0970 C350 3912 AFBE 8E67
#      Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA  8A0D 281F 0DB8 D28D 5469

* remotes/mst/tags/for_upstream: (41 commits)
  mptsas: Fix a migration compatible issue
  vhost: do not update last avail idx on get_vring_base() failure
  vhost: add vhost_net_set_backend()
  vhost-user: add error report in vhost_user_write()
  tests: fix vhost-user-test leak
  tests: plug some leaks in virtio-net-test
  vhost-user: wait until backend init is completed
  char: add and use tcp_chr_wait_connected
  char: add chr_wait_connected callback
  vhost: add assert() to check runtime behaviour
  vhost-net: vhost_migration_done is vhost-user specific
  Revert "vhost-net: do not crash if backend is not present"
  vhost-user: add get_vhost_net() assertions
  vhost-user: keep vhost_net after a disconnection
  vhost-user: check vhost_user_{read,write}() return value
  vhost-user: check qemu_chr_fe_set_msgfds() return value
  vhost-user: call set_msgfds unconditionally
  qemu-char: fix qemu_chr_fe_set_msgfds() crash when disconnected
  vhost: use error_report() instead of fprintf(stderr,...)
  vhost: add missing VHOST_OPS_DEBUG
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Peter Maydell 2016-07-29 11:57:01 +01:00
commit cbe81c6331
24 changed files with 486 additions and 252 deletions

View File

@ -30,9 +30,7 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
int i;
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
/* force virtio-1.0 */
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
virtio_pci_force_virtio_1(vpci_dev);
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
for (i = 0; i < g->conf.max_outputs; i++) {

View File

@ -134,9 +134,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
/* init virtio bits */
qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
/* force virtio-1.0 */
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
virtio_pci_force_virtio_1(vpci_dev);
object_property_set_bool(OBJECT(g), true, "realized", &err);
if (err) {
error_propagate(errp, err);

View File

@ -600,6 +600,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
QLIST_FOREACH(sec, &bus->child, sibling) {
int32_t devfn = sec->parent_dev->devfn;
if (pci_bus_is_root(sec) || pci_bus_is_express(sec)) {
continue;
}
aml_append(method, aml_name("^S%.02X.PCNT", devfn));
}
}
@ -747,6 +751,27 @@ static void crs_range_free(gpointer data)
g_free(entry);
}
typedef struct CrsRangeSet {
GPtrArray *io_ranges;
GPtrArray *mem_ranges;
GPtrArray *mem_64bit_ranges;
} CrsRangeSet;
static void crs_range_set_init(CrsRangeSet *range_set)
{
range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
range_set->mem_64bit_ranges =
g_ptr_array_new_with_free_func(crs_range_free);
}
static void crs_range_set_free(CrsRangeSet *range_set)
{
g_ptr_array_free(range_set->io_ranges, true);
g_ptr_array_free(range_set->mem_ranges, true);
g_ptr_array_free(range_set->mem_64bit_ranges, true);
}
static gint crs_range_compare(gconstpointer a, gconstpointer b)
{
CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
@ -831,18 +856,17 @@ static void crs_range_merge(GPtrArray *range)
g_ptr_array_free(tmp, true);
}
static Aml *build_crs(PCIHostState *host,
GPtrArray *io_ranges, GPtrArray *mem_ranges)
static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
{
Aml *crs = aml_resource_template();
GPtrArray *host_io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
GPtrArray *host_mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
CrsRangeSet temp_range_set;
CrsRangeEntry *entry;
uint8_t max_bus = pci_bus_num(host->bus);
uint8_t type;
int devfn;
int i;
crs_range_set_init(&temp_range_set);
for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
uint64_t range_base, range_limit;
PCIDevice *dev = host->bus->devices[devfn];
@ -866,9 +890,11 @@ static Aml *build_crs(PCIHostState *host,
}
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
crs_range_insert(host_io_ranges, range_base, range_limit);
crs_range_insert(temp_range_set.io_ranges,
range_base, range_limit);
} else { /* "memory" */
crs_range_insert(host_mem_ranges, range_base, range_limit);
crs_range_insert(temp_range_set.mem_ranges,
range_base, range_limit);
}
}
@ -887,7 +913,8 @@ static Aml *build_crs(PCIHostState *host,
* that do not support multiple root buses
*/
if (range_base && range_base <= range_limit) {
crs_range_insert(host_io_ranges, range_base, range_limit);
crs_range_insert(temp_range_set.io_ranges,
range_base, range_limit);
}
range_base =
@ -900,7 +927,14 @@ static Aml *build_crs(PCIHostState *host,
* that do not support multiple root buses
*/
if (range_base && range_base <= range_limit) {
crs_range_insert(host_mem_ranges, range_base, range_limit);
uint64_t length = range_limit - range_base + 1;
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
crs_range_insert(temp_range_set.mem_ranges,
range_base, range_limit);
} else {
crs_range_insert(temp_range_set.mem_64bit_ranges,
range_base, range_limit);
}
}
range_base =
@ -913,35 +947,55 @@ static Aml *build_crs(PCIHostState *host,
* that do not support multiple root buses
*/
if (range_base && range_base <= range_limit) {
crs_range_insert(host_mem_ranges, range_base, range_limit);
uint64_t length = range_limit - range_base + 1;
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
crs_range_insert(temp_range_set.mem_ranges,
range_base, range_limit);
} else {
crs_range_insert(temp_range_set.mem_64bit_ranges,
range_base, range_limit);
}
}
}
}
crs_range_merge(host_io_ranges);
for (i = 0; i < host_io_ranges->len; i++) {
entry = g_ptr_array_index(host_io_ranges, i);
crs_range_merge(temp_range_set.io_ranges);
for (i = 0; i < temp_range_set.io_ranges->len; i++) {
entry = g_ptr_array_index(temp_range_set.io_ranges, i);
aml_append(crs,
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
AML_POS_DECODE, AML_ENTIRE_RANGE,
0, entry->base, entry->limit, 0,
entry->limit - entry->base + 1));
crs_range_insert(io_ranges, entry->base, entry->limit);
crs_range_insert(range_set->io_ranges, entry->base, entry->limit);
}
g_ptr_array_free(host_io_ranges, true);
crs_range_merge(host_mem_ranges);
for (i = 0; i < host_mem_ranges->len; i++) {
entry = g_ptr_array_index(host_mem_ranges, i);
crs_range_merge(temp_range_set.mem_ranges);
for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
aml_append(crs,
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
AML_MAX_FIXED, AML_NON_CACHEABLE,
AML_READ_WRITE,
0, entry->base, entry->limit, 0,
entry->limit - entry->base + 1));
crs_range_insert(mem_ranges, entry->base, entry->limit);
crs_range_insert(range_set->mem_ranges, entry->base, entry->limit);
}
g_ptr_array_free(host_mem_ranges, true);
crs_range_merge(temp_range_set.mem_64bit_ranges);
for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
AML_MAX_FIXED, AML_NON_CACHEABLE,
AML_READ_WRITE,
0, entry->base, entry->limit, 0,
entry->limit - entry->base + 1));
crs_range_insert(range_set->mem_64bit_ranges,
entry->base, entry->limit);
}
crs_range_set_free(&temp_range_set);
aml_append(crs,
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
@ -1898,8 +1952,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
{
CrsRangeEntry *entry;
Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs;
GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
CrsRangeSet crs_range_set;
PCMachineState *pcms = PC_MACHINE(machine);
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
uint32_t nr_mem = machine->ram_slots;
@ -1988,6 +2041,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
aml_append(dsdt, scope);
crs_range_set_init(&crs_range_set);
bus = PC_MACHINE(machine)->bus;
if (bus) {
QLIST_FOREACH(bus, &bus->child, sibling) {
@ -2014,8 +2068,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
aml_append(dev, build_prt(false));
crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent),
io_ranges, mem_ranges);
crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set);
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
aml_append(dsdt, scope);
@ -2036,9 +2089,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
AML_POS_DECODE, AML_ENTIRE_RANGE,
0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
crs_replace_with_free_ranges(io_ranges, 0x0D00, 0xFFFF);
for (i = 0; i < io_ranges->len; i++) {
entry = g_ptr_array_index(io_ranges, i);
crs_replace_with_free_ranges(crs_range_set.io_ranges, 0x0D00, 0xFFFF);
for (i = 0; i < crs_range_set.io_ranges->len; i++) {
entry = g_ptr_array_index(crs_range_set.io_ranges, i);
aml_append(crs,
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
AML_POS_DECODE, AML_ENTIRE_RANGE,
@ -2051,11 +2104,11 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
AML_CACHEABLE, AML_READ_WRITE,
0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
crs_replace_with_free_ranges(mem_ranges,
crs_replace_with_free_ranges(crs_range_set.mem_ranges,
range_lob(pci_hole),
range_upb(pci_hole));
for (i = 0; i < mem_ranges->len; i++) {
entry = g_ptr_array_index(mem_ranges, i);
for (i = 0; i < crs_range_set.mem_ranges->len; i++) {
entry = g_ptr_array_index(crs_range_set.mem_ranges, i);
aml_append(crs,
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_NON_CACHEABLE, AML_READ_WRITE,
@ -2064,11 +2117,18 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
}
if (!range_is_empty(pci_hole64)) {
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
AML_CACHEABLE, AML_READ_WRITE,
0, range_lob(pci_hole64), range_upb(pci_hole64), 0,
range_upb(pci_hole64) + 1 - range_lob(pci_hole64)));
crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges,
range_lob(pci_hole64),
range_upb(pci_hole64));
for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) {
entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i);
aml_append(crs,
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
AML_MAX_FIXED,
AML_CACHEABLE, AML_READ_WRITE,
0, entry->base, entry->limit,
0, entry->limit - entry->base + 1));
}
}
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
@ -2090,8 +2150,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
aml_append(dev, aml_name_decl("_CRS", crs));
aml_append(scope, dev);
g_ptr_array_free(io_ranges, true);
g_ptr_array_free(mem_ranges, true);
crs_range_set_free(&crs_range_set);
/* reserve PCIHP resources */
if (pm->pcihp_io_len) {

View File

@ -140,7 +140,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
{
int r;
bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
struct vhost_net *net = g_malloc(sizeof *net);
struct vhost_net *net = g_new0(struct vhost_net, 1);
uint64_t features = 0;
if (!options->net_backend) {
@ -185,7 +185,6 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
fprintf(stderr, "vhost lacks feature mask %" PRIu64
" for backend\n",
(uint64_t)(~net->dev.features & net->dev.backend_features));
vhost_dev_cleanup(&net->dev);
goto fail;
}
}
@ -197,7 +196,6 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
fprintf(stderr, "vhost lacks feature mask %" PRIu64
" for backend\n",
(uint64_t)(~net->dev.features & features));
vhost_dev_cleanup(&net->dev);
goto fail;
}
}
@ -205,7 +203,9 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
vhost_net_ack_features(net, features);
return net;
fail:
vhost_dev_cleanup(&net->dev);
g_free(net);
return NULL;
}
@ -242,8 +242,7 @@ static int vhost_net_start_one(struct vhost_net *net,
qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
file.fd = net->backend;
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
r = vhost_net_set_backend(&net->dev, &file);
if (r < 0) {
r = -errno;
goto fail;
@ -255,8 +254,7 @@ fail:
file.fd = -1;
if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
while (file.index-- > 0) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
int r = vhost_net_set_backend(&net->dev, &file);
assert(r >= 0);
}
}
@ -277,8 +275,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
int r = vhost_net_set_backend(&net->dev, &file);
assert(r >= 0);
}
}
@ -313,7 +310,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
* properly.
*/
if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
dev->use_guest_notifier_mask = false;
dev->use_guest_notifier_mask = false;
}
}
@ -378,19 +375,16 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
void vhost_net_cleanup(struct vhost_net *net)
{
vhost_dev_cleanup(&net->dev);
g_free(net);
}
int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
{
const VhostOps *vhost_ops = net->dev.vhost_ops;
int r = -1;
if (vhost_ops->vhost_migration_done) {
r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
}
assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
assert(vhost_ops->vhost_migration_done);
return r;
return vhost_ops->vhost_migration_done(&net->dev, mac_addr);
}
bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
@ -418,6 +412,7 @@ VHostNetState *get_vhost_net(NetClientState *nc)
break;
case NET_CLIENT_DRIVER_VHOST_USER:
vhost_net = vhost_user_get_vhost_net(nc);
assert(vhost_net);
break;
default:
break;
@ -429,15 +424,10 @@ VHostNetState *get_vhost_net(NetClientState *nc)
int vhost_set_vring_enable(NetClientState *nc, int enable)
{
VHostNetState *net = get_vhost_net(nc);
const VhostOps *vhost_ops;
const VhostOps *vhost_ops = net->dev.vhost_ops;
nc->vring_enable = enable;
if (!net) {
return 0;
}
vhost_ops = net->dev.vhost_ops;
if (vhost_ops->vhost_set_vring_enable) {
return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
}

View File

@ -100,6 +100,7 @@ static int ioh3420_initfn(PCIDevice *d)
int rc;
Error *err = NULL;
pci_config_set_interrupt_pin(d->config, 1);
pci_bridge_initfn(d, TYPE_PCIE_BUS);
pcie_port_init_reg(d);

View File

@ -11,6 +11,7 @@
*/
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
#include "hw/pci/pci_host.h"
@ -162,30 +163,25 @@ static const TypeInfo pxb_host_info = {
};
/*
* Registers the PXB bus as a child of the i440fx root bus.
*
* Returns 0 on successs, -1 if i440fx host was not
* found or the bus number is already in use.
* Registers the PXB bus as a child of pci host root bus.
*/
static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus)
static void pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus, Error **errp)
{
PCIBus *bus = dev->bus;
int pxb_bus_num = pci_bus_num(pxb_bus);
if (bus->parent_dev) {
error_report("PXB devices can be attached only to root bus.");
return -1;
error_setg(errp, "PXB devices can be attached only to root bus");
return;
}
QLIST_FOREACH(bus, &bus->child, sibling) {
if (pci_bus_num(bus) == pxb_bus_num) {
error_report("Bus %d is already in use.", pxb_bus_num);
return -1;
error_setg(errp, "Bus %d is already in use", pxb_bus_num);
return;
}
}
QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling);
return 0;
}
static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
@ -215,17 +211,18 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
0;
}
static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
{
PXBDev *pxb = convert_to_pxb(dev);
DeviceState *ds, *bds = NULL;
PCIBus *bus;
const char *dev_name = NULL;
Error *local_err = NULL;
if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
pxb->numa_node >= nb_numa_nodes) {
error_report("Illegal numa node %d.", pxb->numa_node);
return -EINVAL;
error_setg(errp, "Illegal numa node %d", pxb->numa_node);
return;
}
if (dev->qdev.id && *dev->qdev.id) {
@ -250,7 +247,9 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
PCI_HOST_BRIDGE(ds)->bus = bus;
if (pxb_register_bus(dev, bus)) {
pxb_register_bus(dev, bus, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto err_register_bus;
}
@ -264,23 +263,22 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
return 0;
return;
err_register_bus:
object_unref(OBJECT(bds));
object_unparent(OBJECT(bus));
object_unref(OBJECT(ds));
return -EINVAL;
}
static int pxb_dev_initfn(PCIDevice *dev)
static void pxb_dev_realize(PCIDevice *dev, Error **errp)
{
if (pci_bus_is_express(dev->bus)) {
error_report("pxb devices cannot reside on a PCIe bus!");
return -EINVAL;
error_setg(errp, "pxb devices cannot reside on a PCIe bus");
return;
}
return pxb_dev_init_common(dev, false);
pxb_dev_realize_common(dev, false, errp);
}
static void pxb_dev_exitfn(PCIDevice *pci_dev)
@ -302,7 +300,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = pxb_dev_initfn;
k->realize = pxb_dev_realize;
k->exit = pxb_dev_exitfn;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
@ -310,6 +308,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
dc->desc = "PCI Expander Bridge";
dc->props = pxb_dev_properties;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}
@ -320,14 +319,14 @@ static const TypeInfo pxb_dev_info = {
.class_init = pxb_dev_class_init,
};
static int pxb_pcie_dev_initfn(PCIDevice *dev)
static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp)
{
if (!pci_bus_is_express(dev->bus)) {
error_report("pxb-pcie devices cannot reside on a PCI bus!");
return -EINVAL;
error_setg(errp, "pxb-pcie devices cannot reside on a PCI bus");
return;
}
return pxb_dev_init_common(dev, true);
pxb_dev_realize_common(dev, true, errp);
}
static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
@ -335,7 +334,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = pxb_pcie_dev_initfn;
k->realize = pxb_pcie_dev_realize;
k->exit = pxb_dev_exitfn;
k->vendor_id = PCI_VENDOR_ID_REDHAT;
k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE;
@ -343,6 +342,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
dc->desc = "PCI Express Expander Bridge";
dc->props = pxb_dev_properties;
dc->hotpluggable = false;
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
}

View File

@ -634,7 +634,7 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
}
}
static int apb_pci_bridge_initfn(PCIDevice *dev)
static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp)
{
pci_bridge_initfn(dev, TYPE_PCI_BUS);
@ -652,7 +652,6 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
pci_set_word(dev->config + PCI_STATUS,
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
PCI_STATUS_DEVSEL_MEDIUM);
return 0;
}
PCIBus *pci_apb_init(hwaddr special_base,
@ -843,7 +842,7 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
k->init = apb_pci_bridge_initfn;
k->realize = apb_pci_bridge_realize;
k->exit = pci_bridge_exitfn;
k->vendor_id = PCI_VENDOR_ID_SUN;
k->device_id = PCI_DEVICE_ID_SUN_SIMBA;

View File

@ -62,6 +62,8 @@ static Property pci_props[] = {
QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
QEMU_PCI_CAP_SERR_BITNR, true),
DEFINE_PROP_BIT("x-pcie-lnksta-dllla", PCIDevice, cap_present,
QEMU_PCIE_LNKSTA_DLLLA_BITNR, true),
DEFINE_PROP_END_OF_LIST()
};

View File

@ -45,8 +45,11 @@
*/
static void
pcie_cap_v1_fill(uint8_t *exp_cap, uint8_t port, uint8_t type, uint8_t version)
pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
{
uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
uint8_t *cmask = dev->cmask + dev->exp.exp_cap;
/* capability register
interrupt message number defaults to 0 */
pci_set_word(exp_cap + PCI_EXP_FLAGS,
@ -69,7 +72,18 @@ pcie_cap_v1_fill(uint8_t *exp_cap, uint8_t port, uint8_t type, uint8_t version)
PCI_EXP_LNK_LS_25);
pci_set_word(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25 |PCI_EXP_LNKSTA_DLLLA);
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
PCI_EXP_LNKSTA_DLLLA);
}
/* We changed link status bits over time, and changing them across
* migrations is generally fine as hardware changes them too.
* Let's not bother checking.
*/
pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
}
int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
@ -88,7 +102,7 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
exp_cap = dev->config + pos;
/* Filling values common with v1 */
pcie_cap_v1_fill(exp_cap, port, type, PCI_EXP_FLAGS_VER2);
pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
/* Filling v2 specific values */
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
@ -103,7 +117,6 @@ int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
{
/* PCIe cap v1 init */
int pos;
uint8_t *exp_cap;
assert(pci_is_express(dev));
@ -112,9 +125,8 @@ int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
return pos;
}
dev->exp.exp_cap = pos;
exp_cap = dev->config + pos;
pcie_cap_v1_fill(exp_cap, port, type, PCI_EXP_FLAGS_VER1);
pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER1);
return pos;
}

View File

@ -1370,7 +1370,7 @@ static const VMStateDescription vmstate_mptsas = {
.post_load = mptsas_post_load,
.fields = (VMStateField[]) {
VMSTATE_PCI_DEVICE(dev, MPTSASState),
VMSTATE_UNUSED(sizeof(bool)), /* Was msi_in_use */
VMSTATE_UINT32(state, MPTSASState),
VMSTATE_UINT8(who_init, MPTSASState),
VMSTATE_UINT8(doorbell_state, MPTSASState),

View File

@ -176,7 +176,7 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
int *fds, int fd_num)
{
CharDriverState *chr = dev->opaque;
int size = VHOST_USER_HDR_SIZE + msg->size;
int ret, size = VHOST_USER_HDR_SIZE + msg->size;
/*
* For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
@ -187,12 +187,19 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
return 0;
}
if (fd_num) {
qemu_chr_fe_set_msgfds(chr, fds, fd_num);
if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
error_report("Failed to set msg fds.");
return -1;
}
return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ?
0 : -1;
ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
if (ret != size) {
error_report("Failed to write msg."
" Wrote %d instead of %d.", ret, size);
return -1;
}
return 0;
}
static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
@ -214,12 +221,14 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
fds[fd_num++] = log->fd;
}
vhost_user_write(dev, &msg, fds, fd_num);
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
return -1;
}
if (shmfd) {
msg.size = 0;
if (vhost_user_read(dev, &msg) < 0) {
return 0;
return -1;
}
if (msg.request != VHOST_USER_SET_LOG_BASE) {
@ -275,7 +284,9 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
msg.size += sizeof(msg.payload.memory.padding);
msg.size += fd_num * sizeof(VhostUserMemoryRegion);
vhost_user_write(dev, &msg, fds, fd_num);
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
return -1;
}
return 0;
}
@ -290,7 +301,9 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev,
.size = sizeof(msg.payload.addr),
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
return 0;
}
@ -313,7 +326,9 @@ static int vhost_set_vring(struct vhost_dev *dev,
.size = sizeof(msg.payload.state),
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
return 0;
}
@ -360,10 +375,12 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
.size = sizeof(msg.payload.state),
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
if (vhost_user_read(dev, &msg) < 0) {
return 0;
return -1;
}
if (msg.request != VHOST_USER_GET_VRING_BASE) {
@ -401,7 +418,9 @@ static int vhost_set_vring_file(struct vhost_dev *dev,
msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
}
vhost_user_write(dev, &msg, fds, fd_num);
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
return -1;
}
return 0;
}
@ -427,7 +446,9 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
.size = sizeof(msg.payload.u64),
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
return 0;
}
@ -455,10 +476,12 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
return 0;
}
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
if (vhost_user_read(dev, &msg) < 0) {
return 0;
return -1;
}
if (msg.request != request) {
@ -489,7 +512,9 @@ static int vhost_user_set_owner(struct vhost_dev *dev)
.flags = VHOST_USER_VERSION,
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
return 0;
}
@ -501,7 +526,9 @@ static int vhost_user_reset_device(struct vhost_dev *dev)
.flags = VHOST_USER_VERSION,
};
vhost_user_write(dev, &msg, NULL, 0);
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
return -1;
}
return 0;
}
@ -588,7 +615,6 @@ static bool vhost_user_requires_shm_log(struct vhost_dev *dev)
static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
{
VhostUserMsg msg = { 0 };
int err;
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
@ -605,8 +631,7 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
memcpy((char *)&msg.payload.u64, mac_addr, 6);
msg.size = sizeof(msg.payload.u64);
err = vhost_user_write(dev, &msg, NULL, 0);
return err;
return vhost_user_write(dev, &msg, NULL, 0);
}
return -1;
}

View File

@ -27,6 +27,18 @@
#include "hw/virtio/virtio-access.h"
#include "migration/migration.h"
/* enabled until disconnected backend stabilizes */
#define _VHOST_DEBUG 1
#ifdef _VHOST_DEBUG
#define VHOST_OPS_DEBUG(fmt, ...) \
do { error_report(fmt ": %s (%d)", ## __VA_ARGS__, \
strerror(errno), errno); } while (0)
#else
#define VHOST_OPS_DEBUG(fmt, ...) \
do { } while (0)
#endif
static struct vhost_log *vhost_log;
static struct vhost_log *vhost_log_shm;
@ -362,6 +374,8 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync)
if (!log) {
return;
}
dev->log = NULL;
dev->log_size = 0;
--log->refcnt;
if (log->refcnt == 0) {
@ -398,7 +412,10 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
/* inform backend of log switching, this must be done before
releasing the current log, to ensure no logging is lost */
r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log);
assert(r >= 0);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_log_base failed");
}
vhost_log_put(dev, true);
dev->log = log;
dev->log_size = size;
@ -422,11 +439,11 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
l = vq->ring_size;
p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
if (!p || l != vq->ring_size) {
fprintf(stderr, "Unable to map ring buffer for ring %d\n", i);
error_report("Unable to map ring buffer for ring %d", i);
r = -ENOMEM;
}
if (p != vq->ring) {
fprintf(stderr, "Ring buffer relocated for ring %d\n", i);
error_report("Ring buffer relocated for ring %d", i);
r = -EBUSY;
}
cpu_physical_memory_unmap(p, l, 0, 0);
@ -565,7 +582,9 @@ static void vhost_commit(MemoryListener *listener)
if (!dev->log_enabled) {
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
assert(r >= 0);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_mem_table failed");
}
dev->memory_changed = false;
return;
}
@ -578,7 +597,9 @@ static void vhost_commit(MemoryListener *listener)
vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
}
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
assert(r >= 0);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_mem_table failed");
}
/* To log less, can only decrease log size after table update. */
if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
vhost_dev_log_resize(dev, log_size);
@ -647,6 +668,7 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
};
int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_vring_addr failed");
return -errno;
}
return 0;
@ -660,12 +682,15 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
features |= 0x1ULL << VHOST_F_LOG_ALL;
}
r = dev->vhost_ops->vhost_set_features(dev, features);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_features failed");
}
return r < 0 ? -errno : 0;
}
static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
{
int r, t, i, idx;
int r, i, idx;
r = vhost_dev_set_features(dev, enable_log);
if (r < 0) {
goto err_features;
@ -682,12 +707,10 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
err_vq:
for (; i >= 0; --i) {
idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
t = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
dev->log_enabled);
assert(t >= 0);
vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
dev->log_enabled);
}
t = vhost_dev_set_features(dev, dev->log_enabled);
assert(t >= 0);
vhost_dev_set_features(dev, dev->log_enabled);
err_features:
return r;
}
@ -710,8 +733,6 @@ static int vhost_migration_log(MemoryListener *listener, int enable)
return r;
}
vhost_log_put(dev, false);
dev->log = NULL;
dev->log_size = 0;
} else {
vhost_dev_log_resize(dev, vhost_get_log_size(dev));
r = vhost_dev_set_log(dev, true);
@ -787,6 +808,7 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
return 0;
}
VHOST_OPS_DEBUG("vhost_set_vring_endian failed");
if (errno == ENOTTY) {
error_report("vhost does not support cross-endian");
return -ENOSYS;
@ -815,12 +837,14 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
vq->num = state.num = virtio_queue_get_num(vdev, idx);
r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_num failed");
return -errno;
}
state.num = virtio_queue_get_last_avail_idx(vdev, idx);
r = dev->vhost_ops->vhost_set_vring_base(dev, &state);
if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_base failed");
return -errno;
}
@ -872,6 +896,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_kick failed");
r = -errno;
goto fail_kick;
}
@ -919,25 +944,21 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
if (r < 0) {
fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
fflush(stderr);
VHOST_OPS_DEBUG("vhost VQ %d ring restore failed: %d", idx, r);
} else {
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
}
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
virtio_queue_invalidate_signalled_used(vdev, idx);
/* In the cross-endian case, we need to reset the vring endianness to
* native as legacy devices expect so by default.
*/
if (vhost_needs_vring_endian(vdev)) {
r = vhost_virtqueue_set_vring_endian_legacy(dev,
!virtio_is_big_endian(vdev),
vhost_vq_index);
if (r < 0) {
error_report("failed to reset vring endianness");
}
vhost_virtqueue_set_vring_endian_legacy(dev,
!virtio_is_big_endian(vdev),
vhost_vq_index);
}
assert (r >= 0);
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
0, virtio_queue_get_ring_size(vdev, idx));
cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
@ -976,6 +997,7 @@ static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state);
if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_busyloop_timeout failed");
return r;
}
@ -997,6 +1019,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
file.fd = event_notifier_get_fd(&vq->masked_notifier);
r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
if (r) {
VHOST_OPS_DEBUG("vhost_set_vring_call failed");
r = -errno;
goto fail_call;
}
@ -1015,42 +1038,41 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
VhostBackendType backend_type, uint32_t busyloop_timeout)
{
uint64_t features;
int i, r;
int i, r, n_initialized_vqs = 0;
hdev->migration_blocker = NULL;
if (vhost_set_backend_type(hdev, backend_type) < 0) {
close((uintptr_t)opaque);
return -1;
}
r = vhost_set_backend_type(hdev, backend_type);
assert(r >= 0);
if (hdev->vhost_ops->vhost_backend_init(hdev, opaque) < 0) {
close((uintptr_t)opaque);
return -errno;
r = hdev->vhost_ops->vhost_backend_init(hdev, opaque);
if (r < 0) {
goto fail;
}
if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) {
fprintf(stderr, "vhost backend memory slots limit is less"
" than current number of present memory slots\n");
close((uintptr_t)opaque);
return -1;
error_report("vhost backend memory slots limit is less"
" than current number of present memory slots");
r = -1;
goto fail;
}
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
r = hdev->vhost_ops->vhost_set_owner(hdev);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_owner failed");
goto fail;
}
r = hdev->vhost_ops->vhost_get_features(hdev, &features);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_get_features failed");
goto fail;
}
for (i = 0; i < hdev->nvqs; ++i) {
for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) {
r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i);
if (r < 0) {
goto fail_vq;
goto fail;
}
}
@ -1105,38 +1127,43 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
hdev->started = false;
hdev->memory_changed = false;
memory_listener_register(&hdev->memory_listener, &address_space_memory);
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
return 0;
fail_busyloop:
while (--i >= 0) {
vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, 0);
}
i = hdev->nvqs;
fail_vq:
while (--i >= 0) {
vhost_virtqueue_cleanup(hdev->vqs + i);
}
fail:
r = -errno;
hdev->vhost_ops->vhost_backend_cleanup(hdev);
QLIST_REMOVE(hdev, entry);
hdev->nvqs = n_initialized_vqs;
vhost_dev_cleanup(hdev);
return r;
}
void vhost_dev_cleanup(struct vhost_dev *hdev)
{
int i;
for (i = 0; i < hdev->nvqs; ++i) {
vhost_virtqueue_cleanup(hdev->vqs + i);
}
memory_listener_unregister(&hdev->memory_listener);
if (hdev->mem) {
/* those are only safe after successful init */
memory_listener_unregister(&hdev->memory_listener);
QLIST_REMOVE(hdev, entry);
}
if (hdev->migration_blocker) {
migrate_del_blocker(hdev->migration_blocker);
error_free(hdev->migration_blocker);
}
g_free(hdev->mem);
g_free(hdev->mem_sections);
hdev->vhost_ops->vhost_backend_cleanup(hdev);
QLIST_REMOVE(hdev, entry);
if (hdev->vhost_ops) {
hdev->vhost_ops->vhost_backend_cleanup(hdev);
}
assert(!hdev->log);
memset(hdev, 0, sizeof(struct vhost_dev));
}
/* Stop processing guest IO notifications in qemu.
@ -1148,8 +1175,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
VirtioBusState *vbus = VIRTIO_BUS(qbus);
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
int i, r, e;
if (!k->ioeventfd_started) {
fprintf(stderr, "binding does not support host notifiers\n");
error_report("binding does not support host notifiers");
r = -ENOSYS;
goto fail;
}
@ -1158,7 +1186,7 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
true);
if (r < 0) {
fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
error_report("vhost VQ %d notifier binding failed: %d", i, -r);
goto fail_vq;
}
}
@ -1169,8 +1197,7 @@ fail_vq:
e = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
false);
if (e < 0) {
fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
fflush(stderr);
error_report("vhost VQ %d notifier cleanup error: %d", i, -r);
}
assert (e >= 0);
}
@ -1192,8 +1219,7 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
false);
if (r < 0) {
fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
fflush(stderr);
error_report("vhost VQ %d notifier cleanup failed: %d", i, -r);
}
assert (r >= 0);
}
@ -1217,6 +1243,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
int r, index = n - hdev->vq_index;
struct vhost_vring_file file;
/* should only be called after backend is connected */
assert(hdev->vhost_ops);
if (mask) {
assert(vdev->use_guest_notifier_mask);
file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
@ -1226,7 +1255,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);
r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
assert(r >= 0);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_vring_call failed");
}
}
uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
@ -1261,6 +1292,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
{
int i, r;
/* should only be called after backend is connected */
assert(hdev->vhost_ops);
hdev->started = true;
r = vhost_dev_set_features(hdev, hdev->log_enabled);
@ -1269,6 +1303,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
}
r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_mem_table failed");
r = -errno;
goto fail_mem;
}
@ -1293,6 +1328,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
hdev->log_size ? log_base : 0,
hdev->log);
if (r < 0) {
VHOST_OPS_DEBUG("vhost_set_log_base failed");
r = -errno;
goto fail_log;
}
@ -1321,6 +1357,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
{
int i;
/* should only be called after backend is connected */
assert(hdev->vhost_ops);
for (i = 0; i < hdev->nvqs; ++i) {
vhost_virtqueue_stop(hdev,
vdev,
@ -1330,7 +1369,14 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
vhost_log_put(hdev, true);
hdev->started = false;
hdev->log = NULL;
hdev->log_size = 0;
}
int vhost_net_set_backend(struct vhost_dev *hdev,
struct vhost_vring_file *file)
{
if (hdev->vhost_ops->vhost_net_set_backend) {
return hdev->vhost_ops->vhost_net_set_backend(hdev, file);
}
return -1;
}

View File

@ -161,7 +161,7 @@ static bool virtio_pci_modern_state_needed(void *opaque)
{
VirtIOPCIProxy *proxy = opaque;
return !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
return virtio_pci_modern(proxy);
}
static const VMStateDescription vmstate_virtio_pci_modern_state = {
@ -300,8 +300,8 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier,
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
VirtQueue *vq = virtio_get_queue(vdev, n);
bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
bool legacy = virtio_pci_legacy(proxy);
bool modern = virtio_pci_modern(proxy);
bool fast_mmio = kvm_ioeventfd_any_length_enabled();
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
MemoryRegion *modern_mr = &proxy->notify.mr;
@ -1574,8 +1574,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
VirtioBusState *bus = &proxy->bus;
bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
bool legacy = virtio_pci_legacy(proxy);
bool modern = virtio_pci_modern(proxy);
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
uint8_t *config;
uint32_t size;
@ -1694,7 +1694,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
static void virtio_pci_device_unplugged(DeviceState *d)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
bool modern = virtio_pci_modern(proxy);
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
virtio_pci_stop_ioeventfd(proxy);
@ -1714,6 +1714,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
{
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
bool pcie_port = pci_bus_is_express(pci_dev->bus) &&
!pci_bus_is_root(pci_dev->bus);
/*
* virtio pci bar layout used by default.
@ -1764,8 +1766,11 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");
if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus) &&
!pci_bus_is_root(pci_dev->bus)) {
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
if (pcie_port && pci_is_express(pci_dev)) {
int pos;
pos = pcie_endpoint_cap_init(pci_dev, 0);
@ -1819,10 +1824,9 @@ static void virtio_pci_reset(DeviceState *qdev)
static Property virtio_pci_properties[] = {
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true),
DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
@ -1839,7 +1843,7 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
PCIDevice *pci_dev = &proxy->pci_dev;
if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) &&
!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN)) {
virtio_pci_modern(proxy)) {
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
}
@ -2301,9 +2305,7 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
DeviceState *vdev = DEVICE(&vinput->vdev);
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
/* force virtio-1.0 */
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
virtio_pci_force_virtio_1(vpci_dev);
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
}

View File

@ -61,8 +61,6 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
enum {
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT,
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT,
VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT,
VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT,
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT,
VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT,
VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT,
@ -77,8 +75,6 @@ enum {
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
/* virtio version flags */
#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
#define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT)
/* migrate extra state */
@ -144,6 +140,8 @@ struct VirtIOPCIProxy {
uint32_t modern_mem_bar;
int config_cap;
uint32_t flags;
bool disable_modern;
OnOffAuto disable_legacy;
uint32_t class_code;
uint32_t nvectors;
uint32_t dfselect;
@ -158,6 +156,21 @@ struct VirtIOPCIProxy {
VirtioBusState bus;
};
static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy)
{
return !proxy->disable_modern;
}
static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy)
{
return proxy->disable_legacy == ON_OFF_AUTO_OFF;
}
static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy)
{
proxy->disable_modern = false;
proxy->disable_legacy = ON_OFF_AUTO_ON;
}
/*
* virtio-scsi-pci: This extends VirtioPCIProxy.

View File

@ -458,6 +458,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove
unsigned num_sg = *p_num_sg;
assert(num_sg <= max_num_sg);
if (!sz) {
error_report("virtio: zero sized buffers are not allowed");
exit(1);
}
while (sz) {
hwaddr len = sz;

View File

@ -6,6 +6,14 @@
.driver = "virtio-mmio",\
.property = "format_transport_address",\
.value = "off",\
},{\
.driver = "virtio-pci",\
.property = "disable-modern",\
.value = "on",\
},{\
.driver = "virtio-pci",\
.property = "disable-legacy",\
.value = "off",\
},
#define HW_COMPAT_2_5 \
@ -80,6 +88,10 @@
.driver = "virtio-rng-pci",\
.property = "any_layout",\
.value = "off",\
},{\
.driver = TYPE_PCI_DEVICE,\
.property = "x-pcie-lnksta-dllla",\
.value = "off",\
},
#define HW_COMPAT_2_2 \

View File

@ -174,6 +174,9 @@ enum {
/* PCI Express capability - Power Controller Present */
#define QEMU_PCIE_SLTCAP_PCP_BITNR 7
QEMU_PCIE_SLTCAP_PCP = (1 << QEMU_PCIE_SLTCAP_PCP_BITNR),
/* Link active status in endpoint capability is always set */
#define QEMU_PCIE_LNKSTA_DLLLA_BITNR 8
QEMU_PCIE_LNKSTA_DLLLA = (1 << QEMU_PCIE_LNKSTA_DLLLA_BITNR),
};
#define TYPE_PCI_DEVICE "pci-device"

View File

@ -86,4 +86,8 @@ uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
uint64_t features);
bool vhost_has_free_slot(void);
int vhost_net_set_backend(struct vhost_dev *hdev,
struct vhost_vring_file *file);
#endif

View File

@ -70,6 +70,7 @@ struct CharDriverState {
int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
int (*chr_add_client)(struct CharDriverState *chr, int fd);
int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
IOEventHandler *chr_event;
IOCanReadHandler *chr_can_read;
IOReadHandler *chr_read;
@ -158,6 +159,13 @@ void qemu_chr_disconnect(CharDriverState *chr);
*/
void qemu_chr_cleanup(void);
/**
* @qemu_chr_wait_connected:
*
* Wait for characted backend to be connected.
*/
int qemu_chr_wait_connected(CharDriverState *chr, Error **errp);
/**
* @qemu_chr_new_noreplay:
*

View File

@ -312,6 +312,7 @@ static void tap_cleanup(NetClientState *nc)
if (s->vhost_net) {
vhost_net_cleanup(s->vhost_net);
g_free(s->vhost_net);
s->vhost_net = NULL;
}

View File

@ -24,6 +24,7 @@ typedef struct VhostUserState {
VHostNetState *vhost_net;
guint watch;
uint64_t acked_features;
bool started;
} VhostUserState;
typedef struct VhostUserChardevProps {
@ -45,11 +46,6 @@ uint64_t vhost_user_get_acked_features(NetClientState *nc)
return s->acked_features;
}
static int vhost_user_running(VhostUserState *s)
{
return (s->vhost_net) ? 1 : 0;
}
static void vhost_user_stop(int queues, NetClientState *ncs[])
{
VhostUserState *s;
@ -59,15 +55,14 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
s = DO_UPCAST(VhostUserState, nc, ncs[i]);
if (!vhost_user_running(s)) {
continue;
}
if (s->vhost_net) {
/* save acked features */
s->acked_features = vhost_net_get_acked_features(s->vhost_net);
uint64_t features = vhost_net_get_acked_features(s->vhost_net);
if (features) {
s->acked_features = features;
}
vhost_net_cleanup(s->vhost_net);
s->vhost_net = NULL;
}
}
}
@ -75,6 +70,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
static int vhost_user_start(int queues, NetClientState *ncs[])
{
VhostNetOptions options;
struct vhost_net *net = NULL;
VhostUserState *s;
int max_queues;
int i;
@ -85,33 +81,39 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
s = DO_UPCAST(VhostUserState, nc, ncs[i]);
if (vhost_user_running(s)) {
continue;
}
options.net_backend = ncs[i];
options.opaque = s->chr;
options.busyloop_timeout = 0;
s->vhost_net = vhost_net_init(&options);
if (!s->vhost_net) {
net = vhost_net_init(&options);
if (!net) {
error_report("failed to init vhost_net for queue %d", i);
goto err;
}
if (i == 0) {
max_queues = vhost_net_get_max_queues(s->vhost_net);
max_queues = vhost_net_get_max_queues(net);
if (queues > max_queues) {
error_report("you are asking more queues than supported: %d",
max_queues);
goto err;
}
}
if (s->vhost_net) {
vhost_net_cleanup(s->vhost_net);
g_free(s->vhost_net);
}
s->vhost_net = net;
}
return 0;
err:
vhost_user_stop(i + 1, ncs);
if (net) {
vhost_net_cleanup(net);
}
vhost_user_stop(i, ncs);
return -1;
}
@ -150,6 +152,7 @@ static void vhost_user_cleanup(NetClientState *nc)
if (s->vhost_net) {
vhost_net_cleanup(s->vhost_net);
g_free(s->vhost_net);
s->vhost_net = NULL;
}
if (s->chr) {
@ -188,12 +191,8 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
void *opaque)
{
VhostUserState *s = opaque;
uint8_t buf[1];
/* We don't actually want to read anything, but CHR_EVENT_CLOSED will be
* raised as a side-effect of the read.
*/
qemu_chr_fe_read_all(s->chr, buf, sizeof(buf));
qemu_chr_disconnect(s->chr);
return FALSE;
}
@ -222,6 +221,7 @@ static void net_vhost_user_event(void *opaque, int event)
return;
}
qmp_set_link(name, true, &err);
s->started = true;
break;
case CHR_EVENT_CLOSED:
qmp_set_link(name, false, &err);
@ -240,7 +240,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
const char *name, CharDriverState *chr,
int queues)
{
NetClientState *nc;
NetClientState *nc, *nc0 = NULL;
VhostUserState *s;
int i;
@ -249,6 +249,9 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
for (i = 0; i < queues; i++) {
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
if (!nc0) {
nc0 = nc;
}
snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
i, chr->label);
@ -259,7 +262,18 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
s->chr = chr;
}
qemu_chr_add_handlers(chr, NULL, NULL, net_vhost_user_event, nc[0].name);
s = DO_UPCAST(VhostUserState, nc, nc0);
do {
Error *err = NULL;
if (qemu_chr_wait_connected(chr, &err) < 0) {
error_report_err(err);
return -1;
}
qemu_chr_add_handlers(chr, NULL, NULL,
net_vhost_user_event, nc0->name);
} while (!s->started);
assert(s->vhost_net);
return 0;
}
@ -316,7 +330,6 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
{
const char *name = opaque;
const char *driver, *netdev;
const char virtio_name[] = "virtio-net-";
driver = qemu_opt_get(opts, "driver");
netdev = qemu_opt_get(opts, "netdev");
@ -326,7 +339,7 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
}
if (strcmp(netdev, name) == 0 &&
strncmp(driver, virtio_name, strlen(virtio_name)) != 0) {
!g_str_has_prefix(driver, "virtio-net-")) {
error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
return -1;
}

View File

@ -2760,14 +2760,16 @@ static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
{
TCPCharDriver *s = chr->opaque;
if (!qio_channel_has_feature(s->ioc,
QIO_CHANNEL_FEATURE_FD_PASS)) {
return -1;
}
/* clear old pending fd array */
g_free(s->write_msgfds);
s->write_msgfds = NULL;
if (!s->connected ||
!qio_channel_has_feature(s->ioc,
QIO_CHANNEL_FEATURE_FD_PASS)) {
return -1;
}
if (num) {
s->write_msgfds = g_new(int, num);
memcpy(s->write_msgfds, fds, num * sizeof(int));
@ -3137,6 +3139,41 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
return TRUE;
}
static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
{
TCPCharDriver *s = chr->opaque;
QIOChannelSocket *sioc;
while (!s->connected) {
if (s->is_listen) {
fprintf(stderr, "QEMU waiting for connection on: %s\n",
chr->filename);
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
} else {
sioc = qio_channel_socket_new();
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
object_unref(OBJECT(sioc));
return -1;
}
tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
}
}
return 0;
}
int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
{
if (chr->chr_wait_connected) {
return chr->chr_wait_connected(chr, errp);
}
return 0;
}
static void tcp_chr_close(CharDriverState *chr)
{
TCPCharDriver *s = chr->opaque;
@ -4391,6 +4428,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
s->addr = QAPI_CLONE(SocketAddress, sock->addr);
chr->opaque = s;
chr->chr_wait_connected = tcp_chr_wait_connected;
chr->chr_write = tcp_chr_write;
chr->chr_sync_read = tcp_chr_sync_read;
chr->chr_close = tcp_chr_close;
@ -4414,32 +4452,30 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
s->reconnect_time = reconnect;
}
sioc = qio_channel_socket_new();
if (s->reconnect_time) {
sioc = qio_channel_socket_new();
qio_channel_socket_connect_async(sioc, s->addr,
qemu_chr_socket_connected,
chr, NULL);
} else if (s->is_listen) {
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
goto error;
}
s->listen_ioc = sioc;
if (is_waitconnect) {
fprintf(stderr, "QEMU waiting for connection on: %s\n",
chr->filename);
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
}
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
if (!s->ioc) {
s->listen_tag = qio_channel_add_watch(
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
}
} else {
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
if (s->is_listen) {
sioc = qio_channel_socket_new();
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
goto error;
}
s->listen_ioc = sioc;
if (is_waitconnect &&
qemu_chr_wait_connected(chr, errp) < 0) {
goto error;
}
if (!s->ioc) {
s->listen_tag = qio_channel_add_watch(
QIO_CHANNEL(s->listen_ioc), G_IO_IN,
tcp_chr_accept, chr, NULL);
}
} else if (qemu_chr_wait_connected(chr, errp) < 0) {
goto error;
}
tcp_chr_new_client(chr, sioc);
object_unref(OBJECT(sioc));
}
return chr;

View File

@ -683,6 +683,7 @@ static void test_reconnect(void)
qtest_get_arch());
g_test_trap_subprocess(path, 0, 0);
g_test_trap_assert_passed();
g_free(path);
}
#endif

View File

@ -149,6 +149,7 @@ static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev,
char test[] = "TEST";
char buffer[64];
int len = htonl(sizeof(test));
QDict *rsp;
struct iovec iov[] = {
{
.iov_base = &len,
@ -165,7 +166,8 @@ static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev,
free_head = qvirtqueue_add(vq, req_addr, 64, true, false);
qvirtqueue_kick(bus, dev, vq, free_head);
qmp("{ 'execute' : 'stop'}");
rsp = qmp("{ 'execute' : 'stop'}");
QDECREF(rsp);
ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
@ -173,8 +175,10 @@ static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev,
/* We could check the status, but this command is more importantly to
* ensure the packet data gets queued in QEMU, before we do 'cont'.
*/
qmp("{ 'execute' : 'query-status'}");
qmp("{ 'execute' : 'cont'}");
rsp = qmp("{ 'execute' : 'query-status'}");
QDECREF(rsp);
rsp = qmp("{ 'execute' : 'cont'}");
QDECREF(rsp);
qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US);
memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
@ -230,8 +234,10 @@ static void pci_basic(gconstpointer data)
/* End test */
close(sv[0]);
qvirtqueue_cleanup(&qvirtio_pci, &tx->vq, alloc);
qvirtqueue_cleanup(&qvirtio_pci, &rx->vq, alloc);
pc_alloc_uninit(alloc);
qvirtio_pci_device_disable(dev);
g_free(dev->pdev);
g_free(dev);
qpci_free_pc(bus);
test_end();