summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDustin Brown <dustinb@codeaurora.org>2017-11-01 11:58:42 -0700
committerDustin Brown <dustinb@codeaurora.org>2017-11-03 10:45:52 -0700
commit2906fc343c1beda4c4aaa49ccc9cdc4a677b0d0d (patch)
tree4a8bc2429e4b509cc41f1f0f47c5170ce739082b
parentadb6434a136216a246931453645ad741b997f207 (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.h41
-rw-r--r--qdf/linux/src/qdf_mem.c521
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