Kernel panics from mmap()'d memory

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi!

I'm writing a kernel module that allocates 4 Mb of kernel memory which
is mmap'd by a daemon via a character device.

For the mmap implementation, I have a vm_operations_struct.nopage
handler routine:

/**
 * sahn_vm_nopage - 'nopage' vm handler, maps shared memory
 * @vma: vma struct
 * @vaddr: virtual address that caused fault
 * @type: output-only param, type of fault
 */
static struct page* sahn_vm_nopage(struct vm_area_struct *vma,
        unsigned long vaddr, int *type)
{
    struct page *page;
    struct sahn_priv *priv = (struct sahn_priv*) vma->vm_private_data;
    unsigned long physaddr, pageframe;

    if ( priv == NULL )
        return NOPAGE_OOM;

    if ( vaddr > vma->vm_end )
        return NOPAGE_SIGBUS;

    physaddr = (vaddr - vma->vm_start) + virt_to_phys(priv->shared);
    pageframe = physaddr >> PAGE_SHIFT;

    page = pfn_to_page(pageframe);

    SAHNDP(1, "In sahn_vm_nopage; mapping physaddr %x, pageframe %x\n",
        (unsigned int) physaddr, (unsigned int) pageframe);

    get_page(page);
    if ( type )
        *type = VM_FAULT_MINOR;
    return page;
}

And here's the mmap routine:



/**
 * sahn_char_mmap - map shared memory
 * @filp file struct
 * @vma vma area struct
 */
int sahn_char_mmap(struct file* filp, struct vm_area_struct *vma)
{
    unsigned long start = vma->vm_start;
    unsigned long size = vma->vm_end - start;
    int id = iminor(filp->f_dentry->d_inode);
    struct net_device* dev = sahn_get_sahndevice(id);
    struct sahn_priv* priv;
    unsigned long pagesize, origsize;

    if ( !dev )
    {
        SAHNERRP("Couldn't find device while trying to mmap()!\n");
        return -EINVAL;
    }

    // Make sure mmap requests reading and writing
    if ( !(vma->vm_flags & (VM_WRITE | VM_READ)) )
    {
        SAHNERRP("Undefined mmap() access.\n");
        return -EINVAL;
    }

    // Verify requested size is = size of shared area
    origsize = sizeof(struct sahn_shared);
    for ( pagesize=PAGE_SIZE; pagesize < origsize; pagesize <<= 1 );
    if ( size > pagesize )
    {
        SAHNERRP("Requested mmap() size out of range.\n");
        return -EINVAL;
    }

    SAHNDP(3, "Configuring mmap() system for device %s (to user addr.
%p)\n", dev->name, (void*) start);

    priv = netdev_priv(dev);

    priv->user_offset = start;

    vma->vm_flags |= VM_RESERVED;
    vma->vm_ops = &sahn_vm_ops;
    vma->vm_private_data = priv;

    return 0;
}



All works well if I only access memory (from the daemon) in the first
page of the shared area.  But if I go over that boundary, and access any
other page than the first, I get kernel panics, which ultimately kill
the system.

Here's a sequence of screen captures: http://mike.tyson.id.au/panics
(That's the best capture speed I could get; skips some information)


Runs like:

    // Map memory
    shared = (struct sahn_shared*)
                mmap(0, sizeof(struct sahn_shared),
                    PROT_READ|PROT_WRITE,
                    MAP_SHARED, fd, 0);

    int i, tmp;
    for ( i=0; i<10; i++ )
    {
        tmp = ((char*) shared)[i];
        ((char*) shared)[i]++;
        ((char*) shared)[i]--;
    }


.. Work fine, whereas if I change the end condition for that for loop
from 10 to, say 16000, the machine crashes after one to three runs.
(Note that it doesn't always happen on the first run.. Sometimes takes
up to three)

What am I doing wrong here?

Cheers =)

Mike




- --
Mike Tyson <mike@xxxxxxxxxxx>
M: (+61) 0407 754 124
W: http://mike.tyson.id.au
B: http://mike.tyson.id.au/blog
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDTKQs/eih+gEb7pQRAkiuAKCbN34I1hGiQeqB9PFryRmNs8N8YwCgqhOQ
lM6al1n3l+wgKzPNhXuMofs=
=4CCW
-----END PGP SIGNATURE-----

--
Kernelnewbies: Help each other learn about the Linux kernel.
Archive:       http://mail.nl.linux.org/kernelnewbies/
FAQ:           http://kernelnewbies.org/faq/


[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux