aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/extents.c
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-08-16 22:05:14 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-08-16 22:05:14 -0400
commit7869a4a6c5caa7b2e5c41ccaf46eb3371f88eea7 (patch)
tree1c55037a6b090b843b7f8669686dfdbbfd9ceb70 /fs/ext4/extents.c
parent107a7bd31ac003e42c0f966aa8e5b26947de6024 (diff)
ext4: add support for extent pre-caching
Add a new fiemap flag which forces the all of the extents in an inode to be cached in the extent_status tree. This is critically important when using AIO to a preallocated file, since if we need to read in blocks from the extent tree, the io_submit(2) system call becomes synchronous, and the AIO is no longer "A", which is bad. In addition, for most files which have an external leaf tree block, the cost of caching the information in the extent status tree will be less than caching the entire 4k block in the buffer cache. So it is generally a win to keep the extent information cached. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs/ext4/extents.c')
-rw-r--r--fs/ext4/extents.c73
1 files changed, 72 insertions, 1 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 08c1ac976479..01838875fcaf 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -482,7 +482,7 @@ __read_extent_tree_block(const char *function, unsigned int line,
482 if (err < 0) 482 if (err < 0)
483 goto errout; 483 goto errout;
484 } 484 }
485 if (buffer_verified(bh)) 485 if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE))
486 return bh; 486 return bh;
487 err = __ext4_ext_check(function, line, inode, 487 err = __ext4_ext_check(function, line, inode,
488 ext_block_hdr(bh), depth, pblk); 488 ext_block_hdr(bh), depth, pblk);
@@ -526,6 +526,71 @@ errout:
526 __read_extent_tree_block(__func__, __LINE__, (inode), (pblk), \ 526 __read_extent_tree_block(__func__, __LINE__, (inode), (pblk), \
527 (depth), (flags)) 527 (depth), (flags))
528 528
529/*
530 * This function is called to cache a file's extent information in the
531 * extent status tree
532 */
533int ext4_ext_precache(struct inode *inode)
534{
535 struct ext4_inode_info *ei = EXT4_I(inode);
536 struct ext4_ext_path *path = NULL;
537 struct buffer_head *bh;
538 int i = 0, depth, ret = 0;
539
540 if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))
541 return 0; /* not an extent-mapped inode */
542
543 down_read(&ei->i_data_sem);
544 depth = ext_depth(inode);
545
546 path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
547 GFP_NOFS);
548 if (path == NULL) {
549 up_read(&ei->i_data_sem);
550 return -ENOMEM;
551 }
552
553 /* Don't cache anything if there are no external extent blocks */
554 if (depth == 0)
555 goto out;
556 path[0].p_hdr = ext_inode_hdr(inode);
557 ret = ext4_ext_check(inode, path[0].p_hdr, depth, 0);
558 if (ret)
559 goto out;
560 path[0].p_idx = EXT_FIRST_INDEX(path[0].p_hdr);
561 while (i >= 0) {
562 /*
563 * If this is a leaf block or we've reached the end of
564 * the index block, go up
565 */
566 if ((i == depth) ||
567 path[i].p_idx > EXT_LAST_INDEX(path[i].p_hdr)) {
568 brelse(path[i].p_bh);
569 path[i].p_bh = NULL;
570 i--;
571 continue;
572 }
573 bh = read_extent_tree_block(inode,
574 ext4_idx_pblock(path[i].p_idx++),
575 depth - i - 1,
576 EXT4_EX_FORCE_CACHE);
577 if (IS_ERR(bh)) {
578 ret = PTR_ERR(bh);
579 break;
580 }
581 i++;
582 path[i].p_bh = bh;
583 path[i].p_hdr = ext_block_hdr(bh);
584 path[i].p_idx = EXT_FIRST_INDEX(path[i].p_hdr);
585 }
586 ext4_set_inode_state(inode, EXT4_STATE_EXT_PRECACHED);
587out:
588 up_read(&ei->i_data_sem);
589 ext4_ext_drop_refs(path);
590 kfree(path);
591 return ret;
592}
593
529#ifdef EXT_DEBUG 594#ifdef EXT_DEBUG
530static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) 595static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
531{ 596{
@@ -4766,6 +4831,12 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
4766 return error; 4831 return error;
4767 } 4832 }
4768 4833
4834 if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) {
4835 error = ext4_ext_precache(inode);
4836 if (error)
4837 return error;
4838 }
4839
4769 /* fallback to generic here if not in extents fmt */ 4840 /* fallback to generic here if not in extents fmt */
4770 if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) 4841 if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)))
4771 return generic_block_fiemap(inode, fieinfo, start, len, 4842 return generic_block_fiemap(inode, fieinfo, start, len,