From 747caee8ebe61adea6b1992f763c9ebbd5e56d53 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 7 Sep 2014 01:00:43 -0400 Subject: [PATCH] save readpage patches --- include-mpage-functions-into-readpage.c | 375 ++++++++++++++++++++++++++++++++ inline-ext4_get_block-into-readpage | 171 +++++++++++++++ move-read-page-functions-to-new-file | 151 +++++++++++++ series | 7 + 4 files changed, 704 insertions(+) create mode 100644 include-mpage-functions-into-readpage.c create mode 100644 inline-ext4_get_block-into-readpage create mode 100644 move-read-page-functions-to-new-file diff --git a/include-mpage-functions-into-readpage.c b/include-mpage-functions-into-readpage.c new file mode 100644 index 00000000..19351744 --- /dev/null +++ b/include-mpage-functions-into-readpage.c @@ -0,0 +1,375 @@ +ext4: copy mpage_readpage() and mpage_readpages() fs/ext4/readpage.c + +Move the functions which we need from fs/mpage.c into +fs/ext4/readpage.c. This will allow us to proceed with the +refactorization of these functions and eventual merger with the +functions in fs/ext4/page_io.c. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/readpage.c | 326 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 320 insertions(+), 6 deletions(-) + +diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c +index b5249db..3b29da1 100644 +--- a/fs/ext4/readpage.c ++++ b/fs/ext4/readpage.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #include "ext4_jbd2.h" + #include "xattr.h" +@@ -30,31 +31,344 @@ + + #include + +-int ext4_readpage(struct file *file, struct page *page) ++/* ++ * I/O completion handler for multipage BIOs. ++ * ++ * The mpage code never puts partial pages into a BIO (except for end-of-file). ++ * If a page does not map to a contiguous run of blocks then it simply falls ++ * back to block_read_full_page(). ++ * ++ * Why is this? If a page's completion depends on a number of different BIOs ++ * which can complete in any order (or at the same time) then determining the ++ * status of that page is hard. See end_buffer_async_read() for the details. ++ * There is no point in duplicating all that complexity. ++ */ ++static void mpage_end_io(struct bio *bio, int err) ++{ ++ struct bio_vec *bv; ++ int i; ++ ++ bio_for_each_segment_all(bv, bio, i) { ++ struct page *page = bv->bv_page; ++ page_endio(page, bio_data_dir(bio), err); ++ } ++ ++ bio_put(bio); ++} ++ ++static struct bio *mpage_bio_submit(int rw, struct bio *bio) ++{ ++ bio->bi_end_io = mpage_end_io; ++ submit_bio(rw, bio); ++ return NULL; ++} ++ ++static struct bio * ++mpage_alloc(struct block_device *bdev, ++ sector_t first_sector, int nr_vecs, ++ gfp_t gfp_flags) ++{ ++ struct bio *bio; ++ ++ bio = bio_alloc(gfp_flags, nr_vecs); ++ ++ if (bio == NULL && (current->flags & PF_MEMALLOC)) { ++ while (!bio && (nr_vecs /= 2)) ++ bio = bio_alloc(gfp_flags, nr_vecs); ++ } ++ ++ if (bio) { ++ bio->bi_bdev = bdev; ++ bio->bi_iter.bi_sector = first_sector; ++ } ++ return bio; ++} ++ ++/* ++ * support function for mpage_readpages. The fs supplied get_block might ++ * return an up to date buffer. This is used to map that buffer into ++ * the page, which allows readpage to avoid triggering a duplicate call ++ * to get_block. ++ * ++ * The idea is to avoid adding buffers to pages that don't already have ++ * them. So when the buffer is up to date and the page size == block size, ++ * this marks the page up to date instead of adding new buffers. ++ */ ++static void ++map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block) ++{ ++ struct inode *inode = page->mapping->host; ++ struct buffer_head *page_bh, *head; ++ int block = 0; ++ ++ if (!page_has_buffers(page)) { ++ /* ++ * don't make any buffers if there is only one buffer on ++ * the page and the page just needs to be set up to date ++ */ ++ if (inode->i_blkbits == PAGE_CACHE_SHIFT && ++ buffer_uptodate(bh)) { ++ SetPageUptodate(page); ++ return; ++ } ++ create_empty_buffers(page, 1 << inode->i_blkbits, 0); ++ } ++ head = page_buffers(page); ++ page_bh = head; ++ do { ++ if (block == page_block) { ++ page_bh->b_state = bh->b_state; ++ page_bh->b_bdev = bh->b_bdev; ++ page_bh->b_blocknr = bh->b_blocknr; ++ break; ++ } ++ page_bh = page_bh->b_this_page; ++ block++; ++ } while (page_bh != head); ++} ++ ++/* ++ * This is the worker routine which does all the work of mapping the disk ++ * blocks and constructs largest possible bios, submits them for IO if the ++ * blocks are not contiguous on the disk. ++ * ++ * We pass a buffer_head back and forth and use its buffer_mapped() flag to ++ * represent the validity of its disk mapping and to decide when to do the next ++ * get_block() call. ++ */ ++static struct bio * ++do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, ++ sector_t *last_block_in_bio, struct buffer_head *map_bh, ++ unsigned long *first_logical_block, get_block_t get_block) + { +- int ret = -EAGAIN; + struct inode *inode = page->mapping->host; ++ const unsigned blkbits = inode->i_blkbits; ++ const unsigned blocks_per_page = PAGE_CACHE_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; ++ unsigned first_hole = blocks_per_page; ++ struct block_device *bdev = NULL; ++ int length; ++ int fully_mapped = 1; ++ unsigned nblocks; ++ unsigned relative_block; ++ ++ if (page_has_buffers(page)) ++ goto confused; ++ ++ block_in_file = (sector_t)page->index << (PAGE_CACHE_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 result from the previous get_blocks call first. ++ */ ++ nblocks = map_bh->b_size >> blkbits; ++ if (buffer_mapped(map_bh) && block_in_file > *first_logical_block && ++ block_in_file < (*first_logical_block + nblocks)) { ++ unsigned map_offset = block_in_file - *first_logical_block; ++ unsigned last = nblocks - map_offset; ++ ++ for (relative_block = 0; ; relative_block++) { ++ if (relative_block == last) { ++ clear_buffer_mapped(map_bh); ++ break; ++ } ++ if (page_block == blocks_per_page) ++ break; ++ blocks[page_block] = map_bh->b_blocknr + map_offset + ++ relative_block; ++ page_block++; ++ block_in_file++; ++ } ++ bdev = map_bh->b_bdev; ++ } ++ ++ /* ++ * Then do more get_blocks calls until we are done with this page. ++ */ ++ map_bh->b_page = page; ++ while (page_block < blocks_per_page) { ++ map_bh->b_state = 0; ++ map_bh->b_size = 0; ++ ++ if (block_in_file < last_block) { ++ map_bh->b_size = (last_block-block_in_file) << blkbits; ++ if (get_block(inode, block_in_file, map_bh, 0)) ++ goto confused; ++ *first_logical_block = block_in_file; ++ } ++ ++ if (!buffer_mapped(map_bh)) { ++ fully_mapped = 0; ++ if (first_hole == blocks_per_page) ++ first_hole = page_block; ++ page_block++; ++ block_in_file++; ++ continue; ++ } ++ ++ /* some filesystems will copy data into the page during ++ * the get_block call, in which case we don't want to ++ * read it again. map_buffer_to_page copies the data ++ * we just collected from get_block into the page's buffers ++ * so readpage doesn't have to repeat the get_block call ++ */ ++ if (buffer_uptodate(map_bh)) { ++ map_buffer_to_page(page, map_bh, page_block); ++ goto confused; ++ } ++ ++ if (first_hole != blocks_per_page) ++ goto confused; /* hole -> non-hole */ ++ ++ /* Contiguous blocks? */ ++ if (page_block && blocks[page_block-1] != map_bh->b_blocknr-1) ++ goto confused; ++ nblocks = map_bh->b_size >> blkbits; ++ for (relative_block = 0; ; relative_block++) { ++ if (relative_block == nblocks) { ++ clear_buffer_mapped(map_bh); ++ break; ++ } else if (page_block == blocks_per_page) ++ break; ++ blocks[page_block] = map_bh->b_blocknr+relative_block; ++ page_block++; ++ block_in_file++; ++ } ++ bdev = map_bh->b_bdev; ++ } ++ ++ if (first_hole != blocks_per_page) { ++ zero_user_segment(page, first_hole << blkbits, PAGE_CACHE_SIZE); ++ if (first_hole == 0) { ++ SetPageUptodate(page); ++ unlock_page(page); ++ goto out; ++ } ++ } 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)) ++ bio = mpage_bio_submit(READ, bio); ++ ++alloc_new: ++ if (bio == NULL) { ++ if (first_hole == blocks_per_page) { ++ if (!bdev_read_page(bdev, blocks[0] << (blkbits - 9), ++ page)) ++ goto out; ++ } ++ bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), ++ min_t(int, nr_pages, bio_get_nr_vecs(bdev)), ++ GFP_KERNEL); ++ if (bio == NULL) ++ goto confused; ++ } ++ ++ length = first_hole << blkbits; ++ if (bio_add_page(bio, page, length, 0) < length) { ++ bio = mpage_bio_submit(READ, bio); ++ goto alloc_new; ++ } ++ ++ relative_block = block_in_file - *first_logical_block; ++ nblocks = map_bh->b_size >> blkbits; ++ if ((buffer_boundary(map_bh) && relative_block == nblocks) || ++ (first_hole != blocks_per_page)) ++ bio = mpage_bio_submit(READ, bio); ++ else ++ *last_block_in_bio = blocks[blocks_per_page - 1]; ++out: ++ return bio; ++ ++confused: ++ if (bio) ++ bio = mpage_bio_submit(READ, bio); ++ if (!PageUptodate(page)) ++ block_read_full_page(page, get_block); ++ else ++ unlock_page(page); ++ goto out; ++} ++ ++int ext4_readpage(struct file *file, struct page *page) ++{ ++ unsigned long first_logical_block = 0; ++ struct buffer_head map_bh; ++ struct inode *inode = page->mapping->host; ++ struct bio *bio = NULL; ++ sector_t last_block_in_bio = 0; ++ int ret = -EAGAIN; + + trace_ext4_readpage(page); + + if (ext4_has_inline_data(inode)) + ret = ext4_readpage_inline(inode, page); + +- if (ret == -EAGAIN) +- return mpage_readpage(page, ext4_get_block); ++ if (ret != -EAGAIN) ++ return ret; + +- return ret; ++ map_bh.b_state = 0; ++ map_bh.b_size = 0; ++ bio = do_mpage_readpage(bio, page, 1, &last_block_in_bio, ++ &map_bh, &first_logical_block, ext4_get_block); ++ if (bio) ++ mpage_bio_submit(READ, bio); ++ return 0; + } + + int ext4_readpages(struct file *file, struct address_space *mapping, + struct list_head *pages, unsigned nr_pages) + { + struct inode *inode = mapping->host; ++ struct bio *bio = NULL; ++ unsigned page_idx; ++ sector_t last_block_in_bio = 0; ++ struct buffer_head map_bh; ++ unsigned long first_logical_block = 0; + + /* If the file has inline data, no need to do readpages. */ + if (ext4_has_inline_data(inode)) + return 0; + +- return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); ++ map_bh.b_state = 0; ++ map_bh.b_size = 0; ++ for (page_idx = 0; page_idx < nr_pages; page_idx++) { ++ struct page *page = list_entry(pages->prev, struct page, lru); ++ ++ prefetchw(&page->flags); ++ list_del(&page->lru); ++ if (!add_to_page_cache_lru(page, mapping, ++ page->index, GFP_KERNEL)) { ++ bio = do_mpage_readpage(bio, page, ++ nr_pages - page_idx, ++ &last_block_in_bio, &map_bh, ++ &first_logical_block, ++ ext4_get_block); ++ } ++ page_cache_release(page); ++ } ++ BUG_ON(!list_empty(pages)); ++ if (bio) ++ mpage_bio_submit(READ, bio); ++ return 0; + } + diff --git a/inline-ext4_get_block-into-readpage b/inline-ext4_get_block-into-readpage new file mode 100644 index 00000000..790b353c --- /dev/null +++ b/inline-ext4_get_block-into-readpage @@ -0,0 +1,171 @@ +ext4: call ext4_map_blocks() directly from read_page.c + +Use ext4_map_blocks() directly instead of going through +ext4_get_block(). This allows us to drop out a lot of generic code +that was not needed for ext4. + +Signed-off-by: Theodore Ts'o + + +--- + fs/ext4/readpage.c | 83 ++++++++++++++++++----------------------------------------------------------------- + 1 file changed, 18 insertions(+), 65 deletions(-) + +diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c +index 3b29da1..ce3ecc1 100644 +--- a/fs/ext4/readpage.c ++++ b/fs/ext4/readpage.c +@@ -85,49 +85,6 @@ mpage_alloc(struct block_device *bdev, + } + + /* +- * support function for mpage_readpages. The fs supplied get_block might +- * return an up to date buffer. This is used to map that buffer into +- * the page, which allows readpage to avoid triggering a duplicate call +- * to get_block. +- * +- * The idea is to avoid adding buffers to pages that don't already have +- * them. So when the buffer is up to date and the page size == block size, +- * this marks the page up to date instead of adding new buffers. +- */ +-static void +-map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block) +-{ +- struct inode *inode = page->mapping->host; +- struct buffer_head *page_bh, *head; +- int block = 0; +- +- if (!page_has_buffers(page)) { +- /* +- * don't make any buffers if there is only one buffer on +- * the page and the page just needs to be set up to date +- */ +- if (inode->i_blkbits == PAGE_CACHE_SHIFT && +- buffer_uptodate(bh)) { +- SetPageUptodate(page); +- return; +- } +- create_empty_buffers(page, 1 << inode->i_blkbits, 0); +- } +- head = page_buffers(page); +- page_bh = head; +- do { +- if (block == page_block) { +- page_bh->b_state = bh->b_state; +- page_bh->b_bdev = bh->b_bdev; +- page_bh->b_blocknr = bh->b_blocknr; +- break; +- } +- page_bh = page_bh->b_this_page; +- block++; +- } while (page_bh != head); +-} +- +-/* + * This is the worker routine which does all the work of mapping the disk + * blocks and constructs largest possible bios, submits them for IO if the + * blocks are not contiguous on the disk. +@@ -138,8 +95,8 @@ map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block) + */ + static struct bio * + do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, +- sector_t *last_block_in_bio, struct buffer_head *map_bh, +- unsigned long *first_logical_block, get_block_t get_block) ++ sector_t *last_block_in_bio, struct buffer_head *map_bh, ++ unsigned long *first_logical_block) + { + struct inode *inode = page->mapping->host; + const unsigned blkbits = inode->i_blkbits; +@@ -151,7 +108,7 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, + sector_t blocks[MAX_BUF_PER_PAGE]; + unsigned page_block; + unsigned first_hole = blocks_per_page; +- struct block_device *bdev = NULL; ++ struct block_device *bdev = inode->i_sb->s_bdev; + int length; + int fully_mapped = 1; + unsigned nblocks; +@@ -188,7 +145,6 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, + page_block++; + block_in_file++; + } +- bdev = map_bh->b_bdev; + } + + /* +@@ -200,9 +156,19 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, + map_bh->b_size = 0; + + if (block_in_file < last_block) { +- map_bh->b_size = (last_block-block_in_file) << blkbits; +- if (get_block(inode, block_in_file, map_bh, 0)) ++ struct ext4_map_blocks map; ++ int ret; ++ ++ map.m_lblk = block_in_file; ++ map.m_len = last_block - block_in_file; ++ ret = ext4_map_blocks(NULL, inode, &map, 0); ++ if (ret < 0) + goto confused; ++ map_bh->b_blocknr = map.m_pblk; ++ map_bh->b_bdev = bdev; ++ map_bh->b_size = inode->i_sb->s_blocksize * map.m_len; ++ map_bh->b_state = map.m_flags; ++ + *first_logical_block = block_in_file; + } + +@@ -215,17 +181,6 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, + continue; + } + +- /* some filesystems will copy data into the page during +- * the get_block call, in which case we don't want to +- * read it again. map_buffer_to_page copies the data +- * we just collected from get_block into the page's buffers +- * so readpage doesn't have to repeat the get_block call +- */ +- if (buffer_uptodate(map_bh)) { +- map_buffer_to_page(page, map_bh, page_block); +- goto confused; +- } +- + if (first_hole != blocks_per_page) + goto confused; /* hole -> non-hole */ + +@@ -243,7 +198,6 @@ do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, + page_block++; + block_in_file++; + } +- bdev = map_bh->b_bdev; + } + + if (first_hole != blocks_per_page) { +@@ -303,7 +257,7 @@ confused: + if (bio) + bio = mpage_bio_submit(READ, bio); + if (!PageUptodate(page)) +- block_read_full_page(page, get_block); ++ block_read_full_page(page, ext4_get_block); + else + unlock_page(page); + goto out; +@@ -329,7 +283,7 @@ int ext4_readpage(struct file *file, struct page *page) + map_bh.b_state = 0; + map_bh.b_size = 0; + bio = do_mpage_readpage(bio, page, 1, &last_block_in_bio, +- &map_bh, &first_logical_block, ext4_get_block); ++ &map_bh, &first_logical_block); + if (bio) + mpage_bio_submit(READ, bio); + return 0; +@@ -361,8 +315,7 @@ int ext4_readpages(struct file *file, struct address_space *mapping, + bio = do_mpage_readpage(bio, page, + nr_pages - page_idx, + &last_block_in_bio, &map_bh, +- &first_logical_block, +- ext4_get_block); ++ &first_logical_block); + } + page_cache_release(page); + } diff --git a/move-read-page-functions-to-new-file b/move-read-page-functions-to-new-file new file mode 100644 index 00000000..6a477f1d --- /dev/null +++ b/move-read-page-functions-to-new-file @@ -0,0 +1,151 @@ +ext4: move ext4_readpage() and ext4_readpages() to their own file + +In preparation for weaning ext4 completely off of fs/mpage.c, move the +readpage[s] function to their own file. Eventually we'll probably end +up moving the writepage[s] function here and renaming this to +something like read_write_page.c, or some such, but for now, let's +keep things simple. + +Signed-off-by: Theodore Ts'o +--- + fs/ext4/Makefile | 2 +- + fs/ext4/ext4.h | 5 +++++ + fs/ext4/inode.c | 29 ----------------------------- + fs/ext4/readpage.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 66 insertions(+), 30 deletions(-) + +diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile +index 0310fec..cd6f50f 100644 +--- a/fs/ext4/Makefile ++++ b/fs/ext4/Makefile +@@ -8,7 +8,7 @@ ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ + ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ + ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ + mmp.o indirect.o extents_status.o xattr.o xattr_user.o \ +- xattr_trusted.o inline.o ++ xattr_trusted.o inline.o readpage.o + + ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o + ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index f70c3fc..5c115ea 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -2775,6 +2775,11 @@ extern int ext4_bio_write_page(struct ext4_io_submit *io, + struct writeback_control *wbc, + bool keep_towrite); + ++/* readpage.c */ ++extern int ext4_readpage(struct file *file, struct page *page); ++extern int ext4_readpages(struct file *file, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages); ++ + /* mmp.c */ + extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t); + +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index d5dd7d4..b3c7b92 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -2798,35 +2798,6 @@ static sector_t ext4_bmap(struct address_space *mapping, sector_t block) + return generic_block_bmap(mapping, block, ext4_get_block); + } + +-static int ext4_readpage(struct file *file, struct page *page) +-{ +- int ret = -EAGAIN; +- struct inode *inode = page->mapping->host; +- +- trace_ext4_readpage(page); +- +- if (ext4_has_inline_data(inode)) +- ret = ext4_readpage_inline(inode, page); +- +- if (ret == -EAGAIN) +- return mpage_readpage(page, ext4_get_block); +- +- return ret; +-} +- +-static int +-ext4_readpages(struct file *file, struct address_space *mapping, +- struct list_head *pages, unsigned nr_pages) +-{ +- struct inode *inode = mapping->host; +- +- /* If the file has inline data, no need to do readpages. */ +- if (ext4_has_inline_data(inode)) +- return 0; +- +- return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); +-} +- + static void ext4_invalidatepage(struct page *page, unsigned int offset, + unsigned int length) + { +diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c +new file mode 100644 +index 0000000..b5249db +--- /dev/null ++++ b/fs/ext4/readpage.c +@@ -0,0 +1,60 @@ ++/* ++ * linux/fs/ext4/readpage.c ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "ext4_jbd2.h" ++#include "xattr.h" ++#include "acl.h" ++ ++#include ++ ++int ext4_readpage(struct file *file, struct page *page) ++{ ++ int ret = -EAGAIN; ++ struct inode *inode = page->mapping->host; ++ ++ trace_ext4_readpage(page); ++ ++ if (ext4_has_inline_data(inode)) ++ ret = ext4_readpage_inline(inode, page); ++ ++ if (ret == -EAGAIN) ++ return mpage_readpage(page, ext4_get_block); ++ ++ return ret; ++} ++ ++int ext4_readpages(struct file *file, struct address_space *mapping, ++ struct list_head *pages, unsigned nr_pages) ++{ ++ struct inode *inode = mapping->host; ++ ++ /* If the file has inline data, no need to do readpages. */ ++ if (ext4_has_inline_data(inode)) ++ return 0; ++ ++ return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); ++} ++ diff --git a/series b/series index dead9a18..6f644ab4 100644 --- a/series +++ b/series @@ -49,6 +49,13 @@ use-non-moveable-memory-for-the-jbd-superblock stable-boundary stable-boundary-undo.patch +# not yet ready; patch series so ext4 has has full responsibility +# for ext4_readpage[s] and does not use mpage. +# +move-read-page-functions-to-new-file +include-mpage-functions-into-readpage.c +inline-ext4_get_block-into-readpage + add-callback-support-for-bio-read-completion add-ext4-encryption-facilities implement-the-ext4-encryption-write-path -- 2.11.4.GIT