zoukankan      html  css  js  c++  java
  • read file page cache

    read file page cache 

    generic_file_buffered_read()里的index表示此次read文件的位置,在要读的某个文件里的位置,这个index是以page为单位的last_index表示此次read的结束位置,同样其单位是page

    这两个变量的值分别是根据kiocb、iov_iter两个结构体来确定的

    如果file.f_op.read没有实现,实现了file.f_op.read_iter,则vfs_read会调用new_sync_read(),在这个函数里,会构建一个kiocb struct,其中的ki_pos即是ppos,即read file的offset; new_sync_read()参数中的len将会被赋值给iov_iter.count:

    fs/read_write.c

    复制代码
    static 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;
        iov_iter_init(&iter, READ, &iov, 1, len);
    
        ret = call_read_iter(filp, &kiocb, &iter);
        BUG_ON(ret == -EIOCBQUEUED);
        *ppos = kiocb.ki_pos;
        return ret;
    }
    复制代码

    以ext4 fs为例,接下来它的call trace如下:

    ext4_file_read_iter
    generic_file_read_iter
    generic_file_buffered_read

    下面分析下generic_file_buffered_read()

    static ssize_t generic_file_buffered_read(struct kiocb *iocb,
            struct iov_iter *iter, ssize_t written)
       loff_t *ppos = &iocb->ki_pos; index
    = *ppos >> PAGE_SHIFT; prev_index = ra->prev_pos >> PAGE_SHIFT; prev_offset = ra->prev_pos & (PAGE_SIZE-1); last_index = (*ppos + iter->count + PAGE_SIZE-1) >> PAGE_SHIFT; offset = *ppos & ~PAGE_MASK; for (;;) { struct page *page; pgoff_t end_index; loff_t isize; unsigned long nr, ret; cond_resched(); find_page: if (fatal_signal_pending(current)) { error = -EINTR; goto out; } page = find_get_page(mapping, index); if (!page) { if (iocb->ki_flags & IOCB_NOWAIT) goto would_block; page_cache_sync_readahead(mapping, ra, filp, index, last_index - index); page = find_get_page(mapping, index); if (unlikely(page == NULL)) goto no_cached_page; } if (PageReadahead(page)) { page_cache_async_readahead(mapping, ra, filp, page, index, last_index - index); } if (!PageUptodate(page)) { if (iocb->ki_flags & IOCB_NOWAIT) { put_page(page); goto would_block; } /* * See comment in do_read_cache_page on why * wait_on_page_locked is used to avoid unnecessarily * serialisations and why it's safe. */ error = wait_on_page_locked_killable(page);

    以第一次读一个文件为例,读的位置是0,find_get_page()是从page cache tree上查找这个page是否已经在page cache里了,针对目前的case,它将找不到这个page,所以调用page_cache_sync_readahead()进行同步读。

    接下来再调用了find_get_page(),如果前面的page_cache_sync_readahead()成功了的话,此时是能find到这个page的,即能从page cache里find到这个page,注意能find到并不能说明这个page已经通过IO读到内存上来了。

    接下来是判断这个page是否有readahead属性,如果有,则说明这个page是之前以read ahead的方式读取到的,则调用page_cache_async_readahead()进行异步再读;

    接下来判断这个page是否是uptodate的,读一个page时默认是没有这个flag的,直到这个page通过IO方式读取到内存里来了才会将这个flag置上;

    接下来是调用wait_on_page_locked_killable(),这个函数是先检查这个page是否有locked flag,如果有则会去等这个flag被clear,所以此时这个线程有可能会睡眠被调度出去,此时这个线程的状态被设置为TASK_KILLABLE,此后去查看这个线程的状态将是D状态。

    https://blog.csdn.net/zouxiaoting/article/details/8738077

    https://blog.csdn.net/u011649400/article/details/96560975

  • 相关阅读:
    web页面静态化与伪静态化
    mysql 优化之空间换时间
    QPS、PV、UV、RT 之间的关系
    接口
    MySQL 索引
    名词解释
    go 语言标识符
    Git版本控制与工作流
    Maven安装与配置
    IDEA工具使用说明
  • 原文地址:https://www.cnblogs.com/aspirs/p/15684828.html
Copyright © 2011-2022 走看看