文件读写(2)

二、文件读过程

我们先看标准的读过程。

1 、准备工作。通过 VFS 层,及一些初始化操作,为真正的读操作做准备。

首先是用户进程通过 read 系统调用发出一个读请求:

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) {

              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;

}

然后通过 VFS 层操作:

ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)

{

       ssize_t ret;

       …… // 一些检查

       ret = rw_verify_area(READ, file, pos, count);

       if (ret >= 0) {

              count = ret;

              ret = security_file_permission (file, MAY_READ);

              if (!ret) {

                     if (file->f_op->read)

                            ret = file->f_op->read(file, buf, count, pos);

                     else

                            ret = do_sync_read(file, buf, count, pos);

                     ……

              }

       }

       return ret;

}

对于 ext2 文件系统,有:

const struct file_operations ext2_file_operations = {

       .llseek            = generic_file_llseek,

       .read              = do_sync_read,

       .write             = do_sync_write,

       .aio_read = generic_file_aio_read,

       .aio_write       = generic_file_aio_write,

       .ioctl              = ext2_ioctl,

#ifdef CONFIG_COMPAT

       .compat_ioctl = ext2_compat_ioctl,

#endif

       .mmap           = generic_file_mmap,

       .open             = generic_file_open,

       .release    = ext2_release_file,

       .fsync            = ext2_sync_file,

       .sendfile = generic_file_sendfile,

       .splice_read    = generic_file_splice_read,

       .splice_write   = generic_file_splice_write,

};

所以它执行的是:

ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)

{

       // 初始化 iov, kiocb 两个数据结构

       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;

       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;

}

可以看,它最后还是调用了 aio_read() 接口函数来完成读操作,即在 2.6 中, aio_read() 为同步和异步读操作的通用接口,由上可以看到,对于 ext2 ,它是 generic_file_aio_read

/**

* generic_file_aio_read - generic filesystem read routine

* @iocb:       kernel I/O control block

* @iov: io vector request

* @nr_segs: number of segments in the iovec

* @pos: current file position

*

* This is the "read()" routine for all filesystems

* that can use the page cache directly.

*/

ssize_t

generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,

              unsigned long nr_segs, loff_t pos)

{

       struct file *filp = iocb->ki_filp;

       ssize_t retval;

       unsigned long seg;

       size_t count;

       loff_t *ppos = &iocb->ki_pos;

       …….// 一些检查    

       /* coalesce the iovecs and go direct-to-BIO for O_DIRECT */

       if (filp->f_flags & O_DIRECT) {

              ……// 直接 IO ,我们这里先跳过

       }

       retval = 0;

       if (count) {

              for (seg = 0; seg < nr_segs; seg++) {

                     read_descriptor_t desc; // 一个读描述符结构

                     desc.written = 0;

                     desc.arg.buf = iov[seg].iov_base;

                     desc.count = iov[seg].iov_len;

                     if (desc.count == 0)

                            continue;

                     desc.error = 0;

                     do_generic_file_read(filp,ppos,&desc,file_read_actor);

                     retval += desc.written;

                     if (desc.error) {

                            retval = retval ?: desc.error;

                            break;

                     }

              }

       }

out:

       return retval;

}

static inline void do_generic_file_read(struct file * filp, loff_t *ppos,

                                   read_descriptor_t * desc,

                                   read_actor_t actor)

{

       do_generic_mapping_read(filp->f_mapping,

                            &filp->f_ra,

                            filp,

                            ppos,

                            desc,

                            actor);

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值