From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Lu7zZ-0008KZ-3L for qemu-devel@nongnu.org; Wed, 15 Apr 2009 12:29:41 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Lu7zT-0008H4-4g for qemu-devel@nongnu.org; Wed, 15 Apr 2009 12:29:39 -0400 Received: from [199.232.76.173] (port=54436 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Lu7zS-0008Gu-Uj for qemu-devel@nongnu.org; Wed, 15 Apr 2009 12:29:34 -0400 Received: from mail04.svc.cra.dublin.eircom.net ([159.134.118.20]:36918) by monty-python.gnu.org with smtp (Exim 4.60) (envelope-from ) id 1Lu7zR-00062h-Uf for qemu-devel@nongnu.org; Wed, 15 Apr 2009 12:29:34 -0400 From: Mark McLoughlin Date: Wed, 15 Apr 2009 17:29:29 +0100 Message-Id: <1239812969-8320-10-git-send-email-markmc@redhat.com> In-Reply-To: <1239812969-8320-9-git-send-email-markmc@redhat.com> References: <1239812969-8320-1-git-send-email-markmc@redhat.com> <1239812969-8320-2-git-send-email-markmc@redhat.com> <1239812969-8320-3-git-send-email-markmc@redhat.com> <1239812969-8320-4-git-send-email-markmc@redhat.com> <1239812969-8320-5-git-send-email-markmc@redhat.com> <1239812969-8320-6-git-send-email-markmc@redhat.com> <1239812969-8320-7-git-send-email-markmc@redhat.com> <1239812969-8320-8-git-send-email-markmc@redhat.com> <1239812969-8320-9-git-send-email-markmc@redhat.com> Subject: [Qemu-devel] [PATCH 9/9] Introduce VLANClientState::cleanup() Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: Jan Kiszka , qemu-devel@nongnu.org, Mark McLoughlin We're currently leaking memory and file descriptors on device hot-unplug. Signed-off-by: Mark McLoughlin --- hw/e1000.c | 12 +++++----- hw/eepro100.c | 12 ++++++++++ hw/etraxfs_eth.c | 11 +++++++++ hw/mcf_fec.c | 18 ++++++++++++--- hw/mipsnet.c | 14 ++++++++++++ hw/musicpal.c | 18 ++++++++++++--- hw/ne2000.c | 24 +++++++++++++++++++++ hw/pcnet.c | 43 ++++++++++++++++++++++++++++++++++--- hw/rtl8139.c | 20 +++++++++++++++++ hw/smc91c111.c | 17 +++++++++++--- hw/stellaris_enet.c | 20 ++++++++++++++--- hw/usb-net.c | 11 ++++++++- hw/virtio-net.c | 14 ++++++++++++ net.c | 57 +++++++++++++++++++++++++++++++++++++------------- net.h | 2 + tap-win32.c | 13 +++++++++++ 16 files changed, 263 insertions(+), 43 deletions(-) diff --git a/hw/e1000.c b/hw/e1000.c index 2d16774..978f789 100644 --- a/hw/e1000.c +++ b/hw/e1000.c @@ -1033,14 +1033,14 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num, excluded_regs[i] - 4); } -static int -pci_e1000_uninit(PCIDevice *dev) +static void +e1000_cleanup(VLANClientState *vc) { - E1000State *d = (E1000State *) dev; + E1000State *d = vc->opaque; - cpu_unregister_io_memory(d->mmio_index); + unregister_savevm("e1000", d); - return 0; + cpu_unregister_io_memory(d->mmio_index); } PCIDevice * @@ -1095,12 +1095,12 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, e1000_receive, e1000_can_receive, d); + d->vc->cleanup = e1000_cleanup; d->vc->link_status_changed = e1000_set_link_status; qemu_format_nic_info_str(d->vc, nd->macaddr); register_savevm(info_str, -1, 2, nic_save, nic_load, d); - d->dev.unregister = pci_e1000_uninit; return (PCIDevice *)d; } diff --git a/hw/eepro100.c b/hw/eepro100.c index c72b990..a54287a 100644 --- a/hw/eepro100.c +++ b/hw/eepro100.c @@ -1710,6 +1710,17 @@ 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); + + cpu_unregister_io_memory(s->mmio_index); + + eeprom93xx_free(s->eeprom); +} + static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) { PCIEEPRO100State *d; @@ -1751,6 +1762,7 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, nic_receive, nic_can_receive, s); + s->vc->cleanup = nic_cleanup; qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/etraxfs_eth.c b/hw/etraxfs_eth.c index c87e55f..b0f7f6d 100644 --- a/hw/etraxfs_eth.c +++ b/hw/etraxfs_eth.c @@ -554,6 +554,16 @@ static CPUWriteMemoryFunc *eth_write[] = { ð_writel, }; +static void etraxfs_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) { @@ -586,6 +596,7 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, eth_receive, eth_can_receive, eth); + eth->vc->cleanup = etraxfs_eth_cleanup; 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 413c569..6204772 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); + s->vc->cleanup = mcf_fec_cleanup; 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 415b04e..f10356a 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); + s->vc->cleanup = mipsnet_cleanup; } else { s->vc = NULL; } diff --git a/hw/musicpal.c b/hw/musicpal.c index 5de1691..c4b73eb 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,10 +746,18 @@ static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = { mv88w8618_eth_write }; +static void mv88w8618_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"); @@ -756,9 +765,10 @@ static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) 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); + s->vc->cleanup = mv88w8618_eth_cleanup; + 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 24a66bb..7fe3975 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,6 +750,7 @@ 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); @@ -743,6 +758,7 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, ne2000_receive, ne2000_can_receive, s); + s->vc->cleanup = isa_ne2000_cleanup; 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; @@ -803,6 +826,7 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) ne2000_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, ne2000_receive, ne2000_can_receive, s); + s->vc->cleanup = ne2000_cleanup; qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/pcnet.c b/hw/pcnet.c index be68f28..7bd150a 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,6 +1930,13 @@ static int pcnet_load(QEMUFile *f, void *opaque, int version_id) return 0; } +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) { d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); @@ -1985,6 +1993,15 @@ 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); + + cpu_unregister_io_memory(d->mmio_index); +} + PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) { PCNetState *d; @@ -2032,6 +2049,9 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) d->pci_dev = &d->dev; pcnet_common_init(d, nd); + + d->vc->cleanup = pci_pcnet_cleanup; + return (PCIDevice *)d; } @@ -2081,29 +2101,44 @@ 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); + + d->vc->cleanup = lance_cleanup; } #endif /* TARGET_SPARC */ diff --git a/hw/rtl8139.c b/hw/rtl8139.c index 9fa69db..e381ab0 100644 --- a/hw/rtl8139.c +++ b/hw/rtl8139.c @@ -3414,6 +3414,25 @@ 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); + + cpu_unregister_io_memory(s->rtl8139_mmio_io_addr); +} + PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) { PCIRTL8139State *d; @@ -3451,6 +3470,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) rtl8139_reset(s); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, rtl8139_receive, rtl8139_can_receive, s); + s->vc->cleanup = rtl8139_cleanup; qemu_format_nic_info_str(s->vc, s->macaddr); diff --git a/hw/smc91c111.c b/hw/smc91c111.c index f5b29a7..b132ca3 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,17 +691,24 @@ 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); @@ -708,6 +716,7 @@ void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, smc91c111_receive, smc91c111_can_receive, s); + s->vc->cleanup = smc91c111_cleanup; qemu_format_nic_info_str(s->vc, s->macaddr); /* ??? Save/restore. */ } diff --git a/hw/stellaris_enet.c b/hw/stellaris_enet.c index 88c5620..48826d8 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,34 @@ 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); + s->vc->cleanup = stellaris_enet_cleanup; qemu_format_nic_info_str(s->vc, s->macaddr); } diff --git a/hw/usb-net.c b/hw/usb-net.c index 863c25f..99c132f 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) @@ -1453,6 +1459,7 @@ USBDevice *usb_net_init(NICInfo *nd) "QEMU USB Network Interface"); s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, usbnet_receive, usbnet_can_receive, s); + s->vc->cleanup = usbnet_cleanup; qemu_format_nic_info_str(s->vc, s->mac); diff --git a/hw/virtio-net.c b/hw/virtio-net.c index 5e7db0d..201872d 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -570,6 +570,19 @@ 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); +} + PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) { VirtIONet *n; @@ -599,6 +612,7 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) 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); + n->vc->cleanup = virtio_net_cleanup; n->vc->link_status_changed = virtio_net_set_link_status; qemu_format_nic_info_str(n->vc, n->mac); diff --git a/net.c b/net.c index 34ec4c8..1378ea8 100644 --- a/net.c +++ b/net.c @@ -362,6 +362,8 @@ 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); @@ -702,6 +704,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 +752,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); + free(s); +} + /* fd support */ static TAPState *net_tap_fd_init(VLANState *vlan, @@ -760,6 +776,7 @@ 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->cleanup = tap_cleanup; 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 +1075,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); + 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) @@ -1079,6 +1104,7 @@ static int net_vde_init(VLANState *vlan, const char *model, return -1; } s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, NULL, s); + s->vc->cleanup = vde_cleanup; 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 +1289,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); + free(s); +} + static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, const char *model, const char *name, @@ -1308,6 +1342,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, s->fd = fd; s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, NULL, s); + s->vc->cleanup = net_socket_cleanup; qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); /* mcast: save bound address as dst */ @@ -1336,6 +1371,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, s->fd = fd; s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive, NULL, s); + s->vc->cleanup = net_socket_cleanup; snprintf(s->vc->info_str, sizeof(s->vc->info_str), "socket: fd=%d", fd); if (is_connected) { @@ -1895,29 +1931,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 1a51be7..5def263 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; diff --git a/tap-win32.c b/tap-win32.c index e8a04dc..5948060 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); + */ + free(s); +} + static void tap_receive(void *opaque, const uint8_t *buf, int size) { TAPState *s = opaque; @@ -673,6 +685,7 @@ int tap_win32_init(VLANState *vlan, const char *model, } s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); + s->vc->cleanup = tap_cleanup; snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: ifname=%s", ifname); -- 1.6.0.6