Merge remote branch 'mst/for_anthony' into staging

This commit is contained in:
Anthony Liguori 2010-12-17 08:21:29 -06:00
commit b254b0d15d
13 changed files with 196 additions and 123 deletions

View File

@ -168,7 +168,8 @@ hw-obj-$(CONFIG_VIRTIO) += virtio.o virtio-console.o
hw-obj-y += fw_cfg.o
# FIXME: Core PCI code and its direct dependencies are required by the
# QMP query-pci command.
hw-obj-y += pci.o pci_bridge.o msix.o msi.o
hw-obj-y += pci.o pci_bridge.o
hw-obj-$(CONFIG_PCI) += msix.o msi.o
hw-obj-$(CONFIG_PCI) += pci_host.o pcie_host.o
hw-obj-$(CONFIG_PCI) += ioh3420.o xio3130_upstream.o xio3130_downstream.o
hw-obj-y += watchdog.o

2
cpus.c
View File

@ -111,6 +111,8 @@ static void do_vm_stop(int reason)
vm_running = 0;
pause_all_vcpus();
vm_state_notify(0, reason);
qemu_aio_flush();
bdrv_flush_all();
monitor_protocol_event(QEVENT_STOP, NULL);
}
}

View File

@ -217,6 +217,14 @@ static QEMUMachine pc_machine = {
.desc = "Standard PC",
.init = pc_init_pci,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
{
.driver = "PCI",
.property = "command_serr_enable",
.value = "off",
},
{ /* end of list */ }
},
.is_default = 1,
};
@ -265,6 +273,10 @@ static QEMUMachine pc_machine_v0_12 = {
.driver = "vmware-svga",
.property = "rombar",
.value = stringify(0),
},{
.driver = "PCI",
.property = "command_serr_enable",
.value = "off",
},
{ /* end of list */ }
}
@ -300,6 +312,10 @@ static QEMUMachine pc_machine_v0_11 = {
.driver = "PCI",
.property = "rombar",
.value = stringify(0),
},{
.driver = "PCI",
.property = "command_serr_enable",
.value = "off",
},
{ /* end of list */ }
}
@ -347,6 +363,10 @@ static QEMUMachine pc_machine_v0_10 = {
.driver = "PCI",
.property = "rombar",
.value = stringify(0),
},{
.driver = "PCI",
.property = "command_serr_enable",
.value = "off",
},
{ /* end of list */ }
},

View File

@ -25,8 +25,6 @@
#include "pci.h"
#include "pci_bridge.h"
#include "pci_internals.h"
#include "msix.h"
#include "msi.h"
#include "monitor.h"
#include "net.h"
#include "sysemu.h"
@ -59,6 +57,8 @@ struct BusInfo pci_bus_info = {
DEFINE_PROP_UINT32("rombar", PCIDevice, rom_bar, 1),
DEFINE_PROP_BIT("multifunction", PCIDevice, cap_present,
QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
QEMU_PCI_CAP_SERR_BITNR, true),
DEFINE_PROP_END_OF_LIST()
}
};
@ -570,6 +570,9 @@ static void pci_init_wmask(PCIDevice *dev)
pci_set_word(dev->wmask + PCI_COMMAND,
PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
PCI_COMMAND_INTX_DISABLE);
if (dev->cap_present & QEMU_PCI_CAP_SERR) {
pci_word_test_and_set_mask(dev->wmask + PCI_COMMAND, PCI_COMMAND_SERR);
}
memset(dev->wmask + PCI_CONFIG_HEADER_SIZE, 0xff,
config_size - PCI_CONFIG_HEADER_SIZE);
@ -1096,23 +1099,6 @@ static void pci_set_irq(void *opaque, int irq_num, int level)
pci_change_irq_level(pci_dev, irq_num, change);
}
bool pci_msi_enabled(PCIDevice *dev)
{
return msix_enabled(dev) || msi_enabled(dev);
}
void pci_msi_notify(PCIDevice *dev, unsigned int vector)
{
if (msix_enabled(dev)) {
msix_notify(dev, vector);
} else if (msi_enabled(dev)) {
msi_notify(dev, vector);
} else {
/* MSI/MSI-X must be enabled */
abort();
}
}
/***********************************************************/
/* monitor info on PCI */

View File

