linux-next: manual merge of the mm-nonmm-unstable tree with the mm tree
From: Mark Brown
Date: Tue Sep 15 2026 - 12:10:33 EST
Hi all,
Today's linux-next merge of the mm-nonmm-unstable tree got a conflict in:
mm/vmalloc.c
between commits:
f71e94f83c2a2 ("mm/vmalloc: ase dedicated unbound workqueues for vmap drain")
662d2275549a8 ("mm/vmalloc: avoid false sharing with drain_vmap_work")
from the mm tree and commit:
75b41adb019c4 ("mm/vmalloc: ase dedicated unbound workqueues for vmap drain")
from the mm-nonmm-unstable tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
diff --combined mm/vmalloc.c
index 859e6d2d57a38,89c327a6ce7d9..0000000000000
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@@ -1090,12 -1090,7 +1090,12 @@@ RB_DECLARE_CALLBACKS_MAX(static, free_v
static void reclaim_and_purge_vmap_areas(void);
static BLOCKING_NOTIFIER_HEAD(vmap_notify_list);
static void drain_vmap_area_work(struct work_struct *work);
-static DECLARE_WORK(drain_vmap_work, drain_vmap_area_work);
+/*
+ * Keep the work item, whose pending bit is updated by freeing CPUs,
+ * away from vmap metadata read by allocation and free paths.
+ */
+static __cacheline_aligned_in_smp
+DECLARE_WORK(drain_vmap_work, drain_vmap_area_work);
static struct workqueue_struct *drain_vmap_helpers_wq;
static struct workqueue_struct *drain_vmap_wq;
@@@ -2452,8 -2447,7 +2452,8 @@@ static bool __purge_vmap_area_lazy(unsi
static void reclaim_and_purge_vmap_areas(void)
{
- mutex_lock(&vmap_purge_lock);
+ if (!mutex_trylock(&vmap_purge_lock))
+ return;
purge_fragmented_blocks_allcpus();
__purge_vmap_area_lazy(ULONG_MAX, 0, true);
mutex_unlock(&vmap_purge_lock);
@@@ -3138,7 -3132,7 +3138,7 @@@ EXPORT_SYMBOL(vm_map_ram)
static struct vm_struct *vmlist __initdata;
-static inline unsigned int vm_area_page_order(struct vm_struct *vm)
+static inline unsigned int vm_area_page_order(const struct vm_struct *vm)
{
#ifdef CONFIG_HAVE_ARCH_HUGE_VMALLOC
return vm->page_order;
@@@ -3147,7 -3141,7 +3147,7 @@@
#endif
}
-unsigned int get_vm_area_page_order(struct vm_struct *vm)
+unsigned int get_vm_area_page_order(const struct vm_struct *vm)
{
return vm_area_page_order(vm);
}
@@@ -3372,18 -3366,14 +3372,18 @@@ struct vm_struct *remove_vm_area(const
}
static inline void set_area_direct_map(const struct vm_struct *area,
- int (*set_direct_map)(struct page *page))
+ int (*set_direct_map)(struct page *page,
+ unsigned int nr))
{
- unsigned long i;
+ unsigned int nr = (1U << vm_area_page_order(area));
- /* HUGE_VMALLOC passes small pages to set_direct_map */
- for (i = 0; i < area->nr_pages; i++)
- if (page_address(area->pages[i]))
- set_direct_map(area->pages[i]);
+ for (unsigned long i = 0; i < area->nr_pages; i += nr) {
+ if (page_address(area->pages[i])) {
+ int err = set_direct_map(area->pages[i], nr);
+
+ WARN_ON_ONCE(err);
+ }
+ }
}
/*
@@@ -3890,7 -3880,7 +3890,7 @@@ static void *__vmalloc_area_node(struc
unsigned long size = get_vm_area_size(area);
unsigned long array_size;
unsigned long nr_small_pages = size >> PAGE_SHIFT;
- unsigned int page_order;
+ unsigned int page_order = page_shift - PAGE_SHIFT;
unsigned int flags;
int ret;
@@@ -3918,6 -3908,9 +3918,6 @@@
goto fail;
}
- set_vm_area_page_order(area, page_shift - PAGE_SHIFT);
- page_order = vm_area_page_order(area);
-
/*
* High-order nofail allocations are really expensive and
* potentially dangerous (pre-mature OOM, disruptive reclaim
@@@ -3972,7 -3965,6 +3972,7 @@@
goto fail;
}
+ set_vm_area_page_order(area, page_order);
return area->addr;
fail:
@@@ -4035,12 -4027,6 +4035,12 @@@ static gfp_t vmalloc_fix_flags(gfp_t fl
* %__GFP_SKIP_KASAN can be used to skip unpoisoning of mapped pages
* (when prot=%PAGE_KERNEL).
*
+ * %VM_ALLOW_HUGE_VMAP allocates huge pages when possible and falls back to
+ * base pages if huge page allocation fails.
+ *
+ * %VM_REQUIRE_HUGE_VMAP implies %VM_ALLOW_HUGE_VMAP and fails instead of
+ * silently falling back to base pages.
+ *
* Can not be called from interrupt nor NMI contexts.
* Return: the address of the area or %NULL on failure
*/
@@@ -4066,10 -4052,6 +4066,10 @@@ void *__vmalloc_node_range_noprof(unsig
return NULL;
}
+ /* VM_REQUIRE_HUGE_VMAP implies VM_ALLOW_HUGE_VMAP */
+ if (vm_flags & VM_REQUIRE_HUGE_VMAP)
+ vm_flags |= VM_ALLOW_HUGE_VMAP;
+
if (vmap_allow_huge && (vm_flags & VM_ALLOW_HUGE_VMAP)) {
/*
* Try huge pages. Only try for PAGE_KERNEL allocations,
@@@ -4086,9 -4068,6 +4086,9 @@@
align = max(original_align, 1UL << shift);
}
+ if ((vm_flags & VM_REQUIRE_HUGE_VMAP) && shift == PAGE_SHIFT)
+ return NULL;
+
again:
area = __get_vm_area_node(size, align, shift, VM_ALLOC |
VM_UNINITIALIZED | vm_flags, start, end, node,
@@@ -4163,7 -4142,7 +4163,7 @@@
return area->addr;
fail:
- if (shift > PAGE_SHIFT) {
+ if (shift > PAGE_SHIFT && !(vm_flags & VM_REQUIRE_HUGE_VMAP)) {
shift = PAGE_SHIFT;
align = original_align;
goto again;
@@@ -5548,20 -5527,10 +5548,20 @@@ vmap_node_shrink_scan(struct shrinker *
{
struct vmap_node *vn;
- guard(mutex)(&vmap_purge_lock);
+ /*
+ * This shrinker is invoked from direct reclaim where memory
+ * pressure is already high. Blocking on vmap_purge_lock here
+ * can deadlock the system: the lock holder may be blocked in
+ * flush_work() waiting for a worker that is stuck in this same
+ * reclaim path trying to acquire the same lock. Use trylock
+ * to avoid this; skipping a pool decay cycle is harmless.
+ */
+ if (!mutex_trylock(&vmap_purge_lock))
+ return SHRINK_STOP;
for_each_vmap_node(vn)
decay_va_pool_node(vn, true);
+ mutex_unlock(&vmap_purge_lock);
return SHRINK_STOP;
}
Attachment:
signature.asc
Description: PGP signature