# HG changeset patch
# User Paul Durrant <paul.durrant@xxxxxxxxxx>
# Date 1275491143 -3600
# Node ID 636a452b175a75c79c711760846f7965cb53f14c
# Parent 166d7745fdaae8b7f1d77e024c64e5709ffc11d2
Device model unplug version 2:
Version 2 of the interface allows unplugging of individual IDE disks and/or
PCI NICs. IO ports 11 and 13 are used to control unplugging. A byte write to
port
11 sets the unplug type (1 == IDE, 2 == NIC) and then a subsequent byte write to
port 13 tells qemu which device of the current type to unplug.
diff -r 166d7745fdaa -r 636a452b175a hw/ide.c
--- a/hw/ide.c Wed Jun 02 16:02:01 2010 +0100
+++ b/hw/ide.c Wed Jun 02 16:05:43 2010 +0100
@@ -3073,45 +3073,57 @@
/* Unplug all of the IDE hard disks, starting at index @start in the
table. */
-static void _ide_unplug_harddisks(int start)
+void ide_unplug_harddisk(int i)
{
IDEState *s;
- int i, j;
+ int j;
if (!principal_ide_controller) {
fprintf(stderr, "No principal controller?\n");
return;
}
+
/* wait for outstanding aio requests */
qemu_aio_flush();
- for (i = start; i < 4; i++) {
- s = principal_ide_controller->ide_if + i;
- if (!s->bs)
- continue; /* drive not present */
- if (s->is_cdrom)
- continue; /* cdrom */
- /* Is a hard disk, unplug it. */
- for (j = 0; j < nb_drives; j++)
- if (drives_table[j].bdrv == s->bs)
- drives_table[j].bdrv = NULL;
- bdrv_flush(s->bs);
- bdrv_close(s->bs);
- s->bs = NULL;
- ide_reset(s);
- }
+
+ s = principal_ide_controller->ide_if + i;
+ if (!s->bs)
+ return; /* drive not present */
+
+ if (s->is_cdrom)
+ return; /* cdrom */
+
+ /* Is a hard disk, unplug it. */
+ for (j = 0; j < nb_drives; j++) {
+ if (drives_table[j].bdrv == s->bs) {
+ fprintf(stderr, "%s: drive %d\n", __func__, i, j);
+ drives_table[j].bdrv = NULL;
+ }
+ }
+
+ bdrv_flush(s->bs);
+ bdrv_close(s->bs);
+ s->bs = NULL;
+ ide_reset(s);
}
/* Unplug all hard disks except for the primary master (which will
almost always be the boot device). */
void ide_unplug_aux_harddisks(void)
{
- _ide_unplug_harddisks(1);
+ int i;
+
+ for (i = 1; i < 4; i++)
+ ide_unplug_harddisk(i);
}
/* Unplug all hard disks, including the boot device. */
-void ide_unplug_harddisks(void)
-{
- _ide_unplug_harddisks(0);
+void ide_unplug_all_harddisks(void)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ ide_unplug_harddisk(i);
}
static void ide_init2(IDEState *ide_state,
diff -r 166d7745fdaa -r 636a452b175a hw/pc.h
--- a/hw/pc.h Wed Jun 02 16:02:01 2010 +0100
+++ b/hw/pc.h Wed Jun 02 16:05:43 2010 +0100
@@ -162,7 +162,8 @@
qemu_irq *pic);
void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
qemu_irq *pic);
-void ide_unplug_harddisks(void);
+void ide_unplug_harddisk(int i);
+void ide_unplug_all_harddisks(void);
void ide_unplug_aux_harddisks(void);
/* ne2000.c */
diff -r 166d7745fdaa -r 636a452b175a hw/pci.c
--- a/hw/pci.c Wed Jun 02 16:02:01 2010 +0100
+++ b/hw/pci.c Wed Jun 02 16:05:43 2010 +0100
@@ -251,6 +251,10 @@
pci_dev->bus = bus;
pci_dev->devfn = devfn;
pstrcpy(pci_dev->name, sizeof(pci_dev->name), name);
+
+ fprintf(stderr, "%s: %02x:%02x:%02x (%s)\n", __func__, bus->bus_num,
+ devfn >> 3, devfn & 7, name);
+
memset(pci_dev->irq_state, 0, sizeof(pci_dev->irq_state));
pci_set_default_subsystem_id(pci_dev);
@@ -823,45 +827,68 @@
return NULL;
}
-void pci_unplug_netifs(void)
+void pci_dev_unplug(PCIDevice *dev)
+{
+ PCIBus *bus = dev->bus;
+
+ fprintf(stderr, "%s: %02x:%02x:%02x\n", __func__, bus->bus_num,
+ dev->devfn >> 3, dev->devfn & 7);
+
+ if (test_pci_slot(dev->devfn >> 3) == 1) {
+ fprintf(stderr, "skipping hotplug device\n");
+ return;
+ }
+
+ bus->devices[dev->devfn] = NULL;
+ pci_unregister_io_regions(dev);
+}
+
+void pci_unplug_all_netifs(void)
{
PCIBus *bus;
- PCIDevice *dev;
- PCIIORegion *region;
int x;
- int i;
/* We only support one PCI bus */
for (bus = first_bus; bus; bus = NULL) {
- for (x = 0; x < 256; x++) {
- dev = bus->devices[x];
- if (dev &&
- dev->config[0xa] == 0 &&
- dev->config[0xb] == 2 &&
- test_pci_slot(x >> 3) != 1) {
- /* Found a netif. Remove it from the bus. Note that
- we don't free it here, since there could still be
- references to it floating around. There are only
- ever one or two structures leaked, and it's not
- worth finding them all. */
- bus->devices[x] = NULL;
- for (i = 0; i < PCI_NUM_REGIONS; i++) {
- region = &dev->io_regions[i];
- if (region->addr == (uint32_t)-1 ||
- region->size == 0)
- continue;
- fprintf(logfile, "region type %d at [%x,%x).\n",
- region->type, region->addr,
- region->addr+region->size);
- if (region->type == PCI_ADDRESS_SPACE_IO) {
- isa_unassign_ioport(region->addr, region->size);
- } else if (region->type == PCI_ADDRESS_SPACE_MEM) {
- unregister_iomem(region->addr);
- }
- }
- }
- }
+ for (x = 0; x < 256; x++) {
+ PCIDevice *dev = bus->devices[x];
+
+ if (dev &&
+ dev->config[0xa] == 0 &&
+ dev->config[0xb] == 2) {
+ pci_dev_unplug(dev);
+ }
+ }
}
+}
+
+int pci_unplug_nic(int i)
+{
+ NICInfo *nd;
+ PCIDevice *pci_dev;
+
+ if (i >= nb_nics)
+ return -1;
+
+ nd = &nd_table[i];
+
+ if (!nd->used)
+ return -1;
+
+ fprintf(stderr, "%s: %02x:%02x:%02x:%02x:%02x:%02x\n", __func__,
+ nd->macaddr[0], nd->macaddr[1], nd->macaddr[2],
+ nd->macaddr[3], nd->macaddr[4], nd->macaddr[5]);
+
+ pci_dev = nd->private;
+ if (!pci_dev) {
+ fprintf(stderr, "%s: not PCI\n", __func__);
+ return -1;
+ }
+
+ pci_dev_unplug(pci_dev);
+
+ nd->used = 0;
+ return nd->vlan->id;
}
typedef struct {
diff -r 166d7745fdaa -r 636a452b175a hw/pci.h
--- a/hw/pci.h Wed Jun 02 16:02:01 2010 +0100
+++ b/hw/pci.h Wed Jun 02 16:05:43 2010 +0100
@@ -268,6 +268,7 @@
PCIDevice *pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn,
const char *default_model);
+void pci_dev_unplug(PCIDevice *dev);
void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
int pci_bus_num(PCIBus *s);
diff -r 166d7745fdaa -r 636a452b175a hw/xen_platform.c
--- a/hw/xen_platform.c Wed Jun 02 16:02:01 2010 +0100
+++ b/hw/xen_platform.c Wed Jun 02 16:05:43 2010 +0100
@@ -49,6 +49,11 @@
{
PCIDevice pci_dev;
} PCIXenPlatformState;
+
+static uint8_t unplug_type;
+
+#define UNPLUG_TYPE_IDE 0x01
+#define UNPLUG_TYPE_NIC 0x02
/* We throttle access to dom0 syslog, to avoid DOS attacks. This is
modelled as a token bucket, with one token for every byte of log.
@@ -144,9 +149,9 @@
unplug, with bit 0 the IDE devices, bit 1 the network
devices, and bit 2 the non-primary-master IDE devices. */
if (val & UNPLUG_ALL_IDE_DISKS)
- ide_unplug_harddisks();
+ ide_unplug_all_harddisks();
if (val & UNPLUG_ALL_NICS) {
- pci_unplug_netifs();
+ pci_unplug_all_netifs();
net_tap_shutdown_all();
}
if (val & UNPLUG_AUX_IDE_DISKS) {
@@ -192,7 +197,8 @@
}
}
-static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t
val)
+static void platform_fixed_ioport_write1(void *opaque, uint32_t addr,
+ uint32_t val)
{
switch (addr - 0x10) {
case 0: /* Platform flags */ {
@@ -209,8 +215,10 @@
}
break;
}
- case 2:
- /* Send bytes to syslog */
+ case 1: /* Unplug type */
+ unplug_type = (uint8_t)val;
+ break;
+ case 2: /* Send bytes to syslog */
if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
/* Flush buffer */
log_buffer[log_buffer_off] = 0;
@@ -221,6 +229,24 @@
}
log_buffer[log_buffer_off++] = val;
break;
+ case 3: /* Unplug index */
+ switch (unplug_type) {
+ case UNPLUG_TYPE_IDE:
+ ide_unplug_harddisk(val);
+ break;
+ case UNPLUG_TYPE_NIC: {
+ int id;
+
+ if ((id = pci_unplug_nic(val)) >= 0)
+ net_tap_shutdown_vlan(id);
+
+ break;
+ }
+ default:
+ fprintf(logfile, "unrecognized unplug type %02x\n",
+ unplug_type);
+ break;
+ }
}
}
@@ -249,7 +275,7 @@
return platform_flags;
case 2:
/* Version number */
- return 1;
+ return 2;
default:
return 0xff;
}
diff -r 166d7745fdaa -r 636a452b175a i386-dm/helper2.c
--- a/i386-dm/helper2.c Wed Jun 02 16:02:01 2010 +0100
+++ b/i386-dm/helper2.c Wed Jun 02 16:05:43 2010 +0100
@@ -580,8 +580,8 @@
do_savevm(qemu_file);
free(qemu_file);
- ide_unplug_harddisks();
- pci_unplug_netifs();
+ ide_unplug_all_harddisks();
+ pci_unplug_all_netifs();
net_tap_shutdown_all();
xenstore_record_dm_state("paused");
diff -r 166d7745fdaa -r 636a452b175a net.c
--- a/net.c Wed Jun 02 16:02:01 2010 +0100
+++ b/net.c Wed Jun 02 16:05:43 2010 +0100
@@ -1992,13 +1992,36 @@
}
}
+static void net_tap_shutdown(struct TAPState *tap)
+{
+ VLANClientState *vc = tap->vc;
+
+ fprintf(stderr, "%s: model=%s,name=%s\n", __func__, vc->model, vc->name);
+
+ qemu_set_fd_handler2(tap->fd, 0,0,0,0);
+ close(tap->fd);
+}
+
void net_tap_shutdown_all(void)
{
- struct IOHandlerRecord **pioh, *ioh;
+ struct TAPState *tap;
- while (head_net_tap) {
- qemu_set_fd_handler2(head_net_tap->fd, 0,0,0,0);
- close(head_net_tap->fd);
- head_net_tap = head_net_tap->next;
+ for (tap = head_net_tap; tap; tap = tap->next)
+ net_tap_shutdown(tap);
+}
+
+void net_tap_shutdown_vlan(int id)
+{
+ struct TAPState *tap;
+
+ for (tap = head_net_tap; tap; tap = tap->next) {
+ VLANClientState *vc = tap->vc;
+ VLANState *vlan = vc->vlan;
+
+ if (vlan->id != id)
+ continue;
+
+ net_tap_shutdown(tap);
}
}
+
diff -r 166d7745fdaa -r 636a452b175a net.h
--- a/net.h Wed Jun 02 16:02:01 2010 +0100
+++ b/net.h Wed Jun 02 16:05:43 2010 +0100
@@ -103,6 +103,7 @@
int slirp_is_inited(void);
void net_client_check(void);
void net_tap_shutdown_all(void);
+void net_tap_shutdown_vlan(int id);
void net_host_device_add(const char *device, const char *opts);
void net_host_device_remove(int vlan_id, const char *device);
diff -r 166d7745fdaa -r 636a452b175a qemu-xen.h
--- a/qemu-xen.h Wed Jun 02 16:02:01 2010 +0100
+++ b/qemu-xen.h Wed Jun 02 16:05:43 2010 +0100
@@ -46,7 +46,8 @@
void unset_vram_mapping(void *opaque);
#endif
-void pci_unplug_netifs(void);
+void pci_unplug_all_netifs(void);
+int pci_unplug_nic(int i);
void destroy_hvm_domain(void);
void unregister_iomem(target_phys_addr_t start);
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|