From 412a969aebc171ac358e4202682a4564fe92a8d7 Mon Sep 17 00:00:00 2001 From: Devender kumar Date: Thu, 23 Dec 2021 10:09:42 +0530 Subject: [PATCH] qcacmn: Fix Atomic Memory Allocation Method Memory allocation in atomic context is not correct, as for MEMORY_DEBUG profile the initial_memory_debug flag is set to 0 which leads in allocating memory with GFP_KERNEL flag Issue is seen with SDX_PINE where the memory allocation is done in sleeping context using GFP_KERNEL in interrupt context Fix is create a new memory allocation API with GFP_ATOMIC flag Change-Id: I3baa5b601b60f88fe2d9ff1f4008703c6507a267 --- qdf/inc/qdf_mem.h | 34 ++++++++++++++++- qdf/linux/src/qdf_mem.c | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index 5a51929870..17833c6a22 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -125,6 +125,37 @@ bool qdf_mem_debug_config_get(void); QDF_STATUS qdf_mem_debug_disabled_config_set(const char *str_value); #endif +/** + * qdf_mem_malloc_atomic_debug() - debug version of QDF memory allocation API + * @size: Number of bytes of memory to allocate. + * @func: Function name of the call site + * @line: Line number of the call site + * @caller: Address of the caller function + * + * This function will dynamicallly allocate the specified number of bytes of + * memory and add it to the qdf tracking list to check for memory leaks and + * corruptions + * + * Return: A valid memory location on success, or NULL on failure + */ +void *qdf_mem_malloc_atomic_debug(size_t size, const char *func, + uint32_t line, void *caller); + +/** + * qdf_mem_malloc_atomic_debug_fl() - allocation QDF memory atomically + * @size: Number of bytes of memory to allocate. + * + * This function will dynamicallly allocate the specified number of bytes of + * memory. + * + * Return: + * Upon successful allocate, returns a non-NULL pointer to the allocated + * memory. If this function is unable to allocate the amount of memory + * specified (for any reason) it returns NULL. + */ +void *qdf_mem_malloc_atomic_debug_fl(qdf_size_t size, const char *func, + uint32_t line); + /** * qdf_mem_malloc_debug() - debug version of QDF memory allocation API * @size: Number of bytes of memory to allocate. @@ -149,7 +180,8 @@ void *qdf_mem_malloc_debug(size_t size, const char *func, uint32_t line, qdf_mem_malloc_debug(size, func, line, QDF_RET_IP, 0) #define qdf_mem_malloc_atomic(size) \ - qdf_mem_malloc_debug(size, __func__, __LINE__, QDF_RET_IP, GFP_ATOMIC) + qdf_mem_malloc_atomic_debug(size, __func__, __LINE__, QDF_RET_IP) + /** * qdf_mem_free_debug() - debug version of qdf_mem_free * @ptr: Pointer to the starting address of the memory to be freed. diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c index 2e5637a5c3..2fff247d04 100644 --- a/qdf/linux/src/qdf_mem.c +++ b/qdf/linux/src/qdf_mem.c @@ -1622,6 +1622,87 @@ void *qdf_mem_malloc_debug(size_t size, const char *func, uint32_t line, } qdf_export_symbol(qdf_mem_malloc_debug); +void *qdf_mem_malloc_atomic_debug(size_t size, const char *func, + uint32_t line, void *caller) +{ + QDF_STATUS status; + enum qdf_debug_domain current_domain = qdf_debug_domain_get(); + qdf_list_t *mem_list = qdf_mem_list_get(current_domain); + struct qdf_mem_header *header; + void *ptr; + unsigned long start, duration; + + if (is_initial_mem_debug_disabled) + return qdf_mem_malloc_atomic_debug_fl(size, func, line); + + if (!size || size > QDF_MEM_MAX_MALLOC) { + qdf_err("Cannot malloc %zu bytes @ %s:%d", size, func, line); + return NULL; + } + + ptr = qdf_mem_prealloc_get(size); + if (ptr) + return ptr; + + start = qdf_mc_timer_get_system_time(); + header = kzalloc(size + QDF_MEM_DEBUG_SIZE, GFP_ATOMIC); + duration = qdf_mc_timer_get_system_time() - start; + + if (duration > QDF_MEM_WARN_THRESHOLD) + qdf_warn("Malloc slept; %lums, %zuB @ %s:%d", + duration, size, func, line); + + if (!header) { + qdf_warn("Failed to malloc %zuB @ %s:%d", size, func, line); + return NULL; + } + + qdf_mem_header_init(header, size, func, line, caller); + qdf_mem_trailer_init(header); + ptr = qdf_mem_get_ptr(header); + + qdf_spin_lock_irqsave(&qdf_mem_list_lock); + status = qdf_list_insert_front(mem_list, &header->node); + qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); + if (QDF_IS_STATUS_ERROR(status)) + qdf_err("Failed to insert memory header; status %d", status); + + qdf_mem_kmalloc_inc(ksize(header)); + + return ptr; +} + +qdf_export_symbol(qdf_mem_malloc_atomic_debug); + +void *qdf_mem_malloc_atomic_debug_fl(size_t size, const char *func, + uint32_t line) +{ + void *ptr; + + if (!size || size > QDF_MEM_MAX_MALLOC) { + qdf_nofl_err("Cannot malloc %zu bytes @ %s:%d", size, func, + line); + return NULL; + } + + ptr = qdf_mem_prealloc_get(size); + if (ptr) + return ptr; + + ptr = kzalloc(size, GFP_ATOMIC); + if (!ptr) { + qdf_nofl_warn("Failed to malloc %zuB @ %s:%d", + size, func, line); + return NULL; + } + + qdf_mem_kmalloc_inc(ksize(ptr)); + + return ptr; +} + +qdf_export_symbol(qdf_mem_malloc_atomic_debug_fl); + void qdf_mem_free_debug(void *ptr, const char *func, uint32_t line) { enum qdf_debug_domain current_domain = qdf_debug_domain_get();