*参照元 [#oad4fb2b] #backlinks *説明 [#o630f803] -パス: [[linux-2.6.33/mm/filemap.c]] -FIXME: これは何? --説明 **引数 [#ceaa3d7e] -struct file *filp -- --[[linux-2.6.33/file]] -loff_t *ppos -- -read_descriptor_t *desc -- --[[linux-2.6.33/read_descriptor_t]] -read_actor_t actor -- --[[linux-2.6.33/read_actor_t]] **返り値 [#d77e6268] -なし **参考 [#c3c0ff91] *実装 [#k88b590e] /** * do_generic_file_read - generic file read routine * @filp: the file to read * @ppos: current file position * @desc: read_descriptor * @actor: read method * * This is a generic file read routine, and uses the * mapping->a_ops->readpage() function for the actual low-level stuff. * * This is really ugly. But the goto's actually try to clarify some * of the logic when it comes to error handling etc. */ 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; - --[[linux-2.6.33/address_space]] - --[[linux-2.6.33/inode]] - --[[linux-2.6.33/file_ra_state]] 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; - --[[linux-2.6.33/page]] cond_resched(); - --[[linux-2.6.33/cond_resched()]] find_page: page = find_get_page(mapping, index); - --[[linux-2.6.33/find_get_page()]] if (!page) { page_cache_sync_readahead(mapping, ra, filp, index, last_index - index); - --[[linux-2.6.33/page_cache_sync_readahead()]] page = find_get_page(mapping, index); if (unlikely(page == NULL)) goto no_cached_page; - --[[linux-2.6.33/unlikely()]] } if (PageReadahead(page)) { - --[[linux-2.6.33/PageReadahead()]] page_cache_async_readahead(mapping, ra, filp, page, index, last_index - index); - --[[linux-2.6.33/page_cache_async_readahead()]] } if (!PageUptodate(page)) { - --[[linux-2.6.33/PageUptodate()]] 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; -mapping->a_ops は address_space_operations 型 --[[linux-2.6.33/address_space_operations]] - --[[linux-2.6.33/trylock_page()]] if (!mapping->a_ops->is_partially_uptodate(page, desc, offset)) goto page_not_up_to_date_locked; unlock_page(page); - --[[linux-2.6.33/unlock_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); - --[[linux-2.6.33/i_size_read()]] end_index = (isize - 1) >> PAGE_CACHE_SHIFT; if (unlikely(!isize || index > end_index)) { page_cache_release(page); goto out; } - --[[linux-2.6.33/page_cache_release()]] /* 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); - --[[linux-2.6.33/mapping_writably_mapped()]] - --[[linux-2.6.33/flush_dcache_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; - --[[linux-2.6.33/mark_page_accessed()]] /* * 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; - --[[linux-2.6.33/actor()]] -generic_file_aio_read() から呼ばれる場合、actor は file_read_actor() が指定されている。 --[[linux-2.6.33/read_actor_t]] --[[linux-2.6.33/file_read_actor()]] 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; - --[[linux-2.6.33/lock_page_killable()]] 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; } - --[[linux-2.6.33/unlock_page()]] - --[[linux-2.6.33/page_cache_release()]] /* Did somebody else fill it already? */ if (PageUptodate(page)) { unlock_page(page); goto page_ok; } - --[[linux-2.6.33/PageUptodate()]] readpage: /* Start the actual read. The read will unlock the page. */ error = mapping->a_ops->readpage(filp, page); -mapping->a_ops は address_space_operations 型 --[[linux-2.6.33/address_space_operations]] 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; - --[[linux-2.6.33/lock_page_killable()]] 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; - --[[linux-2.6.33/shrink_readahead_size_eio()]] } 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; } - --[[linux-2.6.33/page_cache_alloc_cold()]] 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; } - --[[linux-2.6.33/add_to_page_cache_lru()]] - --[[linux-2.6.33/page_cache_release()]] 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); - --[[linux-2.6.33/file_accessed()]] } *コメント [#f994dde1]