On Thu, Dec 09, 2010 at 10:32:57PM +0100, Wouter Coene wrote:
> 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 you specify NULL as your object, you'll be given intr-safe memory.
You want to use kernel object instead:
addr = uvm_km_kmemalloc(kernel_map, uvm.kernel_object,
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
Exception is expected: page is entered by pmap_kenter_pa, but removed by
pmap_remove.
> > 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?
It's not well documented. I think the object parameter is one of the
more recent additions, actually.
I hope this helps you,
--
Ariane