On Mon, Dec 29, 2025 at 05:23:12PM +0100, Martin Pieuchot wrote:
> On 27/12/25(Sat) 18:15, Alexander Bluhm wrote:
> > On Sat, Dec 27, 2025 at 10:26:58AM +0100, Martin Pieuchot wrote:
> > > On 26/12/25(Fri) 13:36, Alexander Bluhm wrote:
> > > > On Fri, Dec 26, 2025 at 01:02:17PM +0100, Alexander Bluhm wrote:
> > > > > Anyway. Currently I cannot reproduce. I will keep an eye on it.
> > > > > I will use the diff below if it happens again.
> > > >
> > > > And just after writing this, I hit the crash.
> > >
> > > Thanks Alexander, so this confirms the race with uvm_pagefree().
> > >
> > > Here's the full diff. Would you please try to reproduce the panic with
> > > it and hopefully report the next bug?
> >
> > Here we go
>
> Thanks a lot Alexander, here's a proper fix. We need to use an iterator
> when scanning the active loop because it releases the pageqlock.
> Without iterator 'nextpg' might no longer be on the list or it might be
> on the list but somewhere else.
>
> Diff below uses the same logic already present in the inactive loop. Do
> you see a different panic with it?
Passed make build on the affected i386 machine twice
Passed regress on i386
Passed regress with witness on amd64
OK bluhm@
> Index: uvm/uvm_pdaemon.c
> ===================================================================
> RCS file: /cvs/src/sys/uvm/uvm_pdaemon.c,v
> diff -u -p -r1.144 uvm_pdaemon.c
> --- uvm/uvm_pdaemon.c 24 Dec 2025 10:29:22 -0000 1.144
> +++ uvm/uvm_pdaemon.c 29 Dec 2025 16:13:20 -0000
> @@ -923,15 +923,18 @@ void
> uvmpd_scan_active(struct uvm_pmalloc *pma, int swap_shortage,
> int inactive_shortage)
> {
> - struct vm_page *p, *nextpg;
> + struct pglist *pglst = &uvm.page_active;
> + struct vm_page *p, iter = { .pg_flags = PQ_ITER };
> struct rwlock *slock;
>
> MUTEX_ASSERT_LOCKED(&uvm.pageqlock);
>
> - for (p = TAILQ_FIRST(&uvm.page_active);
> - p != NULL && (inactive_shortage > 0 || swap_shortage > 0);
> - p = nextpg) {
> - nextpg = TAILQ_NEXT(p, pageq);
> + p = TAILQ_FIRST(pglst);
> +
> + /* Insert iterator. */
> + TAILQ_INSERT_AFTER(pglst, p, &iter, pageq);
> + for (; p != NULL && (inactive_shortage > 0 || swap_shortage > 0);
> + p = uvmpd_iterator(pglst, p, &iter)) {
> if (p->pg_flags & PG_BUSY) {
> continue;
> }
> @@ -993,6 +996,7 @@ uvmpd_scan_active(struct uvm_pmalloc *pm
> */
> rw_exit(slock);
> }
> + TAILQ_REMOVE(pglst, &iter, pageq);
> }
>
> #ifdef HIBERNATE
>