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);

--=-=-=--