set_fs get_fs

本文介绍在Linux内核编程中如何通过系统调用进行文件操作,包括使用filp_open和filp_close函数打开和关闭文件,以及利用set_fs和get_fs确保地址空间的有效性和安全性。

其实内核里面也可以用系统调用的,直接用read/write是可以的。但要注意几个问题:
一个是要记得编译的时候加上-D__KERNEL_SYSCALLS__
另外源文件里面要#include    <linux/unistd.h> 
如果报错,很可能是因为使用的缓冲区超过了用户空间的地址范围。一般系统调用会要求你使用的缓冲区不能在内核区。这个可以用set_fs()、get_fs()来解决。在读写文件前先得到当前fs:
mm_segment_t   old_fs=get_fs();
并设置当前fs为内核fs:set_fs(KERNEL_DS);
在读写文件后再恢复原先fs:   set_fs(old_fs);
set_fs()、get_fs()等相关宏在文件include/asm/uaccess.h中定义。
个人感觉这个办法比较简单。

另外就是用flip_open函数打开文件,得到struct   file    *的指针fp。使用指针fp进行相应操作,如读文件可以用fp-> f_ops-> read。最后用filp_close()函数关闭文件。filp_open()、filp_close()函数在fs/open.c定义,在include/linux/fs.h中声明。

来源:http://blog.youkuaiyun.com/wzws45/article/details/6063668

-------------------------------------------------------------------------------------------------------------------------------

在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.youkuaiyun.com/zjc0888/article/details/7266730

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值