diff options
| author | Rajeev Kumar <rajekuma@qca.qualcomm.com> | 2014-02-13 13:15:53 -0800 |
|---|---|---|
| committer | Akash Patel <c_akashp@qca.qualcomm.com> | 2014-02-18 01:00:26 -0800 |
| commit | 151dc450ed91a71e28e3efa8efbd1a2d5e47af6e (patch) | |
| tree | b2a5c3de96923f0603dc823bdd0c2aff3a15c065 | |
| parent | c5c8601e08b476f4aedb298bd14033baa32288d3 (diff) | |
qcacld: Fix of double free panic caused by vdev detach event
vdev detach event timeout is started in atomic context and when
its freed usig vos_mem_free() SLUB debug enabled driver complains
about double free and calls panic. To fix this issue allow memory
allocation in vos_mem_malloc_debug() using GFP_KERNEL and still
maintain meta info for timer/memory management.
Change-Id: Id172413a53deba23f4034568505c198aa09b0839
CRs-Fixed: 615743
| -rw-r--r-- | CORE/VOSS/src/vos_memory.c | 30 |
1 files changed, 14 insertions, 16 deletions
diff --git a/CORE/VOSS/src/vos_memory.c b/CORE/VOSS/src/vos_memory.c index 00fb555922b9..9b531f2eec5f 100644 --- a/CORE/VOSS/src/vos_memory.c +++ b/CORE/VOSS/src/vos_memory.c @@ -179,6 +179,9 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) struct s_vos_mem_struct* memStruct; v_VOID_t* memPtr = NULL; v_SIZE_t new_size; + int flags = GFP_KERNEL; + unsigned long IrqFlags; + if (size > (1024*1024)) { @@ -189,14 +192,12 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) if (in_interrupt()) { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s is being" - "called from interrupt context, using GPF_ATOMIC.", __func__); - return kmalloc(size, GFP_ATOMIC); + flags = GFP_ATOMIC; } new_size = size + sizeof(struct s_vos_mem_struct) + 8; - memStruct = (struct s_vos_mem_struct*)kmalloc(new_size,GFP_KERNEL); + memStruct = (struct s_vos_mem_struct*)kmalloc(new_size, flags); if(memStruct != NULL) { @@ -209,9 +210,9 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) vos_mem_copy(&memStruct->header[0], &WLAN_MEM_HEADER[0], sizeof(WLAN_MEM_HEADER)); vos_mem_copy( (v_U8_t*)(memStruct + 1) + size, &WLAN_MEM_TAIL[0], sizeof(WLAN_MEM_TAIL)); - spin_lock(&vosMemList.lock); + spin_lock_irqsave(&vosMemList.lock, IrqFlags); vosStatus = hdd_list_insert_front(&vosMemList, &memStruct->pNode); - spin_unlock(&vosMemList.lock); + spin_unlock_irqrestore(&vosMemList.lock, IrqFlags); if(VOS_STATUS_SUCCESS != vosStatus) { VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, @@ -225,14 +226,16 @@ v_VOID_t * vos_mem_malloc_debug( v_SIZE_t size, char* fileName, v_U32_t lineNum) v_VOID_t vos_mem_free( v_VOID_t *ptr ) { + unsigned long IrqFlags; + if (ptr != NULL) { VOS_STATUS vosStatus; struct s_vos_mem_struct* memStruct = ((struct s_vos_mem_struct*)ptr) - 1; - spin_lock(&vosMemList.lock); + spin_lock_irqsave(&vosMemList.lock, IrqFlags); vosStatus = hdd_list_remove_node(&vosMemList, &memStruct->pNode); - spin_unlock(&vosMemList.lock); + spin_unlock_irqrestore(&vosMemList.lock, IrqFlags); if(VOS_STATUS_SUCCESS == vosStatus) { @@ -261,6 +264,7 @@ v_VOID_t vos_mem_free( v_VOID_t *ptr ) #else v_VOID_t * vos_mem_malloc( v_SIZE_t size ) { + int flags = GFP_KERNEL; #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC v_VOID_t* pmem; #endif @@ -271,8 +275,7 @@ v_VOID_t * vos_mem_malloc( v_SIZE_t size ) } if (in_interrupt()) { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__); - return NULL; + flags = GFP_ATOMIC; } #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC if(size > WCNSS_PRE_ALLOC_GET_THRESHOLD) @@ -282,7 +285,7 @@ v_VOID_t * vos_mem_malloc( v_SIZE_t size ) return pmem; } #endif - return kmalloc(size, GFP_KERNEL); + return kmalloc(size, flags); } v_VOID_t vos_mem_free( v_VOID_t *ptr ) @@ -290,11 +293,6 @@ v_VOID_t vos_mem_free( v_VOID_t *ptr ) if (ptr == NULL) return; - if (in_interrupt()) - { - VOS_TRACE(VOS_MODULE_ID_VOSS, VOS_TRACE_LEVEL_ERROR, "%s cannot be called from interrupt context!!!", __func__); - return; - } #ifdef CONFIG_WCNSS_MEM_PRE_ALLOC if(wcnss_prealloc_put(ptr)) return; |
