Je suis en train de développer un module noyau Linux. Je veux utiliser les systèmes de fichiers mmap
et proc
pour partager la mémoire entre le noyau et l'espace utilisateur. J'ai implémenté certaines parties mais je ne sais pas comment le compléter.Comment utiliser la mémoire partagée mmap & proc entre le noyau et l'espace utilisateur
Je veux écrire quelque chose (sk_buff
) dans le module du noyau et les lire dans l'espace utilisateur (lire le fichier proc
et enregistrer le fichier). Que devrais-je faire? Je ne connais pas la signification de file_operations
; devrais-je implémenter fops.write
ou autre chose?
Voici mon code démo, (un module pour 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.");
Et voici le programme de l'espace utilisateur:
#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;
}
je pas tout à fait undestand: Vous avez déjà implémenté la lecture depuis votre fichier 'proc' (le noyau y écrit, l'utilisateur en lit). Alors, qu'est-ce qu'un problème? Voulez-vous autoriser l'utilisateur à écrire votre fichier 'proc'? – Tsyvarev
Je veux écrire le fichier proc dans le module du noyau, et je ne sais pas comment faire. Ce code ne lit que le fichier mais n'écrit pas ... Pouvez-vous me dire comment exporter le message du noyau vers le fichier proc? (En effet, je veux jeter sk_buff au proc et le lire dans l'espace utilisateur) – wack
'seq_file' aide seulement à la lecture à partir du fichier. Vous devez implémenter la méthode 'fops.write' pour écrire dans votre fichier proc. – Tsyvarev