linux read源码,linux内核read操作源代码分析

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也一定是可以搞明白的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值