aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Wojtas <mw@FreeBSD.org>2021-06-14 08:57:54 +0000
committerMarcin Wojtas <mw@FreeBSD.org>2021-06-24 14:02:39 +0000
commit0e7d31f63b9db869c91228d8ed1e984bdee2b931 (patch)
tree04404c904194d20e7e880ef1dec8dcecd23ef763
parentddec69e6a796283497ebada0569f34bd41bbdf37 (diff)
downloadsrc-0e7d31f63b9db869c91228d8ed1e984bdee2b931.tar.gz
src-0e7d31f63b9db869c91228d8ed1e984bdee2b931.zip
ena: hide sysctl nodes for unused ENA queues
IO queue related attributes are registered statically at driver attach with the rest of the ENA specific sysctl nodes. However, the number of queues can be changed at runtime via the `ena_sysctl_io_queues_nb` request, leading to a potential exposure of attributes for non-existing queues. Introduce a new `ena_sysctl_update_queue_node_nb` function, which updates the sysctl nodes after the number of queues is altered. This happens by either registering or unregistering node specific oids, based on a delta between the previous and current queue count. NOTE: All unregistered oids must be registered again before the driver detach, e.g. by another call to this function. Submitted by: Artur Rojek <ar@semihalf.com> Obtained from: Semihalf MFC after: 2 weeks Sponsored by: Amazon, Inc.
-rw-r--r--sys/dev/ena/ena.c4
-rw-r--r--sys/dev/ena/ena.h1
-rw-r--r--sys/dev/ena/ena_sysctl.c46
-rw-r--r--sys/dev/ena/ena_sysctl.h2
4 files changed, 52 insertions, 1 deletions
diff --git a/sys/dev/ena/ena.c b/sys/dev/ena/ena.c
index d7a68e94d361..fbe32a7a930e 100644
--- a/sys/dev/ena/ena.c
+++ b/sys/dev/ena/ena.c
@@ -3830,6 +3830,10 @@ ena_detach(device_t pdev)
ena_destroy_device(adapter, true);
ENA_LOCK_UNLOCK(adapter);
+ /* Restore unregistered sysctl queue nodes. */
+ ena_sysctl_update_queue_node_nb(adapter, adapter->num_io_queues,
+ adapter->max_num_io_queues);
+
#ifdef DEV_NETMAP
netmap_detach(adapter->ifp);
#endif /* DEV_NETMAP */
diff --git a/sys/dev/ena/ena.h b/sys/dev/ena/ena.h
index f3e92f31341a..a49ac70761ba 100644
--- a/sys/dev/ena/ena.h
+++ b/sys/dev/ena/ena.h
@@ -215,6 +215,7 @@ struct ena_que {
uint32_t id;
int cpu;
+ struct sysctl_oid *oid;
};
struct ena_calc_queue_size_ctx {
diff --git a/sys/dev/ena/ena_sysctl.c b/sys/dev/ena/ena_sysctl.c
index 26fc79379e33..0726771e5adc 100644
--- a/sys/dev/ena/ena_sysctl.c
+++ b/sys/dev/ena/ena_sysctl.c
@@ -28,6 +28,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
+#include <sys/param.h>
__FBSDID("$FreeBSD$");
#include "ena_sysctl.h"
@@ -188,6 +189,8 @@ ena_sysctl_add_stats(struct ena_adapter *adapter)
namebuf, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "Queue Name");
queue_list = SYSCTL_CHILDREN(queue_node);
+ adapter->que[i].oid = queue_node;
+
/* TX specific stats */
tx_node = SYSCTL_ADD_NODE(ctx, queue_list, OID_AUTO,
"tx_ring", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "TX ring");
@@ -396,6 +399,42 @@ ena_sysctl_add_tuneables(struct ena_adapter *adapter)
}
+/*
+ * ena_sysctl_update_queue_node_nb - Register/unregister sysctl queue nodes.
+ *
+ * Whether the nodes are registered or unregistered depends on a delta between
+ * the `old` and `new` parameters, representing the number of queues.
+ *
+ * This function is used to hide sysctl attributes for queue nodes which aren't
+ * currently used by the HW (e.g. after a call to `ena_sysctl_io_queues_nb`).
+ *
+ * NOTE:
+ * All unregistered nodes must be registered again at detach, i.e. by a call to
+ * this function.
+ */
+void
+ena_sysctl_update_queue_node_nb(struct ena_adapter *adapter, int old, int new)
+{
+ device_t dev;
+ struct sysctl_oid *oid;
+ int min, max, i;
+
+ dev = adapter->pdev;
+ min = MIN(old, new);
+ max = MIN(MAX(old, new), adapter->max_num_io_queues);
+
+ for (i = min; i < max; ++i) {
+ oid = adapter->que[i].oid;
+
+ sysctl_wlock();
+ if (old > new)
+ sysctl_unregister_oid(oid);
+ else
+ sysctl_register_oid(oid);
+ sysctl_wunlock();
+ }
+}
+
static int
ena_sysctl_buf_ring_size(SYSCTL_HANDLER_ARGS)
{
@@ -488,7 +527,7 @@ static int
ena_sysctl_io_queues_nb(SYSCTL_HANDLER_ARGS)
{
struct ena_adapter *adapter = arg1;
- uint32_t tmp = 0;
+ uint32_t old_num_queues, tmp = 0;
int error;
error = sysctl_wire_old_buffer(req, sizeof(tmp));
@@ -527,7 +566,12 @@ ena_sysctl_io_queues_nb(SYSCTL_HANDLER_ARGS)
"Requested new number of IO queues: %u, current value: "
"%u\n", tmp, adapter->num_io_queues);
+ old_num_queues = adapter->num_io_queues;
error = ena_update_io_queue_nb(adapter, tmp);
+ if (error != 0)
+ return (error);
+
+ ena_sysctl_update_queue_node_nb(adapter, old_num_queues, tmp);
}
return (error);
diff --git a/sys/dev/ena/ena_sysctl.h b/sys/dev/ena/ena_sysctl.h
index 360e32c3ad18..c6059c9cba36 100644
--- a/sys/dev/ena/ena_sysctl.h
+++ b/sys/dev/ena/ena_sysctl.h
@@ -40,6 +40,8 @@
#include "ena.h"
void ena_sysctl_add_nodes(struct ena_adapter *adapter);
+void ena_sysctl_update_queue_node_nb(struct ena_adapter *adapter, int old,
+ int new);
extern int ena_enable_9k_mbufs;
#define ena_mbuf_sz (ena_enable_9k_mbufs ? MJUM9BYTES : MJUMPAGESIZE)