Commit b946a1533209f61a93e34898aebb5b43154b99c3
1 parent
32a8f6ae
Introduce VLANClientState::cleanup() (Mark McLoughlin)
We're currently leaking memory and file descriptors on device hot-unplug. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7150 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
19 changed files
with
347 additions
and
66 deletions
hw/dp8393x.c
| ... | ... | @@ -156,6 +156,7 @@ typedef struct dp8393xState { |
| 156 | 156 | QEMUTimer *watchdog; |
| 157 | 157 | int64_t wt_last_update; |
| 158 | 158 | VLANClientState *vc; |
| 159 | + int mmio_index; | |
| 159 | 160 | |
| 160 | 161 | /* Registers */ |
| 161 | 162 | uint8_t cam[16][6]; |
| ... | ... | @@ -858,12 +859,23 @@ static void nic_reset(void *opaque) |
| 858 | 859 | dp8393x_update_irq(s); |
| 859 | 860 | } |
| 860 | 861 | |
| 862 | +static void nic_cleanup(VLANClientState *vc) | |
| 863 | +{ | |
| 864 | + dp8393xState *s = vc->opaque; | |
| 865 | + | |
| 866 | + cpu_unregister_io_memory(s->mmio_index); | |
| 867 | + | |
| 868 | + qemu_del_timer(s->watchdog); | |
| 869 | + qemu_free_timer(s->watchdog); | |
| 870 | + | |
| 871 | + qemu_free(s); | |
| 872 | +} | |
| 873 | + | |
| 861 | 874 | void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, |
| 862 | 875 | qemu_irq irq, void* mem_opaque, |
| 863 | 876 | void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write)) |
| 864 | 877 | { |
| 865 | 878 | dp8393xState *s; |
| 866 | - int io; | |
| 867 | 879 | |
| 868 | 880 | qemu_check_nic_model(nd, "dp83932"); |
| 869 | 881 | |
| ... | ... | @@ -877,12 +889,12 @@ void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift, |
| 877 | 889 | s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */ |
| 878 | 890 | |
| 879 | 891 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 880 | - nic_receive, nic_can_receive, s); | |
| 892 | + nic_receive, nic_can_receive, nic_cleanup, s); | |
| 881 | 893 | |
| 882 | 894 | qemu_format_nic_info_str(s->vc, nd->macaddr); |
| 883 | 895 | qemu_register_reset(nic_reset, s); |
| 884 | 896 | nic_reset(s); |
| 885 | 897 | |
| 886 | - io = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); | |
| 887 | - cpu_register_physical_memory(base, 0x40 << it_shift, io); | |
| 898 | + s->mmio_index = cpu_register_io_memory(0, dp8393x_read, dp8393x_write, s); | |
| 899 | + cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index); | |
| 888 | 900 | } | ... | ... |
hw/e1000.c
| ... | ... | @@ -1033,6 +1033,14 @@ e1000_mmio_map(PCIDevice *pci_dev, int region_num, |
| 1033 | 1033 | excluded_regs[i] - 4); |
| 1034 | 1034 | } |
| 1035 | 1035 | |
| 1036 | +static void | |
| 1037 | +e1000_cleanup(VLANClientState *vc) | |
| 1038 | +{ | |
| 1039 | + E1000State *d = vc->opaque; | |
| 1040 | + | |
| 1041 | + unregister_savevm("e1000", d); | |
| 1042 | +} | |
| 1043 | + | |
| 1036 | 1044 | static int |
| 1037 | 1045 | pci_e1000_uninit(PCIDevice *dev) |
| 1038 | 1046 | { |
| ... | ... | @@ -1094,7 +1102,8 @@ pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 1094 | 1102 | memset(&d->tx, 0, sizeof d->tx); |
| 1095 | 1103 | |
| 1096 | 1104 | d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 1097 | - e1000_receive, e1000_can_receive, d); | |
| 1105 | + e1000_receive, e1000_can_receive, | |
| 1106 | + e1000_cleanup, d); | |
| 1098 | 1107 | d->vc->link_status_changed = e1000_set_link_status; |
| 1099 | 1108 | |
| 1100 | 1109 | qemu_format_nic_info_str(d->vc, nd->macaddr); | ... | ... |
hw/eepro100.c
| ... | ... | @@ -1710,6 +1710,25 @@ static void nic_save(QEMUFile * f, void *opaque) |
| 1710 | 1710 | qemu_put_buffer(f, s->configuration, sizeof(s->configuration)); |
| 1711 | 1711 | } |
| 1712 | 1712 | |
| 1713 | +static void nic_cleanup(VLANClientState *vc) | |
| 1714 | +{ | |
| 1715 | + EEPRO100State *s = vc->opaque; | |
| 1716 | + | |
| 1717 | + unregister_savevm(vc->model, s); | |
| 1718 | + | |
| 1719 | + eeprom93xx_free(s->eeprom); | |
| 1720 | +} | |
| 1721 | + | |
| 1722 | +static int pci_nic_uninit(PCIDevice *dev) | |
| 1723 | +{ | |
| 1724 | + PCIEEPRO100State *d = (PCIEEPRO100State *) dev; | |
| 1725 | + EEPRO100State *s = &d->eepro100; | |
| 1726 | + | |
| 1727 | + cpu_unregister_io_memory(s->mmio_index); | |
| 1728 | + | |
| 1729 | + return 0; | |
| 1730 | +} | |
| 1731 | + | |
| 1713 | 1732 | static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) |
| 1714 | 1733 | { |
| 1715 | 1734 | PCIEEPRO100State *d; |
| ... | ... | @@ -1720,6 +1739,7 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) |
| 1720 | 1739 | d = (PCIEEPRO100State *) pci_register_device(bus, nd->model, |
| 1721 | 1740 | sizeof(PCIEEPRO100State), -1, |
| 1722 | 1741 | NULL, NULL); |
| 1742 | + d->dev.unregister = pci_nic_uninit; | |
| 1723 | 1743 | |
| 1724 | 1744 | s = &d->eepro100; |
| 1725 | 1745 | s->device = device; |
| ... | ... | @@ -1750,7 +1770,8 @@ static PCIDevice *nic_init(PCIBus * bus, NICInfo * nd, uint32_t device) |
| 1750 | 1770 | nic_reset(s); |
| 1751 | 1771 | |
| 1752 | 1772 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 1753 | - nic_receive, nic_can_receive, s); | |
| 1773 | + nic_receive, nic_can_receive, | |
| 1774 | + nic_cleanup, s); | |
| 1754 | 1775 | |
| 1755 | 1776 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 1756 | 1777 | ... | ... |
hw/etraxfs_eth.c
| ... | ... | @@ -554,6 +554,16 @@ static CPUWriteMemoryFunc *eth_write[] = { |
| 554 | 554 | ð_writel, |
| 555 | 555 | }; |
| 556 | 556 | |
| 557 | +static void eth_cleanup(VLANClientState *vc) | |
| 558 | +{ | |
| 559 | + struct fs_eth *eth = vc->opaque; | |
| 560 | + | |
| 561 | + cpu_unregister_io_memory(eth->ethregs); | |
| 562 | + | |
| 563 | + qemu_free(eth->dma_out); | |
| 564 | + qemu_free(eth); | |
| 565 | +} | |
| 566 | + | |
| 557 | 567 | void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |
| 558 | 568 | qemu_irq *irq, target_phys_addr_t base, int phyaddr) |
| 559 | 569 | { |
| ... | ... | @@ -585,7 +595,8 @@ void *etraxfs_eth_init(NICInfo *nd, CPUState *env, |
| 585 | 595 | cpu_register_physical_memory (base, 0x5c, eth->ethregs); |
| 586 | 596 | |
| 587 | 597 | eth->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 588 | - eth_receive, eth_can_receive, eth); | |
| 598 | + eth_receive, eth_can_receive, | |
| 599 | + eth_cleanup, eth); | |
| 589 | 600 | eth->vc->opaque = eth; |
| 590 | 601 | eth->vc->link_status_changed = eth_set_link; |
| 591 | 602 | ... | ... |
hw/mcf_fec.c
| ... | ... | @@ -24,6 +24,7 @@ do { printf("mcf_fec: " fmt , ##args); } while (0) |
| 24 | 24 | |
| 25 | 25 | typedef struct { |
| 26 | 26 | qemu_irq *irq; |
| 27 | + int mmio_index; | |
| 27 | 28 | VLANClientState *vc; |
| 28 | 29 | uint32_t irq_state; |
| 29 | 30 | uint32_t eir; |
| ... | ... | @@ -441,21 +442,30 @@ static CPUWriteMemoryFunc *mcf_fec_writefn[] = { |
| 441 | 442 | mcf_fec_write |
| 442 | 443 | }; |
| 443 | 444 | |
| 445 | +static void mcf_fec_cleanup(VLANClientState *vc) | |
| 446 | +{ | |
| 447 | + mcf_fec_state *s = vc->opaque; | |
| 448 | + | |
| 449 | + cpu_unregister_io_memory(s->mmio_index); | |
| 450 | + | |
| 451 | + qemu_free(s); | |
| 452 | +} | |
| 453 | + | |
| 444 | 454 | void mcf_fec_init(NICInfo *nd, target_phys_addr_t base, qemu_irq *irq) |
| 445 | 455 | { |
| 446 | 456 | mcf_fec_state *s; |
| 447 | - int iomemtype; | |
| 448 | 457 | |
| 449 | 458 | qemu_check_nic_model(nd, "mcf_fec"); |
| 450 | 459 | |
| 451 | 460 | s = (mcf_fec_state *)qemu_mallocz(sizeof(mcf_fec_state)); |
| 452 | 461 | s->irq = irq; |
| 453 | - iomemtype = cpu_register_io_memory(0, mcf_fec_readfn, | |
| 454 | - mcf_fec_writefn, s); | |
| 455 | - cpu_register_physical_memory(base, 0x400, iomemtype); | |
| 462 | + s->mmio_index = cpu_register_io_memory(0, mcf_fec_readfn, | |
| 463 | + mcf_fec_writefn, s); | |
| 464 | + cpu_register_physical_memory(base, 0x400, s->mmio_index); | |
| 456 | 465 | |
| 457 | 466 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 458 | - mcf_fec_receive, mcf_fec_can_receive, s); | |
| 467 | + mcf_fec_receive, mcf_fec_can_receive, | |
| 468 | + mcf_fec_cleanup, s); | |
| 459 | 469 | memcpy(s->macaddr, nd->macaddr, 6); |
| 460 | 470 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 461 | 471 | } | ... | ... |
hw/mipsnet.c
| ... | ... | @@ -33,6 +33,7 @@ typedef struct MIPSnetState { |
| 33 | 33 | uint32_t intctl; |
| 34 | 34 | uint8_t rx_buffer[MAX_ETH_FRAME_SIZE]; |
| 35 | 35 | uint8_t tx_buffer[MAX_ETH_FRAME_SIZE]; |
| 36 | + int io_base; | |
| 36 | 37 | qemu_irq irq; |
| 37 | 38 | VLANClientState *vc; |
| 38 | 39 | } MIPSnetState; |
| ... | ... | @@ -231,6 +232,17 @@ static int mipsnet_load(QEMUFile *f, void *opaque, int version_id) |
| 231 | 232 | return 0; |
| 232 | 233 | } |
| 233 | 234 | |
| 235 | +static void mipsnet_cleanup(VLANClientState *vc) | |
| 236 | +{ | |
| 237 | + MIPSnetState *s = vc->opaque; | |
| 238 | + | |
| 239 | + unregister_savevm("mipsnet", s); | |
| 240 | + | |
| 241 | + isa_unassign_ioport(s->io_base, 36); | |
| 242 | + | |
| 243 | + qemu_free(s); | |
| 244 | +} | |
| 245 | + | |
| 234 | 246 | void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) |
| 235 | 247 | { |
| 236 | 248 | MIPSnetState *s; |
| ... | ... | @@ -246,10 +258,12 @@ void mipsnet_init (int base, qemu_irq irq, NICInfo *nd) |
| 246 | 258 | register_ioport_write(base, 36, 4, mipsnet_ioport_write, s); |
| 247 | 259 | register_ioport_read(base, 36, 4, mipsnet_ioport_read, s); |
| 248 | 260 | |
| 261 | + s->io_base = base; | |
| 249 | 262 | s->irq = irq; |
| 250 | 263 | if (nd && nd->vlan) { |
| 251 | 264 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 252 | - mipsnet_receive, mipsnet_can_receive, s); | |
| 265 | + mipsnet_receive, mipsnet_can_receive, | |
| 266 | + mipsnet_cleanup, s); | |
| 253 | 267 | } else { |
| 254 | 268 | s->vc = NULL; |
| 255 | 269 | } | ... | ... |
hw/musicpal.c
| ... | ... | @@ -536,6 +536,7 @@ typedef struct mv88w8618_eth_state { |
| 536 | 536 | uint32_t smir; |
| 537 | 537 | uint32_t icr; |
| 538 | 538 | uint32_t imr; |
| 539 | + int mmio_index; | |
| 539 | 540 | int vlan_header; |
| 540 | 541 | uint32_t tx_queue[2]; |
| 541 | 542 | uint32_t rx_queue[4]; |
| ... | ... | @@ -745,20 +746,29 @@ static CPUWriteMemoryFunc *mv88w8618_eth_writefn[] = { |
| 745 | 746 | mv88w8618_eth_write |
| 746 | 747 | }; |
| 747 | 748 | |
| 749 | +static void eth_cleanup(VLANClientState *vc) | |
| 750 | +{ | |
| 751 | + mv88w8618_eth_state *s = vc->opaque; | |
| 752 | + | |
| 753 | + cpu_unregister_io_memory(s->mmio_index); | |
| 754 | + | |
| 755 | + qemu_free(s); | |
| 756 | +} | |
| 757 | + | |
| 748 | 758 | static void mv88w8618_eth_init(NICInfo *nd, uint32_t base, qemu_irq irq) |
| 749 | 759 | { |
| 750 | 760 | mv88w8618_eth_state *s; |
| 751 | - int iomemtype; | |
| 752 | 761 | |
| 753 | 762 | qemu_check_nic_model(nd, "mv88w8618"); |
| 754 | 763 | |
| 755 | 764 | s = qemu_mallocz(sizeof(mv88w8618_eth_state)); |
| 756 | 765 | s->irq = irq; |
| 757 | 766 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 758 | - eth_receive, eth_can_receive, s); | |
| 759 | - iomemtype = cpu_register_io_memory(0, mv88w8618_eth_readfn, | |
| 760 | - mv88w8618_eth_writefn, s); | |
| 761 | - cpu_register_physical_memory(base, MP_ETH_SIZE, iomemtype); | |
| 767 | + eth_receive, eth_can_receive, | |
| 768 | + eth_cleanup, s); | |
| 769 | + s->mmio_index = cpu_register_io_memory(0, mv88w8618_eth_readfn, | |
| 770 | + mv88w8618_eth_writefn, s); | |
| 771 | + cpu_register_physical_memory(base, MP_ETH_SIZE, s->mmio_index); | |
| 762 | 772 | } |
| 763 | 773 | |
| 764 | 774 | /* LCD register offsets */ | ... | ... |
hw/ne2000.c
| ... | ... | @@ -140,6 +140,7 @@ typedef struct NE2000State { |
| 140 | 140 | uint8_t curpag; |
| 141 | 141 | uint8_t mult[8]; /* multicast mask array */ |
| 142 | 142 | qemu_irq irq; |
| 143 | + int isa_io_base; | |
| 143 | 144 | PCIDevice *pci_dev; |
| 144 | 145 | VLANClientState *vc; |
| 145 | 146 | uint8_t macaddr[6]; |
| ... | ... | @@ -718,6 +719,19 @@ static int ne2000_load(QEMUFile* f,void* opaque,int version_id) |
| 718 | 719 | return 0; |
| 719 | 720 | } |
| 720 | 721 | |
| 722 | +static void isa_ne2000_cleanup(VLANClientState *vc) | |
| 723 | +{ | |
| 724 | + NE2000State *s = vc->opaque; | |
| 725 | + | |
| 726 | + unregister_savevm("ne2000", s); | |
| 727 | + | |
| 728 | + isa_unassign_ioport(s->isa_io_base, 16); | |
| 729 | + isa_unassign_ioport(s->isa_io_base + 0x10, 2); | |
| 730 | + isa_unassign_ioport(s->isa_io_base + 0x1f, 1); | |
| 731 | + | |
| 732 | + qemu_free(s); | |
| 733 | +} | |
| 734 | + | |
| 721 | 735 | void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) |
| 722 | 736 | { |
| 723 | 737 | NE2000State *s; |
| ... | ... | @@ -736,13 +750,15 @@ void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd) |
| 736 | 750 | |
| 737 | 751 | register_ioport_write(base + 0x1f, 1, 1, ne2000_reset_ioport_write, s); |
| 738 | 752 | register_ioport_read(base + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
| 753 | + s->isa_io_base = base; | |
| 739 | 754 | s->irq = irq; |
| 740 | 755 | memcpy(s->macaddr, nd->macaddr, 6); |
| 741 | 756 | |
| 742 | 757 | ne2000_reset(s); |
| 743 | 758 | |
| 744 | 759 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 745 | - ne2000_receive, ne2000_can_receive, s); | |
| 760 | + ne2000_receive, ne2000_can_receive, | |
| 761 | + isa_ne2000_cleanup, s); | |
| 746 | 762 | |
| 747 | 763 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 748 | 764 | |
| ... | ... | @@ -777,6 +793,13 @@ static void ne2000_map(PCIDevice *pci_dev, int region_num, |
| 777 | 793 | register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s); |
| 778 | 794 | } |
| 779 | 795 | |
| 796 | +static void ne2000_cleanup(VLANClientState *vc) | |
| 797 | +{ | |
| 798 | + NE2000State *s = vc->opaque; | |
| 799 | + | |
| 800 | + unregister_savevm("ne2000", s); | |
| 801 | +} | |
| 802 | + | |
| 780 | 803 | PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 781 | 804 | { |
| 782 | 805 | PCINE2000State *d; |
| ... | ... | @@ -802,7 +825,8 @@ PCIDevice *pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 802 | 825 | memcpy(s->macaddr, nd->macaddr, 6); |
| 803 | 826 | ne2000_reset(s); |
| 804 | 827 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 805 | - ne2000_receive, ne2000_can_receive, s); | |
| 828 | + ne2000_receive, ne2000_can_receive, | |
| 829 | + ne2000_cleanup, s); | |
| 806 | 830 | |
| 807 | 831 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 808 | 832 | ... | ... |
hw/pcnet.c
| ... | ... | @@ -75,6 +75,7 @@ struct PCNetState_st { |
| 75 | 75 | uint8_t buffer[4096]; |
| 76 | 76 | int tx_busy; |
| 77 | 77 | qemu_irq irq; |
| 78 | + qemu_irq *reset_irq; | |
| 78 | 79 | void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, |
| 79 | 80 | uint8_t *buf, int len, int do_bswap); |
| 80 | 81 | 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) |
| 1929 | 1930 | return 0; |
| 1930 | 1931 | } |
| 1931 | 1932 | |
| 1932 | -static void pcnet_common_init(PCNetState *d, NICInfo *nd) | |
| 1933 | +static void pcnet_common_cleanup(PCNetState *d) | |
| 1934 | +{ | |
| 1935 | + unregister_savevm("pcnet", d); | |
| 1936 | + | |
| 1937 | + qemu_del_timer(d->poll_timer); | |
| 1938 | + qemu_free_timer(d->poll_timer); | |
| 1939 | +} | |
| 1940 | + | |
| 1941 | +static void pcnet_common_init(PCNetState *d, NICInfo *nd, NetCleanup *cleanup) | |
| 1933 | 1942 | { |
| 1934 | 1943 | d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); |
| 1935 | 1944 | |
| ... | ... | @@ -1937,7 +1946,8 @@ static void pcnet_common_init(PCNetState *d, NICInfo *nd) |
| 1937 | 1946 | |
| 1938 | 1947 | if (nd && nd->vlan) { |
| 1939 | 1948 | d->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 1940 | - pcnet_receive, pcnet_can_receive, d); | |
| 1949 | + pcnet_receive, pcnet_can_receive, | |
| 1950 | + cleanup, d); | |
| 1941 | 1951 | |
| 1942 | 1952 | qemu_format_nic_info_str(d->vc, d->nd->macaddr); |
| 1943 | 1953 | } else { |
| ... | ... | @@ -1985,6 +1995,22 @@ static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, |
| 1985 | 1995 | cpu_physical_memory_read(addr, buf, len); |
| 1986 | 1996 | } |
| 1987 | 1997 | |
| 1998 | +static void pci_pcnet_cleanup(VLANClientState *vc) | |
| 1999 | +{ | |
| 2000 | + PCNetState *d = vc->opaque; | |
| 2001 | + | |
| 2002 | + pcnet_common_cleanup(d); | |
| 2003 | +} | |
| 2004 | + | |
| 2005 | +static int pci_pcnet_uninit(PCIDevice *dev) | |
| 2006 | +{ | |
| 2007 | + PCNetState *d = (PCNetState *)dev; | |
| 2008 | + | |
| 2009 | + cpu_unregister_io_memory(d->mmio_index); | |
| 2010 | + | |
| 2011 | + return 0; | |
| 2012 | +} | |
| 2013 | + | |
| 1988 | 2014 | PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 1989 | 2015 | { |
| 1990 | 2016 | PCNetState *d; |
| ... | ... | @@ -1997,7 +2023,7 @@ PCIDevice *pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 1997 | 2023 | |
| 1998 | 2024 | d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState), |
| 1999 | 2025 | devfn, NULL, NULL); |
| 2000 | - | |
| 2026 | + d->dev.unregister = pci_pcnet_uninit; | |
| 2001 | 2027 | pci_conf = d->dev.config; |
| 2002 | 2028 | |
| 2003 | 2029 | 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) |
| 2031 | 2057 | d->phys_mem_write = pci_physical_memory_write; |
| 2032 | 2058 | d->pci_dev = &d->dev; |
| 2033 | 2059 | |
| 2034 | - pcnet_common_init(d, nd); | |
| 2060 | + pcnet_common_init(d, nd, pci_pcnet_cleanup); | |
| 2061 | + | |
| 2035 | 2062 | return (PCIDevice *)d; |
| 2036 | 2063 | } |
| 2037 | 2064 | |
| ... | ... | @@ -2081,29 +2108,42 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = { |
| 2081 | 2108 | NULL, |
| 2082 | 2109 | }; |
| 2083 | 2110 | |
| 2111 | +static void lance_cleanup(VLANClientState *vc) | |
| 2112 | +{ | |
| 2113 | + PCNetState *d = vc->opaque; | |
| 2114 | + | |
| 2115 | + pcnet_common_cleanup(d); | |
| 2116 | + | |
| 2117 | + qemu_free_irqs(d->reset_irq); | |
| 2118 | + | |
| 2119 | + cpu_unregister_io_memory(d->mmio_index); | |
| 2120 | + | |
| 2121 | + qemu_free(d); | |
| 2122 | +} | |
| 2123 | + | |
| 2084 | 2124 | void lance_init(NICInfo *nd, target_phys_addr_t leaddr, void *dma_opaque, |
| 2085 | 2125 | qemu_irq irq, qemu_irq *reset) |
| 2086 | 2126 | { |
| 2087 | 2127 | PCNetState *d; |
| 2088 | - int lance_io_memory; | |
| 2089 | 2128 | |
| 2090 | 2129 | qemu_check_nic_model(nd, "lance"); |
| 2091 | 2130 | |
| 2092 | 2131 | d = qemu_mallocz(sizeof(PCNetState)); |
| 2093 | 2132 | |
| 2094 | - lance_io_memory = | |
| 2133 | + d->mmio_index = | |
| 2095 | 2134 | cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); |
| 2096 | 2135 | |
| 2097 | 2136 | d->dma_opaque = dma_opaque; |
| 2098 | 2137 | |
| 2099 | - *reset = *qemu_allocate_irqs(parent_lance_reset, d, 1); | |
| 2138 | + d->reset_irq = qemu_allocate_irqs(parent_lance_reset, d, 1); | |
| 2139 | + *reset = *d->reset_irq; | |
| 2100 | 2140 | |
| 2101 | - cpu_register_physical_memory(leaddr, 4, lance_io_memory); | |
| 2141 | + cpu_register_physical_memory(leaddr, 4, d->mmio_index); | |
| 2102 | 2142 | |
| 2103 | 2143 | d->irq = irq; |
| 2104 | 2144 | d->phys_mem_read = ledma_memory_read; |
| 2105 | 2145 | d->phys_mem_write = ledma_memory_write; |
| 2106 | 2146 | |
| 2107 | - pcnet_common_init(d, nd); | |
| 2147 | + pcnet_common_init(d, nd, lance_cleanup); | |
| 2108 | 2148 | } |
| 2109 | 2149 | #endif /* TARGET_SPARC */ | ... | ... |
hw/rtl8139.c
| ... | ... | @@ -3414,6 +3414,33 @@ static void rtl8139_timer(void *opaque) |
| 3414 | 3414 | } |
| 3415 | 3415 | #endif /* RTL8139_ONBOARD_TIMER */ |
| 3416 | 3416 | |
| 3417 | +static void rtl8139_cleanup(VLANClientState *vc) | |
| 3418 | +{ | |
| 3419 | + RTL8139State *s = vc->opaque; | |
| 3420 | + | |
| 3421 | + if (s->cplus_txbuffer) { | |
| 3422 | + qemu_free(s->cplus_txbuffer); | |
| 3423 | + s->cplus_txbuffer = NULL; | |
| 3424 | + } | |
| 3425 | + | |
| 3426 | +#ifdef RTL8139_ONBOARD_TIMER | |
| 3427 | + qemu_del_timer(s->timer); | |
| 3428 | + qemu_free_timer(s->timer); | |
| 3429 | +#endif | |
| 3430 | + | |
| 3431 | + unregister_savevm("rtl8139", s); | |
| 3432 | +} | |
| 3433 | + | |
| 3434 | +static int pci_rtl8139_uninit(PCIDevice *dev) | |
| 3435 | +{ | |
| 3436 | + PCIRTL8139State *d = (PCIRTL8139State *)dev; | |
| 3437 | + RTL8139State *s = &d->rtl8139; | |
| 3438 | + | |
| 3439 | + cpu_unregister_io_memory(s->rtl8139_mmio_io_addr); | |
| 3440 | + | |
| 3441 | + return 0; | |
| 3442 | +} | |
| 3443 | + | |
| 3417 | 3444 | PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 3418 | 3445 | { |
| 3419 | 3446 | PCIRTL8139State *d; |
| ... | ... | @@ -3424,6 +3451,7 @@ PCIDevice *pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 3424 | 3451 | "RTL8139", sizeof(PCIRTL8139State), |
| 3425 | 3452 | devfn, |
| 3426 | 3453 | NULL, NULL); |
| 3454 | + d->dev.unregister = pci_rtl8139_uninit; | |
| 3427 | 3455 | pci_conf = d->dev.config; |
| 3428 | 3456 | pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_REALTEK); |
| 3429 | 3457 | 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) |
| 3450 | 3478 | memcpy(s->macaddr, nd->macaddr, 6); |
| 3451 | 3479 | rtl8139_reset(s); |
| 3452 | 3480 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 3453 | - rtl8139_receive, rtl8139_can_receive, s); | |
| 3481 | + rtl8139_receive, rtl8139_can_receive, | |
| 3482 | + rtl8139_cleanup, s); | |
| 3454 | 3483 | |
| 3455 | 3484 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 3456 | 3485 | ... | ... |
hw/smc91c111.c
| ... | ... | @@ -42,6 +42,7 @@ typedef struct { |
| 42 | 42 | uint8_t int_level; |
| 43 | 43 | uint8_t int_mask; |
| 44 | 44 | uint8_t macaddr[6]; |
| 45 | + int mmio_index; | |
| 45 | 46 | } smc91c111_state; |
| 46 | 47 | |
| 47 | 48 | #define RCR_SOFT_RST 0x8000 |
| ... | ... | @@ -690,24 +691,32 @@ static CPUWriteMemoryFunc *smc91c111_writefn[] = { |
| 690 | 691 | smc91c111_writel |
| 691 | 692 | }; |
| 692 | 693 | |
| 694 | +static void smc91c111_cleanup(VLANClientState *vc) | |
| 695 | +{ | |
| 696 | + smc91c111_state *s = vc->opaque; | |
| 697 | + | |
| 698 | + cpu_unregister_io_memory(s->mmio_index); | |
| 699 | + qemu_free(s); | |
| 700 | +} | |
| 701 | + | |
| 693 | 702 | void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq) |
| 694 | 703 | { |
| 695 | 704 | smc91c111_state *s; |
| 696 | - int iomemtype; | |
| 697 | 705 | |
| 698 | 706 | qemu_check_nic_model(nd, "smc91c111"); |
| 699 | 707 | |
| 700 | 708 | s = (smc91c111_state *)qemu_mallocz(sizeof(smc91c111_state)); |
| 701 | - iomemtype = cpu_register_io_memory(0, smc91c111_readfn, | |
| 702 | - smc91c111_writefn, s); | |
| 703 | - cpu_register_physical_memory(base, 16, iomemtype); | |
| 709 | + s->mmio_index = cpu_register_io_memory(0, smc91c111_readfn, | |
| 710 | + smc91c111_writefn, s); | |
| 711 | + cpu_register_physical_memory(base, 16, s->mmio_index); | |
| 704 | 712 | s->irq = irq; |
| 705 | 713 | memcpy(s->macaddr, nd->macaddr, 6); |
| 706 | 714 | |
| 707 | 715 | smc91c111_reset(s); |
| 708 | 716 | |
| 709 | 717 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 710 | - smc91c111_receive, smc91c111_can_receive, s); | |
| 718 | + smc91c111_receive, smc91c111_can_receive, | |
| 719 | + smc91c111_cleanup, s); | |
| 711 | 720 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 712 | 721 | /* ??? Save/restore. */ |
| 713 | 722 | } | ... | ... |
hw/stellaris_enet.c
| ... | ... | @@ -69,6 +69,7 @@ typedef struct { |
| 69 | 69 | VLANClientState *vc; |
| 70 | 70 | qemu_irq irq; |
| 71 | 71 | uint8_t macaddr[6]; |
| 72 | + int mmio_index; | |
| 72 | 73 | } stellaris_enet_state; |
| 73 | 74 | |
| 74 | 75 | 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) |
| 384 | 385 | return 0; |
| 385 | 386 | } |
| 386 | 387 | |
| 388 | +static void stellaris_enet_cleanup(VLANClientState *vc) | |
| 389 | +{ | |
| 390 | + stellaris_enet_state *s = vc->opaque; | |
| 391 | + | |
| 392 | + unregister_savevm("stellaris_enet", s); | |
| 393 | + | |
| 394 | + cpu_unregister_io_memory(s->mmio_index); | |
| 395 | + | |
| 396 | + qemu_free(s); | |
| 397 | +} | |
| 398 | + | |
| 387 | 399 | void stellaris_enet_init(NICInfo *nd, uint32_t base, qemu_irq irq) |
| 388 | 400 | { |
| 389 | 401 | stellaris_enet_state *s; |
| 390 | - int iomemtype; | |
| 391 | 402 | |
| 392 | 403 | qemu_check_nic_model(nd, "stellaris"); |
| 393 | 404 | |
| 394 | 405 | s = (stellaris_enet_state *)qemu_mallocz(sizeof(stellaris_enet_state)); |
| 395 | - iomemtype = cpu_register_io_memory(0, stellaris_enet_readfn, | |
| 396 | - stellaris_enet_writefn, s); | |
| 397 | - cpu_register_physical_memory(base, 0x00001000, iomemtype); | |
| 406 | + s->mmio_index = cpu_register_io_memory(0, stellaris_enet_readfn, | |
| 407 | + stellaris_enet_writefn, s); | |
| 408 | + cpu_register_physical_memory(base, 0x00001000, s->mmio_index); | |
| 398 | 409 | s->irq = irq; |
| 399 | 410 | memcpy(s->macaddr, nd->macaddr, 6); |
| 400 | 411 | |
| 401 | 412 | if (nd->vlan) { |
| 402 | 413 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 403 | - stellaris_enet_receive, stellaris_enet_can_receive, s); | |
| 414 | + stellaris_enet_receive, | |
| 415 | + stellaris_enet_can_receive, | |
| 416 | + stellaris_enet_cleanup, s); | |
| 404 | 417 | qemu_format_nic_info_str(s->vc, s->macaddr); |
| 405 | 418 | } |
| 406 | 419 | ... | ... |
hw/usb-net.c
| ... | ... | @@ -1415,14 +1415,20 @@ static int usbnet_can_receive(void *opaque) |
| 1415 | 1415 | return !s->in_len; |
| 1416 | 1416 | } |
| 1417 | 1417 | |
| 1418 | +static void usbnet_cleanup(VLANClientState *vc) | |
| 1419 | +{ | |
| 1420 | + USBNetState *s = vc->opaque; | |
| 1421 | + | |
| 1422 | + rndis_clear_responsequeue(s); | |
| 1423 | + qemu_free(s); | |
| 1424 | +} | |
| 1425 | + | |
| 1418 | 1426 | static void usb_net_handle_destroy(USBDevice *dev) |
| 1419 | 1427 | { |
| 1420 | 1428 | USBNetState *s = (USBNetState *) dev; |
| 1421 | 1429 | |
| 1422 | 1430 | /* TODO: remove the nd_table[] entry */ |
| 1423 | 1431 | qemu_del_vlan_client(s->vc); |
| 1424 | - rndis_clear_responsequeue(s); | |
| 1425 | - qemu_free(s); | |
| 1426 | 1432 | } |
| 1427 | 1433 | |
| 1428 | 1434 | USBDevice *usb_net_init(NICInfo *nd) |
| ... | ... | @@ -1452,7 +1458,9 @@ USBDevice *usb_net_init(NICInfo *nd) |
| 1452 | 1458 | pstrcpy(s->dev.devname, sizeof(s->dev.devname), |
| 1453 | 1459 | "QEMU USB Network Interface"); |
| 1454 | 1460 | s->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 1455 | - usbnet_receive, usbnet_can_receive, s); | |
| 1461 | + usbnet_receive, | |
| 1462 | + usbnet_can_receive, | |
| 1463 | + usbnet_cleanup, s); | |
| 1456 | 1464 | |
| 1457 | 1465 | qemu_format_nic_info_str(s->vc, s->mac); |
| 1458 | 1466 | ... | ... |
hw/virtio-net.c
| ... | ... | @@ -570,6 +570,21 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int version_id) |
| 570 | 570 | return 0; |
| 571 | 571 | } |
| 572 | 572 | |
| 573 | +static void virtio_net_cleanup(VLANClientState *vc) | |
| 574 | +{ | |
| 575 | + VirtIONet *n = vc->opaque; | |
| 576 | + | |
| 577 | + unregister_savevm("virtio-net", n); | |
| 578 | + | |
| 579 | + qemu_free(n->mac_table.macs); | |
| 580 | + qemu_free(n->vlans); | |
| 581 | + | |
| 582 | + qemu_del_timer(n->tx_timer); | |
| 583 | + qemu_free_timer(n->tx_timer); | |
| 584 | + | |
| 585 | + virtio_cleanup(&n->vdev); | |
| 586 | +} | |
| 587 | + | |
| 573 | 588 | PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 574 | 589 | { |
| 575 | 590 | VirtIONet *n; |
| ... | ... | @@ -598,7 +613,9 @@ PCIDevice *virtio_net_init(PCIBus *bus, NICInfo *nd, int devfn) |
| 598 | 613 | memcpy(n->mac, nd->macaddr, ETH_ALEN); |
| 599 | 614 | n->status = VIRTIO_NET_S_LINK_UP; |
| 600 | 615 | n->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name, |
| 601 | - virtio_net_receive, virtio_net_can_receive, n); | |
| 616 | + virtio_net_receive, | |
| 617 | + virtio_net_can_receive, | |
| 618 | + virtio_net_cleanup, n); | |
| 602 | 619 | n->vc->link_status_changed = virtio_net_set_link_status; |
| 603 | 620 | |
| 604 | 621 | qemu_format_nic_info_str(n->vc, n->mac); | ... | ... |
hw/virtio.c
| ... | ... | @@ -750,6 +750,13 @@ void virtio_load(VirtIODevice *vdev, QEMUFile *f) |
| 750 | 750 | virtio_update_irq(vdev); |
| 751 | 751 | } |
| 752 | 752 | |
| 753 | +void virtio_cleanup(VirtIODevice *vdev) | |
| 754 | +{ | |
| 755 | + if (vdev->config) | |
| 756 | + qemu_free(vdev->config); | |
| 757 | + qemu_free(vdev->vq); | |
| 758 | +} | |
| 759 | + | |
| 753 | 760 | VirtIODevice *virtio_init_pci(PCIBus *bus, const char *name, |
| 754 | 761 | uint16_t vendor, uint16_t device, |
| 755 | 762 | uint16_t subvendor, uint16_t subdevice, | ... | ... |
hw/virtio.h
| ... | ... | @@ -117,6 +117,8 @@ void virtio_save(VirtIODevice *vdev, QEMUFile *f); |
| 117 | 117 | |
| 118 | 118 | void virtio_load(VirtIODevice *vdev, QEMUFile *f); |
| 119 | 119 | |
| 120 | +void virtio_cleanup(VirtIODevice *vdev); | |
| 121 | + | |
| 120 | 122 | void virtio_notify_config(VirtIODevice *vdev); |
| 121 | 123 | |
| 122 | 124 | void virtio_queue_set_notification(VirtQueue *vq, int enable); | ... | ... |
net.c
| ... | ... | @@ -333,6 +333,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
| 333 | 333 | const char *name, |
| 334 | 334 | IOReadHandler *fd_read, |
| 335 | 335 | IOCanRWHandler *fd_can_read, |
| 336 | + NetCleanup *cleanup, | |
| 336 | 337 | void *opaque) |
| 337 | 338 | { |
| 338 | 339 | VLANClientState *vc, **pvc; |
| ... | ... | @@ -344,6 +345,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
| 344 | 345 | vc->name = assign_name(vc, model); |
| 345 | 346 | vc->fd_read = fd_read; |
| 346 | 347 | vc->fd_can_read = fd_can_read; |
| 348 | + vc->cleanup = cleanup; | |
| 347 | 349 | vc->opaque = opaque; |
| 348 | 350 | vc->vlan = vlan; |
| 349 | 351 | |
| ... | ... | @@ -362,6 +364,9 @@ void qemu_del_vlan_client(VLANClientState *vc) |
| 362 | 364 | while (*pvc != NULL) |
| 363 | 365 | if (*pvc == vc) { |
| 364 | 366 | *pvc = vc->next; |
| 367 | + if (vc->cleanup) { | |
| 368 | + vc->cleanup(vc); | |
| 369 | + } | |
| 365 | 370 | free(vc->name); |
| 366 | 371 | free(vc->model); |
| 367 | 372 | free(vc); |
| ... | ... | @@ -521,7 +526,7 @@ static int net_slirp_init(VLANState *vlan, const char *model, const char *name) |
| 521 | 526 | slirp_init(slirp_restrict, slirp_ip); |
| 522 | 527 | } |
| 523 | 528 | slirp_vc = qemu_new_vlan_client(vlan, model, name, |
| 524 | - slirp_receive, NULL, NULL); | |
| 529 | + slirp_receive, NULL, NULL, NULL); | |
| 525 | 530 | slirp_vc->info_str[0] = '\0'; |
| 526 | 531 | return 0; |
| 527 | 532 | } |
| ... | ... | @@ -702,6 +707,8 @@ typedef struct TAPState { |
| 702 | 707 | char down_script_arg[128]; |
| 703 | 708 | } TAPState; |
| 704 | 709 | |
| 710 | +static int launch_script(const char *setup_script, const char *ifname, int fd); | |
| 711 | + | |
| 705 | 712 | static ssize_t tap_receive_iov(void *opaque, const struct iovec *iov, |
| 706 | 713 | int iovcnt) |
| 707 | 714 | { |
| ... | ... | @@ -748,6 +755,18 @@ static void tap_send(void *opaque) |
| 748 | 755 | } |
| 749 | 756 | } |
| 750 | 757 | |
| 758 | +static void tap_cleanup(VLANClientState *vc) | |
| 759 | +{ | |
| 760 | + TAPState *s = vc->opaque; | |
| 761 | + | |
| 762 | + if (s->down_script[0]) | |
| 763 | + launch_script(s->down_script, s->down_script_arg, s->fd); | |
| 764 | + | |
| 765 | + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); | |
| 766 | + close(s->fd); | |
| 767 | + qemu_free(s); | |
| 768 | +} | |
| 769 | + | |
| 751 | 770 | /* fd support */ |
| 752 | 771 | |
| 753 | 772 | static TAPState *net_tap_fd_init(VLANState *vlan, |
| ... | ... | @@ -759,7 +778,8 @@ static TAPState *net_tap_fd_init(VLANState *vlan, |
| 759 | 778 | |
| 760 | 779 | s = qemu_mallocz(sizeof(TAPState)); |
| 761 | 780 | s->fd = fd; |
| 762 | - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); | |
| 781 | + s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, | |
| 782 | + NULL, tap_cleanup, s); | |
| 763 | 783 | s->vc->fd_readv = tap_receive_iov; |
| 764 | 784 | qemu_set_fd_handler(s->fd, tap_send, NULL, s); |
| 765 | 785 | 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) |
| 1058 | 1078 | } |
| 1059 | 1079 | } |
| 1060 | 1080 | |
| 1081 | +static void vde_cleanup(VLANClientState *vc) | |
| 1082 | +{ | |
| 1083 | + VDEState *s = vc->opaque; | |
| 1084 | + qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL); | |
| 1085 | + vde_close(s->vde); | |
| 1086 | + qemu_free(s); | |
| 1087 | +} | |
| 1088 | + | |
| 1061 | 1089 | static int net_vde_init(VLANState *vlan, const char *model, |
| 1062 | 1090 | const char *name, const char *sock, |
| 1063 | 1091 | int port, const char *group, int mode) |
| ... | ... | @@ -1078,7 +1106,8 @@ static int net_vde_init(VLANState *vlan, const char *model, |
| 1078 | 1106 | free(s); |
| 1079 | 1107 | return -1; |
| 1080 | 1108 | } |
| 1081 | - s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, NULL, s); | |
| 1109 | + s->vc = qemu_new_vlan_client(vlan, model, name, vde_from_qemu, | |
| 1110 | + NULL, vde_cleanup, s); | |
| 1082 | 1111 | qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s); |
| 1083 | 1112 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d", |
| 1084 | 1113 | sock, vde_datafd(s->vde)); |
| ... | ... | @@ -1263,6 +1292,14 @@ fail: |
| 1263 | 1292 | return -1; |
| 1264 | 1293 | } |
| 1265 | 1294 | |
| 1295 | +static void net_socket_cleanup(VLANClientState *vc) | |
| 1296 | +{ | |
| 1297 | + NetSocketState *s = vc->opaque; | |
| 1298 | + qemu_set_fd_handler(s->fd, NULL, NULL, NULL); | |
| 1299 | + close(s->fd); | |
| 1300 | + qemu_free(s); | |
| 1301 | +} | |
| 1302 | + | |
| 1266 | 1303 | static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, |
| 1267 | 1304 | const char *model, |
| 1268 | 1305 | const char *name, |
| ... | ... | @@ -1307,7 +1344,8 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, |
| 1307 | 1344 | s = qemu_mallocz(sizeof(NetSocketState)); |
| 1308 | 1345 | s->fd = fd; |
| 1309 | 1346 | |
| 1310 | - s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, NULL, s); | |
| 1347 | + s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive_dgram, | |
| 1348 | + NULL, net_socket_cleanup, s); | |
| 1311 | 1349 | qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); |
| 1312 | 1350 | |
| 1313 | 1351 | /* mcast: save bound address as dst */ |
| ... | ... | @@ -1334,8 +1372,8 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, |
| 1334 | 1372 | NetSocketState *s; |
| 1335 | 1373 | s = qemu_mallocz(sizeof(NetSocketState)); |
| 1336 | 1374 | s->fd = fd; |
| 1337 | - s->vc = qemu_new_vlan_client(vlan, model, name, | |
| 1338 | - net_socket_receive, NULL, s); | |
| 1375 | + s->vc = qemu_new_vlan_client(vlan, model, name, net_socket_receive, | |
| 1376 | + NULL, net_socket_cleanup, s); | |
| 1339 | 1377 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 1340 | 1378 | "socket: fd=%d", fd); |
| 1341 | 1379 | if (is_connected) { |
| ... | ... | @@ -1895,29 +1933,20 @@ done: |
| 1895 | 1933 | |
| 1896 | 1934 | void net_cleanup(void) |
| 1897 | 1935 | { |
| 1898 | -#if !defined(_WIN32) | |
| 1899 | 1936 | VLANState *vlan; |
| 1900 | 1937 | |
| 1901 | 1938 | /* close network clients */ |
| 1902 | 1939 | for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { |
| 1903 | - VLANClientState *vc; | |
| 1940 | + VLANClientState *vc = vlan->first_client; | |
| 1904 | 1941 | |
| 1905 | - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { | |
| 1906 | - if (vc->fd_read == tap_receive) { | |
| 1907 | - TAPState *s = vc->opaque; | |
| 1942 | + while (vc) { | |
| 1943 | + VLANClientState *next = vc->next; | |
| 1908 | 1944 | |
| 1909 | - if (s->down_script[0]) | |
| 1910 | - launch_script(s->down_script, s->down_script_arg, s->fd); | |
| 1911 | - } | |
| 1912 | -#if defined(CONFIG_VDE) | |
| 1913 | - if (vc->fd_read == vde_from_qemu) { | |
| 1914 | - VDEState *s = vc->opaque; | |
| 1915 | - vde_close(s->vde); | |
| 1916 | - } | |
| 1917 | -#endif | |
| 1945 | + qemu_del_vlan_client(vc); | |
| 1946 | + | |
| 1947 | + vc = next; | |
| 1918 | 1948 | } |
| 1919 | 1949 | } |
| 1920 | -#endif | |
| 1921 | 1950 | } |
| 1922 | 1951 | |
| 1923 | 1952 | void net_client_check(void) | ... | ... |
net.h
| ... | ... | @@ -9,6 +9,7 @@ typedef ssize_t (IOReadvHandler)(void *, const struct iovec *, int); |
| 9 | 9 | |
| 10 | 10 | typedef struct VLANClientState VLANClientState; |
| 11 | 11 | |
| 12 | +typedef void (NetCleanup) (VLANClientState *); | |
| 12 | 13 | typedef void (LinkStatusChanged)(VLANClientState *); |
| 13 | 14 | |
| 14 | 15 | struct VLANClientState { |
| ... | ... | @@ -17,6 +18,7 @@ struct VLANClientState { |
| 17 | 18 | /* Packets may still be sent if this returns zero. It's used to |
| 18 | 19 | rate-limit the slirp code. */ |
| 19 | 20 | IOCanRWHandler *fd_can_read; |
| 21 | + NetCleanup *cleanup; | |
| 20 | 22 | LinkStatusChanged *link_status_changed; |
| 21 | 23 | int link_down; |
| 22 | 24 | void *opaque; |
| ... | ... | @@ -40,6 +42,7 @@ VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
| 40 | 42 | const char *name, |
| 41 | 43 | IOReadHandler *fd_read, |
| 42 | 44 | IOCanRWHandler *fd_can_read, |
| 45 | + NetCleanup *cleanup, | |
| 43 | 46 | void *opaque); |
| 44 | 47 | void qemu_del_vlan_client(VLANClientState *vc); |
| 45 | 48 | VLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque); | ... | ... |
tap-win32.c
| ... | ... | @@ -638,6 +638,18 @@ static int tap_win32_open(tap_win32_overlapped_t **phandle, |
| 638 | 638 | tap_win32_overlapped_t *handle; |
| 639 | 639 | } TAPState; |
| 640 | 640 | |
| 641 | +static void tap_cleanup(VLANClientState *vc) | |
| 642 | +{ | |
| 643 | + TAPState *s = vc->opaque; | |
| 644 | + | |
| 645 | + qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); | |
| 646 | + | |
| 647 | + /* FIXME: need to kill thread and close file handle: | |
| 648 | + tap_win32_close(s); | |
| 649 | + */ | |
| 650 | + qemu_free(s); | |
| 651 | +} | |
| 652 | + | |
| 641 | 653 | static void tap_receive(void *opaque, const uint8_t *buf, int size) |
| 642 | 654 | { |
| 643 | 655 | TAPState *s = opaque; |
| ... | ... | @@ -672,7 +684,8 @@ int tap_win32_init(VLANState *vlan, const char *model, |
| 672 | 684 | return -1; |
| 673 | 685 | } |
| 674 | 686 | |
| 675 | - s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, NULL, s); | |
| 687 | + s->vc = qemu_new_vlan_client(vlan, model, name, tap_receive, | |
| 688 | + NULL, tap_cleanup, s); | |
| 676 | 689 | |
| 677 | 690 | snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 678 | 691 | "tap: ifname=%s", ifname); | ... | ... |