@ -118,6 +118,10 @@ enum {
/* multifunction capable device */
#define QEMU_PCI_CAP_MULTIFUNCTION_BITNR 3
QEMU_PCI_CAP_MULTIFUNCTION = (1 << QEMU_PCI_CAP_MULTIFUNCTION_BITNR),
/* command register SERR bit enabled */
#define QEMU_PCI_CAP_SERR_BITNR 4
QEMU_PCI_CAP_SERR = (1 << QEMU_PCI_CAP_SERR_BITNR),
};
struct PCIDevice {
@ -257,9 +261,6 @@ void do_pci_info_print(Monitor *mon, const QObject *data);
void do_pci_info(Monitor *mon, QObject **ret_data);
void pci_bridge_update_mappings(PCIBus *b);
bool pci_msi_enabled(PCIDevice *dev);
void pci_msi_notify(PCIDevice *dev, unsigned int vector);
static inline void
pci_set_byte(uint8_t *config, uint8_t val)
{

View File

@ -167,10 +167,12 @@ static void hotplug_event_notify(PCIDevice *dev)
* The Port may optionally send an MSI when there are hot-plug events that
* occur while interrupt generation is disabled, and interrupt generation is
* subsequently enabled. */
if (!pci_msi_enabled(dev)) {
if (msix_enabled(dev)) {
msix_notify(dev, pcie_cap_flags_get_vector(dev));
} else if (msi_enabled(dev)) {
msi_notify(dev, pcie_cap_flags_get_vector(dev));
} else {
qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
} else if (dev->exp.hpev_notified) {
pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
}
}

View File

@ -257,30 +257,49 @@ static unsigned int pcie_aer_root_get_vector(PCIDevice *dev)
return (root_status & PCI_ERR_ROOT_IRQ) >> PCI_ERR_ROOT_IRQ_SHIFT;
}
/* Given a status register, get corresponding bits in the command register */
static uint32_t pcie_aer_status_to_cmd(uint32_t status)
{
uint32_t cmd = 0;
if (status & PCI_ERR_ROOT_COR_RCV) {
cmd |= PCI_ERR_ROOT_CMD_COR_EN;
}
if (status & PCI_ERR_ROOT_NONFATAL_RCV) {
cmd |= PCI_ERR_ROOT_CMD_NONFATAL_EN;
}
if (status & PCI_ERR_ROOT_FATAL_RCV) {
cmd |= PCI_ERR_ROOT_CMD_FATAL_EN;
}
return cmd;
}
static void pcie_aer_root_notify(PCIDevice *dev)
{
if (msix_enabled(dev)) {
msix_notify(dev, pcie_aer_root_get_vector(dev));
} else if (msi_enabled(dev)) {
msi_notify(dev, pcie_aer_root_get_vector(dev));
} else {
qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
}
}
/*
* return value:
* true: error message is sent up
* false: error message is masked
*
* 6.2.6 Error Message Control
* Figure 6-3
* root port part
*/
static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
static void pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
{
bool msg_sent;
uint16_t cmd;
uint8_t *aer_cap;
uint32_t root_cmd;
uint32_t root_status;
bool msi_trigger;
uint32_t root_status, prev_status;
msg_sent = false;
cmd = pci_get_word(dev->config + PCI_COMMAND);
aer_cap = dev->config + dev->exp.aer_cap;
root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
msi_trigger = false;
prev_status = root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
if (cmd & PCI_COMMAND_SERR) {
/* System Error.
@ -299,25 +318,14 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
if (root_status & PCI_ERR_ROOT_COR_RCV) {
root_status |= PCI_ERR_ROOT_MULTI_COR_RCV;
} else {
if (root_cmd & PCI_ERR_ROOT_CMD_COR_EN) {
msi_trigger = true;
}
pci_set_word(aer_cap + PCI_ERR_ROOT_COR_SRC, msg->source_id);
}
root_status |= PCI_ERR_ROOT_COR_RCV;
break;
case PCI_ERR_ROOT_CMD_NONFATAL_EN:
if (!(root_status & PCI_ERR_ROOT_NONFATAL_RCV) &&
root_cmd & PCI_ERR_ROOT_CMD_NONFATAL_EN) {
msi_trigger = true;
}
root_status |= PCI_ERR_ROOT_NONFATAL_RCV;
break;
case PCI_ERR_ROOT_CMD_FATAL_EN:
if (!(root_status & PCI_ERR_ROOT_FATAL_RCV) &&
root_cmd & PCI_ERR_ROOT_CMD_FATAL_EN) {
msi_trigger = true;
}
if (!(root_status & PCI_ERR_ROOT_UNCOR_RCV)) {
root_status |= PCI_ERR_ROOT_FIRST_FATAL;
}
@ -337,18 +345,17 @@ static bool pcie_aer_msg_root_port(PCIDevice *dev, const PCIEAERMsg *msg)
}
pci_set_long(aer_cap + PCI_ERR_ROOT_STATUS, root_status);
if (root_cmd & msg->severity) {
/* 6.2.4.1.2 Interrupt Generation */
if (pci_msi_enabled(dev)) {
if (msi_trigger) {
pci_msi_notify(dev, pcie_aer_root_get_vector(dev));
}
} else {
qemu_set_irq(dev->irq[dev->exp.aer_intx], 1);
}
msg_sent = true;
/* 6.2.4.1.2 Interrupt Generation */
/* All the above did was set some bits in the status register.
* Specifically these that match message severity.
* The below code relies on this fact. */
if (!(root_cmd & msg->severity) ||
(pcie_aer_status_to_cmd(prev_status) & root_cmd)) {
/* Condition is not being set or was already true so nothing to do. */
return;
}
return msg_sent;
pcie_aer_root_notify(dev);
}
/*
@ -739,40 +746,26 @@ void pcie_aer_root_reset(PCIDevice *dev)
*/
}
static bool pcie_aer_root_does_trigger(uint32_t cmd, uint32_t status)
{
return
((cmd & PCI_ERR_ROOT_CMD_COR_EN) && (status & PCI_ERR_ROOT_COR_RCV)) ||
((cmd & PCI_ERR_ROOT_CMD_NONFATAL_EN) &&
(status & PCI_ERR_ROOT_NONFATAL_RCV)) ||
((cmd & PCI_ERR_ROOT_CMD_FATAL_EN) &&
(status & PCI_ERR_ROOT_FATAL_RCV));
}
void pcie_aer_root_write_config(PCIDevice *dev,
uint32_t addr, uint32_t val, int len,
uint32_t root_cmd_prev)
{
uint8_t *aer_cap = dev->config + dev->exp.aer_cap;
/* root command register */
uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
uint32_t enabled_cmd = pcie_aer_status_to_cmd(root_status);
uint32_t root_cmd = pci_get_long(aer_cap + PCI_ERR_ROOT_COMMAND);
if (root_cmd & PCI_ERR_ROOT_CMD_EN_MASK) {
/* 6.2.4.1.2 Interrupt Generation */
/* 0 -> 1 */
uint32_t root_cmd_set = (root_cmd_prev ^ root_cmd) & root_cmd;
uint32_t root_status = pci_get_long(aer_cap + PCI_ERR_ROOT_STATUS);
if (pci_msi_enabled(dev)) {
if (pcie_aer_root_does_trigger(root_cmd_set, root_status)) {
pci_msi_notify(dev, pcie_aer_root_get_vector(dev));
}
} else {
int int_level = pcie_aer_root_does_trigger(root_cmd, root_status);
qemu_set_irq(dev->irq[dev->exp.aer_intx], int_level);
}
/* 6.2.4.1.2 Interrupt Generation */
if (!msix_enabled(dev) && !msi_enabled(dev)) {
qemu_set_irq(dev->irq[dev->exp.aer_intx], !!(root_cmd & enabled_cmd));
return;
}
if ((root_cmd_prev & enabled_cmd) || !(root_cmd & enabled_cmd)) {
/* Send MSI on transition from false to true. */
return;
}
pcie_aer_root_notify(dev);
}
static const VMStateDescription vmstate_pcie_aer_err = {

View File

@ -99,9 +99,14 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
}
}
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
static bool virtio_net_started(VirtIONet *n, uint8_t status)
{
return (status & VIRTIO_CONFIG_S_DRIVER_OK) &&
(n->status & VIRTIO_NET_S_LINK_UP) && n->vm_running;
}
static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
{
VirtIONet *n = to_virtio_net(vdev);
if (!n->nic->nc.peer) {
return;
}
@ -112,9 +117,7 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
if (!tap_get_vhost_net(n->nic->nc.peer)) {
return;
}
if (!!n->vhost_started == ((status & VIRTIO_CONFIG_S_DRIVER_OK) &&
(n->status & VIRTIO_NET_S_LINK_UP) &&
n->vm_running)) {
if (!!n->vhost_started == virtio_net_started(n, status)) {
return;
}
if (!n->vhost_started) {
@ -131,6 +134,32 @@ static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
}
}
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = to_virtio_net(vdev);
virtio_net_vhost_status(n, status);
if (!n->tx_waiting) {
return;
}
if (virtio_net_started(n, status) && !n->vhost_started) {
if (n->tx_timer) {
qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + n->tx_timeout);
} else {
qemu_bh_schedule(n->tx_bh);
}
} else {
if (n->tx_timer) {
qemu_del_timer(n->tx_timer);
} else {
qemu_bh_cancel(n->tx_bh);
}
}
}
static void virtio_net_set_link_status(VLANClientState *nc)
{
VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
@ -424,6 +453,9 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq)
static int virtio_net_can_receive(VLANClientState *nc)
{
VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque;
if (!n->vm_running) {
return 0;
}
if (!virtio_queue_ready(n->rx_vq) ||
!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK))
@ -672,11 +704,12 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq)
{
VirtQueueElement elem;
int32_t num_packets = 0;
if (!(n->vdev.status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return num_packets;
}
assert(n->vm_running);
if (n->async_tx.elem.out_num) {
virtio_queue_set_notification(n->tx_vq, 0);
return num_packets;
@ -735,6 +768,12 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIONet *n = to_virtio_net(vdev);
/* This happens when device was stopped but VCPU wasn't. */
if (!n->vm_running) {
n->tx_waiting = 1;
return;
}
if (n->tx_waiting) {
virtio_queue_set_notification(vq, 1);
qemu_del_timer(n->tx_timer);
@ -755,14 +794,19 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq)
if (unlikely(n->tx_waiting)) {
return;
}
n->tx_waiting = 1;
/* This happens when device was stopped but VCPU wasn't. */
if (!n->vm_running) {
return;
}
virtio_queue_set_notification(vq, 0);
qemu_bh_schedule(n->tx_bh);
n->tx_waiting = 1;
}
static void virtio_net_tx_timer(void *opaque)
{
VirtIONet *n = opaque;
assert(n->vm_running);
n->tx_waiting = 0;
@ -779,6 +823,8 @@ static void virtio_net_tx_bh(void *opaque)
VirtIONet *n = opaque;
int32_t ret;
assert(n->vm_running);
n->tx_waiting = 0;
/* Just in case the driver is not ready on more */
@ -923,15 +969,6 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
}
}
n->mac_table.first_multi = i;
if (n->tx_waiting) {
if (n->tx_timer) {
qemu_mod_timer(n->tx_timer,
qemu_get_clock(vm_clock) + n->tx_timeout);
} else {
qemu_bh_schedule(n->tx_bh);
}
}
return 0;
}

