-
Notifications
You must be signed in to change notification settings - Fork 19
/
Copy pathmmap_simple_kernel.c
120 lines (100 loc) · 2.82 KB
/
mmap_simple_kernel.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/debugfs.h>
#include <linux/mm.h> /* mmap related stuff */
struct dentry *file1;
struct mmap_info {
char *data; /* the data */
int reference; /* how many times it is mmapped */
};
/* keep track of how many times it is mmapped */
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--;
}
/* nopage is called the first time a memory area is accessed which is not in memory,
* it does the actual mapping between kernel and user space memory
*/
struct page *mmap_nopage(struct vm_area_struct *vma, unsigned long address, int *type)
{
struct page *page;
struct mmap_info *info;
/* is the address valid? */
if (address > vma->vm_end) {
printk("invalid address\n");
return NOPAGE_SIGBUS;
}
/* the data is in vma->vm_private_data */
info = (struct mmap_info *)vma->vm_private_data;
if (!info->data) {
printk("no data\n");
return NULL;
}
/* get the page */
page = virt_to_page(info->data);
/* increment the reference count of this page */
get_page(page);
/* type is the page fault type */
if (type)
*type = VM_FAULT_MINOR;
return page;
}
struct vm_operations_struct mmap_vm_ops = {
.open = mmap_open,
.close = mmap_close,
.nopage = mmap_nopage,
};
int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
vma->vm_ops = &mmap_vm_ops;
vma->vm_flags |= VM_RESERVED;
/* assign the file private data to the vm private data */
vma->vm_private_data = filp->private_data;
mmap_open(vma);
return 0;
}
int my_close(struct inode *inode, struct file *filp)
{
struct mmap_info *info = filp->private_data;
/* obtain new memory */
free_page((unsigned long)info->data);
kfree(info);
filp->private_data = NULL;
return 0;
}
int my_open(struct inode *inode, struct file *filp)
{
struct mmap_info *info = kmalloc(sizeof(struct mmap_info), GFP_KERNEL);
/* obtain new memory */
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 my_fops = {
.open = my_open,
.release = my_close,
.mmap = my_mmap,
};
static int __init mmapexample_module_init(void)
{
file1 = debugfs_create_file("mmap_example", 0644, NULL, NULL, &my_fops);
return 0;
}
static void __exit mmapexample_module_exit(void)
{
debugfs_remove(file1);
}
module_init(mmapexample_module_init);
module_exit(mmapexample_module_exit);
MODULE_LICENSE("GPL");