Re: [PATCH v3 01/15] mm/mempolicy: charge shared policy nodes

From: Balbir Singh

Date: Wed Oct 28 2026 - 06:03:04 EST


On Wed, Oct 28, 2026 at 10:54:59AM +0100, David Hildenbrand (Arm) wrote:
> From: Chris Mason <mason@xxxxxxxxxx>
>
> Any local user can bypass memory.max with mbind() on a tmpfs file, and
> allocate unbounded kernel memory.
>
> mbind() sets a NUMA memory policy for a range of a mapping. If the
> mapping is of a shmem and friends, the kernel also stores the policy on
> the inode, in a tree with one entry per range of the file.
>
> Each mbind() on a single page of a mapping can add one shared policy node
> (struct sp_node) and one struct mempolicy to that tree. They outlive the
> mapping and stay around until the inode is destroyed. The tree is not
> bounded by the file size, so the file can be empty.
>
> Memory that user space can allocate must be charged to a memory cgroup. A
> slab cache does that for all of its objects if it is created with
> SLAB_ACCOUNT. numa_policy_init() creates the slab caches for both
> structs without SLAB_ACCOUNT, so they are not charged to any cgroup.
>
> Reproduced with mbind() on single pages of an empty tmpfs file, from a
> cgroup with memory.max=8M: the global OOM killer killed tasks owned by
> root, and the machine panicked.
>
> Fix this by creating both caches with SLAB_ACCOUNT. This change implies
> that mbind() can now fail when running into memcg limits. Further,
> the policy_cache also serves task and VMA policies, so they are
> similarly accounted now.
>
> Note that per-file limits are not really helpful, as the user could
> simply use many files; having limits per user is tricky as well.
>
> Fix generated by an LLM and submitted by Chris Mason in private.
>
> Fixes: 5d097056c9a0 ("kmemcg: account certain kmem allocations to memcg")
> Cc: stable@xxxxxxxxxxxxxxx
> Signed-off-by: Chris Mason <mason@xxxxxxxxxx>
> Acked-by: Pedro Falcato <pfalcato@xxxxxxx>
> Acked-by: Kiryl Shutsemau (Meta) <kas@xxxxxxxxxx>
> Acked-by: Zi Yan <ziy@xxxxxxxxxx>
> Reviewed-by: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
> Tested-by: Gregory Price (Meta) <gourry@xxxxxxxxxx>
> [ david: smaller description tweaks ]
> Signed-off-by: David Hildenbrand (Arm) <david@xxxxxxxxxx>
> ---
> mm/mempolicy.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index 0884c629670d..4da1cb8777f6 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -3372,11 +3372,11 @@ void __init numa_policy_init(void)
>
> policy_cache = kmem_cache_create("numa_policy",
> sizeof(struct mempolicy),
> - 0, SLAB_PANIC, NULL);
> + 0, SLAB_PANIC | SLAB_ACCOUNT, NULL);
>
> sn_cache = kmem_cache_create("shared_policy_node",
> sizeof(struct sp_node),
> - 0, SLAB_PANIC, NULL);
> + 0, SLAB_PANIC | SLAB_ACCOUNT, NULL);
>
> for_each_node(nid) {
> preferred_node_policy[nid] = (struct mempolicy) {
>

You have many of them already, but anyway

Reviewed-by: Balbir Singh <balbirs@xxxxxxxxxx>