diff options
author | cindi <none@none> | 2006-11-13 19:51:46 -0800 |
---|---|---|
committer | cindi <none@none> | 2006-11-13 19:51:46 -0800 |
commit | fa52d01bb7e683bd3f348e8daeacb561fc8b0a52 (patch) | |
tree | 98ac8af566752599368ec8d9adec4e482ca15189 /usr/src | |
parent | 3a9d44d99a8352803b186773302a309b65111b23 (diff) | |
download | illumos-gate-fa52d01bb7e683bd3f348e8daeacb561fc8b0a52.tar.gz |
6480790 deadlock, fmc_grow does a kmem_free while a high level (spin) mutex is held from ndi_fmc_insert
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/uts/common/os/ndifm.c | 20 | ||||
-rw-r--r-- | usr/src/uts/common/sys/ddifm_impl.h | 3 |
2 files changed, 13 insertions, 10 deletions
diff --git a/usr/src/uts/common/os/ndifm.c b/usr/src/uts/common/os/ndifm.c index b626dbb9c4..8c7d1c7d23 100644 --- a/usr/src/uts/common/os/ndifm.c +++ b/usr/src/uts/common/os/ndifm.c @@ -188,6 +188,7 @@ i_ndi_fmc_create(ndi_fmc_t **fcpp, int qlen, ddi_iblock_cookie_t ibc) fcp = kmem_zalloc(sizeof (ndi_fmc_t), KM_SLEEP); mutex_init(&fcp->fc_lock, NULL, MUTEX_DRIVER, ibc); + mutex_init(&fcp->fc_free_lock, NULL, MUTEX_DRIVER, NULL); /* Preallocate and initialize entries for this fm cache */ fcp->fc_elems = kmem_zalloc(qlen * sizeof (ndi_fmcentry_t), KM_SLEEP); @@ -230,7 +231,7 @@ fmc_grow(ndi_fmc_t *fcp, int flag, int grow_sz) ndi_fmcentry_t *ncp, *oep, *nep, *nnep; ASSERT(grow_sz); - ASSERT(MUTEX_HELD(&fcp->fc_lock)); + ASSERT(MUTEX_HELD(&fcp->fc_free_lock)); /* Allocate a new cache */ nlen = grow_sz + fcp->fc_len; @@ -335,7 +336,7 @@ ndi_fmc_insert(dev_info_t *dip, int flag, void *resource, void *bus_specific) } ASSERT(*fpp == NULL); - mutex_enter(&fcp->fc_lock); + mutex_enter(&fcp->fc_free_lock); /* Get an entry from the free list */ fep = fcp->fc_free; @@ -347,13 +348,14 @@ ndi_fmc_insert(dev_info_t *dip, int flag, void *resource, void *bus_specific) /* Unable to get an entry or grow this cache */ atomic_add_64( &fmhdl->fh_kstat.fek_fmc_full.value.ui64, 1); - mutex_exit(&fcp->fc_lock); + mutex_exit(&fcp->fc_free_lock); return; } atomic_add_64(&fmhdl->fh_kstat.fek_fmc_grew.value.ui64, 1); fep = fcp->fc_free; } fcp->fc_free = fep->fce_prev; + mutex_exit(&fcp->fc_free_lock); /* * Set-up the handle resource and bus_specific information. @@ -365,6 +367,7 @@ ndi_fmc_insert(dev_info_t *dip, int flag, void *resource, void *bus_specific) *fpp = fep; /* Add entry to the end of the active list */ + mutex_enter(&fcp->fc_lock); fep->fce_prev = fcp->fc_tail; fcp->fc_tail->fce_next = fep; fcp->fc_tail = fep; @@ -404,7 +407,6 @@ ndi_fmc_remove(dev_info_t *dip, int flag, const void *resource) ASSERT(fcp); - mutex_enter(&fcp->fc_lock); fep = ((ddi_dma_impl_t *)resource)->dmai_error.err_fep; ((ddi_dma_impl_t *)resource)->dmai_error.err_fep = NULL; } else if (flag == ACC_HANDLE) { @@ -417,7 +419,6 @@ ndi_fmc_remove(dev_info_t *dip, int flag, const void *resource) ASSERT(fcp); - mutex_enter(&fcp->fc_lock); fep = ((ddi_acc_impl_t *)resource)->ahi_err->err_fep; ((ddi_acc_impl_t *)resource)->ahi_err->err_fep = NULL; } @@ -425,21 +426,22 @@ ndi_fmc_remove(dev_info_t *dip, int flag, const void *resource) /* * Resource not in cache, return */ - if (fep == NULL) { - mutex_exit(&fcp->fc_lock); + if (fep == NULL) return; - } + mutex_enter(&fcp->fc_lock); fep->fce_prev->fce_next = fep->fce_next; if (fep == fcp->fc_tail) fcp->fc_tail = fep->fce_prev; else fep->fce_next->fce_prev = fep->fce_prev; + mutex_exit(&fcp->fc_lock); /* Add entry back to the free list */ + mutex_enter(&fcp->fc_free_lock); fep->fce_prev = fcp->fc_free; fcp->fc_free = fep; - mutex_exit(&fcp->fc_lock); + mutex_exit(&fcp->fc_free_lock); } int diff --git a/usr/src/uts/common/sys/ddifm_impl.h b/usr/src/uts/common/sys/ddifm_impl.h index fa5d648b77..a8dd18cce5 100644 --- a/usr/src/uts/common/sys/ddifm_impl.h +++ b/usr/src/uts/common/sys/ddifm_impl.h @@ -64,7 +64,8 @@ struct i_ddi_fmc_entry { }; struct i_ddi_fmc { - kmutex_t fc_lock; /* exclusive cache access */ + kmutex_t fc_lock; /* cache active access */ + kmutex_t fc_free_lock; /* cache freelist access */ int fc_len; /* length of FM cache array */ struct i_ddi_fmc_entry *fc_elems; /* FM cache array */ struct i_ddi_fmc_entry *fc_free; /* free list */ |