在用户空间和内核

时间:2017-12-29 14:15:09

标签: c linux linux-kernel shared-memory kernel-module

我想在内核和用户空间中的1个特定进程之间创建共享内存机制。此过程将生成将访问此共享内存区域的线程。

在用户空间和内核之间设置区域不一定非常快,但是一旦完成,用户空间进程就不应该进行系统调用,以便从区域写入/读取,并且该区域应该是可访问的任何内核线程(不仅是用户空间进程的内核部分)

理想情况下,我想提出类似的内容:

  • 用户空间使用mmap()或posix_memalign()在自己的地址空间中分配 k 字节,其中 k 通常大于页面。

  • 用户空间使用内核模块或系统调用将mmap()返回的地址发送到内核。

  • 内核使用此地址将此区域映射到其自己的地址空间,以便在进程退出调用后也可以看到在此区域中写入的所有内容。这意味着映射需要在内核虚拟地址空间的其他地方完成

我设法用一个单独的页面来创建一个示例,内核模块执行如下操作:

#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>

#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/errno.h>

#include <linux/pagemap.h>


/*
 * Prototypes
 */
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos);

static struct file_operations led_ops = {
    .owner    = THIS_MODULE,
    .open     = device_open,
    .release  = device_release,
    .write =    device_write
};



static char *my_page_address;
static struct page *kernel_page;


static ssize_t device_write(struct file *filp, const char __user *buf,   s  ize_t count, loff_t * ppos)
{
    int res;
    unsigned long uaddr;
    char addrstr[80];

    unsigned long copied = copy_from_user(addrstr, buf, count);

    struct task_struct *task = current; // getting global current pointer       

    if (copied != 0)
    {
        pr_err("Error);
    }

    //Convert adress to long
    uaddr = simple_strtoul(addrstr, NULL, 0);
    uint64_t new_addr = uaddr;
    printk(KERN_NOTICE "Module received the user adddress %p", uaddr);

    //Locks the current process memory map
    down_read(&current->mm->mmap_sem);

    res = get_user_pages(
                 uaddr,
                 1, //resquest 1 page 
                 1, //write enable                  
                 &kernel_page,
                 NULL);
    if (res == 1) {

        pr_err("Storing shared page");
        my_page_address = kmap(kernel_page);            
    }

    //Release the lock 
    up_read(&current->mm->mmap_sem);


    return count;
}

现在,这似乎适用于单个页面。但是有几个问题浮现在脑海中:

  1. 我可以将此机制扩展到比页面更大的区域吗?理想情况下,我希望内核以与用户空间进程相同的方式访问内存区域(只需在自己的地址空间中拥有自己的指针)

  2. get_user_pages可以将对应于每个页面的vma的指针数组作为最后一个参数。如果用户空间在其地址空间中分配了一个大的连续缓冲区,我可以使用这个vma重新映射内核空间中相同的连续区域吗?

  3. 从我从其他答案中看到的,有人建议从内核中分配内存并允许用户mmap到它(例如here)。但是由于进程的地址空间在进程调用时在内核空间中是可见的,所以应该可以简单地将用户地址空间的一部分重新映射到内核地址空间,对吗?

  4. 编辑:不是this question的副本。我想知道将用户空间区域映射到内核地址空间的好方法。不通过copy_from_user()

    访问它

0 个答案:

没有答案