为什么 mmap 在 Linux 内核模块 return MAP_FAILED 中定义?

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

我正在尝试使用 linux 3.10.10 中的 mmap 方法映射用户 space 中的内核缓冲区。但它正在返回 MAP_FAILED。为什么映射缓冲区失败。

内核模块

#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);

申请代码

#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;
}

我总是以 "MAP failed" 结束。 我的代码有问题吗?

好吧,我无法发表评论,所以我 post 不是一个答案,但我希望它仍然有用:

我不确定驱动程序,但您可以使用 mmap 上的 errno 方法 (http://man7.org/linux/man-pages/man3/errno.3.html) 更好地回答它失败的原因:

在正确的地方添加您的应用程序代码:

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

或者如果您不想打印错误号,您可以使用以下命令:

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

来自 How to know what the 'errno' means?

第一个问题是您试图使用 fopen 打开文件并将 return 值放入整数中,但 fopen 没有 return 一个整数。它 returns FILE *。这告诉我你忽略了编译器警告和错误。这是个坏主意:它们的生产是有原因的。

第二个问题是您实际上确实需要一个整数文件句柄才能将其作为参数提供给 mmap(2)。为此,您应该调用 open(2) 而不是 fopen(3))。

此代码可能还有其他问题,但这只是一个开始。

debugfs 无法处理mmap

我知道这不是你的确切情况,但它也会导致 mmap 失败并显示 MAP_FAILED,这可能对未来的 Google 员工有帮助:https://patchwork.kernel.org/patch/9252557/

这里是 fully working procfs example with an userland test.