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

Reply via email to