read 操作是任何操作系统里的基本操作,我们来看一下在 linux 内核里,read 文件是怎样实现的。

read 函数在用户空间是由 read 系统调用实现的,由编译器编译成软中断 int 0x80 来进入内核空间,然后在中断门上进入函数 sys_read,从而进入内核空间执行 read 操作。

sys_read 函数定义在 fs / read_write.c 文件,定义如下

asmlinkage ssize_t sys_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){/*file 结构体里的指示文件读写位置的 int 变量读取*/loff_t pos = file_pos_read(file);/*vfs 虚拟文件系统实现 read 操作的地方*/ret = vfs_read(file, buf, count, &pos);/*file 结构体里的指示文件读写位置的 int 变量写入*/file_pos_write(file, pos);/*释放 file 结构体指针*/fput_light(file, fput_needed);}return ret;
}

首先看看 file_pos_read 和 file_pos_write 函数吧,定义如下

static inline loff_t file_pos_read(struct file *file)
{return file->f_pos;
}
static inline void file_pos_write(struct file *file, loff_t pos)
{file->f_pos = pos;
}

定义很简单,读取的时候就是读出 file 结构体的 f_pos,写入的时候就是写到对应变量。指示文件的读写位置的变量就是在 file 结构体里。

然后看一下 fget_light 和 fput_light 函数,定义如下

struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
{struct file *file;/*得到当前进程的 task_struct 的打开的 files 指针*/struct files_struct *files = current->files;*fput_needed = 0;/*如果只有一个进程使用这个结构体,就不必考虑锁,否则要先得到锁才可以读取*/if (likely((atomic_read(&files->count) == 1))){/*从 files 结构体的 fd 数组上得到 file 结构体*/file = fcheck_files(files, fd);}else{/*先上锁,在得到对应结构体*/rcu_read_lock();file = fcheck_files(files, fd);if (file){if (atomic_inc_not_zero(&file->f_count))*fput_needed = 1;else/* Didn't get the reference, someone's freed */file = NULL;}rcu_read_unlock();}return file;
}
static inline void fput_light(struct file *file, int fput_needed)
{ /*释放并减少使用计数*/if (unlikely(fput_needed))fput(file);
}

然后返回来看我们最重要的 vfs_read 函数,vfs_read 函数定义在 fs / read_write.c,定义如下

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;/*安全操作*/ret = security_file_permission(file, MAY_READ);if (!ret){/*如果 file 结构体里有 read 函数,就调用*/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;
}

然后我们在进入 do_sync_read 函数看一看异步读取是怎么实现的,do_sync_read 函数定义在 fs / read_write.c,定义如下

ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{struct iovec iov = {.iov_base = buf, .iov_len = len};struct kiocb kiocb;ssize_t ret;/*初始化读写控制块*/init_sync_kiocb(&kiocb, filp);kiocb.ki_pos = *ppos;kiocb.ki_left = len;/*调用 file_operation 结构体的异步读取函数*/for (;;){ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);if (ret != -EIOCBRETRY)break;wait_on_retry_sync_kiocb(&kiocb);}/*如果没结束,就等待*/if (-EIOCBQUEUED == ret)ret = wait_on_sync_kiocb(&kiocb);*ppos = kiocb.ki_pos;return ret;
}

至此,linux 内核的 read 操作就算 ok 了,linux 内核的 sys_write 和 read 很相似哦,只要弄明白 read,write 也一定是可以搞明白的。

转载于:https://blog.csdn.net/sanwenyublog/article/details/50811957

(SAW:Game Over!)

