Re: [PATCH v2] mm/mempolicy: recompute automatic interleave weights on memory hotplug

From: Joshua Hahn

Date: Mon Nov 02 2026 - 12:49:06 EST


On Fri, Oct 30, 2026 at 7:43 PM Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> wrote:
>
> On Fri, 30 Oct 2026 12:35:38 -0400 Joshua Hahn <joshua.hahnjy@xxxxxxxxx> wrote:
>
> > On Fri, Oct 30, 2026 at 12:12 PM Gregory Price (Meta) <gourry@xxxxxxxxxx> wrote:
> > >
> > > In auto mode, weighted interleave derives each node's weight from its
> > > bandwidth, reduced over the nodes in N_MEMORY. HMAT and CXL report a
> > > node's bandwidth once, when the node first gains memory, and nothing
> > > else on the hotplug path recomputes the weights.
> > >
> > > This can result in a major skew in distribution and overload tiers
> > > with more data than their respective bandwidth can support, resulting
> > > in a performance regression.
> >
> > ...
> >
> > I think you may have dropped my review tag from the previous
> > version!!! I believe the only thing that changes is the warn, so
> > please feel free to add:
> > Reviewed-by: Joshua Hahn <joshua.hahnjy@xxxxxxxxx>
>
> Actually, quite a lot changed, so dropping the v1 tags seems
> appropriate.

Hi Andrew,
Ah, thank you for the catch. Looking through the code again, I think
it still looks good to me so my review tag should stil stay. I'll be
more careful about stuff like this in the future!

> v1->v2:
>
> mm/mempolicy.c | 36 ++++++++++++++++++++++++++++--------
> 1 file changed, 28 insertions(+), 8 deletions(-)
>
> --- a/mm/mempolicy.c~mm-mempolicy-recompute-automatic-interleave-weights-on-memory-hotplug-v2
> +++ a/mm/mempolicy.c
> @@ -261,7 +261,11 @@ static int wi_state_refresh(void)
> mutex_lock(&wi_state_lock);
> old_wi_state = rcu_dereference_protected(wi_state,
> lockdep_is_held(&wi_state_lock));
> - /* NULL wi_state assumes auto=true */
> + /*
> + * Hotplug events can arrive before any node reported its bandwidth,
> + * leaving nothing to compute weights from. NULL wi_state assumes
> + * auto=true.
> + */
> if (!node_bw_table || (old_wi_state && !old_wi_state->mode_auto)) {
> mutex_unlock(&wi_state_lock);
> kfree(new_wi_state);
> @@ -302,6 +306,28 @@ int mempolicy_set_node_perf(unsigned int
> return wi_state_refresh();
> }
>
> +/*
> + * HMAT and CXL report a node's bandwidth only when it first gains memory, so
> + * recompute the weights whenever N_MEMORY changes.
> + */
> +static int wi_state_node_notifier(struct notifier_block *nb,
> + unsigned long action, void *data)
> +{
> + struct node_notify *nn = data;
> + int err;
> +
> + if (action != NODE_ADDED_FIRST_MEMORY &&
> + action != NODE_REMOVED_LAST_MEMORY)
> + return NOTIFY_OK;
> +
> + /* The hotplug is done, failing the notification would not undo it */
> + err = wi_state_refresh();
> + if (err)
> + pr_warn_once("failed to recompute weighted interleave weights for node%d: %d\n",
> + nn->nid, err);
> + return NOTIFY_OK;
> +}
> +
> /**
> * numa_nearest_node - Find nearest node by state
> * @node: Node id to start the search
> @@ -3424,6 +3450,7 @@ void __init numa_policy_init(void)
> if (do_set_mempolicy(MPOL_INTERLEAVE, 0, &interleave_nodes))
> pr_err("%s: interleaving failed\n", __func__);
>
> + hotplug_node_notifier(wi_state_node_notifier, DEFAULT_CALLBACK_PRI);
> check_numabalancing_enable();
> }
>
> @@ -3910,15 +3937,8 @@ static int wi_node_notifier(struct notif
> case NODE_REMOVED_LAST_MEMORY:
> sysfs_wi_node_delete(nid);
> break;
> - default:
> - return NOTIFY_OK;
> }
>
> - /*
> - * HMAT and CXL report a node's bandwidth only when it first gains
> - * memory, so recompute the weights whenever N_MEMORY changes.
> - */
> - wi_state_refresh();
> return NOTIFY_OK;
> }
>
> _
>