对于大缓冲区,mmap失败

时间:2014-06-11 16:29:10

标签: c linux linux-kernel linux-device-driver

我正在尝试做一个简单的mmap驱动程序,涵盖了非常基础知识。更像一个简单的示例驱动程序。但我试图使用通过kzalloc分配的大块内存(102页四舍五入到100)。我不明白为什么我的mmap无法从用户空间访问页面。为什么我无法访问超过10-14页?我们的驱动程序是否必须手动处理页面错误?

map_dev.c

#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/mm.h>
//#include <asm-generic/io.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <asm/io.h>

//#define MEM_SIZE  409600
#define MEM_SIZE    4096
#define NPAGES      100
#ifndef VM_RESERVED
# define  VM_RESERVED   (VM_DONTEXPAND | VM_DONTDUMP)
#endif

static void *dmem;
static unsigned int *dmem_area;
static int in_use;

static int dmem_map(struct file *filp,  struct vm_area_struct *vma)
{
    long length = vma->vm_end - vma->vm_start;
    if(length > NPAGES * PAGE_SIZE)
        return -EIO;
    printk("%s: mapping\n", __func__);
    if(remap_pfn_range( vma,
                vma->vm_start,
                virt_to_phys((void *)dmem_area) >> PAGE_SHIFT,
                length, vma->vm_page_prot) < 0)
    {
        printk("%s: Error remap failed\n", __func__);
        return -EAGAIN;
    }
    printk("%s: mapping done\n", __func__);
    return 0;

}
static int mmap_dev_open(struct inode *inod, struct file *file)
{
    int i;
    printk("%s: open\n", __func__);
        if(in_use)
                return -EBUSY;
        in_use++;
    dmem = kzalloc((size_t) ((NPAGES + 2) * PAGE_SIZE), GFP_KERNEL);
    dmem_area = (int *)((((unsigned long)dmem) + PAGE_SIZE - 1) & PAGE_MASK);
    printk("%s: PAGE_SIZE = %lu\n", __func__, PAGE_SIZE);
    printk("%s: dmem = %lu\n", __func__, (unsigned long)(virt_to_page((unsigned long)dmem)));
    for(i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
        SetPageReserved(virt_to_page(((unsigned long)dmem_area) + i));
    for(i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
        printk("i= %d \t: Reserved: %lu dmem: 0x%x \n",
            i,
            (unsigned long)(virt_to_page(((unsigned long)dmem_area) + i)),
            (unsigned int)((unsigned long) dmem_area));
    printk("%s: Validating memory\n", __func__);
    printk("%s: Count size = %lu\n", __func__, (NPAGES - 1)*PAGE_SIZE);
    for(i=0;i < (NPAGES-1) * PAGE_SIZE; i++){
        dmem_area[i] = i;
        if ( (i%4096) == 0)
            printk("%s: checking page : %d\n",__func__, i/4096);
    }

    printk("%s: Final value of i = %d\n", __func__, i);
    dmem_area[0] = 0xFF00FF00;
        return 0;
}

static int mmap_dev_release(struct inode *inod, struct file *file)
{
        in_use = 0;
    //free_page((unsigned long) dmem);
    kfree(dmem);
        return 0;
}

static const struct file_operations mmap_dev_fops = {
    .owner          =       THIS_MODULE,
        .open           =       mmap_dev_open,
        .release        =       mmap_dev_release,
    .mmap       =   dmem_map,
};

static struct miscdevice mmap_dev_device = \
{
        .minor      =   MISC_DYNAMIC_MINOR,
        .name       =   "mmap_dev",
        .fops       =   &mmap_dev_fops,
    .nodename   =   "mmap_dev",
    .mode       =   0666
};

module_driver(mmap_dev_device, misc_register, misc_deregister);

MODULE_DESCRIPTION("Platform device for mmap_dev_driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("MMAP:DRV");
MODULE_AUTHOR("Preetam S Reddy <preetam@mistralsolutions.com>");

以上是内核驱动程序。

以下文件在内核中注册设备。

map_device.c

#include <linux/platform_device.h>
#include <linux/init.h>
#include <linux/module.h>

static struct platform_device mmap_pdev = {
    .name = "mmap_dev",
};

int __init pmod_init(void)
{
    platform_device_register(&mmap_pdev);
    return 0;
}
void __exit pmod_exit(void)
{
    platform_device_unregister(&mmap_pdev);

}

MODULE_DESCRIPTION("Platform device for mmap driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("MMAP:DRV");
MODULE_AUTHOR("Preetam S Reddy <preetam@mistralsolutions.com>");

以下代码适用于用户空间应用。

mmap_example.c

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>

#define NPAGES  100
int main(void)
{
    int len = NPAGES * getpagesize();
    unsigned int *mm_addr;
    printf("page size = %d\n", getpagesize());
    printf("length = %d", len);
    int fd = open("/dev/mmap_dev", O_RDWR);
    getc(stdin);
    printf("Opening file...\n");
    printf("mmap ...\n");
    mm_addr = mmap(0, len, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED, fd, 0);
    if(mm_addr == MAP_FAILED) {
        printf("mmap failed\n");
        perror("mmap");
        exit(-1);
    }
    printf("mmap complete. \n");
    getc(stdin);
    printf("data @[0] : 0x%x\n", mm_addr[0]);
    close(fd);
    #if 1
    printf("um-mmap ...\n");
    munmap(mm_addr, len);
    printf("umap... done\n");
    #endif
    return 0;
}

以下是内核输出的主要部分:

[ 7782.754615] map_dev_open: open
[ 7782.754703] map_dev_open: PAGE_SIZE = 4096
[ 7782.754706] map_dev_open: dmem = 18446719884479594496
[ 7782.754711] i= 0     : Reserved: 18446719884479594496 dmem: 0x62a00000 
[ 7782.754714] i= 4096  : Reserved: 18446719884479594560 dmem: 0x62a00000 
[ 7782.754716] i= 8192  : Reserved: 18446719884479594624 dmem: 0x62a00000 
[ 7782.754719] i= 12288     : Reserved: 18446719884479594688 dmem: 0x62a00000 
[ 7782.754722] i= 16384     : Reserved: 18446719884479594752 dmem: 0x62a00000 
[ 7782.754725] i= 20480     : Reserved: 18446719884479594816 dmem: 0x62a00000 
[ 7782.754728] i= 24576     : Reserved: 18446719884479594880 dmem: 0x62a00000 
[ 7782.754731] i= 28672     : Reserved: 18446719884479594944 dmem: 0x62a00000 
[ 7782.754734] i= 32768     : Reserved: 18446719884479595008 dmem: 0x62a00000 
[ 7782.754736] i= 36864     : Reserved: 18446719884479595072 dmem: 0x62a00000 
[ 7782.754739] i= 40960     : Reserved: 18446719884479595136 dmem: 0x62a00000 
[ 7782.754742] i= 45056     : Reserved: 18446719884479595200 dmem: 0x62a00000 
[ 7782.754745] i= 49152     : Reserved: 18446719884479595264 dmem: 0x62a00000 
[ 7782.754748] i= 53248     : Reserved: 18446719884479595328 dmem: 0x62a00000 
[ 7782.754751] i= 57344     : Reserved: 18446719884479595392 dmem: 0x62a00000 
[ 7782.754753] i= 61440     : Reserved: 18446719884479595456 dmem: 0x62a00000 
[ 7782.754756] i= 65536     : Reserved: 18446719884479595520 dmem: 0x62a00000 
[ 7782.754759] i= 69632     : Reserved: 18446719884479595584 dmem: 0x62a00000 
[ 7782.754762] i= 73728     : Reserved: 18446719884479595648 dmem: 0x62a00000 
[ 7782.754765] i= 77824     : Reserved: 18446719884479595712 dmem: 0x62a00000 
[ 7782.754768] i= 81920     : Reserved: 18446719884479595776 dmem: 0x62a00000 
[ 7782.754770] i= 86016     : Reserved: 18446719884479595840 dmem: 0x62a00000 
[ 7782.754773] i= 90112     : Reserved: 18446719884479595904 dmem: 0x62a00000 
[ 7782.754776] i= 94208     : Reserved: 18446719884479595968 dmem: 0x62a00000 
[ 7782.754779] i= 98304     : Reserved: 18446719884479596032 dmem: 0x62a00000 
[ 7782.754782] i= 102400    : Reserved: 18446719884479596096 dmem: 0x62a00000 
[ 7782.754784] i= 106496    : Reserved: 18446719884479596160 dmem: 0x62a00000 
[ 7782.754787] i= 110592    : Reserved: 18446719884479596224 dmem: 0x62a00000 
[ 7782.754790] i= 114688    : Reserved: 18446719884479596288 dmem: 0x62a00000 
[ 7782.754793] i= 118784    : Reserved: 18446719884479596352 dmem: 0x62a00000 
[ 7782.754796] i= 122880    : Reserved: 18446719884479596416 dmem: 0x62a00000 
[ 7782.754798] i= 126976    : Reserved: 18446719884479596480 dmem: 0x62a00000 
[ 7782.754801] i= 131072    : Reserved: 18446719884479596544 dmem: 0x62a00000 
[ 7782.754804] i= 135168    : Reserved: 18446719884479596608 dmem: 0x62a00000 
[ 7782.754807] i= 139264    : Reserved: 18446719884479596672 dmem: 0x62a00000 
[ 7782.754810] i= 143360    : Reserved: 18446719884479596736 dmem: 0x62a00000 
[ 7782.754812] i= 147456    : Reserved: 18446719884479596800 dmem: 0x62a00000 
[ 7782.754815] i= 151552    : Reserved: 18446719884479596864 dmem: 0x62a00000 
[ 7782.754818] i= 155648    : Reserved: 18446719884479596928 dmem: 0x62a00000 
[ 7782.754821] i= 159744    : Reserved: 18446719884479596992 dmem: 0x62a00000 
[ 7782.754824] i= 163840    : Reserved: 18446719884479597056 dmem: 0x62a00000 
[ 7782.754826] i= 167936    : Reserved: 18446719884479597120 dmem: 0x62a00000 
[ 7782.754829] i= 172032    : Reserved: 18446719884479597184 dmem: 0x62a00000 
[ 7782.754832] i= 176128    : Reserved: 18446719884479597248 dmem: 0x62a00000 
[ 7782.754835] i= 180224    : Reserved: 18446719884479597312 dmem: 0x62a00000 
[ 7782.754837] i= 184320    : Reserved: 18446719884479597376 dmem: 0x62a00000 
[ 7782.754840] i= 188416    : Reserved: 18446719884479597440 dmem: 0x62a00000 
[ 7782.754843] i= 192512    : Reserved: 18446719884479597504 dmem: 0x62a00000 
[ 7782.754846] i= 196608    : Reserved: 18446719884479597568 dmem: 0x62a00000 
[ 7782.754849] i= 200704    : Reserved: 18446719884479597632 dmem: 0x62a00000 
[ 7782.754851] i= 204800    : Reserved: 18446719884479597696 dmem: 0x62a00000 
[ 7782.754854] i= 208896    : Reserved: 18446719884479597760 dmem: 0x62a00000 
[ 7782.754857] i= 212992    : Reserved: 18446719884479597824 dmem: 0x62a00000 
[ 7782.754860] i= 217088    : Reserved: 18446719884479597888 dmem: 0x62a00000 
[ 7782.754863] i= 221184    : Reserved: 18446719884479597952 dmem: 0x62a00000 
[ 7782.754865] i= 225280    : Reserved: 18446719884479598016 dmem: 0x62a00000 
[ 7782.754868] i= 229376    : Reserved: 18446719884479598080 dmem: 0x62a00000 
[ 7782.754871] i= 233472    : Reserved: 18446719884479598144 dmem: 0x62a00000 
[ 7782.754874] i= 237568    : Reserved: 18446719884479598208 dmem: 0x62a00000 
[ 7782.754877] i= 241664    : Reserved: 18446719884479598272 dmem: 0x62a00000 
[ 7782.754879] i= 245760    : Reserved: 18446719884479598336 dmem: 0x62a00000 
[ 7782.754882] i= 249856    : Reserved: 18446719884479598400 dmem: 0x62a00000 
[ 7782.754885] i= 253952    : Reserved: 18446719884479598464 dmem: 0x62a00000 
[ 7782.754888] i= 258048    : Reserved: 18446719884479598528 dmem: 0x62a00000 
[ 7782.754891] i= 262144    : Reserved: 18446719884479598592 dmem: 0x62a00000 
[ 7782.754893] i= 266240    : Reserved: 18446719884479598656 dmem: 0x62a00000 
[ 7782.754896] i= 270336    : Reserved: 18446719884479598720 dmem: 0x62a00000 
[ 7782.754899] i= 274432    : Reserved: 18446719884479598784 dmem: 0x62a00000 
[ 7782.754902] i= 278528    : Reserved: 18446719884479598848 dmem: 0x62a00000 
[ 7782.754905] i= 282624    : Reserved: 18446719884479598912 dmem: 0x62a00000 
[ 7782.754908] i= 286720    : Reserved: 18446719884479598976 dmem: 0x62a00000 
[ 7782.754910] i= 290816    : Reserved: 18446719884479599040 dmem: 0x62a00000 
[ 7782.754913] i= 294912    : Reserved: 18446719884479599104 dmem: 0x62a00000 
[ 7782.754916] i= 299008    : Reserved: 18446719884479599168 dmem: 0x62a00000 
[ 7782.754919] i= 303104    : Reserved: 18446719884479599232 dmem: 0x62a00000 
[ 7782.754922] i= 307200    : Reserved: 18446719884479599296 dmem: 0x62a00000 
[ 7782.754924] i= 311296    : Reserved: 18446719884479599360 dmem: 0x62a00000 
[ 7782.754927] i= 315392    : Reserved: 18446719884479599424 dmem: 0x62a00000 
[ 7782.754930] i= 319488    : Reserved: 18446719884479599488 dmem: 0x62a00000 
[ 7782.754933] i= 323584    : Reserved: 18446719884479599552 dmem: 0x62a00000 
[ 7782.754936] i= 327680    : Reserved: 18446719884479599616 dmem: 0x62a00000 
[ 7782.754938] i= 331776    : Reserved: 18446719884479599680 dmem: 0x62a00000 
[ 7782.754941] i= 335872    : Reserved: 18446719884479599744 dmem: 0x62a00000 
[ 7782.754944] i= 339968    : Reserved: 18446719884479599808 dmem: 0x62a00000 
[ 7782.754947] i= 344064    : Reserved: 18446719884479599872 dmem: 0x62a00000 
[ 7782.754950] i= 348160    : Reserved: 18446719884479599936 dmem: 0x62a00000 
[ 7782.754952] i= 352256    : Reserved: 18446719884479600000 dmem: 0x62a00000 
[ 7782.754955] i= 356352    : Reserved: 18446719884479600064 dmem: 0x62a00000 
[ 7782.754958] i= 360448    : Reserved: 18446719884479600128 dmem: 0x62a00000 
[ 7782.754961] i= 364544    : Reserved: 18446719884479600192 dmem: 0x62a00000 
[ 7782.754963] i= 368640    : Reserved: 18446719884479600256 dmem: 0x62a00000 
[ 7782.754966] i= 372736    : Reserved: 18446719884479600320 dmem: 0x62a00000 
[ 7782.754969] i= 376832    : Reserved: 18446719884479600384 dmem: 0x62a00000 
[ 7782.754972] i= 380928    : Reserved: 18446719884479600448 dmem: 0x62a00000 
[ 7782.754975] i= 385024    : Reserved: 18446719884479600512 dmem: 0x62a00000 
[ 7782.754977] i= 389120    : Reserved: 18446719884479600576 dmem: 0x62a00000 
[ 7782.754980] i= 393216    : Reserved: 18446719884479600640 dmem: 0x62a00000 
[ 7782.754983] i= 397312    : Reserved: 18446719884479600704 dmem: 0x62a00000 
[ 7782.754986] i= 401408    : Reserved: 18446719884479600768 dmem: 0x62a00000 
[ 7782.754989] i= 405504    : Reserved: 18446719884479600832 dmem: 0x62a00000 
[ 8304.656599] systemd-hostnamed[6482]: Warning: nss-myhostname is not installed. Changing the local hostname might make it unresolveable. Please install nss-myhostname!
[ 8407.896365] BUG: Bad page state: 40 messages suppressed
[ 8407.896373] BUG: Bad page state in process a.out  pfn:62a00
[ 8407.896379] page:ffffea00018a8000 count:0 mapcount:0 mapping:          (null) index:0x0
[ 8407.896381] page flags: 0x1ffff0000004400(reserved|head)
[ 8407.896388] Modules linked in: map_dev(OF) map_device(OF) rfcomm bnep binfmt_misc arc4 brcmsmac cordic brcmutil btusb intel_powerclamp b43 bluetooth coretemp kvm_intel kvm mac80211 i915 crct10dif_pclmul crc32_pclmul snd_hda_codec_hdmi cfg80211 snd_hda_codec_realtek uvcvideo snd_hda_intel ssb snd_hda_codec ghash_clmulni_intel drm_kms_helper snd_hwdep aesni_intel snd_pcm videobuf2_vmalloc snd_page_alloc aes_x86_64 drm acer_wmi videobuf2_memops lrw snd_seq_midi i2c_algo_bit gf128mul parport_pc glue_helper snd_seq_midi_event sparse_keymap ppdev videobuf2_core ablk_helper snd_rawmidi cryptd joydev videodev serio_raw lp bcma snd_seq wmi mei_me mei snd_seq_device snd_timer snd intel_ips soundcore mac_hid lpc_ich video parport psmouse tg3 ahci ptp libahci pps_core [last unloaded: map_dev]
[ 8407.896482] CPU: 1 PID: 6444 Comm: a.out Tainted: GF   B      O 3.13.0-27-generic #50-Ubuntu
[ 8407.896485] Hardware name: Acer            TravelMate 4740                /TravelMate 4740                , BIOS V1.12           05/04/2010

1 个答案:

答案 0 :(得分:0)

所以,我认为你担心的printk就是这个:

[ 7782.754711] i= 0     : Reserved: 18446719884479594496 dmem: 0x62a00000 
[ 7782.754714] i= 4096  : Reserved: 18446719884479594560 dmem: 0x62a00000

来自这里:

for(i = 0; i < NPAGES * PAGE_SIZE; i += PAGE_SIZE)
    printk("i= %d \t: Reserved: %lu dmem: 0x%x \n",
        i,
        (unsigned long)(virt_to_page(((unsigned long)dmem_area) + i)),
        (unsigned int)((unsigned long) dmem_area));

因为i每次增加4096,但页面帧编号(来自virt_to_page)不是。如果查看virt_to_page的定义,您会看到它将虚拟地址参数转换为物理地址,然后将其右移PAGE_SHIFT位。因此,您记录的PFN必须增加小于i

您系统上的PAGE_SHIFT是什么?如果是6,那么4096 >> 6 == 64就会解释您的困惑。


现在,这是您在评论中提到的问题。你原来的问题是

  

我不明白为什么我的mmap无法从用户空间访问这些页面。为什么我无法访问超过10-14页?

但你还没有说出症状是什么。当您尝试访问第15页时,会发生什么?

好吧,在用户空间中,您将其作为int访问。因此,您将一次访问4个字节,因此您可以调整for循环。 您获得的地址也是页面帧编号。不是完整的字节地址。