博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
do_generic_file_read()函数
阅读量:4074 次
发布时间:2019-05-25

本文共 5417 字,大约阅读时间需要 18 分钟。

本文重点分析一下linux内核中的do_generic_file_read函数,该函数实现文件系统的读功能。

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;			/* Did it get truncated before we got the lock? */			if (!page->mapping)				goto page_not_up_to_date_locked;			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:		/*		 * A previous I/O error may have been due to temporary		 * failures, eg. multipath errors.		 * PG_error will be set again if readpage fails.		 */		ClearPageError(page);		/* 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_mapping_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://ukbni.baihongyu.com/

你可能感兴趣的文章
大数据入门:Spark RDD基础概念
查看>>
大数据入门:SparkCore开发调优原则
查看>>
大数据入门:Java和Scala编程对比
查看>>
大数据入门:Scala函数式编程
查看>>
【数据结构周周练】002顺序表与链表
查看>>
C++报错:C4700:使用了非初始化的局部变量
查看>>
【数据结构周周练】003顺序栈与链栈
查看>>
C++类、结构体、函数、变量等命名规则详解
查看>>
C++ goto语句详解
查看>>
【数据结构周周练】008 二叉树的链式创建及测试
查看>>
《软件体系结构》 第九章 软件体系结构评估
查看>>
《软件体系结构》 第十章 软件产品线体系结构
查看>>
《软件过程管理》 第六章 软件过程的项目管理
查看>>
《软件过程管理》 第九章 软件过程的评估和改进
查看>>
分治法 动态规划法 贪心法 回溯法 小结
查看>>
《软件体系结构》 练习题
查看>>
《数据库系统概论》 第一章 绪论
查看>>
《数据库系统概论》 第二章 关系数据库
查看>>
《数据库系统概论》 第三章 关系数据库标准语言SQL
查看>>
SQL语句(二)查询语句
查看>>