From b946a1533209f61a93e34898aebb5b43154b99c3 Mon Sep 17 00:00:00 2001 From: aliguori Date: Fri, 17 Apr 2009 17:11:08 +0000 Subject: [PATCH] Introduce VLANClientState::cleanup() (Mark McLoughlin) We're currently leaking memory and file descriptors on device hot-unplug. Signed-off-by: Mark McLoughlin Signed-off-by: Anthony Liguori git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7150 c046a42c-6fe2-441c-8c8c-71466251a162 --- hw/dp8393x.c | 20 ++++++++++--- hw/e1000.c | 11 ++++++- hw/eepro100.c | 23 ++++++++++++++- hw/etraxfs_eth.c | 13 ++++++++- hw/mcf_fec.c | 20 +++++++++---- hw/mipsnet.c | 16 +++++++++- hw/musicpal.c | 20 +++++++++---- hw/ne2000.c | 28 ++++++++++++++++-- hw/pcnet.c | 58 ++++++++++++++++++++++++++++++------ hw/rtl8139.c | 31 +++++++++++++++++++- hw/smc91c111.c | 19 ++++++++---- hw/stellaris_enet.c | 23 +++++++++++---- hw/usb-net.c | 14 +++++++-- hw/virtio-net.c | 19 +++++++++++- hw/virtio.c | 7 +++++ hw/virtio.h | 2 ++ net.c | 71 +++++++++++++++++++++++++++++++-------------- net.h | 3 ++ tap-win32.c | 15 +++++++++- 19 files changed, 347 insertions(+), 66 deletions(-) diff --git a/hw/dp8393x.c b/hw/dp8393x.c index eed6eebab3..6170588e99 100644 --- a/hw/dp8393x.c +++ b/hw/dp8393x.c @@ -156,6 +156,7 @@ typedef struct dp8393xState { QEMUTimer *watchdog; int64_t wt_last_update; VLANClientState *vc; + int mmio_index; /* Registers */ uint8_t cam[16][6]; @@ -858,12 +859,23 @@ static void nic_reset(void *opaque) dp8393x_update_irq(s); } +static void nic_cleanup(VLANClientState *vc) +{ + dp8393xState *s = vc->opaque; + + cpu_unregister_io_memory(s->mmio_index); + + qemu_del_timer(s->watchdog); + qemu_free_timer(s->watchdog); + + qemu_free(s); +} + void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, qemu_irq irq, void* mem_opaque, void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) { dp8393xState *s; - int io; qemu_check_nic_model(nd, "dp83932"); @@ -877,12 +889,12 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - nic_receive, nic_can_receive, s); + nic_receive, nic_can_receive, nic_cleanup, s); qemu_format_nic_info_str(s->vc, nd->macaddr); qemu_register_reset(nic_reset, s); nic_reset(s); - io = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); - cpu_register_physical_memory(base, 0x40 << it_shift, io); + s->mmio_index = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); + cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index); } diff --git a/hw/e1000.c b/hw/e1000.c index 2d16774dad..1729db28e1 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1033,6 +1033,14 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num, excluded_regs[i] - 4); } +static void +e1000_cleanup(VLANClientState *vc) +{ + E1000State *d = vc->opaque; + + unregister_savevm("e1000", d); +} + static int pci_e1000_uninit(PCIDevice *dev) { @@ -1094,7 +1102,8 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) memset(&d->tx, 0, sizeof d->tx); d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - e1000_receive, e1000_can_receive, d); + e1000_receive, e1000_can_receive, + e1000_cleanup, d); d->vc->link_status_changed = e1000_set_link_status; qemu_format_nic_info_str(d->vc, nd->macaddr); diff --git a/hw/eepro100.c b/hw/eepro100.c index c72b990f22..18d81153bf 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1710,6 +1710,25 @@ static void nic_save(QEMUFile * f, void *opaque) qemu_put_buffer(f, s->configuration, sizeof(s->configuration)); } +static void nic_cleanup(VLANClientState *vc) +{ + EEPRO100State *s = vc->opaque; + + unregister_savevm(vc->model, s); + + eeprom93xx_free(s->eeprom); +} + +static int pci_nic_uninit(PCIDevice *dev) +{ + PCIEEPRO100State *d = (PCIEEPRO100State *) dev; + EEPRO100State *s = &d->eepro100; + + cpu_unregister_io_memory(s->mmio_index); + + return 0; +} + static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) { PCIEEPRO100State *d; @@ -1720,6 +1739,7 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) d = (PCIEEPRO100State *) pci_register_device(bus, nd->model, sizeof(PCIEEPRO100State), -1, NULL, NULL); + d->dev.unregister = pci_nic_uninit; s = &d->eepro100; s->device = device; @@ -1750,7 +1770,8 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) nic_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - nic_receive, nic_can_receive, s); + nic_receive, nic_can_receive, + nic_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index c87e55f61d..15270f573d 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -554,6 +554,16 @@ static CPUWriteMemoryFunc *eth_write[] = { ð_writel, }; +static void eth_cleanup(VLANClientState *vc) +{ + struct fs_eth *eth = vc->opaque; + + cpu_unregister_io_memory(eth->ethregs); + + qemu_free(eth->dma_out); + qemu_free(eth); +} + void *etraxfs_eth_init(NICInfo *nd, CPUState *env, qemu_irq *irq, target_phys_addr_t base, int phyaddr) { @@ -585,7 +595,8 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, cpu_register_physical_memory (base, 0x5c, eth->ethregs); eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - eth_receive, eth_can_receive, eth); + eth_receive, eth_can_receive, + eth_cleanup, eth); eth->vc->opaque = eth; eth->vc->link_status_changed = eth_set_link; diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c index 413c5694db..1ca847b22b 100644 --- a/hw/mcf_fec.c +++ b/hw/mcf_fec.c @@ -24,6 +24,7 @@ do { printf("mcf_fec: " fmt , ##args); } while (0) typedef struct { qemu_irq *irq; + int mmio_index; VLANClientState *vc; uint32_t irq_state; uint32_t eir; @@ -441,21 +442,30 @@ static CPUWriteMemoryFunc *mcf_fec_writefn[] = { mcf_fec_write }; +static void mcf_fec_cleanup(VLANClientState *vc) +{ + mcf_fec_state *s = vc->opaque; + + cpu_unregister_io_memory(s->mmio_index); + + qemu_free(s); +} + void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) { mcf_fec_state *s; - int iomemtype; qemu_check_nic_model(nd, "mcf_fec"); s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); s->irq = irq; - iomemtype = cpu_register_io_memory(0, mcf_fec_readfn, - mcf_fec_writefn, s); - cpu_register_physical_memory(base, 0x400, iomemtype); + s->mmio_index = cpu_register_io_memory(0, mcf_fec_readfn, + mcf_fec_writefn, s); + cpu_register_physical_memory(base, 0x400, s->mmio_index); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - mcf_fec_receive, mcf_fec_can_receive, s); + mcf_fec_receive, mcf_fec_can_receive, + mcf_fec_cleanup, s); memcpy(s->macaddr, nd->macaddr, 6); qemu_format_nic_info_str(s->vc, s->macaddr); } diff --git a/hw/mipsnet.c b/hw/mipsnet.c index 415b04e2ce..e842984219 100644 --- a/hw/mipsnet.c +++ b/hw/mipsnet.c @@ -33,6 +33,7 @@ typedef struct MIPSnetState { uint32_t intctl; uint8_t rx_buffer[MAX_ETH_FRAME_SIZE]; uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; + int io_base; qemu_irq irq; VLANClientState *vc; } MIPSnetState; @@ -231,6 +232,17 @@ static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static void mipsnet_cleanup(VLANClientState *vc) +{ + MIPSnetState *s = vc->opaque; + + unregister_savevm("mipsnet", s); + + isa_unassign_ioport(s->io_base, 36); + + qemu_free(s); +} + void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) { MIPSnetState *s; @@ -246,10 +258,12 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) register_ioport_write(base, 36, 4, mipsnet_ioport_write, s); register_ioport_read(base, 36, 4, mipsnet_ioport_read, s); + s->io_base = base; s->irq = irq; if (nd && nd->vlan) { s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - mipsnet_receive, mipsnet_can_receive, s); + mipsnet_receive, mipsnet_can_receive, + mipsnet_cleanup, s); } else { s->vc = NULL; } diff --git a/hw/musicpal.c b/hw/musicpal.c index 5de16911ae..fc227e97aa 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -536,6 +536,7 @@ typedef struct mv88w8618_eth_state { uint32_t smir; uint32_t icr; uint32_t imr; + int mmio_index; int vlan_header; uint32_t tx_queue[2]; uint32_t rx_queue[4]; @@ -745,20 +746,29 @@ static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = { mv88w8618_eth_write }; +static void eth_cleanup(VLANClientState *vc) +{ + mv88w8618_eth_state *s = vc->opaque; + + cpu_unregister_io_memory(s->mmio_index); + + qemu_free(s); +} + static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) { mv88w8618_eth_state *s; - int iomemtype; qemu_check_nic_model(nd, "mv88w8618"); s = qemu_mallocz(sizeof(mv88w8618_eth_state)); s->irq = irq; s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - eth_receive, eth_can_receive, s); - iomemtype = cpu_register_io_memory(0, mv88w8618_eth_readfn, - mv88w8618_eth_writefn, s); - cpu_register_physical_memory(base, MP_ETH_SIZE, iomemtype); + eth_receive, eth_can_receive, + eth_cleanup, s); + s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, + mv88w8618_eth_writefn, s); + cpu_register_physical_memory(base, MP_ETH_SIZE, s->mmio_index); } /* LCD register offsets */ diff --git a/hw/ne2000.c b/hw/ne2000.c index 24a66bb5b8..99612e2589 100644 --- a/hw/ne2000.c +++ b/hw/ne2000.c @@ -140,6 +140,7 @@ typedef struct NE2000State { uint8_t curpag; uint8_t mult[8]; /* multicast mask array */ qemu_irq irq; + int isa_io_base; PCIDevice *pci_dev; VLANClientState *vc; uint8_t macaddr[6]; @@ -718,6 +719,19 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) return 0; } +static void isa_ne2000_cleanup(VLANClientState *vc) +{ + NE2000State *s = vc->opaque; + + unregister_savevm("ne2000", s); + + isa_unassign_ioport(s->isa_io_base, 16); + isa_unassign_ioport(s->isa_io_base + 0x10, 2); + isa_unassign_ioport(s->isa_io_base + 0x1f, 1); + + qemu_free(s); +} + void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) { NE2000State *s; @@ -736,13 +750,15 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); + s->isa_io_base = base; s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - ne2000_receive, ne2000_can_receive, s); + ne2000_receive, ne2000_can_receive, + isa_ne2000_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); @@ -777,6 +793,13 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); } +static void ne2000_cleanup(VLANClientState *vc) +{ + NE2000State *s = vc->opaque; + + unregister_savevm("ne2000", s); +} + PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) { PCINE2000State *d; @@ -802,7 +825,8 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) memcpy(s->macaddr, nd->macaddr, 6); ne2000_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - ne2000_receive, ne2000_can_receive, s); + ne2000_receive, ne2000_can_receive, + ne2000_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/pcnet.c b/hw/pcnet.c index be68f284ed..acbaee6cdd 100644 --- a/hw/pcnet.c +++ b/hw/pcnet.c @@ -75,6 +75,7 @@ struct PCNetState_st { uint8_t buffer[4096]; int tx_busy; qemu_irq irq; + qemu_irq *reset_irq; void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, uint8_t *buf, int len, int do_bswap); void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, @@ -1929,7 +1930,15 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static void pcnet_common_init(PCNetState *d, NICInfo *nd) +static void pcnet_common_cleanup(PCNetState *d) +{ + unregister_savevm("pcnet", d); + + qemu_del_timer(d->poll_timer); + qemu_free_timer(d->poll_timer); +} + +static void pcnet_common_init(PCNetState *d, NICInfo *nd, NetCleanup *cleanup) { d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); @@ -1937,7 +1946,8 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd) if (nd && nd->vlan) { d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - pcnet_receive, pcnet_can_receive, d); + pcnet_receive, pcnet_can_receive, + cleanup, d); qemu_format_nic_info_str(d->vc, d->nd->macaddr); } else { @@ -1985,6 +1995,22 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, cpu_physical_memory_read(addr, buf, len); } +static void pci_pcnet_cleanup(VLANClientState *vc) +{ + PCNetState *d = vc->opaque; + + pcnet_common_cleanup(d); +} + +static int pci_pcnet_uninit(PCIDevice *dev) +{ + PCNetState *d = (PCNetState *)dev; + + cpu_unregister_io_memory(d->mmio_index); + + return 0; +} + PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) { PCNetState *d; @@ -1997,7 +2023,7 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), devfn, NULL, NULL); - + d->dev.unregister = pci_pcnet_uninit; pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); @@ -2031,7 +2057,8 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) d->phys_mem_write = pci_physical_memory_write; d->pci_dev = &d->dev; - pcnet_common_init(d, nd); + pcnet_common_init(d, nd, pci_pcnet_cleanup); + return (PCIDevice *)d; } @@ -2081,29 +2108,42 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { NULL, }; +static void lance_cleanup(VLANClientState *vc) +{ + PCNetState *d = vc->opaque; + + pcnet_common_cleanup(d); + + qemu_free_irqs(d->reset_irq); + + cpu_unregister_io_memory(d->mmio_index); + + qemu_free(d); +} + void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, qemu_irq irq, qemu_irq *reset) { PCNetState *d; - int lance_io_memory; qemu_check_nic_model(nd, "lance"); d = qemu_mallocz(sizeof(PCNetState)); - lance_io_memory = + d->mmio_index = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); d->dma_opaque = dma_opaque; - *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1); + d->reset_irq = qemu_allocate_irqs(parent_lance_reset, d, 1); + *reset = *d->reset_irq; - cpu_register_physical_memory(leaddr, 4, lance_io_memory); + cpu_register_physical_memory(leaddr, 4, d->mmio_index); d->irq = irq; d->phys_mem_read = ledma_memory_read; d->phys_mem_write = ledma_memory_write; - pcnet_common_init(d, nd); + pcnet_common_init(d, nd, lance_cleanup); } #endif /* TARGET_SPARC */ diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 9fa69dbd69..0093ff4a93 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3414,6 +3414,33 @@ static void rtl8139_timer(void *opaque) } #endif /* RTL8139_ONBOARD_TIMER */ +static void rtl8139_cleanup(VLANClientState *vc) +{ + RTL8139State *s = vc->opaque; + + if (s->cplus_txbuffer) { + qemu_free(s->cplus_txbuffer); + s->cplus_txbuffer = NULL; + } + +#ifdef RTL8139_ONBOARD_TIMER + qemu_del_timer(s->timer); + qemu_free_timer(s->timer); +#endif + + unregister_savevm("rtl8139", s); +} + +static int pci_rtl8139_uninit(PCIDevice *dev) +{ + PCIRTL8139State *d = (PCIRTL8139State *)dev; + RTL8139State *s = &d->rtl8139; + + cpu_unregister_io_memory(s->rtl8139_mmio_io_addr); + + return 0; +} + PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) { PCIRTL8139State *d; @@ -3424,6 +3451,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) "RTL8139", sizeof(PCIRTL8139State), devfn, NULL, NULL); + d->dev.unregister = pci_rtl8139_uninit; pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK); pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_REALTEK_8139); @@ -3450,7 +3478,8 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) memcpy(s->macaddr, nd->macaddr, 6); rtl8139_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - rtl8139_receive, rtl8139_can_receive, s); + rtl8139_receive, rtl8139_can_receive, + rtl8139_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index f5b29a7049..9f567aba75 100644 --- a/hw/smc91c111.c +++ b/hw/smc91c111.c @@ -42,6 +42,7 @@ typedef struct { uint8_t int_level; uint8_t int_mask; uint8_t macaddr[6]; + int mmio_index; } smc91c111_state; #define RCR_SOFT_RST 0x8000 @@ -690,24 +691,32 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = { smc91c111_writel }; +static void smc91c111_cleanup(VLANClientState *vc) +{ + smc91c111_state *s = vc->opaque; + + cpu_unregister_io_memory(s->mmio_index); + qemu_free(s); +} + void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) { smc91c111_state *s; - int iomemtype; qemu_check_nic_model(nd, "smc91c111"); s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); - iomemtype = cpu_register_io_memory(0, smc91c111_readfn, - smc91c111_writefn, s); - cpu_register_physical_memory(base, 16, iomemtype); + s->mmio_index = cpu_register_io_memory(0, smc91c111_readfn, + smc91c111_writefn, s); + cpu_register_physical_memory(base, 16, s->mmio_index); s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); smc91c111_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - smc91c111_receive, smc91c111_can_receive, s); + smc91c111_receive, smc91c111_can_receive, + smc91c111_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); /* ??? Save/restore. */ } diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 88c56204e3..a4c2011113 100644 --- a/hw/stellaris_enet.c +++ b/hw/stellaris_enet.c @@ -69,6 +69,7 @@ typedef struct { VLANClientState *vc; qemu_irq irq; uint8_t macaddr[6]; + int mmio_index; } stellaris_enet_state; static void stellaris_enet_update(stellaris_enet_state *s) @@ -384,23 +385,35 @@ static int stellaris_enet_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static void stellaris_enet_cleanup(VLANClientState *vc) +{ + stellaris_enet_state *s = vc->opaque; + + unregister_savevm("stellaris_enet", s); + + cpu_unregister_io_memory(s->mmio_index); + + qemu_free(s); +} + void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) { stellaris_enet_state *s; - int iomemtype; qemu_check_nic_model(nd, "stellaris"); s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state)); - iomemtype = cpu_register_io_memory(0, stellaris_enet_readfn, - stellaris_enet_writefn, s); - cpu_register_physical_memory(base, 0x00001000, iomemtype); + s->mmio_index = cpu_register_io_memory(0, stellaris_enet_readfn, + stellaris_enet_writefn, s); + cpu_register_physical_memory(base, 0x00001000, s->mmio_index); s->irq = irq; memcpy(s->macaddr, nd->macaddr, 6); if (nd->vlan) { s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - stellaris_enet_receive, stellaris_enet_can_receive, s); + stellaris_enet_receive, + stellaris_enet_can_receive, + stellaris_enet_cleanup, s); qemu_format_nic_info_str(s->vc, s->macaddr); } diff --git a/hw/usb-net.c b/hw/usb-net.c index 863c25fd9c..9e6442506f 100644 --- a/hw/usb-net.c +++ b/hw/usb-net.c @@ -1415,14 +1415,20 @@ static int usbnet_can_receive(void *opaque) return !s->in_len; } +static void usbnet_cleanup(VLANClientState *vc) +{ + USBNetState *s = vc->opaque; + + rndis_clear_responsequeue(s); + qemu_free(s); +} + static void usb_net_handle_destroy(USBDevice *dev) { USBNetState *s = (USBNetState *) dev; /* TODO: remove the nd_table[] entry */ qemu_del_vlan_client(s->vc); - rndis_clear_responsequeue(s); - qemu_free(s); } USBDevice *usb_net_init(NICInfo *nd) @@ -1452,7 +1458,9 @@ USBDevice *usb_net_init(NICInfo *nd) pstrcpy(s->dev.devname, sizeof(s->dev.devname), "QEMU USB Network Interface"); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - usbnet_receive, usbnet_can_receive, s); + usbnet_receive, + usbnet_can_receive, + usbnet_cleanup, s); qemu_format_nic_info_str(s->vc, s->mac); diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 5e7db0dfc8..f9717c02e1 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -570,6 +570,21 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) return 0; } +static void virtio_net_cleanup(VLANClientState *vc) +{ + VirtIONet *n = vc->opaque; + + unregister_savevm("virtio-net", n); + + qemu_free(n->mac_table.macs); + qemu_free(n->vlans); + + qemu_del_timer(n->tx_timer); + qemu_free_timer(n->tx_timer); + + virtio_cleanup(&n->vdev); +} + PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) { VirtIONet *n; @@ -598,7 +613,9 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) memcpy(n->mac, nd->macaddr, ETH_ALEN); n->status = VIRTIO_NET_S_LINK_UP; n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, - virtio_net_receive, virtio_net_can_receive, n); + virtio_net_receive, + virtio_net_can_receive, + virtio_net_cleanup, n); n->vc->link_status_changed = virtio_net_set_link_status; qemu_format_nic_info_str(n->vc, n->mac); diff --git a/hw/virtio.c b/hw/virtio.c index 93a7de6899..4aa5f20a78 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -750,6 +750,13 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) virtio_update_irq(vdev); } +void virtio_cleanup(VirtIODevice *vdev) +{ + if (vdev->config) + qemu_free(vdev->config); + qemu_free(vdev->vq); +} + VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name, uint16_t vendor, uint16_t device, uint16_t subvendor, uint16_t subdevice, diff --git a/hw/virtio.h b/hw/virtio.h index cce8a47475..935b118545 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -117,6 +117,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f); void virtio_load(VirtIODevice *vdev, QEMUFile *f); +void virtio_cleanup(VirtIODevice *vdev); + void virtio_notify_config(VirtIODevice *vdev); void virtio_queue_set_notification(VirtQueue *vq, int enable); diff --git a/net.c b/net.c index 34ec4c810b..5a8f824055 100644 --- a/net.c +++ b/net.c @@ -333,6 +333,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, const char *name, IOReadHandler *fd_read, IOCanRWHandler *fd_can_read, + NetCleanup *cleanup, void *opaque) { VLANClientState *vc, **pvc; @@ -344,6 +345,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, vc->name = assign_name(vc, model); vc->fd_read = fd_read; vc->fd_can_read = fd_can_read; + vc->cleanup = cleanup; vc->opaque = opaque; vc->vlan = vlan; @@ -362,6 +364,9 @@ void qemu_del_vlan_client(VLANClientState *vc) while (*pvc != NULL) if (*pvc == vc) { *pvc = vc->next; + if (vc->cleanup) { + vc->cleanup(vc); + } free(vc->name); free(vc->model); free(vc); @@ -521,7 +526,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) slirp_init(slirp_restrict, slirp_ip); } slirp_vc = qemu_new_vlan_client(vlan, model, name, - slirp_receive, NULL, NULL); + slirp_receive, NULL, NULL, NULL); slirp_vc->info_str[0] = '\0'; return 0; } @@ -702,6 +707,8 @@ typedef struct TAPState { char down_script_arg[128]; } TAPState; +static int launch_script(const char *setup_script, const char *ifname, int fd); + static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, int iovcnt) { @@ -748,6 +755,18 @@ static void tap_send(void *opaque) } } +static void tap_cleanup(VLANClientState *vc) +{ + TAPState *s = vc->opaque; + + if (s->down_script[0]) + launch_script(s->down_script, s->down_script_arg, s->fd); + + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + close(s->fd); + qemu_free(s); +} + /* fd support */ static TAPState *net_tap_fd_init(VLANState *vlan, @@ -759,7 +778,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan, s = qemu_mallocz(sizeof(TAPState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); + s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, + NULL, tap_cleanup, s); s->vc->fd_readv = tap_receive_iov; qemu_set_fd_handler(s->fd, tap_send, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd); @@ -1058,6 +1078,14 @@ static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) } } +static void vde_cleanup(VLANClientState *vc) +{ + VDEState *s = vc->opaque; + qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); + vde_close(s->vde); + qemu_free(s); +} + static int net_vde_init(VLANState *vlan, const char *model, const char *name, const char *sock, int port, const char *group, int mode) @@ -1078,7 +1106,8 @@ static int net_vde_init(VLANState *vlan, const char *model, free(s); return -1; } - s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, NULL, s); + s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, + NULL, vde_cleanup, s); qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", sock, vde_datafd(s->vde)); @@ -1263,6 +1292,14 @@ fail: return -1; } +static void net_socket_cleanup(VLANClientState *vc) +{ + NetSocketState *s = vc->opaque; + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); + close(s->fd); + qemu_free(s); +} + static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, const char *model, const char *name, @@ -1307,7 +1344,8 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, s = qemu_mallocz(sizeof(NetSocketState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, NULL, s); + s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, + NULL, net_socket_cleanup, s); qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); /* mcast: save bound address as dst */ @@ -1334,8 +1372,8 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, NetSocketState *s; s = qemu_mallocz(sizeof(NetSocketState)); s->fd = fd; - s->vc = qemu_new_vlan_client(vlan, model, name, - net_socket_receive, NULL, s); + s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive, + NULL, net_socket_cleanup, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: fd=%d", fd); if (is_connected) { @@ -1895,29 +1933,20 @@ done: void net_cleanup(void) { -#if !defined(_WIN32) VLANState *vlan; /* close network clients */ for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { - VLANClientState *vc; + VLANClientState *vc = vlan->first_client; - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc->fd_read == tap_receive) { - TAPState *s = vc->opaque; + while (vc) { + VLANClientState *next = vc->next; - if (s->down_script[0]) - launch_script(s->down_script, s->down_script_arg, s->fd); - } -#if defined(CONFIG_VDE) - if (vc->fd_read == vde_from_qemu) { - VDEState *s = vc->opaque; - vde_close(s->vde); - } -#endif + qemu_del_vlan_client(vc); + + vc = next; } } -#endif } void net_client_check(void) diff --git a/net.h b/net.h index 1a51be7983..413f7054b2 100644 --- a/net.h +++ b/net.h @@ -9,6 +9,7 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); typedef struct VLANClientState VLANClientState; +typedef void (NetCleanup) (VLANClientState *); typedef void (LinkStatusChanged)(VLANClientState *); struct VLANClientState { @@ -17,6 +18,7 @@ struct VLANClientState { /* Packets may still be sent if this returns zero. It's used to rate-limit the slirp code. */ IOCanRWHandler *fd_can_read; + NetCleanup *cleanup; LinkStatusChanged *link_status_changed; int link_down; void *opaque; @@ -40,6 +42,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, const char *name, IOReadHandler *fd_read, IOCanRWHandler *fd_can_read, + NetCleanup *cleanup, void *opaque); void qemu_del_vlan_client(VLANClientState *vc); VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); diff --git a/tap-win32.c b/tap-win32.c index e8a04dc7c0..3ff957fe69 100644 --- a/tap-win32.c +++ b/tap-win32.c @@ -638,6 +638,18 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, tap_win32_overlapped_t *handle; } TAPState; +static void tap_cleanup(VLANClientState *vc) +{ + TAPState *s = vc->opaque; + + qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); + + /* FIXME: need to kill thread and close file handle: + tap_win32_close(s); + */ + qemu_free(s); +} + static void tap_receive(void *opaque, const uint8_t *buf, int size) { TAPState *s = opaque; @@ -672,7 +684,8 @@ int tap_win32_init(VLANState *vlan, const char *model, return -1; } - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); + s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, + NULL, tap_cleanup, s); snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname);