有时候需要在Linuxkernel--大多是在需要调试的驱动程序--中读写文件数据。在kernel中操作文件没有标准库可用,需要利用kernel的一些函数,这些函数主要有: filp_open() filp_close(), vfs_read()vfs_write(),set_fs(),get_fs()等,这些函数在linux/fs.h和asm/uaccess.h头文件中声明。下面介绍主要步骤:
1. 打开文件
filp_open()在kernel中可以打开文件,其原形如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/syscalls.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#define MY_FILE "/root/LogFile"
char buf[128];
struct file *file = NULL;
static int __init init(void)
{
mm_segment_t old_fs;
printk("Hello, I'm the module that intends to write messages to file.\n");
if(file == NULL)
file = filp_open(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
if (IS_ERR(file)) {
printk("error occured while opening file %s, exiting...\n", MY_FILE);
return 0;
}
sprintf(buf,"%s", "The Messages.");
old_fs = get_fs();
set_fs(KERNEL_DS);
file->f_op->write(file, (char *)buf, sizeof(buf), &file->f_pos);
set_fs(old_fs);
filp_close(file, NULL);
file = NULL;
return 0;
}
static void __exit fini(void)
{
if(file != NULL)
filp_close(file, NULL);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
在linux内核编程时,进行系统调用(如文件操作)时如果要访问用户空间的参数,可以用set_fs,get_ds等函数实现访问。get_ds获得kernel的内存访问地址范围(IA32是4GB),set_fs是设置当前的地址访问限制值,get_fs是取得当前的地址访问限制值。进程由用户态进入核态,linux进程的task_struct结构中的成员addr_limit也应该由0xBFFFFFFF变为0xFFFFFFFF(addr_limit规定了进程有用户态核内核态情况下的虚拟地址空间访问范围,在用户态,addr_limit成员值是0xBFFFFFFF也就是有3GB的虚拟内存空间,在核心态,是0xFFFFFFFF,范围扩展了1GB)。使用这三个函数是为了安全性。为了保证用户态的地址所指向空间有效,函数会做一些检查工作。
如果set_fs(KERNEL_DS),函数将跳过这些检查。
下面是典型用法:
//#define __NO_VERSION__
//#define __KERNEL__
//#define MODULE
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>;
#include <linux/init.h>;
#include <linux/module.h>;
#include <linux/kernel.h>;
#include <linux/file.h>;
#include <linux/fs.h>;
#include <linux/sched.h>;
#include <asm/uaccess.h>;
#include <asm/processor.h>;
int init_module(void)
{
struct file *fp = NULL;
char buf[100];
int i;
for(i=0;i<100;i++)
buf[i] = 0;
printk(KERN_ALERT "Hello ,ftyjl.\n");
fp = filp_open("/tmp/8899", 3, 0); //内核的open函数,返回struct file *
if (fp == NULL)
printk(KERN_ALERT "filp_open error ,ftyjl.\n");
mm_segment_t old_fs=get_fs(); //下面两步,设置当前执行环境为kernel_ds,否则会出错
set_fs(get_ds());
fp->f_op->read(fp, buf, 2, &fp->f_pos); //调用真正的read
set_fs(old_fs); //恢复环境
printk(KERN_ALERT "ftyjl:read[%s]\n", buf);
printk(KERN_ALERT "end of Hello ,ftyjl.\n");
return 0;
}
void cleanup_module(void)
{
printk(KERN_ALERT "Good bye, ftyjl\n");
}
MODULE_LICENSE("Proprietary");
转自:http://blog.csdn.net/tommy_wxie/article/details/8193954
http://blog.csdn.net/zjc0888/article/details/7266730