View File

@ -370,8 +370,6 @@ void migrate_fd_put_ready(void *opaque)
DPRINTF("done iterating\n");
vm_stop(0);
qemu_aio_flush();
bdrv_flush_all();
if ((qemu_savevm_state_complete(s->mon, s->file)) < 0) {
if (old_vm_running) {
vm_start();

4
net.c
View File

@ -1050,6 +1050,10 @@ static const struct {
.name = "mcast",
.type = QEMU_OPT_STRING,
.help = "UDP multicast address and port number",
}, {
.name = "localaddr",
.type = QEMU_OPT_STRING,
.help = "source address for multicast packets",
},
{ /* end of list */ }
},

View File

@ -149,7 +149,7 @@ static void net_socket_send_dgram(void *opaque)
qemu_send_packet(&s->nc, s->buf, size);
}
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr *localaddr)
{
struct ip_mreq imr;
int fd;
@ -183,7 +183,11 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
/* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
if (localaddr) {
imr.imr_interface = *localaddr;
} else {
imr.imr_interface.s_addr = htonl(INADDR_ANY);
}
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq));
@ -201,6 +205,15 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
goto fail;
}
/* If a bind address is given, only send packets from that address */
if (localaddr != NULL) {
ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, localaddr, sizeof(*localaddr));
if (ret < 0) {
perror("setsockopt(IP_MULTICAST_IF)");
goto fail;
}
}
socket_set_nonblock(fd);
return fd;
fail:
@ -248,7 +261,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
return NULL;
}
/* clone dgram socket */
newfd = net_socket_mcast_create(&saddr);
newfd = net_socket_mcast_create(&saddr, NULL);
if (newfd < 0) {
/* error already reported by net_socket_mcast_create() */
close(fd);
@ -468,17 +481,26 @@ static int net_socket_connect_init(VLANState *vlan,
static int net_socket_mcast_init(VLANState *vlan,
const char *model,
const char *name,
const char *host_str)
const char *host_str,
const char *localaddr_str)
{
NetSocketState *s;
int fd;
struct sockaddr_in saddr;
struct in_addr localaddr, *param_localaddr;
if (parse_host_port(&saddr, host_str) < 0)
return -1;
if (localaddr_str != NULL) {
if (inet_aton(localaddr_str, &localaddr) == 0)
return -1;
param_localaddr = &localaddr;
} else {
param_localaddr = NULL;
}
fd = net_socket_mcast_create(&saddr);
fd = net_socket_mcast_create(&saddr, param_localaddr);
if (fd < 0)
return -1;
@ -505,8 +527,9 @@ int net_init_socket(QemuOpts *opts,
if (qemu_opt_get(opts, "listen") ||
qemu_opt_get(opts, "connect") ||
qemu_opt_get(opts, "mcast")) {
error_report("listen=, connect= and mcast= is invalid with fd=");
qemu_opt_get(opts, "mcast") ||
qemu_opt_get(opts, "localaddr")) {
error_report("listen=, connect=, mcast= and localaddr= is invalid with fd=\n");
return -1;
}
@ -524,8 +547,9 @@ int net_init_socket(QemuOpts *opts,
if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "connect") ||
qemu_opt_get(opts, "mcast")) {
error_report("fd=, connect= and mcast= is invalid with listen=");
qemu_opt_get(opts, "mcast") ||
qemu_opt_get(opts, "localaddr")) {
error_report("fd=, connect=, mcast= and localaddr= is invalid with listen=\n");
return -1;
}
@ -539,8 +563,9 @@ int net_init_socket(QemuOpts *opts,
if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "listen") ||
qemu_opt_get(opts, "mcast")) {
error_report("fd=, listen= and mcast= is invalid with connect=");
qemu_opt_get(opts, "mcast") ||
qemu_opt_get(opts, "localaddr")) {
error_report("fd=, listen=, mcast= and localaddr= is invalid with connect=\n");
return -1;
}
@ -550,7 +575,7 @@ int net_init_socket(QemuOpts *opts,
return -1;
}
} else if (qemu_opt_get(opts, "mcast")) {
const char *mcast;
const char *mcast, *localaddr;
if (qemu_opt_get(opts, "fd") ||
qemu_opt_get(opts, "connect") ||
@ -560,8 +585,9 @@ int net_init_socket(QemuOpts *opts,
}
mcast = qemu_opt_get(opts, "mcast");
localaddr = qemu_opt_get(opts, "localaddr");
if (net_socket_mcast_init(vlan, "socket", name, mcast) == -1) {
if (net_socket_mcast_init(vlan, "socket", name, mcast, localaddr) == -1) {
return -1;
}
} else {

View File

@ -1061,8 +1061,9 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
#endif
"-net socket[,vlan=n][,name=str][,fd=h][,listen=[host]:port][,connect=host:port]\n"
" connect the vlan 'n' to another VLAN using a socket connection\n"
"-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port]\n"
"-net socket[,vlan=n][,name=str][,fd=h][,mcast=maddr:port[,localaddr=addr]]\n"
" connect the vlan 'n' to multicast maddr and port\n"
" use 'localaddr=addr' to specify the host address to send packets from\n"
#ifdef CONFIG_VDE
"-net vde[,vlan=n][,name=str][,sock=socketpath][,port=n][,group=groupname][,mode=octalmode]\n"
" connect the vlan 'n' to port 'n' of a vde switch running\n"
@ -1256,7 +1257,7 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:57 \
-net socket,connect=127.0.0.1:1234
@end example
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,mcast=@var{maddr}:@var{port}]
@item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]]
Create a VLAN @var{n} shared with another QEMU virtual
machines using a UDP multicast socket, effectively making a bus for
@ -1296,6 +1297,12 @@ qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
/path/to/linux ubd0=/path/to/root_fs eth0=mcast
@end example
Example (send packets from host's 1.2.3.4):
@example
qemu linux.img -net nic,macaddr=52:54:00:12:34:56 \
-net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4
@end example
@item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}]
Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and
listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname}

View File

@ -1575,8 +1575,6 @@ static int qemu_savevm_state(Monitor *mon, QEMUFile *f)
saved_vm_running = vm_running;
vm_stop(0);
bdrv_flush_all();
ret = qemu_savevm_state_begin(mon, f, 0, 0);
if (ret < 0)
goto out;
@ -1885,8 +1883,6 @@ void do_savevm(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "No block device can accept snapshots\n");
return;
}
/* ??? Should this occur after vm_stop? */
qemu_aio_flush();
saved_vm_running = vm_running;
vm_stop(0);