mac80211: Re-structure aqm debugfs output and keep CoDel stats per txq

Currently the 'aqm' stats in mac80211 only keeps overlimit drop stats,
not CoDel stats. This moves the CoDel stats into the txqi structure to
keep them per txq in order to show them in debugfs.

In addition, the aqm debugfs output is restructured by splitting it up
into three files: One global per phy, one per netdev and one per
station, in the appropriate directories. The files are all called aqm,
and are only created if the driver supports the wake_tx_queue op (rather
than emitting an error on open as previously).

Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Toke Høiland-Jørgensen
2016-09-12 15:55:43 +02:00
committed by Johannes Berg
parent 53f249747d
commit 8d51dbb8c7
5 changed files with 122 additions and 134 deletions

View File

@ -71,138 +71,39 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
struct aqm_info {
struct ieee80211_local *local;
size_t size;
size_t len;
unsigned char buf[0];
};
#define AQM_HDR_LEN 200
#define AQM_HW_ENTRY_LEN 40
#define AQM_TXQ_ENTRY_LEN 110
static int aqm_open(struct inode *inode, struct file *file)
{
struct ieee80211_local *local = inode->i_private;
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct txq_info *txqi;
struct fq *fq = &local->fq;
struct aqm_info *info = NULL;
int len = 0;
int i;
if (!local->ops->wake_tx_queue)
return -EOPNOTSUPP;
len += AQM_HDR_LEN;
len += 6 * AQM_HW_ENTRY_LEN;
rcu_read_lock();
list_for_each_entry_rcu(sdata, &local->interfaces, list)
len += AQM_TXQ_ENTRY_LEN;
list_for_each_entry_rcu(sta, &local->sta_list, list)
len += AQM_TXQ_ENTRY_LEN * ARRAY_SIZE(sta->sta.txq);
rcu_read_unlock();
info = vmalloc(len);
if (!info)
return -ENOMEM;
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
file->private_data = info;
info->local = local;
info->size = len;
len = 0;
len += scnprintf(info->buf + len, info->size - len,
"* hw\n"
"access name value\n"
"R fq_flows_cnt %u\n"
"R fq_backlog %u\n"
"R fq_overlimit %u\n"
"R fq_collisions %u\n"
"RW fq_limit %u\n"
"RW fq_quantum %u\n",
fq->flows_cnt,
fq->backlog,
fq->overlimit,
fq->collisions,
fq->limit,
fq->quantum);
len += scnprintf(info->buf + len,
info->size - len,
"* vif\n"
"ifname addr ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
list_for_each_entry_rcu(sdata, &local->interfaces, list) {
txqi = to_txq_info(sdata->vif.txq);
len += scnprintf(info->buf + len, info->size - len,
"%s %pM %u %u %u %u %u %u %u %u\n",
sdata->name,
sdata->vif.addr,
txqi->txq.ac,
txqi->tin.backlog_bytes,
txqi->tin.backlog_packets,
txqi->tin.flows,
txqi->tin.overlimit,
txqi->tin.collisions,
txqi->tin.tx_bytes,
txqi->tin.tx_packets);
}
len += scnprintf(info->buf + len,
info->size - len,
"* sta\n"
"ifname addr tid ac backlog-bytes backlog-packets flows overlimit collisions tx-bytes tx-packets\n");
list_for_each_entry_rcu(sta, &local->sta_list, list) {
sdata = sta->sdata;
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
txqi = to_txq_info(sta->sta.txq[i]);
len += scnprintf(info->buf + len, info->size - len,
"%s %pM %d %d %u %u %u %u %u %u %u\n",
sdata->name,
sta->sta.addr,
txqi->txq.tid,
txqi->txq.ac,
txqi->tin.backlog_bytes,
txqi->tin.backlog_packets,
txqi->tin.flows,
txqi->tin.overlimit,
txqi->tin.collisions,
txqi->tin.tx_bytes,
txqi->tin.tx_packets);
}
}
info->len = len;
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
return 0;
}
static int aqm_release(struct inode *inode, struct file *file)
{
vfree(file->private_data);
return 0;
}
static ssize_t aqm_read(struct file *file,
char __user *user_buf,
size_t count,
loff_t *ppos)
{
struct aqm_info *info = file->private_data;
struct ieee80211_local *local = file->private_data;
struct fq *fq = &local->fq;
char buf[200];
int len = 0;
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
len = scnprintf(buf, sizeof(buf),
"access name value\n"
"R fq_flows_cnt %u\n"
"R fq_backlog %u\n"
"R fq_overlimit %u\n"
"R fq_collisions %u\n"
"RW fq_limit %u\n"
"RW fq_quantum %u\n",
fq->flows_cnt,
fq->backlog,
fq->overlimit,
fq->collisions,
fq->limit,
fq->quantum);
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
return simple_read_from_buffer(user_buf, count, ppos,
info->buf, info->len);
buf, len);
}
static ssize_t aqm_write(struct file *file,
@ -210,8 +111,7 @@ static ssize_t aqm_write(struct file *file,
size_t count,
loff_t *ppos)
{
struct aqm_info *info = file->private_data;
struct ieee80211_local *local = info->local;
struct ieee80211_local *local = file->private_data;
char buf[100];
size_t len;
@ -237,8 +137,7 @@ static ssize_t aqm_write(struct file *file,
static const struct file_operations aqm_ops = {
.write = aqm_write,
.read = aqm_read,
.open = aqm_open,
.release = aqm_release,
.open = simple_open,
.llseek = default_llseek,
};
@ -428,7 +327,9 @@ void debugfs_hw_add(struct ieee80211_local *local)
DEBUGFS_ADD(hwflags);
DEBUGFS_ADD(user_power);
DEBUGFS_ADD(power);
DEBUGFS_ADD_MODE(aqm, 0600);
if (local->ops->wake_tx_queue)
DEBUGFS_ADD_MODE(aqm, 0600);
statsd = debugfs_create_dir("statistics", phyd);