On 9 dec 2010, at 08:32, Ariane van der Steldt wrote:
> I'm not yet convinced. What are you trying to do?
Pretty much as I described: I allocate kernel memory through
uvm_km_kmemalloc() from kernel_map, and then free it through uvm_km_free(),
returning it to the kernel_map.
The code I'm working on is a bit large as a test-case, but I've abused
diskmap(4) to reproduce the panic:
Index: diskmap.c
===================================================================
RCS file: /cvs/openbsd/src/sys/dev/diskmap.c,v
retrieving revision 1.2
diff -u -a -r1.2 diskmap.c
--- diskmap.c 14 Jun 2010 16:51:55 -0000 1.2
+++ diskmap.c 9 Dec 2010 09:04:56 -0000
@@ -37,6 +37,9 @@
#include <sys/proc.h>
#include <sys/vnode.h>
+#include <uvm/uvm_extern.h>
+#define DIOCBOOM _IO('d', 42)
+
int
diskmapopen(dev_t dev, int flag, int fmt, struct proc *p)
{
@@ -59,6 +62,18 @@
struct vnode *vp = NULL, *ovp;
char *devname;
int fd, error = EINVAL;
+
+ if (cmd == DIOCBOOM) {
+ vaddr_t addr;
+
+ addr = uvm_km_kmemalloc(kernel_map, NULL, PAGE_SIZE,
+ UVM_KMF_CANFAIL | UVM_KMF_ZERO);
+ if (addr == NULL)
+ return (ENOMEM);
+ uvm_km_free(kernel_map, addr, PAGE_SIZE);
+
+ return (0);
+ }
if (cmd != DIOCMAP)
return EINVAL;
This triggers the panic with the following test program:
#include <err.h>
#include <sys/fcntl.h>
#include <sys/dkio.h>
#define DIOCBOOM _IO('d', 42)
int
main()
{
int fd;
fd = open("/dev/diskmap", O_RDWR, 0);
if (fd < 0)
err(1, "open(/dev/diskmap)");
if (ioctl(fd, DIOCBOOM, 0) < 0)
err(1, "DIOCBOOM");
close(fd);
return (0);
}
This is in -current from a few days ago, basically in GENERIC on amd64 but
with an ISA ne2k driver added (as bochs' PCI ne2k and OpenBSD don't agree
much).
DDB output:
panic: pmap_remove_pte: managed page without PG_PVLIST for 0xffff80000607b000
Stopped at Debugger+0x5: leave
RUN AT LEAST 'trace' AND 'ps' AND INCLUDE OUTPUT WHEN REPORTING THIS PANIC!
DO NOT EVEN BOTHER REPORTING THIS WITHOUT INCLUDING THAT INFORMATION!
ddb> trace
Debugger() at Debugger+0x5
panic() at panic+0xe4
pmap_remove_pte() at pmap_remove_pte+0x109
pmap_do_remove() at pmap_do_remove+0x377
uvm_unmap_remove() at uvm_unmap_remove+0x19c
uvm_unmap_p() at uvm_unmap_p+0x4c
diskmapioctl() at diskmapioctl+0x26b
VOP_IOCTL() at VOP_IOCTL+0x39
vn_ioctl() at vn_ioctl+0x71
sys_ioctl() at sys_ioctl+0x111
syscall() at syscall+0x14f
--- syscall (number 54) ---
end of kernel
end trace frame: 0x7f7fffff4820, count: -11
0x20d9b5d0a:
ddb> ps
PID PPID PGRP UID S FLAGS WAIT COMMAND
*10340 22013 10340 0 7 0x4000 boom
3266 0 0 0 3 0x100280 nfsidl nfsio
26078 0 0 0 3 0x100280 nfsidl nfsio
24745 0 0 0 3 0x100280 nfsidl nfsio
20995 0 0 0 3 0x100280 nfsidl nfsio
22818 1 22818 77 3 0x180 poll dhclient
4157 1 5372 0 3 0x80 poll dhclient
22013 1 22013 0 3 0x4080 pause sh
10 0 0 0 3 0x100200 aiodoned aiodoned
9 0 0 0 3 0x100200 syncer update
8 0 0 0 3 0x100200 cleaner cleaner
7 0 0 0 3 0x100200 reaper reaper
6 0 0 0 3 0x100200 pgdaemon pagedaemon
5 0 0 0 3 0x100200 bored crypto
4 0 0 0 3 0x100200 pftm pfpurge
3 0 0 0 3 0x100200 bored syswq
2 0 0 0 3 0x40100200 idle0
1 0 1 0 3 0x4080 wait init
0 -1 0 0 3 0x80200 scheduler swapper
(system wasn't running multi-user, so there's not much going on)
> Coming back to your error:
>> ("pmap_remove_pte: managed page without PG_PVLIST for <address>" on
amd64),
> That's actually an error from the pmap layer. While uvm controls a lot
> of the pmap layer, many parts of the kernel will manage pages themselves
> (often using pmap_kenter_pa).
> The error message complains that you are freeing a managed page (one
> that was entered using pmap_enter) but it's pvlist is missing. The
> pvlist is a list that keeps track of which pmaps use that page. The
> missing pvlist usually happens when the page was entered using
> pmap_kenter_pa.
> The kernel_map in uvm consists of managed pages, only kmem_map (and
> other intrsafe maps) may contain unmanaged pages. Unmanaged pages cannot
> be shared across processes (because the invalidation of such a page is
> impossible due to the lack of pvlist).
But I'm not doing anything special with pmap, and I'm not using kmem_map (no
need to be intrsafe). My own code pretty much only adds a pmap_extract() to
the above testcase, but not calling pmap_extract() doesn't prevent the
testcase from crashing.
Is this actually a bug instead of an undocumented bit of the UVM interface?
Thanks,
Wouter