do_generic_file_read()函数

news/2024/7/8 8:38:40

这个函数完成了文件读的主要流程

核心在于操作页高速缓存,如缺页,失效,预读等操作。

函数中goto语句不计其数,

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

        read_descriptor_t *desc, read_actor_t actor)
{
    struct address_space *mapping = filp->f_mapping;
    struct inode *inode = mapping->host;
    struct file_ra_state *ra = &filp->f_ra;
    pgoff_t index;
    pgoff_t last_index;
    pgoff_t prev_index;
    unsigned long offset;      /* offset into pagecache page */
    unsigned int prev_offset;
    int error;

    index = *ppos >> PAGE_CACHE_SHIFT;
    prev_index = ra->prev_pos >> PAGE_CACHE_SHIFT;
    prev_offset = ra->prev_pos & (PAGE_CACHE_SIZE-1);
    last_index = (*ppos + desc->count + PAGE_CACHE_SIZE-1) >> PAGE_CACHE_SHIFT;
    offset = *ppos & ~PAGE_CACHE_MASK;

    for (;;) {
        struct page *page;
        pgoff_t end_index;
        loff_t isize;
        unsigned long nr, ret;

        cond_resched();
find_page:
        page = find_get_page(mapping, index);
        if (!page) {
            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 (inode->i_blkbits == PAGE_CACHE_SHIFT ||
                    !mapping->a_ops->is_partially_uptodate)
                goto page_not_up_to_date;
            if (!trylock_page(page))
                goto page_not_up_to_date;
            if (!mapping->a_ops->is_partially_uptodate(page,
                                desc, offset))
                goto page_not_up_to_date_locked;
            unlock_page(page);
        }
page_ok:
        /*
         * i_size must be checked after we know the page is Uptodate.
         *
         * Checking i_size after the check allows us to calculate
         * the correct value for "nr", which means the zero-filled
         * part of the page is not copied back to userspace (unless
         * another truncate extends the file - this is desired though).
         */

        isize = i_size_read(inode);
        end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
        if (unlikely(!isize || index > end_index)) {
            page_cache_release(page);
            goto out;
        }

        /* nr is the maximum number of bytes to copy from this page */
        nr = PAGE_CACHE_SIZE;
        if (index == end_index) {
            nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
            if (nr <= offset) {
                page_cache_release(page);
                goto out;
            }
        }
        nr = nr - offset;

        /* If users can be writing to this page using arbitrary
         * virtual addresses, take care about potential aliasing
         * before reading the page on the kernel side.
         */
        if (mapping_writably_mapped(mapping))
            flush_dcache_page(page);

        /*
         * When a sequential read accesses a page several times,
         * only mark it as accessed the first time.
         */
        if (prev_index != index || offset != prev_offset)
            mark_page_accessed(page);
        prev_index = index;

        /*
         * Ok, we have the page, and it's up-to-date, so
         * now we can copy it to user space...
         *
         * The actor routine returns how many bytes were actually used..
         * NOTE! This may not be the same as how much of a user buffer
         * we filled up (we may be padding etc), so we can only update
         * "pos" here (the actor routine has to update the user buffer
         * pointers and the remaining count).
         */
        ret = actor(desc, page, offset, nr);
        offset += ret;
        index += offset >> PAGE_CACHE_SHIFT;
        offset &= ~PAGE_CACHE_MASK;
        prev_offset = offset;

        page_cache_release(page);
        if (ret == nr && desc->count)
            continue;
        goto out;

page_not_up_to_date:
        /* Get exclusive access to the page ... */
        error = lock_page_killable(page);
        if (unlikely(error))
            goto readpage_error;

page_not_up_to_date_locked:
        /* Did it get truncated before we got the lock? */
        if (!page->mapping) {
            unlock_page(page);
            page_cache_release(page);
            continue;
        }

        /* Did somebody else fill it already? */
        if (PageUptodate(page)) {
            unlock_page(page);
            goto page_ok;
        }

readpage:
        /* Start the actual read. The read will unlock the page. */
        error = mapping->a_ops->readpage(filp, page);

        if (unlikely(error)) {
            if (error == AOP_TRUNCATED_PAGE) {
                page_cache_release(page);
                goto find_page;
            }
            goto readpage_error;
        }

        if (!PageUptodate(page)) {
            error = lock_page_killable(page);
            if (unlikely(error))
                goto readpage_error;
            if (!PageUptodate(page)) {
                if (page->mapping == NULL) {
                    /*
                     * invalidate_inode_pages got it
                     */
                    unlock_page(page);
                    page_cache_release(page);
                    goto find_page;
                }
                unlock_page(page);
                shrink_readahead_size_eio(filp, ra);
                error = -EIO;
                goto readpage_error;
            }
            unlock_page(page);
        }

        goto page_ok;

readpage_error:
        /* UHHUH! A synchronous read error occurred. Report it */
        desc->error = error;
        page_cache_release(page);
        goto out;

no_cached_page:
        /*
         * Ok, it wasn't cached, so we need to create a new
         * page..
         */
        page = page_cache_alloc_cold(mapping);
        if (!page) {
            desc->error = -ENOMEM;
            goto out;
        }
        error = add_to_page_cache_lru(page, mapping,
                        index, GFP_KERNEL);
        if (error) {
            page_cache_release(page);
            if (error == -EEXIST)
                goto find_page;
            desc->error = error;
            goto out;
        }
        goto readpage;
    }

out:
    ra->prev_pos = prev_index;
    ra->prev_pos <<= PAGE_CACHE_SHIFT;
    ra->prev_pos |= prev_offset;

    *ppos = ((loff_t)index << PAGE_CACHE_SHIFT) + offset;
    file_accessed(filp);



http://www.niftyadmin.cn/n/3060758.html

相关文章

ECLIPSE、INTELLIJ IDEA格式化统一ECLIPSE CODE FORMATTER

Eclipse、Intellij idea格式化结果不一样&#xff0c;导致长时间都是用两个开发工具&#xff0c;idea开发eclipse进行格式化。但是现在这个问题可以解决了。使用Eclipse Code Formatter。 具体的插件地址&#xff1a;http://plugins.jetbrains.com/plugin/6546?pridea&off…

文件读写流程

在《linux内核虚拟文件系统浅析》这篇文章中&#xff0c;我们看到文件是如何被打开、文件的读写是如何被触发的。 对一个已打开的文件fd进行read/write系统调用时&#xff0c;内核中该文件所对应的file结构的f_op->read/f_op->write被调用。 本文将顺着这条路走下去&…

网站无法显示logo?

那是因为你没有配置favicon.ico&#xff0c;每个网站根目录都会有一个favicon.ico&#xff0c;因为每个服务器都会请求根目录下的它。

改变图片尺寸

// 改变图片尺寸 -(UIImage *)thumbnailWithImageWithoutScale:(UIImage *)image size:(CGSize)asize{UIImage *newimage;if (nil image) {newimage nil;}else{CGSize oldsize image.size;CGRect rect;if (asize.width/asize.height > oldsize.width/oldsize.height) {re…

Git建立远程/本地服务器和git命令的使用

Github 远程仓库 1、github.com 注册账户 2、在github上创建仓库 3、生成本地ssh key [rootlocalhost ~]# ssh-keygen -t rsa -C maiya163.com # 邮箱要与github上注册的相同 [rootlocalhost ~]# cat .ssh/id_rsa.pub ssh-rsaAAAAB3NzaC1yc2EAAAADAQABAAABAQDVThfq4brrlsPGtAkn…

磁盘格式化、磁盘挂载以及手动增加swap空间

磁盘格式化cat /etc/filesystems&#xff1a;查看centos7操作系统所支持的文件系统类型。centos7默认的文件系统类型为xfs。早期版本使用的是ext文件系统&#xff0c;6使用的是ext4&#xff0c;5使用的是ext3&#xff0c;依此类推。可以使用mount命令来查看分区的挂载情况以及文…

android动画笔记

动画 插值器 估值器 动画分类 View动画&#xff08;补间动画&#xff09;、帧动画、属性动画View动画&#xff08;补间动画&#xff09;包括&#xff1a;平移、旋转、缩放、透明度&#xff0c;View动画是一种渐近式动画 帧动画&#xff1a;图片切换动画属性动画&#xff1a;通过…

Linux-redhat7-----静态ip配置

1、配置子网IP和子网掩码&#xff0c;25&#xff08;网段&#xff09;可更改为其他值&#xff0c; 2、点击上图&#xff0c;“NAT设置”可查看默认网关&#xff0c;配置IP时需要用到 3、vi /etc/sysconfig/network-scripts/ifcfg-eno16777736 编辑网卡配置信息 4、vi /etc/res…