[PATCH] cfg80211: use IDA to allocate wiphy indeces

From: Brian Norris
Date: Wed Jun 20 2018 - 21:30:09 EST


It's annoying to see the phy index increase arbitrarily, just because a
device got removed and re-probed (e.g., during a device reset, or due to
probe testing). We can use the in-kernel index allocator for this,
instead of just an increasing counter.

Signed-off-by: Brian Norris <briannorris@xxxxxxxxxxxx>
---
net/wireless/core.c | 31 ++++++++++++++-----------------
1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/net/wireless/core.c b/net/wireless/core.c
index c0fd8a85e7f7..80c108c3ca38 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -8,6 +8,7 @@

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

+#include <linux/idr.h>
#include <linux/if.h>
#include <linux/module.h>
#include <linux/err.h>
@@ -380,11 +381,11 @@ static void cfg80211_propagate_cac_done_wk(struct work_struct *work)

/* exported functions */

+static DEFINE_IDA(wiphy_ida);
+
struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
const char *requested_name)
{
- static atomic_t wiphy_counter = ATOMIC_INIT(0);
-
struct cfg80211_registered_device *rdev;
int alloc_size;

@@ -413,18 +414,12 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,

rdev->ops = ops;

- rdev->wiphy_idx = atomic_inc_return(&wiphy_counter);
-
+ rdev->wiphy_idx = ida_simple_get(&wiphy_ida, 0, 0, GFP_KERNEL);
if (unlikely(rdev->wiphy_idx < 0)) {
- /* ugh, wrapped! */
- atomic_dec(&wiphy_counter);
kfree(rdev);
return NULL;
}

- /* atomic_inc_return makes it start at 1, make it start at 0 */
- rdev->wiphy_idx--;
-
/* give it a proper name */
if (requested_name && requested_name[0]) {
int rv;
@@ -452,10 +447,8 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
* value, and use a different name if this one exists?
*/
rv = dev_set_name(&rdev->wiphy.dev, PHY_NAME "%d", rdev->wiphy_idx);
- if (rv < 0) {
- kfree(rdev);
- return NULL;
- }
+ if (rv < 0)
+ goto err;
}

INIT_LIST_HEAD(&rdev->wiphy.wdev_list);
@@ -497,10 +490,8 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
&rdev->wiphy.dev, RFKILL_TYPE_WLAN,
&rdev->rfkill_ops, rdev);

- if (!rdev->rfkill) {
- kfree(rdev);
- return NULL;
- }
+ if (!rdev->rfkill)
+ goto err;

INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
@@ -525,6 +516,11 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
rdev->wiphy.max_sched_scan_plan_interval = U32_MAX;

return &rdev->wiphy;
+
+err:
+ ida_simple_remove(&wiphy_ida, rdev->wiphy_idx);
+ kfree(rdev);
+ return NULL;
}
EXPORT_SYMBOL(wiphy_new_nm);

@@ -972,6 +968,7 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
}
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&rdev->wiphy, &scan->pub);
+ ida_simple_remove(&wiphy_ida, rdev->wiphy_idx);
kfree(rdev);
}

--
2.18.0.rc1.244.gcf134e6275-goog