分类: LINUX
2010-05-12 16:43:31
因为系统调用的函数都是针对用户态的,所以再内核态使用系统调用的函数是就要重新设置环境,跳过系统调用对访问范围的检查。
转自:
原来是在每个进程的进程数据结构里面保存了一个用户空间范围, current->addr_limit,因为内核空间在用户空间上面,所以进程在一般做
系统调用时只要简单检测用户传递参数访问的空间是不是小于等于这个范围就是了。
我看到access.h中有如下定义:
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)
#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
#define get_ds() (KERNEL_DS)
#define get_fs() (current->addr_limit)
#define set_fs(x) (current->addr_limit = (x))
那么读文件时先set_fs(get_ds())是把current->addr_limit 赋为KERNEL_DS了,因为用户空间所访问的地址空间必须是受限制的,
核心态不会有这个限制
The fs value determines whether argument validity checking should be
* performed or not. If get_fs() == USER_DS, checking is performed, with
* get_fs() == KERNEL_DS, checking is bypassed.
在内核中读写文件时为什么会出现EFAULT(-14)错误?
a. 内核文件系统提供的read()和write()之类的函数,期望是对用户态程序服务的,
所以它会验证读写缓冲区不超过用户空间的上限即0xC000 0000。但现在内核中
要读写文件,缓冲区在内核中即地址会超过0xC000 0000。
b. 在读写文件前先得到当前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中定义。