Эх сурвалжийг харах

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
Devender kumar 3 жил өмнө
parent
commit
412a969aeb

+ 33 - 1
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.

+ 81 - 0
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();