Abdul Basit
Abdul Basit

Reputation: 33

Why does mmap defined in a Linux kernel module return MAP_FAILED?

I am trying to map a kernel buffer in user space using mmap method in linux 3.10.10. But it is returning MAP_FAILED. Why it is failed to map the buffer.

Kernel module

#include <linux/module.h>  /* Needed by all modules */
#include <linux/kernel.h>  /* Needed for KERN_ALERT */
#include <linux/init.h>         /* Needed for the macros */
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <linux/io.h>
//#include <linux/malloc.h>

#include <linux/mm.h>  /* mmap related stuff */

long long  *buf1;
long long* buf;


static int driver_mmap(struct file *file, struct vm_area_struct *vma)
{
  vma->vm_flags |= VM_LOCKED|VM_SHARED;

  int i = remap_pfn_range(vma, vma->vm_start,
             virt_to_phys(buf) >> PAGE_SHIFT,
             vma->vm_end-vma->vm_start, vma->vm_page_prot);

  SetPageReserved(virt_to_page(buf));
  printk("MMAP \n");
  return 0;
}


struct file_operations proc_fops =
{
  mmap:driver_mmap,
};
int init_module_test(void)
{
  int i;
  buf1 = kmalloc(4096, __GFP_COLD|GFP_DMA);

  buf = ((int)buf1 + PAGE_SIZE -1) & PAGE_MASK;
  printk("<1>Hello world1\n");
  for (i = 0; i < 512; i++)
  {
    buf[i] = (long long) i + 1;
  }
  proc_create ("mmap_example",0,NULL, &proc_fops);
  printk("<1>Hello world3\n");
  printk("<1>BUF1 = 0x%08x\n BUF = 0x%08x\n", buf1,buf);
  return 0;
}


void cleanup_module_test(void)
{
  remove_proc_entry ("mmap_example", NULL);
  kfree(buf1);
  printk("Goodbye world\n");
}



module_init(init_module_test);
module_exit(cleanup_module_test);

Application code

#include<stdio.h>
#include<stdlib.h>
#include<sys/mman.h>

int main(void)
{
  int fd, i;
  long long *msg = NULL;

  if ((fd = fopen("/proc/mmap_example", "r")) < 0)
  {
    printf("File not opened");
  }
  msg = mmap(NULL, 4096, PROT_READ, MAP_SHARED, fd, 0);
  if (msg == MAP_FAILED)
  {
    printf("MAP failed");
    return 0;
  }
  for (i = 0; i < 512; i++)
    printf("0x%llx,", msg[i]);

  fclose(fd);
  return 0;
}

I always end up seing "MAP failed". Is there something wrong with my code?

Upvotes: 1

Views: 3722

Answers (3)

debugfs can't handle mmap

I know this is not your exact case, but it also makes mmap fail with MAP_FAILED, and it may help future Googlers: https://patchwork.kernel.org/patch/9252557/

And here is a fully working procfs example with an userland test.

Upvotes: 0

Gil Hamilton
Gil Hamilton

Reputation: 12357

The first problem is that you are attempting to use fopen to open a file and placing the return value in an integer, but fopen doesn't return an integer. It returns FILE *. This tells me you are ignoring compiler warnings and errors. That's a bad idea: they're produced for a reason.

The second problem is that you actually do need an integer file handle in order to provide it as an argument to mmap(2). For that, you should be calling open(2) (not fopen(3)).

There may well be additional problems with this code, but that's a start.

Upvotes: 2

evoliptic
evoliptic

Reputation: 343

well, i can't comment so i post an answer that is not one, but i hope it will be still useful:

i'm not sure about the driver, but you can use the errno method (http://man7.org/linux/man-pages/man3/errno.3.html) on mmap to have a better answer on why it's failing:

add in your application code at the right place:

#include <errno.h>
printf("%i",errno);

or you could maybe use the following if you don't want to print the errno :

cpp -dM /usr/include/errno.h | grep 'define E' | sort -n -k 3

from How to know what the 'errno' means?

Upvotes: 1

Related Questions