Linux内核态文件操作
# 函数
功能 | 函数 |
---|---|
打开文件 | strcut file* **filp_open**(const char* filename, int open_mode, int mode); |
读取文件 | ssize_t vfs_read(struct file* filp, char __user* buffer, size_t len, loff_t* pos); |
写文件 | ssize_t vfs_write(struct file* filp, const char __user* buffer, size_t len, loff_t* pos); |
关闭文件 | int filp_close(struct file*filp, fl_owner_t id); |
# 读写
注意读写函数的第二个参数 buffer,前面有 __user 修饰符,这就要求这两个 buffer 指针都应该指向用户空间的内存;如果对该参数传递 kernel 空间的指针,这两个函数都会返回失败-EDAULT。
但在 Kernel 中,我们一般不容易生成用户空间的指针,或者不方便独立使用用户空间内存。
## set_fs()、get_fs()
#define get_fs() (current_thread_info()->addr_limit)
#define set_fs(x) (current_thread_info()->addr_limit = (x))
要使得这个函数使用 Kernel 空间的 buffer 也能正常工作,需要使用 set_fs() 函数(也可能是宏定义),该函数只有一个参数,两种取值可能:USER_DS,KERNEL_DS,分别代表用户空间和内核空间,默认情况下,kernle取值为 USER_DS,即对用户空间地址检查并做变换。那么要在这种对内存地址做检查变换的函数中使用内核空间地址,就需要使用 set_fs(KERNEL_DS)进行设置,即改变(current_thread_info()->addr_limit
的大小。 get_fs() 一般也可能是宏定义,它的作用是取得当前的设置。
#define KERNEL_DS ((mm_segment_t) { 0UL })
#define USER_DS ((mm_segment_t) { -0x40000000000UL })
KERNEL_DS 范围很大,意味着可以访问整个内存空间,USER_DS 只能访问用户空间内存。
filp.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <asm/fcntl.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
int __init hello_init(void)
{
unsigned char buf1[12]="hello world.";
unsigned char buf2[12]="kernel file.";
struct file *fp;
mm_segment_t fs;
loff_t pos;
printk("hello enter\n");
fp = filp_open("/home/wifi_group/liyongjun/filp/kernel_file", O_RDWR | O_CREAT, 0644);
if (IS_ERR(fp)) {
printk("create file error\n");
return -1;
}
fs = get_fs();
set_fs(KERNEL_DS);
pos = fp->f_pos;
vfs_write(fp, buf1, sizeof(buf1), &pos);
fp->f_pos = pos;
pos = fp->f_pos;
vfs_write(fp, buf2, sizeof(buf2), &pos);
fp->f_pos = pos;
set_fs(fs);
filp_close(fp, NULL);
return 0;
}
void __exit hello_exit(void)
{
printk("hello exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
Makefile
CROSS_COMPILE=
AR=$(CROSS_COMPILE)ar
ARCH=x86_64
LD=$(CROSS_COMPILE)ld
CC=$(CROSS_COMPILE)gcc
obj-m := filp.o
KDIR := /lib/modules/$(shell uname -r)/build
all:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -rf $(srcdir)*.o $(srcdir)*.mod.o $(srcdir)*.ko $(srcdir)*.mod.c *.o *.mod.o *.ko *.mod.c *.symvers *.order .*.cmd
参考: