首先分析一下sys_read系统调用(内核版本为2.6.19.4)。
源代码如下(摘自fs/read_write.c)
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) { struct file *file; ssize_t ret = -EBADF; int fput_needed; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); file_pos_write(file, pos); fput_light(file, fput_needed); } return ret; }
这里用到了fget_light(),file_pos_read(),vfs_read(),file_pos_write(),fput_light()。
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) { ssize_t ret; if (!(file->f_mode & FMODE_READ)) return -EBADF; if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read)) return -EINVAL; if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) return -EFAULT; ret = rw_verify_area(READ, file, pos, count); if (ret >= 0) { count = ret; if (file->f_op->read) ret = file->f_op->read(file, buf, count, pos); else ret = do_sync_read(file, buf, count, pos); if (ret > 0) { fsnotify_access(file->f_path.dentry); add_rchar(current, ret); } inc_syscr(current); } return ret; }
通过源码可以看出,内核中无法直接使用sys_read()来进行文件操作,因为sys_read()总会在当前进程的struct files_struct中查找文件。
(除非内核想对当前进程打开的某个文件进行操作,不知道这种情况是否存在)
内核可以使用vfs_read()来进行文件操作,一个例子如下
ssize_t nread; loff_t pos; mm_segment_t old_fs; struct file *file=NULL; old_fs = get_fs(); set_fs(KERNEL_DS); file = filp_open("filename", O_RDONLY, 0); if(IS_ERR(file)) { printk(KERN_INFO"filp open error/n"); set_fs(old_fs); return -1; } else printk(KERN_INFO"filp open succeeded/n"); pos=0; nread = vfs_read(file, (char __user *)buffer, len, &pos); if(nread < 0) printk(KERN_INFO"vfs_read failed!/n"); else if(nread < len) printk(KERN_INFO"vfs_read PART data/n"); else printk(KERN_INFO"vfs_read succeeded/n"); if(file)filp_close(file, NULL); set_fs(old_fs);
主要区别就是在操作前调用set_fs()(位于arch/x86/boot/boot.h)将当前fs段寄存器设为KERNEL_DS,在完成后再调用该函数将fs段寄存器设为原来的值,这样做的原因尚不明,希望高手指点。
问题:
1.内核中atomic_read()加锁是怎么进行的
2.还可调用kernel_read()(位于fs/exec.c,在include/linux/fs.h中声明)来直接读文件,该函数中完成了fs段期存期的保存,但找不到对应的kernel_write()函数