2016-04-21 19 views
3

Я разрабатываю модуль ядра Linux. Я хочу использовать mmap и proc файловую систему для обмена памятью между ядром и пользовательским пространством. Я реализовал некоторые части, но я не знаю, как это сделать.Как использовать разделяемую память mmap и proc между ядром и пользовательским пространством

Я хочу что-то написать (sk_buff) в модуле ядра и прочитать их в пользовательском пространстве (прочтите файл proc и сохраните файл). Что мне делать? Я не знаю значения file_operations; следует ли использовать fops.write или что-то еще?

Вот мой код демо (модуль для Linux 3.16):

#include <linux/version.h> 
#include <linux/module.h> 
#include <linux/proc_fs.h> 
#include <linux/mm.h> 
#include <linux/fs.h> 
#include <linux/seq_file.h> 

#define PROC_MEMSHARE_DIR "memshare" 
#define PROC_MEMSHARE_INFO "phymem_info" 
#define PROC_MMAP_FILE "mmap" 

/* alloc one page. 4096 bytes */ 
#define PAGE_ORDER 0 
/* this value can get from PAGE_ORDER */ 
#define PAGES_NUMBER 1 

struct proc_dir_entry *proc_memshare_dir ; 
unsigned long kernel_memaddr = 0; 
unsigned long kernel_memsize= 0; 

int proc_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
    unsigned long page; 
    page = virt_to_phys((void*)kernel_memaddr) >> PAGE_SHIFT; 

    if (remap_pfn_range(vma, vma->vm_start, page, (vma->vm_end - vma->vm_start), 
       vma->vm_page_prot)) 
    { 
     printk("remap failed..."); 
     return -1; 
    } 
    vma->vm_flags |= (VM_DONTDUMP|VM_DONTEXPAND); 
    printk("remap_pfn_rang page:[%lu] ok.\n", page); 
    return 0; 
} 

static int proc_show_meminfo(struct seq_file *m, void *v) { 
    seq_printf(m, "%08lx %lu\n",__pa(kernel_memaddr), kernel_memsize); 
    return 0; 
} 

static int proc_open_meminfo(struct inode *inode, struct file *file) { 
    return single_open(file, proc_show_meminfo, NULL); 
} 

static const struct file_operations read_phymem_info_fops = { 
    .owner = THIS_MODULE, 
    .open = proc_open_meminfo, 
    .read = seq_read, 
    .llseek = seq_lseek, 
    .release = seq_release 
}; 

static const struct file_operations proc_mmap_fops = { 
    .owner = THIS_MODULE, 
    .mmap = proc_mmap 
}; 

static int __init init(void) 
{ 
    /* build proc dir "memshare"and two proc files: phymem_addr, phymem_size in the dir */ 
    proc_memshare_dir = proc_mkdir(PROC_MEMSHARE_DIR, NULL); 
    proc_create_data(PROC_MEMSHARE_INFO, 0, proc_memshare_dir, &read_phymem_info_fops,NULL); 
    proc_create_data(PROC_MMAP_FILE, 0, proc_memshare_dir, &proc_mmap_fops,NULL); 

    /* alloc one page */ 
    kernel_memaddr =__get_free_pages(GFP_KERNEL, PAGE_ORDER); 
    if (!kernel_memaddr) { 
     printk("Allocate memory failure!/n"); 
    } else { 
     SetPageReserved(virt_to_page(kernel_memaddr)); 
     kernel_memsize = PAGES_NUMBER * PAGE_SIZE; 
     printk("Allocate memory success!. The phy mem addr=%08lx, size=%lu\n", __pa(kernel_memaddr), kernel_memsize); 
    } 
    return 0; 
} 

static void __exit fini(void) 
{ 
    printk("The content written by user is: %s\n", (unsigned char*) kernel_memaddr); 
    ClearPageReserved(virt_to_page(kernel_memaddr)); 
    free_pages(kernel_memaddr, PAGE_ORDER); 
    remove_proc_entry(PROC_MEMSHARE_INFO, proc_memshare_dir); 
    remove_proc_entry(PROC_MEMSHARE_DIR, NULL); 
    return; 
} 
module_init(init); 
module_exit(fini); 
MODULE_LICENSE("GPL"); 
MOUDLE_AUTHOR("wack"); 
MODULE_DESCRIPTION("Kernel memory share module."); 

А вот программа в пользовательском пространстве:

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

