给一个Linux向一个page写内容的c代码demo
以下是一个在 Linux 中使用 C 语言向内存页写入内容的示例代码。该程序通过 mmap 分配一个内存页,向其中写入数据,并演示基本操作:
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
| #include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <unistd.h> #include <string.h> #include <errno.h>
int main() { long page_size = sysconf(_SC_PAGESIZE); if (page_size == -1) { perror("sysconf() failed"); return EXIT_FAILURE; }
void *page = mmap( NULL, page_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0 );
if (page == MAP_FAILED) { perror("mmap() failed"); return EXIT_FAILURE; }
printf("成功分配内存页,地址: %p\n", page);
const char *message = "Hello, Linux Page!"; size_t msg_len = strlen(message) + 1;
if (msg_len > page_size) { fprintf(stderr, "消息过长,超出页大小\n"); munmap(page, page_size); return EXIT_FAILURE; }
memcpy(page, message, msg_len);
printf("内存页内容: %s\n", (char *)page);
if (munmap(page, page_size) == -1) { perror("munmap() failed"); return EXIT_FAILURE; }
return EXIT_SUCCESS; }
|
关键步骤说明:
- 获取页大小:使用
sysconf(_SC_PAGESIZE) 动态获取系统内存页大小(通常为 4096 字节)。
- 内存映射:通过
mmap 分配匿名内存页,设置 PROT_READ | PROT_WRITE 权限允许读写,MAP_ANONYMOUS 表示不关联文件。
- 写入数据:使用
memcpy 将字符串复制到内存页,确保不超过页大小。
- 释放内存:使用
munmap 释放映射的内存页。
编译与运行:
1 2
| gcc page_write.c -o page_write ./page_write
|
输出示例:
1 2
| 成功分配内存页,地址: 0x7f8c5e2e6000 内存页内容: Hello, Linux Page!
|
注意事项:
- 匿名映射:此示例使用
MAP_ANONYMOUS,内存页不关联到文件,仅存在于进程内存中。
- 错误处理:检查
mmap 返回值是否为 MAP_FAILED,并处理可能的错误(如内存不足)。
- 页大小适配:代码动态获取页大小,确保在不同系统上兼容。
- 内存安全:写入数据时需确保不越界,避免内存损坏。
如需操作文件映射页,可修改 mmap 参数,传入文件描述符并移除 MAP_ANONYMOUS 标志。
给一个Linux内核态,向page写内容的c代码demo
以下是一个简单的 Linux 内核模块示例,演示在内核态向内存页写入内容的操作:
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
| #include <linux/module.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/string.h>
#define MESSAGE "Hello from Kernel Space!"
static int __init page_writer_init(void) { struct page *page; char *virt_addr;
page = alloc_page(GFP_KERNEL); if (!page) { pr_err("Failed to allocate page\n"); return -ENOMEM; }
virt_addr = kmap(page); if (!virt_addr) { pr_err("Failed to map page\n"); __free_page(page); return -EFAULT; }
strncpy(virt_addr, MESSAGE, strlen(MESSAGE) + 1); pr_info("Written to page: %s\n", virt_addr);
kunmap(page);
__free_page(page);
return 0; }
static void __exit page_writer_exit(void) { pr_info("Module unloaded\n"); }
module_init(page_writer_init); module_exit(page_writer_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("Kernel page writing demo");
|
关键点说明:
内存分配:
- 使用
alloc_page(GFP_KERNEL) 分配单个物理页
- GFP_KERNEL 标志允许在需要时触发直接内存回收
地址映射:
kmap() 将物理页映射到内核虚拟地址空间
- 对于高端内存(32位系统),可能需要特殊处理
- 使用后必须用
kunmap() 解除映射
数据写入:
- 使用内核的
strncpy 进行安全拷贝
- 写入长度不应超过
PAGE_SIZE (通常4096字节)
资源释放:
- 必须显式释放分配的页面
- 实际驱动中可能需要保持页面长期有效
编译与测试:
创建 Makefile:
1 2 3 4 5
| obj-m += page_writer.o all: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules clean: make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
|
编译和加载模块:
1 2 3 4
| make sudo insmod page_writer.ko dmesg | tail sudo rmmod page_writer
|
输出示例:
1 2
| [ 1234.567890] Written to page: Hello from Kernel Space! [ 1234.567891] Module unloaded
|
注意事项:
内存管理:
- 内核态没有自动内存回收机制
- 必须严格配对
alloc_page/__free_page 和 kmap/kunmap
并发安全:
- 在多核环境下需考虑锁机制(如
spin_lock)
- 本示例未包含同步机制,实际使用时需根据场景添加
地址类型:
- 物理地址使用
page_to_phys(page) 转换
- 虚拟地址映射后的有效性仅限于当前上下文
错误处理:
- 必须检查所有可能失败的操作
- 使用
pr_err 输出错误信息到系统日志
该代码展示了内核态内存操作的基本模式,实际使用时需要根据具体需求添加同步机制、错误恢复等功能。对于高性能场景,可能需要使用 kmap_atomic 等原子映射方法。