Browse Source

qcacld-3.0: Fix kernel panic during driver load failure

In low memory conditions TX/RX histogram memory allocation failure
is not handled properly and because of it 2 kernel panics are observed.
1st kernel panic is caused when freed HDD context is de-referenced in
hdd_wlan_startup and 2nd kernel panic is caused by kernel wake lock
list corruption because WLAN driver during load failure corrupted kernel's
wake lock list.

As part of this fix make sure TX/RX histogram memory allocation failure
is handled gracefully by properly sending failure reason code to
hdd_wlan_startup.

Also in order to make fix complete and avoid any other kernel panic, deinit
HDD context properly by freeing all HDD created wake locks such that when
HDD context is freed its wake locks are not poisoned to 0x6b6b6b6b6b6b6b6b
(SLUB magic pattern) pattern by kernel and hence corrupting kernel wake lock
list.

This fix ensures driver load failure caused by TX/RX histogram allocation
failure is handled gracefully in low memory conditions without leading to
any kernel panic.

Change-Id: I17a46c346402642f39e6548cd40bedd1f7ff96a4
CRs-Fixed: 1069014
Rajeev Kumar 8 years ago
parent
commit
fb02a5e3ed
2 changed files with 37 additions and 5 deletions
  1. 0 1
      core/hdd/inc/wlan_hdd_main.h
  2. 37 4
      core/hdd/src/wlan_hdd_main.c

+ 0 - 1
core/hdd/inc/wlan_hdd_main.h

@@ -1676,7 +1676,6 @@ void wlan_hdd_txrx_pause_cb(uint8_t vdev_id,
 	enum netif_action_type action, enum netif_reason_type reason);
 
 void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value);
-int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx);
 void wlan_hdd_deinit_tx_rx_histogram(hdd_context_t *hdd_ctx);
 void wlan_hdd_display_tx_rx_histogram(hdd_context_t *pHddCtx);
 void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *pHddCtx);

+ 37 - 4
core/hdd/src/wlan_hdd_main.c

@@ -5263,7 +5263,7 @@ static void hdd_bus_bw_compute_cbk(void *priv)
  *
  * Return: 0 for success or error code
  */
-int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx)
+static int wlan_hdd_init_tx_rx_histogram(hdd_context_t *hdd_ctx)
 {
 	hdd_ctx->hdd_txrx_hist = qdf_mem_malloc(
 		(sizeof(struct hdd_tx_rx_histogram) * NUM_TX_RX_HISTOGRAM));
@@ -6129,6 +6129,36 @@ static void hdd_set_trace_level_for_each(hdd_context_t *hdd_ctx)
 	hdd_cfg_print(hdd_ctx);
 }
 
+/**
+ * hdd_context_deinit() - Deinitialize HDD context
+ * @hdd_ctx:    HDD context.
+ *
+ * Deinitialize HDD context along with all the feature specific contexts but
+ * do not free hdd context itself. Caller of this API is supposed to free
+ * HDD context.
+ *
+ * return: 0 on success and errno on failure.
+ */
+static int hdd_context_deinit(hdd_context_t *hdd_ctx)
+{
+	wlan_hdd_cfg80211_deinit(hdd_ctx->wiphy);
+
+	hdd_roc_context_destroy(hdd_ctx);
+
+	hdd_sap_context_destroy(hdd_ctx);
+
+	hdd_rx_wake_lock_destroy(hdd_ctx);
+
+	hdd_tdls_context_destroy(hdd_ctx);
+
+	hdd_scan_context_destroy(hdd_ctx);
+
+	qdf_list_destroy(&hdd_ctx->hddAdapters);
+
+	return 0;
+}
+
+
 /**
  * hdd_context_init() - Initialize HDD context
  * @hdd_ctx:	HDD context.
@@ -6286,9 +6316,9 @@ hdd_context_t *hdd_context_create(struct device *dev)
 
 	cds_set_multicast_logging(hdd_ctx->config->multicast_host_fw_msgs);
 
-	status = wlan_hdd_init_tx_rx_histogram(hdd_ctx);
-	if (status)
-		goto err_free_config;
+	ret = wlan_hdd_init_tx_rx_histogram(hdd_ctx);
+	if (ret)
+		goto err_deinit_hdd_context;
 
 	ret = hdd_logging_sock_activate_svc(hdd_ctx);
 	if (ret)
@@ -6311,6 +6341,9 @@ skip_multicast_logging:
 err_free_histogram:
 	wlan_hdd_deinit_tx_rx_histogram(hdd_ctx);
 
+err_deinit_hdd_context:
+	hdd_context_deinit(hdd_ctx);
+
 err_free_config:
 	qdf_mem_free(hdd_ctx->config);