int main(int argc, char *argv[]) 
{ 
    char *str ; 
    if (argc != 2) { 
     printf("Usage: %s string\n", argv[0]); 
     return 0; 
    } 

    unsigned long phymem_addr, phymem_size; 
    char *map_addr; 
    char s[256]; 
    int fd; 

    /*get the physical address & size of allocated memory in kernel*/ 
    fd = open("/proc/memshare/phymem_info", O_RDONLY); 
    if (fd < 0) { 
     printf("cannot open file /proc/memshare/phymem_info\n"); 
     return 0; 
    } 
    read(fd, s, sizeof(s)); 
    sscanf(s, "%lx %lu", &phymem_addr,&phymem_size); 
    close(fd); 

    printf("phymem_addr=%lx, phymem_size=%lu\n", phymem_addr, phymem_size); 
    /*memory map*/ 
    int map_fd = open("/proc/memshare/mmap", O_RDWR|O_SYNC); 
    if (map_fd < 0) { 
     printf("cannot open file /proc/memshare/mmap\n"); 
     return -1; 
    } 
    map_addr = mmap(NULL, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr); 
    if (map_addr ==MAP_FAILED) { 
     perror("mmap"); 
     printf("MAP_FAILED : %s",map_addr); 
     close(map_fd); 
     return -1; 
    } else{ 
     printf("mmap: %s \n",map_addr); 
     printf("addr: %p \n",map_addr); 
     printf("addr: %d \n",*map_addr); 
    } 
    //memcpy(map_addr, argv[1],sizeof(argv)); 
    strcpy(map_addr,argv[1]); 
    memcpy(str,map_addr,256); 
    printf("str is :%s \n",str); 
    int ret = munmap(map_addr, phymem_size); 
    if (ret) { 
     printf("munmap failed:%d \n",ret); 
    } 
    close(map_fd); 
    return 0; 
} 
+0

Я не совсем undestand: вы уже выполнили чтение из вашего файла 'proc' (ядро записывает на него, читает с него пользователя). Итак, в чем проблема? Вы хотите разрешить пользователю писать файл 'proc'? – Tsyvarev

+0

Я хочу написать файл proc в модуле ядра, и я не знаю, как это сделать. Этот код только читал файл, но не записывал ... Можете ли вы рассказать мне, как выгрузить сообщение ядра в файл proc? (Действительно, я хочу выгрузить sk_buff в proc и прочитать его в пространстве пользователя) – wack

+0

'seq_file' помогает только при чтении из файла. Вы должны реализовать метод 'fops.write' для записи в файл proc. – Tsyvarev

ответ

0

Лучшее, что я был в состоянии сделать на собственный:

  • В этой проблеме я хочу написать sk_buff в общую память и прочитать ее из пользовательского пространства.
  • Здесь я использую крюк netfilter PRE_ROUTING, и в моем крюке я могу получить skb.
  • На вопрос о том, как писать в общую память, как предложил пользователь Цыварев, я могу написать память I malloc напрямую.

Первого таНос разделяемая память:

нуждается
kernel_memaddr = __get_free_pages(GFP_KERNEL, PAGE_ORDER); //or use kmalloc vmalloc 
SetPageReserved(virt_to_page(kernel_memaddr)); 

пространства пользователя, чтобы знать памяти физического адреса (прок чтения):

static int proc_show_meminfo(struct seq_file *m, void *v) { 
    seq_printf(m, "%08lx %lu\n",__pa(kernel_memaddr), kernel_memsize); 
    return 0; 
} 

В proc_mmap(), нам нужна remap_pfn_range память:

int proc_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
    unsigned long page; 
    page = virt_to_phys((void *)kernel_memaddr) >> PAGE_SHIFT; 

    if(remap_pfn_range(vma, vma->vm_start, page, (vma->vm_end - vma->vm_start), 
     vma->vm_page_prot)) 
    { 
     printk("remap failed..."); 
     return -1; 
    } 
    vma->vm_flags |= (VM_DONTDUMP|VM_DONTEXPAND); 
    printk("remap_pfn_rang page:[%lu] ok.\n", page); 
    return 0; 
} 

Когда мы хотим записать данные в общую память, просто скопируйте его:

memcpy((void *)(memaddr + offset),data, dataLen); //data is what you want to write 

И в пользовательском пространстве, после того, как мы получим kernel_memaddr, мы используем mmap(), чтобы получить адрес

map_addr = mmap(NULL, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, map_fd, phymem_addr); 
memcpy(str,map_addr,256);