diff options
| author | Dustin Brown <dustinb@codeaurora.org> | 2017-11-01 11:58:42 -0700 |
|---|---|---|
| committer | Dustin Brown <dustinb@codeaurora.org> | 2017-11-03 10:45:52 -0700 |
| commit | 2906fc343c1beda4c4aaa49ccc9cdc4a677b0d0d (patch) | |
| tree | 4a8bc2429e4b509cc41f1f0f47c5170ce739082b | |
| parent | adb6434a136216a246931453645ad741b997f207 (diff) | |
qcacmn: Extract memory debugging features from qdf_mem
When memory debugging is enabled, qdf_mem_malloc and qdf_mem_free do a
number of memory corruption checks. Extract these checks into their own
functions to allow other memory allocation/free logic to leverage the
same logic.
Change-Id: I07802093119c90b3d8c40a50d5b4bb152cb8243f
CRs-Fixed: 2136659
| -rw-r--r-- | qdf/inc/qdf_mem.h | 41 | ||||
| -rw-r--r-- | qdf/linux/src/qdf_mem.c | 521 |
2 files changed, 298 insertions, 264 deletions
diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index a8eec4574e1f..e05af7634bce 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -126,9 +126,33 @@ void qdf_mem_set_domain(enum qdf_mem_domain domain); const uint8_t *qdf_mem_domain_name(enum qdf_mem_domain domain); #ifdef MEMORY_DEBUG +/** + * qdf_mem_malloc_debug() - debug version of QDF memory allocation API + * @size: Number of bytes of memory to allocate. + * @file: File name of the call site + * @line: Line number of the call site + * + * 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_debug(size_t size, const char *file, uint32_t line); + #define qdf_mem_malloc(size) \ qdf_mem_malloc_debug(size, __FILE__, __LINE__) -void *qdf_mem_malloc_debug(size_t size, char *file_name, uint32_t line_num); + +/** + * qdf_mem_free_debug() - debug version of qdf_mem_free + * @ptr: Pointer to the starting address of the memory to be freed. + * + * Return: None + */ +void qdf_mem_free_debug(void *ptr, const char *file, uint32_t line); + +#define qdf_mem_free(ptr) \ + qdf_mem_free_debug(ptr, __FILE__, __LINE__) /** * qdf_mem_check_for_leaks() - Assert that the current memory domain is empty @@ -164,20 +188,19 @@ void qdf_mem_check_for_leaks(void); #else void *qdf_mem_malloc(qdf_size_t size); -static inline void qdf_mem_check_for_leaks(void) { } -#endif /* MEMORY_DEBUG */ - -void *qdf_mem_alloc_outline(qdf_device_t osdev, qdf_size_t size); - /** * qdf_mem_free() - free QDF memory * @ptr: Pointer to the starting address of the memory to be free'd. - * This function will free the memory pointed to by 'ptr'. - * Return: - * None + * + * Return: None */ void qdf_mem_free(void *ptr); +static inline void qdf_mem_check_for_leaks(void) { } +#endif /* MEMORY_DEBUG */ + +void *qdf_mem_alloc_outline(qdf_device_t osdev, qdf_size_t size); + void qdf_mem_set(void *ptr, uint32_t num_bytes, uint32_t value); void qdf_mem_zero(void *ptr, uint32_t num_bytes); diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c index 34e0829c4c0a..f4d59a9c15de 100644 --- a/qdf/linux/src/qdf_mem.c +++ b/qdf/linux/src/qdf_mem.c @@ -56,6 +56,10 @@ #include <net/cnss_prealloc.h> #endif +/* Preprocessor Definitions and Constants */ +#define QDF_MEM_MAX_MALLOC (1024 * 1024) /* 1MiB */ +#define QDF_MEM_WARN_THRESHOLD 300 /* ms */ + static enum qdf_mem_domain qdf_mem_current_domain = QDF_MEM_DOMAIN_INIT; enum qdf_mem_domain qdf_mem_get_domain(void) @@ -95,7 +99,15 @@ static qdf_list_t qdf_mem_domains[QDF_MEM_DOMAIN_MAX_COUNT]; static qdf_spinlock_t qdf_mem_list_lock; static uint64_t WLAN_MEM_HEADER = 0x6162636465666768; -static uint64_t WLAN_MEM_TAIL = 0x8081828384858687; +static uint64_t WLAN_MEM_TRAILER = 0x8081828384858687; + +static inline qdf_list_t *qdf_mem_list(enum qdf_mem_domain domain) +{ + if (domain < QDF_MEM_DOMAIN_INIT || domain >= QDF_MEM_DOMAIN_MAX_COUNT) + return NULL; + + return &qdf_mem_domains[domain]; +} static inline qdf_list_t *qdf_mem_active_list(void) { @@ -103,26 +115,172 @@ static inline qdf_list_t *qdf_mem_active_list(void) } /** - * struct s_qdf_mem_struct - memory object to dubug - * @node: node to the list - * @filename: name of file - * @line_num: line number - * @size: size of the file - * @header: array that contains header - * @in_use: memory usage count + * struct qdf_mem_header - memory object to dubug + * @node: node to the list + * @domain: the active memory domain at time of allocation + * @freed: flag set during free, used to detect double frees + * Use uint8_t so we can detect corruption + * @file: name of the file the allocation was made from + * @line: line number of the file the allocation was made from + * @size: size of the allocation in bytes + * @header: a known value, used to detect out-of-bounds access */ -struct s_qdf_mem_struct { +struct qdf_mem_header { qdf_list_node_t node; - char *file_name; - uint32_t line_num; + enum qdf_mem_domain domain; + uint8_t freed; + const char *file; + uint32_t line; uint32_t size; uint64_t header; - enum qdf_mem_domain domain; }; -#endif /* MEMORY_DEBUG */ -/* Preprocessor Definitions and Constants */ -#define QDF_GET_MEMORY_TIME_THRESHOLD 300 +static inline struct qdf_mem_header *qdf_mem_get_header(void *ptr) +{ + return (struct qdf_mem_header *)ptr - 1; +} + +static inline uint64_t *qdf_mem_get_trailer(struct qdf_mem_header *header) +{ + return (uint64_t *)((void *)(header + 1) + header->size); +} + +static inline void *qdf_mem_get_ptr(struct qdf_mem_header *header) +{ + return (void *)(header + 1); +} + +/* number of bytes needed for the qdf memory debug information */ +#define QDF_MEM_DEBUG_SIZE \ + (sizeof(struct qdf_mem_header) + sizeof(WLAN_MEM_TRAILER)) + +static void qdf_mem_header_init(struct qdf_mem_header *header, qdf_size_t size, + const char *file, uint32_t line) +{ + QDF_BUG(header); + if (!header) + return; + + header->domain = qdf_mem_get_domain(); + header->freed = false; + header->file = file; + header->line = line; + header->size = size; + header->header = WLAN_MEM_HEADER; + *qdf_mem_get_trailer(header) = WLAN_MEM_TRAILER; +} + +enum qdf_mem_validation_bitmap { + QDF_MEM_BAD_HEADER = 1 << 0, + QDF_MEM_BAD_TRAILER = 1 << 1, + QDF_MEM_BAD_SIZE = 1 << 2, + QDF_MEM_DOUBLE_FREE = 1 << 3, + QDF_MEM_BAD_FREED = 1 << 4, + QDF_MEM_BAD_NODE = 1 << 5, + QDF_MEM_BAD_DOMAIN = 1 << 6, + QDF_MEM_WRONG_DOMAIN = 1 << 7, +}; + +/** + * qdf_mem_validate_list_node() - validate that the node is in a list + * @qdf_node: node to check for being in a list + * + * Return: true if the node validly linked in an anchored doubly linked list + */ +static bool qdf_mem_validate_list_node(qdf_list_node_t *qdf_node) +{ + struct list_head *node = qdf_node; + + /* + * if the node is an empty list, it is not tied to an anchor node + * and must have been removed with list_del_init + */ + if (list_empty(node)) + return false; + + if (!node->prev || !node->next) + return false; + + if (node->prev->next != node || node->next->prev != node) + return false; + + return true; +} + +static enum qdf_mem_validation_bitmap +qdf_mem_header_validate(struct qdf_mem_header *header, + enum qdf_mem_domain domain) +{ + enum qdf_mem_validation_bitmap error_bitmap = 0; + + if (header->header != WLAN_MEM_HEADER) + error_bitmap |= QDF_MEM_BAD_HEADER; + + if (header->size > QDF_MEM_MAX_MALLOC) + error_bitmap |= QDF_MEM_BAD_SIZE; + else if (*qdf_mem_get_trailer(header) != WLAN_MEM_TRAILER) + error_bitmap |= QDF_MEM_BAD_TRAILER; + + if (header->freed == true) + error_bitmap |= QDF_MEM_DOUBLE_FREE; + else if (header->freed) + error_bitmap |= QDF_MEM_BAD_FREED; + + if (!qdf_mem_validate_list_node(&header->node)) + error_bitmap |= QDF_MEM_BAD_NODE; + + if (header->domain < QDF_MEM_DOMAIN_INIT || + header->domain >= QDF_MEM_DOMAIN_MAX_COUNT) + error_bitmap |= QDF_MEM_BAD_DOMAIN; + else if (header->domain != domain) + error_bitmap |= QDF_MEM_WRONG_DOMAIN; + + return error_bitmap; +} + +static void +qdf_mem_header_assert_valid(struct qdf_mem_header *header, + enum qdf_mem_domain current_domain, + enum qdf_mem_validation_bitmap error_bitmap, + const char *file, + uint32_t line) +{ + if (!error_bitmap) + return; + + if (error_bitmap & QDF_MEM_BAD_HEADER) + qdf_err("Corrupted memory header 0x%llx (expected 0x%llx)", + header->header, WLAN_MEM_HEADER); + + if (error_bitmap & QDF_MEM_BAD_SIZE) + qdf_err("Corrupted memory size %u (expected < %d)", + header->size, QDF_MEM_MAX_MALLOC); + + if (error_bitmap & QDF_MEM_BAD_TRAILER) + qdf_err("Corrupted memory trailer 0x%llx (expected 0x%llx)", + *qdf_mem_get_trailer(header), WLAN_MEM_TRAILER); + + if (error_bitmap & QDF_MEM_DOUBLE_FREE) + qdf_err("Memory has previously been freed"); + + if (error_bitmap & QDF_MEM_BAD_FREED) + qdf_err("Corrupted memory freed flag 0x%x", header->freed); + + if (error_bitmap & QDF_MEM_BAD_NODE) + qdf_err("Corrupted memory header node or double free"); + + if (error_bitmap & QDF_MEM_BAD_DOMAIN) + qdf_err("Corrupted memory domain 0x%x", header->domain); + + if (error_bitmap & QDF_MEM_WRONG_DOMAIN) + qdf_err("Memory domain mismatch; found %s(%d), expected %s(%d)", + qdf_mem_domain_name(header->domain), header->domain, + qdf_mem_domain_name(current_domain), current_domain); + + panic("A fatal memory error was detected @ %s:%d", + kbasename(file), line); +} +#endif /* MEMORY_DEBUG */ int qdf_dbg_mask; qdf_declare_param(qdf_dbg_mask, int); @@ -206,15 +364,15 @@ static int seq_printf_printer(void *priv, const char *fmt, ...) /** * struct __qdf_mem_info - memory statistics - * @file_name: the file which allocated memory - * @line_num: the line at which allocation happened - * @size: the size of allocation - * @count: how many allocations of same type + * @file: the file which allocated memory + * @line: the line at which allocation happened + * @size: the size of allocation + * @count: how many allocations of same type * */ struct __qdf_mem_info { - char *file_name; - uint32_t line_num; + const char *file; + uint32_t line; uint32_t size; uint32_t count; }; @@ -265,8 +423,8 @@ static void qdf_mem_meta_table_print(struct __qdf_mem_info *table, table[i].count, table[i].size, table[i].count * table[i].size, - kbasename(table[i].file_name), - table[i].line_num); + kbasename(table[i].file), + table[i].line); } } @@ -278,21 +436,21 @@ static void qdf_mem_meta_table_print(struct __qdf_mem_info *table, * Return: true if the table is full after inserting, false otherwise */ static bool qdf_mem_meta_table_insert(struct __qdf_mem_info *table, - struct s_qdf_mem_struct *meta) + struct qdf_mem_header *meta) { int i; for (i = 0; i < QDF_MEM_STAT_TABLE_SIZE; i++) { if (!table[i].count) { - table[i].file_name = meta->file_name; - table[i].line_num = meta->line_num; + table[i].file = meta->file; + table[i].line = meta->line; table[i].size = meta->size; table[i].count = 1; break; } - if (table[i].file_name == meta->file_name && - table[i].line_num == meta->line_num && + if (table[i].file == meta->file && + table[i].line == meta->line && table[i].size == meta->size) { table[i].count++; break; @@ -326,7 +484,7 @@ static void qdf_mem_domain_print(qdf_list_t *domain, qdf_spin_lock(&qdf_mem_list_lock); status = qdf_list_peek_front(domain, &node); while (QDF_IS_STATUS_SUCCESS(status)) { - struct s_qdf_mem_struct *meta = (struct s_qdf_mem_struct *)node; + struct qdf_mem_header *meta = (struct qdf_mem_header *)node; bool is_full = qdf_mem_meta_table_insert(table, meta); qdf_spin_unlock(&qdf_mem_list_lock); @@ -768,16 +926,18 @@ qdf_export_symbol(qdf_mem_zero_outline); */ static void *qdf_mem_prealloc_get(size_t size) { - void *mem; + void *ptr; if (size <= WCNSS_PRE_ALLOC_GET_THRESHOLD) return NULL; - mem = wcnss_prealloc_get(size); - if (mem) - memset(mem, 0, size); + ptr = wcnss_prealloc_get(size); + if (!ptr) + return NULL; + + memset(ptr, 0, size); - return mem; + return ptr; } static inline bool qdf_mem_prealloc_put(void *ptr) @@ -796,6 +956,14 @@ static inline bool qdf_mem_prealloc_put(void *ptr) } #endif /* CONFIG_WCNSS_MEM_PRE_ALLOC */ +static int qdf_mem_malloc_flags(void) +{ + if (in_interrupt() || irqs_disabled() || in_atomic()) + return GFP_ATOMIC; + + return GFP_KERNEL; +} + /* External Function implementation */ #ifdef MEMORY_DEBUG @@ -900,124 +1068,51 @@ static void qdf_mem_debug_exit(void) qdf_spinlock_destroy(&qdf_mem_list_lock); } -/** - * qdf_mem_malloc_debug() - debug version of QDF memory allocation API - * @size: Number of bytes of memory to allocate. - * @file_name: File name from which memory allocation is called - * @line_num: Line number from which memory allocation is called - * - * This function will dynamicallly allocate the specified number of bytes of - * memory and ad it in qdf tracking list to check against memory leaks and - * corruptions - * - * 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_debug(size_t size, char *file_name, uint32_t line_num) +void *qdf_mem_malloc_debug(size_t size, const char *file, uint32_t line) { + QDF_STATUS status; qdf_list_t *mem_list = qdf_mem_active_list(); - struct s_qdf_mem_struct *mem_struct; - void *mem_ptr = NULL; - uint32_t new_size; - int flags = GFP_KERNEL; - unsigned long time_before_kzalloc; + struct qdf_mem_header *header; + void *ptr; + unsigned long start, duration; - if (size > (1024 * 1024) || size == 0) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, - "%s: called with invalid arg; passed in %zu !!!", - __func__, size); + if (!size || size > QDF_MEM_MAX_MALLOC) { + qdf_err("Cannot malloc %zu bytes @ %s:%d", size, file, line); return NULL; } - mem_ptr = qdf_mem_prealloc_get(size); - if (mem_ptr) - return mem_ptr; - - if (in_interrupt() || irqs_disabled() || in_atomic()) - flags = GFP_ATOMIC; - - new_size = sizeof(*mem_struct) + size + sizeof(WLAN_MEM_TAIL); - time_before_kzalloc = qdf_mc_timer_get_system_time(); - mem_struct = kzalloc(new_size, flags); - /** - * If time taken by kmalloc is greater than - * QDF_GET_MEMORY_TIME_THRESHOLD msec - */ - if (qdf_mc_timer_get_system_time() - time_before_kzalloc >= - QDF_GET_MEMORY_TIME_THRESHOLD) - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, - "%s: kzalloc took %lu msec for size %zu called from %p_s at line %d", - __func__, - qdf_mc_timer_get_system_time() - time_before_kzalloc, - size, (void *)_RET_IP_, line_num); - - if (mem_struct) { - QDF_STATUS status; - uint64_t *trailer; - - mem_ptr = (void *)(mem_struct + 1); - trailer = (uint64_t *)(mem_ptr + size); - - mem_struct->file_name = file_name; - mem_struct->line_num = line_num; - mem_struct->size = size; - mem_struct->domain = qdf_mem_current_domain; - mem_struct->header = WLAN_MEM_HEADER; - *trailer = WLAN_MEM_TAIL; - - qdf_mem_kmalloc_inc(ksize(mem_struct)); - - qdf_spin_lock_irqsave(&qdf_mem_list_lock); - status = qdf_list_insert_front(mem_list, &mem_struct->node); - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - if (QDF_IS_STATUS_ERROR(status)) - qdf_err("Unable to insert into list status %d", status); - } - - return mem_ptr; -} -qdf_export_symbol(qdf_mem_malloc_debug); + ptr = qdf_mem_prealloc_get(size); + if (ptr) + return ptr; -/** - * qdf_mem_validate_node_for_free() - validate that the node is in a list - * @qdf_node: node to check for being in a list - * - * qdf_node should be a non null value. - * - * Return: true if the node validly linked in an anchored doubly linked list - */ -static bool qdf_mem_validate_node_for_free(qdf_list_node_t *qdf_node) -{ - struct list_head *node = qdf_node; + start = qdf_mc_timer_get_system_time(); + header = kzalloc(size + QDF_MEM_DEBUG_SIZE, qdf_mem_malloc_flags()); + duration = qdf_mc_timer_get_system_time() - start; - /* - * if the node is an empty list, it is not tied to an anchor node - * and must have been removed with list_del_init - */ - if (list_empty(node)) - return false; + if (duration > QDF_MEM_WARN_THRESHOLD) + qdf_warn("Malloc slept; %lums, %zuB @ %s:%d", + duration, size, file, line); - if (node->prev == NULL) - return false; + if (!header) + return NULL; - if (node->next == NULL) - return false; + qdf_mem_header_init(header, size, file, line); + ptr = qdf_mem_get_ptr(header); - if (node->prev->next != node) - return false; + 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); - if (node->next->prev != node) - return false; + qdf_mem_kmalloc_inc(size); - return true; + return ptr; } - - +qdf_export_symbol(qdf_mem_malloc_debug); /** - * qdf_mem_free() - QDF memory free API + * qdf_mem_free_debug() - QDF memory free API * @ptr: Pointer to the starting address of the memory to be free'd. * * This function will free the memory pointed to by 'ptr'. It also checks @@ -1025,118 +1120,38 @@ static bool qdf_mem_validate_node_for_free(qdf_list_node_t *qdf_node) * * Return: none */ -void qdf_mem_free(void *ptr) +void qdf_mem_free_debug(void *ptr, const char *file, uint32_t line) { - qdf_list_t *mem_list = qdf_mem_active_list(); - struct s_qdf_mem_struct *mem_struct; - uint64_t *trailer; + enum qdf_mem_domain domain = qdf_mem_get_domain(); + struct qdf_mem_header *header; + enum qdf_mem_validation_bitmap error_bitmap; /* freeing a null pointer is valid */ - if (qdf_unlikely(ptr == NULL)) + if (qdf_unlikely(!ptr)) return; if (qdf_mem_prealloc_put(ptr)) return; - mem_struct = ((struct s_qdf_mem_struct *)ptr) - 1; - - if (qdf_unlikely(mem_struct == NULL)) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, - "%s: null mem_struct", __func__); - QDF_BUG(0); - } - - trailer = (uint64_t *)(ptr + mem_struct->size); + if (qdf_unlikely((qdf_size_t)ptr <= sizeof(*header))) + panic("Failed to free invalid memory location %pK", ptr); qdf_spin_lock_irqsave(&qdf_mem_list_lock); - - /* - * invalid memory access when checking the header/tailer - * would be a use after free and would indicate a double free - * or invalid pointer passed. - */ - if (mem_struct->header != WLAN_MEM_HEADER) - goto error; - - /* - * invalid memory access while checking validate node - * would indicate corruption in the nodes pointed to - */ - if (!qdf_mem_validate_node_for_free(&mem_struct->node)) - goto error; - - /* - * invalid memory access here is unlikely and would imply - * that the size value was corrupted/incorrect. - * It is unlikely that the above checks would pass in a - * double free case. - */ - if (*trailer != WLAN_MEM_TAIL) - goto error; - - /* make sure the memory belongs to the current domain */ - if (mem_struct->domain != qdf_mem_current_domain) { - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - qdf_err("Memory domain mismatch; found %s, expected %s (%s:%u)", - qdf_mem_domain_name(mem_struct->domain), - qdf_mem_domain_name(qdf_mem_current_domain), - kbasename(mem_struct->file_name), - mem_struct->line_num); - qdf_mem_leak_panic(); - - /* continue de-allocation if we didn't crash */ - qdf_spin_lock_irqsave(&qdf_mem_list_lock); + header = qdf_mem_get_header(ptr); + error_bitmap = qdf_mem_header_validate(header, domain); + if (!error_bitmap) { + header->freed = true; + list_del_init(&header->node); + qdf_mem_list(header->domain)->count--; } - - /* - * make the node an empty list before doing the spin unlock - * The empty list check will guarantee that we avoid a race condition. - */ - list_del_init(&mem_struct->node); - mem_list->count--; qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - qdf_mem_kmalloc_dec(ksize(mem_struct)); - kfree(mem_struct); - return; - -error: - if (!qdf_list_has_node(mem_list, &mem_struct->node)) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, - "%s: Unallocated memory (double free?)", - __func__); - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - QDF_BUG(0); - } - - if (mem_struct->header != WLAN_MEM_HEADER) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, - "Memory Header is corrupted."); - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - QDF_BUG(0); - } + qdf_mem_header_assert_valid(header, domain, error_bitmap, file, line); - if (!qdf_mem_validate_node_for_free(&mem_struct->node)) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, - "Memory_struct is corrupted."); - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - QDF_BUG(0); - } - - if (*trailer != WLAN_MEM_TAIL) { - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, - "Memory Trailer is corrupted. mem_info: Filename %s, line_num %d", - mem_struct->file_name, (int)mem_struct->line_num); - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - QDF_BUG(0); - } - - QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_FATAL, - "%s unexpected error", __func__); - qdf_spin_unlock_irqrestore(&qdf_mem_list_lock); - QDF_BUG(0); + qdf_mem_kmalloc_dec(header->size); + kfree(header); } -qdf_export_symbol(qdf_mem_free); +qdf_export_symbol(qdf_mem_free_debug); void qdf_mem_check_for_leaks(void) { @@ -1170,23 +1185,19 @@ static void qdf_mem_debug_exit(void) {} */ void *qdf_mem_malloc(size_t size) { - int flags = GFP_KERNEL; - void *mem; - - mem = qdf_mem_prealloc_get(size); - if (mem) - return mem; + void *ptr; - if (in_interrupt() || irqs_disabled()) - flags = GFP_ATOMIC; + ptr = qdf_mem_prealloc_get(size); + if (ptr) + return ptr; - mem = kzalloc(size, flags); - - if (mem) - qdf_mem_kmalloc_inc(ksize(mem)); + ptr = kzalloc(size, qdf_mem_malloc_flags()); + if (!ptr) + return NULL; - return mem; + qdf_mem_kmalloc_inc(ksize(ptr)); + return ptr; } qdf_export_symbol(qdf_mem_malloc); @@ -1497,18 +1508,18 @@ void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, void *qdf_mem_alloc_consistent(qdf_device_t osdev, void *dev, qdf_size_t size, qdf_dma_addr_t *phy_addr) { - int flags = GFP_KERNEL; - void *alloc_mem = NULL; + void *ptr; - if (in_interrupt() || irqs_disabled() || in_atomic()) - flags = GFP_ATOMIC; + ptr = dma_alloc_coherent(dev, size, phy_addr, qdf_mem_malloc_flags()); + if (!ptr) { + qdf_warn("Warning: unable to alloc consistent memory of size %zu!\n", + size); + return NULL; + } - alloc_mem = dma_alloc_coherent(dev, size, phy_addr, flags); - if (alloc_mem == NULL) - qdf_print("%s Warning: unable to alloc consistent memory of size %zu!\n", - __func__, size); qdf_mem_dma_inc(size); - return alloc_mem; + + return ptr; } #endif |
