Subject: ubc_fault, failure of pmap_enter, and also uvm_fault
To: None <tech-kern@netbsd.org>
From: Jed Davis <jdev@panix.com>
List: tech-kern
Date: 04/19/2006 22:39:37
--=-=-=
I notice that ubc_fault is permitted to sleep; yet, when it calls
pmap_enter, it instructs it to panic if resources are unavailable,
rather than passing in PMAP_CANFAIL and retrying later.
The i386 pmap_enter, for example, can panic with "no pv entries
available" if it can't get an additional page; I'm not clear on how
that can happen (lots of wired mappings?), but it does, and I have
several core files where it has failed in this way, and uvmexp shows
exactly one page free (the one ubc_fault is in the process of
allocating? or is it reserved for the pagedaemon?).
I also notice that, where ubc_fault does sleep, it does so on &lbolt,
which I'm hoping is for a halfway good reason, like that it doesn't
know if the resource it's waiting for there is in fact memory (and not
that this is a historical artifact that no-one's gotten around to
fixing). But see PR 33278, where a pmap_enter fails, uvm_wait is
called, and yet that doesn't help the pmap_enter proceed, and the
presence of tens of thousands of free pages makes me feel that free
memory isn't what's missing.
If someone with a better understanding of UVM could shed some light on
this, that would be nice.
Also, in the spirit of offering more than just talk, I've attached a
small patch which makes ubc_fault wait on &lbolt (as uneasy as that
makes me) and retry if pmap_enter fails. It doesn't obviously break
anything, but unfortunately I don't yet have a convenient test case to
trigger the pmap_enter failure.
--
(let ((C call-with-current-continuation)) (apply (lambda (x y) (x y)) (map
((lambda (r) ((C C) (lambda (s) (r (lambda l (apply (s s) l)))))) (lambda
(f) (lambda (l) (if (null? l) C (lambda (k) (display (car l)) ((f (cdr l))
(C k))))))) '((#\J #\d #\D #\v #\s) (#\e #\space #\a #\i #\newline)))))
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=ubc_pmap_sleep.diff
Index: uvm_bio.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_bio.c,v
retrieving revision 1.37.2.1
diff -u -p -r1.37.2.1 uvm_bio.c
--- uvm_bio.c 24 Aug 2005 18:43:38 -0000 1.37.2.1
+++ uvm_bio.c 19 Apr 2006 21:44:22 -0000
@@ -365,8 +365,13 @@ again:
pg->offset < umap->writeoff ||
pg->offset + PAGE_SIZE > umap->writeoff + umap->writelen);
mask = rdonly ? ~VM_PROT_WRITE : VM_PROT_ALL;
- pmap_enter(ufi->orig_map->pmap, va, VM_PAGE_TO_PHYS(pg),
- prot & mask, access_type & mask);
+enteragain: error = pmap_enter(ufi->orig_map->pmap, va,
+ VM_PAGE_TO_PHYS(pg), prot & mask,
+ PMAP_CANFAIL | (access_type & mask));
+ if (error) {
+ tsleep(&lbolt, PVM, "ubc_pmap_enter", 0);
+ goto enteragain;
+ }
uvm_pageactivate(pg);
pg->flags &= ~(PG_BUSY);
UVM_PAGE_OWN(pg, NULL);
--=-=-=--