NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/56764



The following reply was made to PR kern/56764; it has been noted by GNATS.

From: Robert Elz <kre%munnari.OZ.AU@localhost>
To: Thomas Klausner <wiz%netbsd.org@localhost>
Cc: gnats-bugs%netbsd.org@localhost
Subject: Re: kern/56764
Date: Sun, 22 Feb 2026 01:14:26 +0700

     Date:        Sat, 21 Feb 2026 18:30:55 +0100
     From:        Thomas Klausner <wiz%netbsd.org@localhost>
     Message-ID:  <aZnqBQcezBYRM5zw%exadelic.gatalith.at@localhost>
 
 
   | It only accesses uvmexp members and still grabs the lock.
 
 OK, like I said, I am guessing a lot, but if
 
   | If you look closely you'll find that swpginuse is only modified when
   | uvm_swap_data_lock is held.
 
 that's true, then good.
 
   | I've hijacked this PR a bit - it was about
   | kernel diagnostic assertion "uvmexp.swpgonly > 0" failed
 
 Yes.   I saw.
 
   | while I was hitting
   |
   | kernel diagnostic assertion "uvmexp.swpgonly < uvmexp.swpginuse" failed
 
 But that's an assertion you just added in Jan, right?
 
   | the swpgonly > 0 definitely sounds sane while the other one should
   | (according to Chuck) always be true too.
 
 Logically, I agree, but with new compilers and the current C rules,
 I'm not sure the code can guarantee that.
 
 Since the addr of uvmexp.swpgonly is passed to the atomic functions,
 the compiler must assume that it might be being modified, which of
 course it is.   But that means it needs to be read from the struct
 on any reference after one of those operations (there's just the one
 in uvmpd_scan_queue() which is the KASSERT() in question).
 
 But that's not true of uvmexp.swpginuse ... uvmpd_scan_queue() is just one
 big loop, runs until it has nothing left to do, over and over.   The compiler
 might read uvmexp.swpginuse, stick in a register, and as nothing in that
 func is touching it, nor passing its addr to any other funcs, and it isn't
 volatile, the compiler is entitled (by modern C rules) to assume that nothing
 is changing it.   Maybe that doesn't apply to extern structs, beats me.
 
 But I also see this code in uvmpd_scan_queue() (not that I expect this
 is related to your issue):
 
                 if ((p->flags & PG_SWAPBACKED) == 0) {
                         KASSERT(uobj != NULL);
                         (void) (uobj->pgops->pgo_put)(uobj, p->offset,
                             p->offset + PAGE_SIZE, PGO_CLEANIT|PGO_FREE);
                         continue;
                 }       
 
 
 That's going around the big loop again - but I see no attempt to
 
 			rw_exit(slock);
 
 slock is a local var in uvmpd_scan_queue() so whatever the function is
 (uobj->pgops->pgo_put) it cannot be exiting the locked region.
 
 Every other "continue;" in that section of code (before and after that one
 - from after the slock is obtained) has that rw_exit(slock) just before the
 continue, so there may well be lots of locked stuff hanging around, if
 that particular piece of code ever runs.   Very unlikely to be related to
 your issue(s) but it looks broken to me.
 
 kre
 


Home | Main Index | Thread Index | Old Index