Browse Source

qcacmn: Add objmgr check for peer leaks API

During objmgr psoc teardown, it would be useful to assert that there are
no longer any peers attached. Add an API that logs a list of all
peers attached to a given psoc, and panics if any are found.

Change-Id: I30deeba87c5575a17e0b6e3a2a1840e5cfb3f1bf
CRs-Fixed: 2285139
Dustin Brown 6 years ago
parent
commit
a0e0bbc6b7

+ 8 - 0
umac/cmn_services/obj_mgr/inc/wlan_objmgr_psoc_obj.h

@@ -1452,6 +1452,14 @@ void wlan_objmgr_psoc_check_for_pdev_leaks(struct wlan_objmgr_psoc *psoc);
  */
 void wlan_objmgr_psoc_check_for_vdev_leaks(struct wlan_objmgr_psoc *psoc);
 
+/**
+ * wlan_objmgr_psoc_check_for_peer_leaks() - Assert no peers attached to @psoc
+ * @psoc: The psoc to check
+ *
+ * Return: None
+ */
+void wlan_objmgr_psoc_check_for_peer_leaks(struct wlan_objmgr_psoc *psoc);
+
 /**
 * wlan_objmgr_psoc_get_dual_mac_disable () - get user config
 * data for DBS disable

+ 76 - 30
umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj.c

@@ -31,6 +31,7 @@
 #include "wlan_objmgr_global_obj_i.h"
 #include "wlan_objmgr_psoc_obj_i.h"
 #include "wlan_objmgr_pdev_obj_i.h"
+#include "wlan_objmgr_vdev_obj_i.h"
 
 /**
  ** APIs to Create/Delete Global object APIs
@@ -2010,8 +2011,9 @@ QDF_STATUS wlan_objmgr_psoc_set_user_config(struct wlan_objmgr_psoc *psoc,
 void wlan_objmgr_psoc_check_for_pdev_leaks(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_objmgr_psoc_objmgr *_psoc;
+	struct wlan_objmgr_pdev *pdev;
 	int pdev_id;
-	int ref_id;
+	uint32_t leaks = 0;
 
 	QDF_BUG(psoc);
 	if (!psoc)
@@ -2029,38 +2031,34 @@ void wlan_objmgr_psoc_check_for_pdev_leaks(struct wlan_objmgr_psoc *psoc)
 	obj_mgr_err("Pdev Id   Refs   Module");
 	obj_mgr_err("--------------------------------------------------------");
 
-	for (pdev_id = 0; pdev_id < WLAN_UMAC_MAX_PDEVS; pdev_id++) {
-		struct wlan_objmgr_pdev *pdev = _psoc->wlan_pdev_list[pdev_id];
+	wlan_objmgr_for_each_psoc_pdev(psoc, pdev_id, pdev) {
 		qdf_atomic_t *ref_id_dbg;
-
-		if (!pdev)
-			continue;
+		int ref_id;
+		int32_t refs;
 
 		wlan_pdev_obj_lock(pdev);
 		ref_id_dbg = pdev->pdev_objmgr.ref_id_dbg;
-		for (ref_id = 0; ref_id < WLAN_REF_ID_MAX; ref_id++) {
-			int32_t refs = qdf_atomic_read(&ref_id_dbg[ref_id]);
-
-			if (refs <= 0)
-				continue;
-
-			obj_mgr_err("%7u   %4u x %s",
+		wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) {
+			leaks++;
+			obj_mgr_err("%7u   %4u   %s",
 				    pdev_id, refs, string_from_dbgid(ref_id));
 		}
 		wlan_pdev_obj_unlock(pdev);
 	}
 
-	wlan_psoc_obj_unlock(psoc);
+	QDF_DEBUG_PANIC("%u objmgr pdev leaks detected for psoc %u!",
+			leaks, _psoc->psoc_id);
 
-	QDF_DEBUG_PANIC();
+	wlan_psoc_obj_unlock(psoc);
 }
 qdf_export_symbol(wlan_objmgr_psoc_check_for_pdev_leaks);
 
 void wlan_objmgr_psoc_check_for_vdev_leaks(struct wlan_objmgr_psoc *psoc)
 {
 	struct wlan_objmgr_psoc_objmgr *_psoc;
+	struct wlan_objmgr_vdev *vdev;
 	int vdev_id;
-	int ref_id;
+	uint32_t leaks = 0;
 
 	QDF_BUG(psoc);
 	if (!psoc)
@@ -2078,30 +2076,78 @@ void wlan_objmgr_psoc_check_for_vdev_leaks(struct wlan_objmgr_psoc *psoc)
 	obj_mgr_err("Vdev Id   Refs   Module");
 	obj_mgr_err("--------------------------------------------------------");
 
-	for (vdev_id = 0; vdev_id < _psoc->max_vdev_count; vdev_id++) {
-		struct wlan_objmgr_vdev *vdev = _psoc->wlan_vdev_list[vdev_id];
+	wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) {
 		qdf_atomic_t *ref_id_dbg;
-
-		if (!vdev)
-			continue;
+		int ref_id;
+		int32_t refs;
 
 		wlan_vdev_obj_lock(vdev);
 		ref_id_dbg = vdev->vdev_objmgr.ref_id_dbg;
-		for (ref_id = 0; ref_id < WLAN_REF_ID_MAX; ref_id++) {
-			int32_t refs = qdf_atomic_read(&ref_id_dbg[ref_id]);
-
-			if (refs <= 0)
-				continue;
-
-			obj_mgr_err("%7u   %4u x %s",
+		wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) {
+			leaks++;
+			obj_mgr_err("%7u   %4u   %s",
 				    vdev_id, refs, string_from_dbgid(ref_id));
 		}
 		wlan_vdev_obj_unlock(vdev);
 	}
 
-	wlan_psoc_obj_unlock(psoc);
+	QDF_DEBUG_PANIC("%u objmgr vdev leaks detected for psoc %u!",
+			leaks, _psoc->psoc_id);
 
-	QDF_DEBUG_PANIC();
+	wlan_psoc_obj_unlock(psoc);
 }
 qdf_export_symbol(wlan_objmgr_psoc_check_for_vdev_leaks);
 
+void wlan_objmgr_psoc_check_for_peer_leaks(struct wlan_objmgr_psoc *psoc)
+{
+	struct wlan_objmgr_psoc_objmgr *_psoc;
+	struct wlan_objmgr_vdev *vdev;
+	int vdev_id;
+	uint32_t leaks = 0;
+
+	QDF_BUG(psoc);
+	if (!psoc)
+		return;
+
+	wlan_psoc_obj_lock(psoc);
+	_psoc = &psoc->soc_objmgr;
+	if (!_psoc->temp_peer_count && !_psoc->wlan_peer_count) {
+		wlan_psoc_obj_unlock(psoc);
+		return;
+	}
+
+	obj_mgr_err("objmgr peer leaks detected for psoc %u!", _psoc->psoc_id);
+	obj_mgr_err("--------------------------------------------------------");
+	obj_mgr_err("Peer MAC          Vdev Id   Refs   Module");
+	obj_mgr_err("--------------------------------------------------------");
+
+	wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) {
+		struct wlan_objmgr_peer *peer;
+
+		wlan_vdev_obj_lock(vdev);
+		wlan_objmgr_for_each_vdev_peer(vdev, peer) {
+			qdf_atomic_t *ref_id_dbg;
+			int ref_id;
+			int32_t refs;
+
+			wlan_peer_obj_lock(peer);
+			ref_id_dbg = peer->peer_objmgr.ref_id_dbg;
+			wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) {
+				leaks++;
+				obj_mgr_err(QDF_MAC_ADDR_STR " %7u   %4u   %s",
+					    QDF_MAC_ADDR_ARRAY(peer->macaddr),
+					    vdev_id,
+					    refs,
+					    string_from_dbgid(ref_id));
+			}
+			wlan_peer_obj_unlock(peer);
+		}
+		wlan_vdev_obj_unlock(vdev);
+	}
+
+	QDF_DEBUG_PANIC("%u objmgr peer leaks detected for psoc %u!",
+			leaks, _psoc->psoc_id);
+
+	wlan_psoc_obj_unlock(psoc);
+}
+qdf_export_symbol(wlan_objmgr_psoc_check_for_peer_leaks);

+ 40 - 1
umac/cmn_services/obj_mgr/src/wlan_objmgr_psoc_obj_i.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -21,6 +21,45 @@
 #ifndef _WLAN_OBJMGR_PSOC_OBJ_I_H_
 #define _WLAN_OBJMGR_PSOC_OBJ_I_H_
 
+/**
+ * wlan_objmgr_for_each_psoc_pdev() - iterate over each pdev for @psoc
+ * @psoc: the psoc whose pdevs should be iterated
+ * @pdev_id: pdev Id index cursor
+ * @pdev: pdev object cursor
+ *
+ * Note: The caller is responsible for grabbing @psoc's object lock before
+ * using this iterator
+ */
+#define wlan_objmgr_for_each_psoc_pdev(psoc, pdev_id, pdev) \
+	for (pdev_id = 0; pdev_id < WLAN_UMAC_MAX_PDEVS; pdev_id++) \
+		if ((pdev = (psoc)->soc_objmgr.wlan_pdev_list[pdev_id]))
+
+/**
+ * wlan_objmgr_for_each_psoc_vdev() - iterate over each vdev for @psoc
+ * @psoc: the psoc whose vdevs should be iterated
+ * @vdev_id: vdev Id index cursor
+ * @vdev: vdev object cursor
+ *
+ * Note: The caller is responsible for grabbing @psoc's object lock before
+ * using this iterator
+ */
+#define wlan_objmgr_for_each_psoc_vdev(psoc, vdev_id, vdev) \
+	for (vdev_id = 0; vdev_id < WLAN_UMAC_PSOC_MAX_VDEVS; vdev_id++) \
+		if ((vdev = (psoc)->soc_objmgr.wlan_vdev_list[vdev_id]))
+
+/**
+ * wlan_objmgr_for_each_refs() - iterate non-zero ref counts in @ref_id_dbg
+ * @ref_id_dbg: the ref count array to iterate
+ * @ref_id: the reference Id index cursor
+ * @refs: the ref count cursor
+ *
+ * Note: The caller is responsible for grabbing @ref_id_dbg's parent object lock
+ * before using this iterator
+ */
+#define wlan_objmgr_for_each_refs(ref_id_dbg, ref_id, refs) \
+	for (ref_id = 0; ref_id < WLAN_REF_ID_MAX; ref_id++) \
+		if ((refs = qdf_atomic_read(&(ref_id_dbg)[ref_id])) > 0)
+
 /**
  * wlan_objmgr_psoc_pdev_attach() - store pdev in psoc's pdev list
  * @psoc - PSOC object

+ 12 - 1
umac/cmn_services/obj_mgr/src/wlan_objmgr_vdev_obj_i.h

@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016,2018 The Linux Foundation. All rights reserved.
  *
  * Permission to use, copy, modify, and/or distribute this software for
  * any purpose with or without fee is hereby granted, provided that the
@@ -21,6 +21,17 @@
 #ifndef _WLAN_OBJMGR_VDEV_OBJ_I_H_
 #define _WLAN_OBJMGR_VDEV_OBJ_I_H_
 
+/**
+ * wlan_objmgr_for_each_vdev_peer() - iterate over each peer for @vdev
+ * @vdev: the vdev whose peers should be iterated
+ * @peer: peer object cursor
+ *
+ * Note: The caller is responsible for grabbing @vdev's object lock before
+ * using this iterator
+ */
+#define wlan_objmgr_for_each_vdev_peer(vdev, peer) \
+	qdf_list_for_each(&(vdev)->vdev_objmgr.wlan_peer_list, peer, vdev_peer)
+
 /**
  * wlan_objmgr_vdev_peer_attach() - attach peer to vdev peer list
  * @vdev: VDEV object