From e16e606c956892bda991ffc50dedc85042ddd3ca Mon Sep 17 00:00:00 2001 From: Maharaja Kennadyrajan Date: Mon, 4 Jan 2021 23:47:57 +0530 Subject: [PATCH 2/2] ath11k/mac80211: Add support to account memory stats Memory allocations in the driver & mac80211 are logged and populate those values to the user space via debugfs. This stats will give the snapshot of the memory being used by the driver at the time of dumping these memory stats. Command: cat /sys/kernel/debug/ath11k/ipq8074\ hw2.0/memory_stats Sample output of the stats MEMORY STATS IN BYTES: malloc size : 6287583 ce_ring_alloc size: 109308 dma_alloc size:: 10831860 htc_skb_alloc size: 3840 wmi alloc size: 0 per peer object: 4644 rx_post_buf size: 5091840 Total size: 22329075 User can disable/enable the memory stats accounting with the below command. echo N > /sys/kernel/debug/ath11k/ipq8074\ hw2.0/enable_memory_stats where N = 0 to disable logging, 1 to enable the logging. Note: This should be enabled/disabled only after wifi is down. User shouldn't enable/disable when the wifi is up to avoid accounting the negative values which cause incorrect values in the memory stats. Command: cat /sys/kernel/debug/ieee80211/phyX/memory_stats memory stats: malloc_size: 108 Signed-off-by: Maharaja Kennadyrajan --- net/mac80211/chan.c | 12 ++++++++++++ net/mac80211/debugfs.c | 4 ++++ net/mac80211/ieee80211_i.h | 6 ++++++ net/mac80211/iface.c | 5 +++++ net/mac80211/mesh.c | 4 ++++ net/mac80211/mesh_hwmp.c | 5 +++++ net/mac80211/mesh_pathtbl.c | 12 ++++++++++++ net/mac80211/offchannel.c | 7 +++++++ net/mac80211/scan.c | 18 ++++++++++++++++++ net/mac80211/sta_info.c | 16 ++++++++++++++++ 10 files changed, 89 insertions(+) --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -517,6 +517,9 @@ ieee80211_alloc_chanctx(struct ieee80211 if (!ctx) return NULL; + atomic_add(sizeof(*ctx) + local->hw.chanctx_data_size, + &local->memory_stats.malloc_size); + INIT_LIST_HEAD(&ctx->assigned_vifs); INIT_LIST_HEAD(&ctx->reserved_vifs); ctx->conf.def = *chandef; @@ -577,6 +580,8 @@ ieee80211_new_chanctx(struct ieee80211_l err = ieee80211_add_chanctx(local, ctx); if (err) { + atomic_sub(sizeof(*ctx) + local->hw.chanctx_data_size, + &local->memory_stats.malloc_size); kfree(ctx); return ERR_PTR(err); } @@ -629,6 +634,8 @@ static void ieee80211_free_chanctx(struc list_del_rcu(&ctx->list); ieee80211_del_chanctx(local, ctx); + atomic_sub(sizeof(*ctx) + local->hw.chanctx_data_size, + &local->memory_stats.malloc_size); kfree_rcu(ctx, rcu_head); } @@ -1265,6 +1272,9 @@ static int ieee80211_chsw_switch_vifs(st if (!vif_chsw) return -ENOMEM; + atomic_add(sizeof(vif_chsw[0]) * n_vifs, + &local->memory_stats.malloc_size); + i = 0; list_for_each_entry(ctx, &local->chanctx_list, list) { if (ctx->replace_state != IEEE80211_CHANCTX_REPLACES_OTHER) @@ -1294,6 +1304,8 @@ static int ieee80211_chsw_switch_vifs(st CHANCTX_SWMODE_SWAP_CONTEXTS); out: + atomic_sub(sizeof(vif_chsw[0]) * n_vifs, + &local->memory_stats.malloc_size); kfree(vif_chsw); return err; } --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -71,6 +71,8 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x", local->wep_iv & 0xffffff); DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s", local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver"); +DEBUGFS_READONLY_FILE(memory_stats, "memory stats: malloc_size: %u", + atomic_read(&local->memory_stats.malloc_size)); static ssize_t aqm_read(struct file *file, char __user *user_buf, @@ -587,6 +589,8 @@ void debugfs_hw_add(struct ieee80211_loc if (!statsd) return; + DEBUGFS_ADD(memory_stats); + #ifdef CPTCFG_MAC80211_DEBUG_COUNTERS DEBUGFS_STATS_ADD(dot11TransmittedFragmentCount); DEBUGFS_STATS_ADD(dot11MulticastTransmittedFrameCount); --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1164,6 +1164,10 @@ enum mac80211_scan_state { SCAN_ABORT, }; +struct mac80211_memory_stats { + atomic_t malloc_size; +}; + struct ieee80211_local { /* embed the driver visible part. * don't cast (use the static inlines below), but we keep @@ -1451,6 +1455,8 @@ struct ieee80211_local { /* TDLS channel switch */ struct work_struct tdls_chsw_work; struct sk_buff_head skb_queue_tdls_chsw; + + struct mac80211_memory_stats memory_stats; }; static inline struct ieee80211_sub_if_data * --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1065,6 +1065,9 @@ int ieee80211_add_virtual_monitor(struct return ret; } + atomic_add(sizeof(*sdata) + local->hw.vif_data_size, + &local->memory_stats.malloc_size); + skb_queue_head_init(&sdata->skb_queue); INIT_WORK(&sdata->work, ieee80211_iface_work); @@ -1100,6 +1103,8 @@ void ieee80211_del_virtual_monitor(struc drv_remove_interface(local, sdata); + atomic_sub(sizeof(*sdata) + local->hw.vif_data_size, + &local->memory_stats.malloc_size); kfree(sdata); } --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -173,6 +173,8 @@ int mesh_rmc_init(struct ieee80211_sub_i sdata->u.mesh.rmc = kmalloc(sizeof(struct mesh_rmc), GFP_KERNEL); if (!sdata->u.mesh.rmc) return -ENOMEM; + atomic_add(sizeof(struct mesh_rmc), + &sdata->local->memory_stats.malloc_size); sdata->u.mesh.rmc->idx_mask = RMC_BUCKETS - 1; for (i = 0; i < RMC_BUCKETS; i++) INIT_HLIST_HEAD(&sdata->u.mesh.rmc->bucket[i]); @@ -196,6 +198,8 @@ void mesh_rmc_free(struct ieee80211_sub_ } } + atomic_sub(sizeof(struct mesh_rmc), + &sdata->local->memory_stats.malloc_size); kfree(rmc); sdata->u.mesh.rmc = NULL; } --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -997,6 +997,9 @@ static void mesh_queue_preq(struct mesh_ return; } + atomic_add(sizeof(struct mesh_preq_queue), + &sdata->local->memory_stats.malloc_size); + memcpy(preq_node->dst, mpath->dst, ETH_ALEN); preq_node->flags = flags; @@ -1111,6 +1114,8 @@ void mesh_path_start_discovery(struct ie enddiscovery: rcu_read_unlock(); + atomic_sub(sizeof(struct mesh_preq_queue), + &sdata->local->memory_stats.malloc_size); kfree(preq_node); } --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -764,6 +764,9 @@ int mesh_pathtbl_init(struct ieee80211_s struct mesh_table *tbl_path, *tbl_mpp; int ret; + atomic_add(sizeof(struct mesh_table), + &sdata->local->memory_stats.malloc_size); + tbl_path = mesh_table_alloc(); if (!tbl_path) return -ENOMEM; @@ -774,12 +777,17 @@ int mesh_pathtbl_init(struct ieee80211_s goto free_path; } + atomic_add(sizeof(struct mesh_table), + &sdata->local->memory_stats.malloc_size); + sdata->u.mesh.mesh_paths = tbl_path; sdata->u.mesh.mpp_paths = tbl_mpp; return 0; free_path: + atomic_sub(sizeof(struct mesh_table), + &sdata->local->memory_stats.malloc_size); mesh_table_free(tbl_path); return ret; } @@ -809,6 +817,10 @@ void mesh_path_expire(struct ieee80211_s void mesh_pathtbl_unregister(struct ieee80211_sub_if_data *sdata) { + atomic_sub(sizeof(struct mesh_table), + &sdata->local->memory_stats.malloc_size); + atomic_sub(sizeof(struct mesh_table), + &sdata->local->memory_stats.malloc_size); mesh_table_free(sdata->u.mesh.mesh_paths); mesh_table_free(sdata->u.mesh.mpp_paths); } --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -168,6 +168,7 @@ void ieee80211_offchannel_return(struct static void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) { + struct ieee80211_sub_if_data *sdata = roc->sdata; /* was never transmitted */ if (roc->frame) { cfg80211_mgmt_tx_status(&roc->sdata->wdev, roc->mgmt_tx_cookie, @@ -186,6 +187,8 @@ static void ieee80211_roc_notify_destroy roc->chan, GFP_KERNEL); list_del(&roc->list); + atomic_sub(sizeof(*roc), + &sdata->local->memory_stats.malloc_size); kfree(roc); } @@ -548,6 +551,8 @@ static int ieee80211_start_roc_work(stru if (!roc) return -ENOMEM; + atomic_add(sizeof(*roc), &local->memory_stats.malloc_size); + /* * If the duration is zero, then the driver * wouldn't actually do anything. Set it to @@ -593,6 +598,8 @@ static int ieee80211_start_roc_work(stru ret = drv_remain_on_channel(local, sdata, channel, duration, type); if (ret) { + atomic_sub(sizeof(*roc), + &local->memory_stats.malloc_size); kfree(roc); return ret; } --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -441,6 +441,12 @@ static void __ieee80211_scan_completed(s scan_req = rcu_dereference_protected(local->scan_req, lockdep_is_held(&local->mtx)); + atomic_sub(sizeof(*local->hw_scan_req) + + scan_req->n_channels * + sizeof(scan_req->channels[0]) + + local->hw_scan_ies_bufsize, + &local->memory_stats.malloc_size); + if (scan_req != local->int_scan_req) { local->scan_info.aborted = aborted; cfg80211_scan_done(scan_req, &local->scan_info); @@ -710,6 +716,12 @@ static int __ieee80211_start_scan(struct if (!local->hw_scan_req) return -ENOMEM; + atomic_add(sizeof(*local->hw_scan_req) + + req->n_channels * + sizeof(req->channels[0]) + + local->hw_scan_ies_bufsize, + &local->memory_stats.malloc_size); + local->hw_scan_req->req.chandef = req->chandef; local->hw_scan_req->req.ssids = req->ssids; local->hw_scan_req->req.n_ssids = req->n_ssids; @@ -799,6 +811,12 @@ static int __ieee80211_start_scan(struct } if (rc) { + atomic_sub(sizeof(*local->hw_scan_req) + + req->n_channels * + sizeof(req->channels[0]) + + local->hw_scan_ies_bufsize, + &local->memory_stats.malloc_size); + kfree(local->hw_scan_req); local->hw_scan_req = NULL; local->scanning = 0; --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -258,6 +258,7 @@ struct sta_info *sta_info_get_by_idx(str */ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { + struct ieee80211_hw *hw = &local->hw; /* * If we had used sta_info_pre_move_state() then we might not * have gone through the state transitions down again, so do @@ -285,8 +286,13 @@ void sta_info_free(struct ieee80211_loca kfree(to_txq_info(sta->sta.txq[0])); kfree(rcu_dereference_raw(sta->sta.rates)); #ifdef CPTCFG_MAC80211_MESH + if (sta->mesh) + atomic_sub(sizeof(*sta->mesh), + &local->memory_stats.malloc_size); kfree(sta->mesh); #endif + atomic_sub(sizeof(*sta) + hw->sta_data_size, + &local->memory_stats.malloc_size); free_percpu(sta->pcpu_rx_stats); kfree(sta); } @@ -345,6 +351,9 @@ struct sta_info *sta_info_alloc(struct i if (!sta) return NULL; + atomic_add(sizeof(*sta) + hw->sta_data_size, + &local->memory_stats.malloc_size); + if (ieee80211_hw_check(hw, USES_RSS)) { sta->pcpu_rx_stats = alloc_percpu_gfp(struct ieee80211_sta_rx_stats, gfp); @@ -362,6 +371,8 @@ struct sta_info *sta_info_alloc(struct i sta->mesh = kzalloc(sizeof(*sta->mesh), gfp); if (!sta->mesh) goto free; + atomic_add(sizeof(*sta->mesh), + &local->memory_stats.malloc_size); sta->mesh->plink_sta = sta; spin_lock_init(&sta->mesh->plink_lock); if (ieee80211_vif_is_mesh(&sdata->vif) && @@ -526,8 +537,12 @@ free_txq: free: free_percpu(sta->pcpu_rx_stats); #ifdef CPTCFG_MAC80211_MESH + atomic_sub(sizeof(*sta->mesh), + &local->memory_stats.malloc_size); kfree(sta->mesh); #endif + atomic_sub(sizeof(*sta) + hw->sta_data_size, + &local->memory_stats.malloc_size); kfree(sta); return NULL; }