vm: Fix iterator usage in vm_thread_stack_create()

After commit 7a79d06697 we no longer hold the VM object lock when
initializing or advancing the domainset iterator in
vm_thread_stack_create().

We could lift the lock out of vm_thread_stack_back() but that poses
complications since we cannot allocate KVA with a VM object lock held.

Instead of overridding the object's iterator, just borrow that of the
current thread.  Kernel stacks are basically always allocated with a
DOMAINSET_POLICY_PREFER policy, so it's not very important to maintain a
global iterator for round-robin allocation.

As a part of this, fix up flag handling: make sure we handle
M_NOWAIT/M_WAITOK from the caller.  Delete a comment in vm_thread_new()
which refers to a non-existent consideration (stack swapping has been
removed).  I suspect vm_thread_new() can use M_WAITOK but opted not to
make that change here.

Reported by:	olce
Reviewed by:	olce, alc, kib
Fixes:		7a79d06697 ("vm: improve kstack_object pindex calculation to avoid pindex holes")
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D52982
This commit is contained in:
Mark Johnston committed 2025-10-16 23:13:34 +00:00
1 parent 0050289464
commit 3b9b644576
1 file changed
+8 -16
+8 -16
View File
@@ -441,19 +441,16 @@ vm_thread_kstack_arena_release(void *arena, vmem_addr_t addr, vmem_size_t size)
* Create the kernel stack for a new thread.
*/
static vm_offset_t
vm_thread_stack_create(struct domainset *ds, int pages)
vm_thread_stack_create(struct domainset *ds, int pages, int flags)
{
vm_page_t ma[KSTACK_MAX_PAGES];
struct vm_domainset_iter di;
int req = VM_ALLOC_NORMAL;
vm_object_t obj;
int req;
vm_offset_t ks;
int domain, i;
obj = vm_thread_kstack_size_to_obj(pages);
if (vm_ndomains > 1)
obj->domain.dr_policy = ds;
vm_domainset_iter_page_init(&di, obj, 0, &domain, &req);
vm_domainset_iter_policy_init(&di, ds, &domain, &flags);
req = malloc2vm_flags(flags);
do {
/*
* Get a kernel virtual address for this thread's kstack.
@@ -480,7 +477,7 @@ vm_thread_stack_create(struct domainset *ds, int pages)
vm_page_valid(ma[i]);
pmap_qenter(ks, ma, pages);
return (ks);
} while (vm_domainset_iter_page(&di, obj, &domain, NULL) == 0);
} while (vm_domainset_iter_policy(&di, &domain) == 0);
return (0);
}
@@ -532,15 +529,9 @@ vm_thread_new(struct thread *td, int pages)
ks = 0;
if (pages == kstack_pages && kstack_cache != NULL)
ks = (vm_offset_t)uma_zalloc(kstack_cache, M_NOWAIT);
/*
* Ensure that kstack objects can draw pages from any memory
* domain. Otherwise a local memory shortage can block a process
* swap-in.
*/
if (ks == 0)
ks = vm_thread_stack_create(DOMAINSET_PREF(PCPU_GET(domain)),
pages);
pages, M_NOWAIT);
if (ks == 0)
return (0);
@@ -660,7 +651,8 @@ kstack_import(void *arg, void **store, int cnt, int domain, int flags)
ds = DOMAINSET_PREF(domain);
for (i = 0; i < cnt; i++) {
store[i] = (void *)vm_thread_stack_create(ds, kstack_pages);
store[i] = (void *)vm_thread_stack_create(ds, kstack_pages,
flags);
if (store[i] == NULL)
break;
}