2016-04-13 21 views
3

私は、mmapを使ってカーネルで作成された共有メモリセグメントを持っています。カーネルとユーザー空間の両方からこのマップされたメモリにアクセスする必要があります。同時アクセスからメモリを保護するためにどのようなメカニズムを使用する必要がありますか?カーネルとユーザ空間の間の共有メモリセグメントの保護

カーネルモジュール:

#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/fs.h> 
#include <linux/debugfs.h> 
#include <linux/slab.h> 
#include <linux/mm.h> 

#ifndef VM_RESERVED 
# define VM_RESERVED (VM_DONTEXPAND | VM_DONTDUMP) 
#endif 

struct dentry *file; 

struct mmap_info 
{ 
    char *data;    
    int reference;  
}; 

void mmap_open(struct vm_area_struct *vma) 
{ 
    struct mmap_info *info = (struct mmap_info *)vma->vm_private_data; 
    info->reference++; 
} 

void mmap_close(struct vm_area_struct *vma) 
{ 
    struct mmap_info *info = (struct mmap_info *)vma->vm_private_data; 
    info->reference--; 
} 

static int mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) 
{ 
    struct page *page; 
    struct mmap_info *info;  

    info = (struct mmap_info *)vma->vm_private_data; 
    if (!info->data) 
    { 
     printk("No data\n"); 
     return 0;  
    } 
    page = virt_to_page(info->data);  
    get_page(page); 
    vmf->page = page;    
    return 0; 
} 

struct vm_operations_struct mmap_vm_ops = 
{ 
    .open =  mmap_open, 
    .close = mmap_close, 
    .fault = mmap_fault,  
}; 

int op_mmap(struct file *filp, struct vm_area_struct *vma) 
{ 
    vma->vm_ops = &mmap_vm_ops; 
    vma->vm_flags |= VM_RESERVED;  
    vma->vm_private_data = filp->private_data; 
    mmap_open(vma); 
    return 0; 
} 

int mmapfop_close(struct inode *inode, struct file *filp) 
{ 
    struct mmap_info *info = filp->private_data; 
    free_page((unsigned long)info->data); 
    kfree(info); 
    filp->private_data = NULL; 
    return 0; 
} 

int mmapfop_open(struct inode *inode, struct file *filp) 
{ 
    struct mmap_info *info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);  
    info->data = (char *)get_zeroed_page(GFP_KERNEL); 
    memcpy(info->data, "hello from kernel this is file: ", 32); 
    memcpy(info->data + 32, filp->f_dentry->d_name.name, strlen(filp->f_dentry->d_name.name)); 
    /* assign this info struct to the file */ 
    filp->private_data = info; 
    return 0; 
} 

static const struct file_operations mmap_fops = { 
    .open = mmapfop_open, 
    .release = mmapfop_close, 
    .mmap = op_mmap, 
}; 

static int __init mmapexample_module_init(void) 
{ 
    file = debugfs_create_file("mmap_example", 0644, NULL, NULL, &mmap_fops); 
    return 0; 
} 

static void __exit mmapexample_module_exit(void) 
{ 
    debugfs_remove(file); 
} 

module_init(mmapexample_module_init); 
module_exit(mmapexample_module_exit); 
MODULE_LICENSE("GPL"); 

ユーザースペース:

#include <stdio.h> 
#include <string.h> 
#include <fcntl.h> 
#include <sys/mman.h> 

#define PAGE_SIZE  4096 

int main (int argc, char **argv) 
{ 
    int configfd; 
    char * address = NULL; 

    configfd = open("/sys/kernel/debug/mmap_example", O_RDWR); 
    if(configfd < 0) 
    { 
     perror("Open call failed"); 
     return -1; 
    } 

    address = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, configfd, 0); 
    if (address == MAP_FAILED) 
    { 
     perror("mmap operation failed"); 
     return -1; 
    } 
    printf("Initial message: %s\n", address); 
    memcpy(address + 11 , "*user*", 6); 
    printf("Changed message: %s\n", address); 
    close(configfd);  
    return 0; 
} 

が、ロックと は、私のようなものを持っていると思います。

+0

関連するコード**を質問自体にコピーしてください**。問題は自立していて、コアコンテンツを理解するために外部リンクを読む必要があると仮定しないでください。 –

+0

ok、コードをコピーして貼り付けた –

答えて

1

カーネルスペースとユーザースペースには、同時アクセス保護のための共有メカニズムがありません。あなたがそれらを望むなら、あなたはそれを自分で実装する必要があります。

それはあなたのカーネルモジュール内に実装され、特別なioctl要求を介してユーザ空間からアクセスし、ミューテックスのいくつかの並べ替えすることができ

カーネル:

DECLARE_WAIT_QUEUE_HEAD(wq); 
int my_mutex_val = 0; 

/* 
* Lock mutex. 
* 
* May be used directly by the kernel or via 'ioctl(MY_CMD_LOCK)' by user. 
*/ 
void my_mutex_lock(void) 
{ 
    spin_lock(&wq.lock); 
    wait_event_interruptible_locked(&wq, my_mutex_val == 0); 
    my_mutex_val = 1; 
    spin_unlock(&wq.lock); 
} 

/* 
* Unlock mutex. 
* 
* May be used directly by the kernel or via 'ioctl(MY_CMD_UNLOCK)' by user. 
*/ 
void my_mutex_unlock(void) 
{ 
    spin_lock(&wq.lock); 
    my_mutex_val = 0; 
    wake_up(&wq); 
    spin_unlock(&wq.lock); 
} 

long unlocked_ioctl (struct file * filp, unsigned int cmd, unsigned long val) 
{ 
    switch(cmd) { 
    case MY_CMD_LOCK: 
     my_mutex_lock(); 
    break; 
    case MY_CMD_UNLOCK: 
     my_mutex_unlock(); 
    break; 
    } 
} 

ユーザー:

int main() 
{ 
    ... 
    ioctl(MY_CMD_LOCK); 
    <read data> 
    ioctl(MY_CMD_UNLOCK); 
    ... 
} 

これはスピンロックのようなものです。この値はmmap-ed領域に格納されます(カーネル空間とユーザ空間の両方に表示されます)。

いずれにしても、ユーザ空間アプリケーションがロック規則に従わない場合、カーネルモジュールを準備する必要があります。これはおそらく、カーネルによって生成されたmmap-ed領域の内容に関する期待を取り消しますが、カーネルモジュールはその場合にはをクラッシュさせるべきではありません。 [これは、上記のコードで標準カーネルのstruct mutexが使用されていない理由です:ユーザスペースがそれを誤って使用する可能性があります]。

0

ioctlの問題は、共有情報 - >データにアクセスするたびにカーネルスイッチが必要になることです。それが問題ないのであれば、ioctlは良いですが、代わりに標準の文字読み書き操作をするのではないのですか?

ロックレスメカニズムを試すこともできます。共有情報 - >データ領域にバリア変数を追加します。ユーザーがアクセスする必要がある場合、バリア変数のatomic_compare_and_xchgを0(未使用)に設定してから1に設定します。カーネルがアクセスする必要がある場合は同じ操作を行いますが、2に設定します。gcc原子組み込みのドキュメント。

+0

また、ユーザ空間とカーネル空間の両方は、共有メモリ領域にアクセスしていないときにバリア変数を0に設定します。 – dturvene

関連する問題