OS / linux 内核 read 操作源代码分析相关推荐

  1. linux内核网络初始化,Linux内核--网络栈实现分析

    本文分析基于内核Linux Kernel 1.2.13 以后的系列博文将深入分析Linux内核的网络栈实现原理,这里看到曹桂平博士的分析后,也决定选择Linux内核1.2.13版本进行分析. 原因如下 ...

  2. Linux内核--网络栈实现分析(一)--网络栈初始化--转

    转载地址 http://blog.csdn.net/yming0221/article/details/7488828 作者:闫明 本文分析基于内核Linux Kernel 1.2.13 以后的系列博 ...

  3. Linux内核--网络栈实现分析(二)--数据包的传递过程--转

    转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的&qu ...

  4. Linux内核抢占实现机制分析【转】

    Linux内核抢占实现机制分析 转自:http://blog.chinaunix.net/uid-24227137-id-3050754.html [摘要]本文详解了Linux内核抢占实现机制.首先介 ...

  5. linux内核中链表代码分析---list.h头文件分析(二)【转】

    转自:http://blog.chinaunix.net/uid-30254565-id-5637598.html linux内核中链表代码分析---list.h头文件分析(二) 16年2月28日16 ...

  6. 【转载】linux环境下tcpdump源代码分析

    linux环境下tcpdump源代码分析 原文时间 2013-10-11 13:13:02  CSDN博客 原文链接  http://blog.csdn.net/han_dawei/article/d ...

  7. 【嵌入式Linux学习七步曲之第五篇 Linux内核及驱动编程】Linux内核抢占实现机制分析

    Linux内核抢占实现机制分析 Sailor_forever  sailing_9806@163.com 转载请注明 http://blog.csdn.net/sailor_8318/archive/ ...

  8. linux内核中链表代码分析---list.h头文件分析(一)

    linux内核中链表代码分析---list.h头文件分析(一) 16年2月27日17:13:14 在学习数据结构时,有一个重要的知识点就是链表.对于链表的一些基本操作,它的最好学习资料就是内核中的li ...

  9. 在linux内核中操作文件的方法--使用get_fs()和set_fs(KERNEL_DS)

    在linux内核中操作文件的方法--使用get_fs()和set_fs(KERNEL_DS) #include <linux/kernel.h> #include <linux/mo ...

最新文章

  1. 多帧点云拼接的全局ICP算法【附Matlab代码链接】
  2. ISME:中科院微生物所揭示细菌利用光能新机制!
  3. 16、Java Swing JProgressBar:进度条组件
  4. linux下使用alias提升开发效率
  5. ssm整合之web.xml配置
  6. 一文理解设计模式--单例模式(Singleton)
  7. Python: 更改Jupyter Notebook默认工作路径?
  8. Java-基础---继承,方法重写,super关键字
  9. Docker两种方式进入后台运行的容器
  10. PMP备考资料和备考经验分享(基于PMP第六版)
  11. 互联网的世界安全吗?且行且珍惜
  12. 这些年,这些ACM大佬-施韩原访谈
  13. (8.1)基于牛顿-欧拉公式的动力学方程
  14. 为什么要使用Typescript
  15. 基于photoshop滤色混合模式的图片亮度改变
  16. 联想台式计算机HDMI使用,联想电脑怎样连接电视
  17. 安卓手机版微信聊天加密软件 悬浮窗版本
  18. Linux的markdown笔记软件,Markdown工具满天飞,哪一款适合用印象笔记的你?
  19. 在线视频网站加密技术详解
  20. zabbix结合qqmail发送故障信息

热门文章

  1. Step By Step_Java通过JNI调C程序执行
  2. 屏蔽浏览器退格键页面后退
  3. ConcurrentSkipListMap深入分析
  4. tsinsen A1067. Fibonacci数列整除问题 dp
  5. Linux Oracle10g安装
  6. 【tensorflow】安装cuda10.0 and cudnn 7.5.0 and tensorflow-gpu==1.14.0
  7. 【Python】原创 | 写一个符合人类思维的四舍五入函数(No round !!!)
  8. vue elementUI表单输入完成后回车触发事件@keyup.enter.native
  9. 详解k8s deployment的滚动更新
  10. k8s:服务发现Service