mlx5: Preallocate ktls tags asynchronously

Change tag preallocation to happen asynchronously when an interface is
brought up, so as to reduce boot times when preallocating tags.

- A new mlx5-tls-prealloc_wq is allocated when preallocation is
  desired, and started when an interface is opened

- The bulk of the prealloc code remains the same, except the
  allocations are now M_NOWAIT. M_NOWAIT is needed because, since the
  preallocation is done asynchronously, and since tag allocation is
  not instant, we could race with a real TLS session trying to
  allocate a tag. Note that in this case, we take allocation failure
  as a sign that we were unable to obtain the entire zone due to there
  being other consumers.  This was suggested by @markj as a way to
  keep things simple, after discussing why uma_zone_get_cur() didn't
  immediately report a fully allocated zone.  If this turns out to be
  problematic, we could use uma_zone_set_maxaction() to stop
  pre-allocations (also suggested by Mark)

Reviewed by: glebius, kib, markj
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D53570
This commit is contained in:
Andrew Gallatin committed 2025-11-05 18:58:33 -05:00
1 parent a7c558b4ad
commit 9349214a28
3 files changed
+50 -9

No files matched your search

+3
View File
@@ -82,6 +82,8 @@ struct mlx5e_tls {
struct sysctl_ctx_list ctx;
struct mlx5e_tls_stats stats;
struct workqueue_struct *wq;
struct workqueue_struct *prealloc_wq;
struct work_struct prealloc_work;
uma_zone_t zone;
uint32_t max_resources; /* max number of resources */
int zone_max;
@@ -92,6 +94,7 @@ struct mlx5e_tls {
int mlx5e_tls_init(struct mlx5e_priv *);
void mlx5e_tls_cleanup(struct mlx5e_priv *);
int mlx5e_sq_tls_xmit(struct mlx5e_sq *, struct mlx5e_xmit_args *, struct mbuf **);
void mlx5e_tls_prealloc_tags(struct mlx5e_priv *priv);
if_snd_tag_alloc_t mlx5e_tls_snd_tag_alloc;
+44 -9
View File
@@ -80,23 +80,39 @@ static const char *mlx5e_tls_stats_desc[] = {
};
static void mlx5e_tls_work(struct work_struct *);
static void mlx5e_tls_prealloc_work(struct work_struct *);
/*
* Expand the tls tag UMA zone in a sleepable context
* Expand the tls tag UMA zone in an async context
*/
static void
mlx5e_prealloc_tags(struct mlx5e_priv *priv, int nitems)
mlx5e_tls_prealloc_work(struct work_struct *work)
{
struct mlx5e_priv *priv;
struct mlx5e_tls *ptls;
struct mlx5e_tls_tag **tags;
int i;
int i, nitems;
ptls = container_of(work, struct mlx5e_tls, prealloc_work);
priv = container_of(ptls, struct mlx5e_priv, tls);
nitems = ptls->zone_max;
tags = malloc(sizeof(tags[0]) * nitems,
M_MLX5E_TLS, M_WAITOK);
for (i = 0; i < nitems; i++)
tags[i] = uma_zalloc(priv->tls.zone, M_WAITOK);
M_MLX5E_TLS, M_WAITOK | M_ZERO);
for (i = 0; i < nitems; i++) {
tags[i] = uma_zalloc(priv->tls.zone, M_NOWAIT);
/*
* If the allocation fails, its likely we are competing
* with real consumers of tags and the zone is full,
* so exit the loop, and release the tags like we would
* if we allocated all "nitems"
*/
if (tags[i] == NULL)
break;
}
__compiler_membar();
for (i = 0; i < nitems; i++)
for (i = 0; i < nitems && tags[i] != NULL; i++)
uma_zfree(priv->tls.zone, tags[i]);
free(tags, M_MLX5E_TLS);
}
@@ -244,8 +260,6 @@ mlx5e_tls_init(struct mlx5e_priv *priv)
}
uma_zone_set_max(ptls->zone, ptls->zone_max);
if (prealloc_tags != 0)
mlx5e_prealloc_tags(priv, ptls->zone_max);
for (x = 0; x != MLX5E_TLS_STATS_NUM; x++)
ptls->stats.arg[x] = counter_u64_alloc(M_WAITOK);
@@ -270,6 +284,23 @@ mlx5e_tls_init(struct mlx5e_priv *priv)
return (0);
}
void
mlx5e_tls_prealloc_tags(struct mlx5e_priv *priv)
{
struct mlx5e_tls *ptls = &priv->tls;
int prealloc_tags = 0;
if (ptls->prealloc_wq != NULL)
return;
TUNABLE_INT_FETCH("hw.mlx5.tls_prealloc_tags", &prealloc_tags);
if (prealloc_tags == 0)
return;
ptls->prealloc_wq = create_singlethread_workqueue("mlx5-tls-prealloc_wq");
INIT_WORK(&ptls->prealloc_work, mlx5e_tls_prealloc_work);
queue_work(ptls->prealloc_wq, &ptls->prealloc_work);
}
void
mlx5e_tls_cleanup(struct mlx5e_priv *priv)
{
@@ -280,6 +311,10 @@ mlx5e_tls_cleanup(struct mlx5e_priv *priv)
return;
ptls->init = 0;
if (ptls->prealloc_wq != NULL) {
flush_workqueue(ptls->prealloc_wq);
destroy_workqueue(ptls->prealloc_wq);
}
flush_workqueue(ptls->wq);
sysctl_ctx_free(&ptls->ctx);
uma_zdestroy(ptls->zone);
+3
View File
@@ -3335,6 +3335,9 @@ mlx5e_open_locked(if_t ifp)
mlx5e_update_carrier(priv);
if ((if_getcapenable(ifp) & (IFCAP_TXTLS4 | IFCAP_TXTLS6)) != 0)
mlx5e_tls_prealloc_tags(priv);
return (0);
err_close_channels: