linux read 分析

STEP1: user space===>read    man 2 
 n = read(fd[0], line, MAXLINE);

STEP2: kernel===>sys_read     unistd.h

 /* fs/pipe.c */
#define __NR_pipe2 59
__SYSCALL(__NR_pipe2, sys_pipe2)

/* fs/quota.c */
#define __NR_quotactl 60
__SYSCALL(__NR_quotactl, sys_quotactl)

/* fs/readdir.c */
#define __NR_getdents64 61
#define __ARCH_WANT_COMPAT_SYS_GETDENTS64
__SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64)

/* fs/read_write.c */
#define __NR3264_lseek 62
__SC_3264(__NR3264_lseek, sys_llseek, sys_lseek)
#define __NR_read 63
__SYSCALL(__NR_read, sys_read)
#define __NR_write 64
__SYSCALL(__NR_write, sys_write)
 
STEP3:  read_write.c 
SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)//argv:fd, buf, count
{
    struct fd f = fdget_pos(fd);//fd-->f
    ssize_t ret = -EBADF;

    if (f.file) {
        loff_t pos = file_pos_read(f.file);//pos出世,拿到此文件当前的pos
        ret = vfs_read(f.file, buf, count, &pos);//调用到 vfs_read(), argv:f.file, buf, cout, pos
        if (ret >= 0)
            file_pos_write(f.file, pos);//一旦vfs_read成功返回,我需要修改f.file中pos的位置,这样内核就一直记录着每个文件的pos
        fdput_pos(f);
    }
    return ret;
}
STEP4: read-->vfs_read(f.file, buf, count, &pos);
        这里还没有调用到我们对应设备的fops
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_mode & FMODE_CAN_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);//调用到file->f_op->read注意参数.
        else if (file->f_op->aio_read)
            ret = do_sync_read(file, buf, count, pos);
        else
            ret = new_sync_read(file, buf, count, pos);
        if (ret > 0) {
            fsnotify_access(file);
            add_rchar(current, ret);
        }
        inc_syscr(current);
    }

    return ret;
}
STEP5: 使用读管道的例子.
 n = read(fd[0], line, MAXLINE);
 const struct file_operations pipefifo_fops = {
    .open        = fifo_open,
    .llseek        = no_llseek,
    .read        = new_sync_read,//会调用到设备的read
    .read_iter    = pipe_read,
    .write        = new_sync_write,
    .write_iter    = pipe_write,
    .poll        = pipe_poll,
    .unlocked_ioctl    = pipe_ioctl,
    .release    = pipe_release,
    .fasync        = pipe_fasync,
};
调用方STEP4: ret = file->f_op->read(file, buf, count, pos);//调用到file->f_op->read注意参数.
ssize_t new_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;
    struct iov_iter iter;
    ssize_t ret;

    init_sync_kiocb(&kiocb, filp);
    kiocb.ki_pos = *ppos;
    kiocb.ki_nbytes = len;
    iov_iter_init(&iter, READ, &iov, 1, len);

    ret = filp->f_op->read_iter(&kiocb, &iter);//注意参数改变.
    if (-EIOCBQUEUED == ret)
        ret = wait_on_sync_kiocb(&kiocb);
    *ppos = kiocb.ki_pos;
    return ret;
}
STEP6:new_sync_read调用方
    ret = filp->f_op->read_iter(&kiocb, &iter);//注意参数改变.
    pipe_read(struct kiocb *iocb, struct iov_iter *to);参数在调用方函数中.

STEP: END 回顾调用流程
1.read(fd[0], line, MAXLINE);
2.SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
3.在2中被调用vfs_read(f.file, buf, count, &pos)   ---> 可以参看vfs_open 中会回调open会调用到设备的open,完成filpe和inode的关联
4.在3中被调用ret = file->f_op->read(file, buf, count, pos);
5.对应于4,new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
6.在5中被调用ret = filp->f_op->read_iter(&kiocb, &iter)
7.对应于6,pipe_read(struct kiocb *iocb, struct iov_iter *to)



你可能感兴趣的:(linux read 分析)