/* * Release a Storage Pool * * Frees all dynamic storage acquired for a storage pool. * This function is normally called just prior to a module's unloading. * * Arguments: * sip pointer to sp_info for storage pool * * Returns: * none * */ void atm_release_pool(struct sp_info *sip) { struct sp_chunk *scp, *scp_next; crit_enter(); /* * Free each chunk in pool */ for (scp = sip->si_poolh; scp; scp = scp_next) { /* * Check for memory leaks */ if (scp->sc_used) panic("atm_release_pool: unfreed blocks"); scp_next = scp->sc_next; KM_FREE((caddr_t)scp, sip->si_chunksiz, M_DEVBUF); } /* * Update pool controls */ sip->si_poolh = NULL; sip->si_chunks = 0; sip->si_total = 0; sip->si_free = 0; /* * Unlink pool from active chain */ sip->si_chunksiz = 0; UNLINK(sip, struct sp_info, atm_pool_head, si_next); crit_exit(); return; }
/* * Procedure to release a buffer previously allocated from adapter * RAM. When possible, we'll compact memory. * * Arguments: * eup pointer to per unit structure * base base adapter address of buffer to be freed * * Returns: * none * */ void eni_free_buffer(Eni_unit *eup, caddr_t base) { Mbd *eptr = eup->eu_memmap; int nclicks; /* Look through entire list */ while ( eptr ) { /* Is this the buffer to be freed? */ if ( eptr->base == base ) { /* * We're probably asking for trouble but, * assume this is it. */ if ( eptr->state != MEM_INUSE ) { eup->eu_stats.eni_st_drv.drv_mm_notuse++; /* Huh? Something's wrong */ return; } /* Reset state to FREE */ eptr->state = MEM_FREE; /* Determine size for stats info */ for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ ) if ( ( 1 << nclicks ) * ENI_BUF_PGSZ == eptr->size ) break; /* Valid size? Yes - decrement inuse count */ if ( nclicks < ENI_BUF_NBIT ) eup->eu_memclicks[nclicks]--; /* Try to compact neighbors */ /* with previous */ if ( eptr->prev ) if ( eptr->prev->state == MEM_FREE ) { Mbd *etmp = eptr; /* Add to previous block */ eptr->prev->size += eptr->size; /* Set prev block to skip this one */ eptr->prev->next = eptr->next; /* Set next block to skip this one */ if ( eptr->next ) eptr->next->prev = eptr->prev; /* Reset to where we want to be */ eptr = eptr->prev; /* and free this element */ (void)KM_FREE(etmp, etmp->size, M_DEVBUF); } /* with next */ if ( eptr->next ) if ( eptr->next->state == MEM_FREE ) { Mbd *etmp = eptr->next; /* add following block in */ eptr->size += etmp->size; /* set next next block to skip next block */ if ( etmp->next ) etmp->next->prev = eptr; /* skip next block */ eptr->next = etmp->next; /* and free next element */ (void)KM_FREE(etmp, etmp->size, M_DEVBUF); } /* * We've freed the buffer and done any compaction, * we needn't look any further... */ return; } eptr = eptr->next; } if ( eptr == NULL ) { /* Oops - failed to find the buffer. This is BAD */ eup->eu_stats.eni_st_drv.drv_mm_notfnd++; } }
/* * Storage Pool Compaction * * Called periodically in order to perform compaction of the * storage pools. Each pool will be checked to see if any chunks * can be freed, taking some care to avoid freeing too many chunks * in order to avoid memory thrashing. * * Called from a critical section. * * Arguments: * tip pointer to timer control block (atm_compactimer) * * Returns: * none * */ static void atm_compact(struct atm_time *tip) { struct sp_info *sip; struct sp_chunk *scp; int i; struct sp_chunk *scp_prev; /* * Check out all storage pools */ for (sip = atm_pool_head; sip; sip = sip->si_next) { /* * Always keep a minimum number of chunks around */ if (sip->si_chunks <= SPOOL_MIN_CHUNK) continue; /* * Maximum chunks to free at one time will leave * pool with at least 50% utilization, but never * go below minimum chunk count. */ i = ((sip->si_free * 2) - sip->si_total) / sip->si_blkcnt; i = MIN(i, sip->si_chunks - SPOOL_MIN_CHUNK); /* * Look for chunks to free */ scp_prev = NULL; for (scp = sip->si_poolh; scp && i > 0; ) { if (scp->sc_used == 0) { /* * Found a chunk to free, so do it */ if (scp_prev) { scp_prev->sc_next = scp->sc_next; if (sip->si_poolt == scp) sip->si_poolt = scp_prev; } else sip->si_poolh = scp->sc_next; KM_FREE((caddr_t)scp, sip->si_chunksiz, M_DEVBUF); /* * Update pool controls */ sip->si_chunks--; sip->si_total -= sip->si_blkcnt; sip->si_free -= sip->si_blkcnt; i--; if (scp_prev) scp = scp_prev->sc_next; else scp = sip->si_poolh; } else { scp_prev = scp; scp = scp->sc_next; } } } /* * Restart the compaction timer */ atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact); return; }