Mercurial > illumos > illumos-gate
changeset 10041:b0f22b3cef0c
6850554 unplumb hio enabled vnet with linkprop set causes memory leaks
author | WENTAO YANG <Wentao.Yang@Sun.COM> |
---|---|
date | Mon, 06 Jul 2009 16:54:01 -0700 |
parents | 38b25aeeaf7a |
children | c022bae2f0d3 |
files | usr/src/uts/sun4v/io/vsw.c usr/src/uts/sun4v/io/vsw_ldc.c usr/src/uts/sun4v/sys/vsw.h |
diffstat | 3 files changed, 63 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/sun4v/io/vsw.c Mon Jul 06 15:04:34 2009 -0700 +++ b/usr/src/uts/sun4v/io/vsw.c Mon Jul 06 16:54:01 2009 -0700 @@ -80,7 +80,7 @@ static int vsw_unattach(vsw_t *vswp); static int vsw_get_md_physname(vsw_t *, md_t *, mde_cookie_t, char *); static int vsw_get_md_smodes(vsw_t *, md_t *, mde_cookie_t, uint8_t *); -static int vsw_mod_cleanup(void); +void vsw_destroy_rxpools(void *); /* MDEG routines */ static int vsw_mdeg_register(vsw_t *vswp); @@ -186,6 +186,8 @@ int vsw_ldc_delay = 1000; /* 1 ms delay for ldc_close() */ boolean_t vsw_ldc_rxthr_enabled = B_TRUE; /* LDC Rx thread enabled */ boolean_t vsw_ldc_txthr_enabled = B_TRUE; /* LDC Tx thread enabled */ +int vsw_rxpool_cleanup_delay = 100000; /* 100ms */ + uint32_t vsw_fdb_nchains = 8; /* # of chains in fdb hash table */ uint32_t vsw_vlan_nchains = 4; /* # of chains in vlan id hash table */ @@ -352,7 +354,6 @@ * Linked list of "vsw_t" structures - one per instance. */ vsw_t *vsw_head = NULL; -vio_mblk_pool_t *vsw_rx_poolp = NULL; krwlock_t vsw_rw; /* @@ -485,10 +486,6 @@ { int status; - status = vsw_mod_cleanup(); - if (status != 0) - return (status); - status = mod_remove(&modlinkage); if (status != 0) return (status); @@ -594,6 +591,17 @@ progress |= PROG_taskq; + (void) snprintf(qname, TASKQ_NAMELEN, "vsw_rxp_taskq%d", + vswp->instance); + if ((vswp->rxp_taskq = ddi_taskq_create(vswp->dip, qname, 1, + TASKQ_DEFAULTPRI, 0)) == NULL) { + cmn_err(CE_WARN, "!vsw%d: Unable to create rxp task queue", + vswp->instance); + goto vsw_attach_fail; + } + + progress |= PROG_rxp_taskq; + /* prevent auto-detaching */ if (ddi_prop_update_int(DDI_DEV_T_NONE, vswp->dip, DDI_NO_AUTODETACH, 1) != DDI_SUCCESS) { @@ -716,7 +724,6 @@ static int vsw_unattach(vsw_t *vswp) { - vio_mblk_pool_t *poolp, *npoolp; vsw_attach_progress_t progress; progress = vswp->attach_progress; @@ -747,24 +754,6 @@ if (progress & PROG_mdreg) { vsw_mdeg_unregister(vswp); vsw_detach_ports(vswp); - - /* - * At this point, we attempt to free receive mblk pools that - * couldn't be destroyed when the ports were detached; if this - * attempt also fails, we hook up the pool(s) to the module so - * they can be cleaned up in _fini(). - */ - poolp = vswp->rxh; - while (poolp != NULL) { - npoolp = vswp->rxh = poolp->nextp; - if (vio_destroy_mblks(poolp) != 0) { - WRITE_ENTER(&vsw_rw); - poolp->nextp = vsw_rx_poolp; - vsw_rx_poolp = poolp; - RW_EXIT(&vsw_rw); - } - poolp = npoolp; - } progress &= ~PROG_mdreg; } @@ -796,6 +785,17 @@ } /* + * We now destroy the taskq used to clean up rx mblk pools that + * couldn't be destroyed when the ports/channels were detached. + * We implicitly wait for those tasks to complete in + * ddi_taskq_destroy(). + */ + if (progress & PROG_rxp_taskq) { + ddi_taskq_destroy(vswp->rxp_taskq); + progress &= ~PROG_rxp_taskq; + } + + /* * By now any pending tasks have finished and the underlying * ldc's have been destroyed, so its safe to delete the control * message taskq. @@ -844,32 +844,19 @@ return (0); } -/* - * one time cleanup. - */ -static int -vsw_mod_cleanup(void) +void +vsw_destroy_rxpools(void *arg) { - vio_mblk_pool_t *poolp, *npoolp; - - /* - * If any rx mblk pools are still in use, return - * error and stop the module from unloading. - */ - WRITE_ENTER(&vsw_rw); - poolp = vsw_rx_poolp; + vio_mblk_pool_t *poolp = (vio_mblk_pool_t *)arg; + vio_mblk_pool_t *npoolp; + while (poolp != NULL) { - npoolp = vsw_rx_poolp = poolp->nextp; - if (vio_destroy_mblks(poolp) != 0) { - vsw_rx_poolp = poolp; - RW_EXIT(&vsw_rw); - return (EBUSY); + npoolp = poolp->nextp; + while (vio_destroy_mblks(poolp) != 0) { + drv_usecwait(vsw_rxpool_cleanup_delay); } poolp = npoolp; } - RW_EXIT(&vsw_rw); - - return (0); } /*
--- a/usr/src/uts/sun4v/io/vsw_ldc.c Mon Jul 06 15:04:34 2009 -0700 +++ b/usr/src/uts/sun4v/io/vsw_ldc.c Mon Jul 06 16:54:01 2009 -0700 @@ -209,7 +209,7 @@ extern void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp); extern int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type); extern void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type); - +extern void vsw_destroy_rxpools(void *arg); #define VSW_NUM_VMPOOLS 3 /* number of vio mblk pools */ @@ -865,6 +865,7 @@ vsw_ldc_list_t *ldcl = &port->p_ldclist; int rv; int retries = 0; + vio_mblk_pool_t *fvmp = NULL; prev_ldcp = ldcl->head; for (; (ldcp = prev_ldcp) != NULL; prev_ldcp = ldcp->ldc_next) { @@ -931,13 +932,17 @@ /* - * Most likely some mblks are still in use and - * have not been returned to the pool. These mblks are - * added to the pool that is maintained in the device instance. - * Another attempt will be made to destroy the pool - * when the device detaches. + * If we can't destroy all the rx pools for this channel, dispatch + * a task to retry and clean up those rx pools. Note that we don't + * need to wait for the task to complete. If the vsw device itself + * gets detached (vsw_detach()), it will wait for the task to complete + * implicitly in ddi_taskq_destroy(). */ - vio_destroy_multipools(&ldcp->vmp, &vswp->rxh); + vio_destroy_multipools(&ldcp->vmp, &fvmp); + if (fvmp != NULL) { + (void) ddi_taskq_dispatch(vswp->rxp_taskq, + vsw_destroy_rxpools, fvmp, DDI_SLEEP); + } /* unlink it from the list */ prev_ldcp = ldcp->ldc_next; @@ -1606,11 +1611,22 @@ vsw_t *vswp = ldcp->ldc_vswp; vsw_port_t *port; vsw_ldc_list_t *ldcl; + vio_mblk_pool_t *fvmp = NULL; D1(vswp, "%s: enter", __func__); - /* free receive mblk pools for the channel */ - vio_destroy_multipools(&ldcp->vmp, &vswp->rxh); + /* + * If we can't destroy all the rx pools for this channel, dispatch + * a task to retry and clean up those rx pools. Note that we don't + * need to wait for the task to complete. If the vsw device itself + * gets detached (vsw_detach()), it will wait for the task to complete + * implicitly in ddi_taskq_destroy(). + */ + vio_destroy_multipools(&ldcp->vmp, &fvmp); + if (fvmp != NULL) { + (void) ddi_taskq_dispatch(vswp->rxp_taskq, + vsw_destroy_rxpools, fvmp, DDI_SLEEP); + } port = ldcp->ldc_port; ldcl = &port->p_ldclist;
--- a/usr/src/uts/sun4v/sys/vsw.h Mon Jul 06 15:04:34 2009 -0700 +++ b/usr/src/uts/sun4v/sys/vsw.h Mon Jul 06 16:54:01 2009 -0700 @@ -99,9 +99,10 @@ PROG_fdb = 0x04, PROG_mfdb = 0x08, PROG_taskq = 0x10, - PROG_swmode = 0x20, - PROG_macreg = 0x40, - PROG_mdreg = 0x80 + PROG_rxp_taskq = 0x20, + PROG_swmode = 0x40, + PROG_macreg = 0x80, + PROG_mdreg = 0x100 } vsw_attach_progress_t; /* @@ -143,7 +144,7 @@ mod_hash_t *mfdb; /* multicast FDB */ krwlock_t mfdbrw; /* rwlock for mFDB */ - vio_mblk_pool_t *rxh; /* Receive pool handle */ + ddi_taskq_t *rxp_taskq; /* VIO rx pool taskq */ void (*vsw_switch_frame) (struct vsw *, mblk_t *, int, vsw_port_t *, mac_resource_handle_t);