ext4_mpage_readpages

来源:互联网 发布:dd是什么意思网络用语 编辑:程序博客网 时间:2024/06/06 03:34
int ext4_mpage_readpages(struct address_space *mapping, struct list_head *pages, struct page *page, unsigned nr_pages){struct bio *bio = NULL;sector_t last_block_in_bio = 0;struct inode *inode = mapping->host;const unsigned blkbits = inode->i_blkbits;const unsigned blocks_per_page = PAGE_SIZE >> blkbits;const unsigned blocksize = 1 << blkbits;sector_t block_in_file;sector_t last_block;sector_t last_block_in_file;sector_t blocks[MAX_BUF_PER_PAGE];unsigned page_block;struct block_device *bdev = inode->i_sb->s_bdev;int length;unsigned relative_block = 0;struct ext4_map_blocks map;map.m_pblk = 0;map.m_lblk = 0;map.m_len = 0;map.m_flags = 0;for (; nr_pages; nr_pages--) {int fully_mapped = 1;unsigned first_hole = blocks_per_page;prefetchw(&page->flags);if (pages) {page = list_entry(pages->prev, struct page, lru);list_del(&page->lru);if (add_to_page_cache_lru(page, mapping, page->index,  readahead_gfp_mask(mapping)))goto next_page;}if (page_has_buffers(page))goto confused;block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits);last_block = block_in_file + nr_pages * blocks_per_page;last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;if (last_block > last_block_in_file)last_block = last_block_in_file;page_block = 0;/* * Map blocks using the previous result first. */if ((map.m_flags & EXT4_MAP_MAPPED) &&    block_in_file > map.m_lblk &&    block_in_file < (map.m_lblk + map.m_len)) {unsigned map_offset = block_in_file - map.m_lblk;unsigned last = map.m_len - map_offset;for (relative_block = 0; ; relative_block++) {if (relative_block == last) {/* needed? */map.m_flags &= ~EXT4_MAP_MAPPED;break;}if (page_block == blocks_per_page)break;blocks[page_block] = map.m_pblk + map_offset +relative_block;page_block++;block_in_file++;}}/* * Then do more ext4_map_blocks() calls until we are * done with this page. */while (page_block < blocks_per_page) {if (block_in_file < last_block) {map.m_lblk = block_in_file;map.m_len = last_block - block_in_file;if (ext4_map_blocks(NULL, inode, &map, 0) < 0) {set_error_page:SetPageError(page);zero_user_segment(page, 0,  PAGE_SIZE);unlock_page(page);goto next_page;}}if ((map.m_flags & EXT4_MAP_MAPPED) == 0) {fully_mapped = 0;if (first_hole == blocks_per_page)first_hole = page_block;page_block++;block_in_file++;continue;}if (first_hole != blocks_per_page)goto confused;/* hole -> non-hole *//* Contiguous blocks? */if (page_block && blocks[page_block-1] != map.m_pblk-1)goto confused;for (relative_block = 0; ; relative_block++) {if (relative_block == map.m_len) {/* needed? */map.m_flags &= ~EXT4_MAP_MAPPED;break;} else if (page_block == blocks_per_page)break;blocks[page_block] = map.m_pblk+relative_block;page_block++;block_in_file++;}}if (first_hole != blocks_per_page) {zero_user_segment(page, first_hole << blkbits,  PAGE_SIZE);if (first_hole == 0) {SetPageUptodate(page);unlock_page(page);goto next_page;}} else if (fully_mapped) {SetPageMappedToDisk(page);}if (fully_mapped && blocks_per_page == 1 &&    !PageUptodate(page) && cleancache_get_page(page) == 0) {SetPageUptodate(page);goto confused;}/* * This page will go to BIO.  Do we need to send this * BIO off first? */if (bio && (last_block_in_bio != blocks[0] - 1)) {submit_and_realloc:submit_bio(bio);bio = NULL;}if (bio == NULL) {struct fscrypt_ctx *ctx = NULL;if (ext4_encrypted_inode(inode) &&    S_ISREG(inode->i_mode)) {ctx = fscrypt_get_ctx(inode, GFP_NOFS);if (IS_ERR(ctx))goto set_error_page;}bio = bio_alloc(GFP_KERNEL,min_t(int, nr_pages, BIO_MAX_PAGES));if (!bio) {if (ctx)fscrypt_release_ctx(ctx);goto set_error_page;}bio->bi_bdev = bdev;bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9);bio->bi_end_io = mpage_end_io;bio->bi_private = ctx;bio_set_op_attrs(bio, REQ_OP_READ, 0);}length = first_hole << blkbits;if (bio_add_page(bio, page, length, 0) < length)goto submit_and_realloc;if (((map.m_flags & EXT4_MAP_BOUNDARY) &&     (relative_block == map.m_len)) ||    (first_hole != blocks_per_page)) {submit_bio(bio);bio = NULL;} elselast_block_in_bio = blocks[blocks_per_page - 1];goto next_page;confused:if (bio) {submit_bio(bio);bio = NULL;}if (!PageUptodate(page))block_read_full_page(page, ext4_get_block);elseunlock_page(page);next_page:if (pages)put_page(page);}BUG_ON(pages && !list_empty(pages));if (bio)submit_bio(bio);return 0;}
0 0