diff options
author | Chao Yu <chao2.yu@samsung.com> | 2016-01-26 02:42:58 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2016-02-22 19:07:23 -0500 |
commit | da85985c6142decea67ee5ff67eadf3f13103a91 (patch) | |
tree | 3a8b2b04014b0cd73270e61f94625353769171b4 /fs/f2fs | |
parent | 3cf4574705b4e1a1a0aeaae0332e8c2c8b56cc8f (diff) |
f2fs: speed up handling holes in fiemap
This patch makes f2fs_map_blocks supporting returning next potential
page offset which skips hole region in indirect tree of inode, and
use it to speed up fiemap in handling big hole case.
Test method:
xfs_io -f /mnt/f2fs/file -c "pwrite 1099511627776 4096"
time xfs_io -f /mnt/f2fs/file -c "fiemap -v"
Before:
time xfs_io -f /mnt/f2fs/file -c "fiemap -v"
/mnt/f2fs/file:
EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS
0: [0..2147483647]: hole 2147483648
1: [2147483648..2147483655]: 81920..81927 8 0x1
real 3m3.518s
user 0m0.000s
sys 3m3.456s
After:
time xfs_io -f /mnt/f2fs/file -c "fiemap -v"
/mnt/f2fs/file:
EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS
0: [0..2147483647]: hole 2147483648
1: [2147483648..2147483655]: 81920..81927 8 0x1
real 0m0.008s
user 0m0.000s
sys 0m0.008s
Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
Diffstat (limited to 'fs/f2fs')
-rw-r--r-- | fs/f2fs/data.c | 35 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 1 | ||||
-rw-r--r-- | fs/f2fs/file.c | 2 |
3 files changed, 28 insertions, 10 deletions
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index bb60e6afbb72..e0b09c33fc0f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -539,6 +539,7 @@ static int __allocate_data_blocks(struct inode *inode, loff_t offset, | |||
539 | 539 | ||
540 | map.m_lblk = F2FS_BYTES_TO_BLK(offset); | 540 | map.m_lblk = F2FS_BYTES_TO_BLK(offset); |
541 | map.m_len = F2FS_BYTES_TO_BLK(count); | 541 | map.m_len = F2FS_BYTES_TO_BLK(count); |
542 | map.m_next_pgofs = NULL; | ||
542 | 543 | ||
543 | return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_DIO); | 544 | return f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_DIO); |
544 | } | 545 | } |
@@ -586,8 +587,12 @@ next_dnode: | |||
586 | set_new_dnode(&dn, inode, NULL, NULL, 0); | 587 | set_new_dnode(&dn, inode, NULL, NULL, 0); |
587 | err = get_dnode_of_data(&dn, pgofs, mode); | 588 | err = get_dnode_of_data(&dn, pgofs, mode); |
588 | if (err) { | 589 | if (err) { |
589 | if (err == -ENOENT) | 590 | if (err == -ENOENT) { |
590 | err = 0; | 591 | err = 0; |
592 | if (map->m_next_pgofs) | ||
593 | *map->m_next_pgofs = | ||
594 | get_next_page_offset(&dn, pgofs); | ||
595 | } | ||
591 | goto unlock_out; | 596 | goto unlock_out; |
592 | } | 597 | } |
593 | 598 | ||
@@ -609,6 +614,11 @@ next_block: | |||
609 | map->m_flags = F2FS_MAP_NEW; | 614 | map->m_flags = F2FS_MAP_NEW; |
610 | blkaddr = dn.data_blkaddr; | 615 | blkaddr = dn.data_blkaddr; |
611 | } else { | 616 | } else { |
617 | if (flag == F2FS_GET_BLOCK_FIEMAP && | ||
618 | blkaddr == NULL_ADDR) { | ||
619 | if (map->m_next_pgofs) | ||
620 | *map->m_next_pgofs = pgofs + 1; | ||
621 | } | ||
612 | if (flag != F2FS_GET_BLOCK_FIEMAP || | 622 | if (flag != F2FS_GET_BLOCK_FIEMAP || |
613 | blkaddr != NEW_ADDR) { | 623 | blkaddr != NEW_ADDR) { |
614 | if (flag == F2FS_GET_BLOCK_BMAP) | 624 | if (flag == F2FS_GET_BLOCK_BMAP) |
@@ -669,13 +679,15 @@ out: | |||
669 | } | 679 | } |
670 | 680 | ||
671 | static int __get_data_block(struct inode *inode, sector_t iblock, | 681 | static int __get_data_block(struct inode *inode, sector_t iblock, |
672 | struct buffer_head *bh, int create, int flag) | 682 | struct buffer_head *bh, int create, int flag, |
683 | pgoff_t *next_pgofs) | ||
673 | { | 684 | { |
674 | struct f2fs_map_blocks map; | 685 | struct f2fs_map_blocks map; |
675 | int ret; | 686 | int ret; |
676 | 687 | ||
677 | map.m_lblk = iblock; | 688 | map.m_lblk = iblock; |
678 | map.m_len = bh->b_size >> inode->i_blkbits; | 689 | map.m_len = bh->b_size >> inode->i_blkbits; |
690 | map.m_next_pgofs = next_pgofs; | ||
679 | 691 | ||
680 | ret = f2fs_map_blocks(inode, &map, create, flag); | 692 | ret = f2fs_map_blocks(inode, &map, create, flag); |
681 | if (!ret) { | 693 | if (!ret) { |
@@ -687,16 +699,18 @@ static int __get_data_block(struct inode *inode, sector_t iblock, | |||
687 | } | 699 | } |
688 | 700 | ||
689 | static int get_data_block(struct inode *inode, sector_t iblock, | 701 | static int get_data_block(struct inode *inode, sector_t iblock, |
690 | struct buffer_head *bh_result, int create, int flag) | 702 | struct buffer_head *bh_result, int create, int flag, |
703 | pgoff_t *next_pgofs) | ||
691 | { | 704 | { |
692 | return __get_data_block(inode, iblock, bh_result, create, flag); | 705 | return __get_data_block(inode, iblock, bh_result, create, |
706 | flag, next_pgofs); | ||
693 | } | 707 | } |
694 | 708 | ||
695 | static int get_data_block_dio(struct inode *inode, sector_t iblock, | 709 | static int get_data_block_dio(struct inode *inode, sector_t iblock, |
696 | struct buffer_head *bh_result, int create) | 710 | struct buffer_head *bh_result, int create) |
697 | { | 711 | { |
698 | return __get_data_block(inode, iblock, bh_result, create, | 712 | return __get_data_block(inode, iblock, bh_result, create, |
699 | F2FS_GET_BLOCK_DIO); | 713 | F2FS_GET_BLOCK_DIO, NULL); |
700 | } | 714 | } |
701 | 715 | ||
702 | static int get_data_block_bmap(struct inode *inode, sector_t iblock, | 716 | static int get_data_block_bmap(struct inode *inode, sector_t iblock, |
@@ -707,7 +721,7 @@ static int get_data_block_bmap(struct inode *inode, sector_t iblock, | |||
707 | return -EFBIG; | 721 | return -EFBIG; |
708 | 722 | ||
709 | return __get_data_block(inode, iblock, bh_result, create, | 723 | return __get_data_block(inode, iblock, bh_result, create, |
710 | F2FS_GET_BLOCK_BMAP); | 724 | F2FS_GET_BLOCK_BMAP, NULL); |
711 | } | 725 | } |
712 | 726 | ||
713 | static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) | 727 | static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) |
@@ -725,6 +739,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | |||
725 | { | 739 | { |
726 | struct buffer_head map_bh; | 740 | struct buffer_head map_bh; |
727 | sector_t start_blk, last_blk; | 741 | sector_t start_blk, last_blk; |
742 | pgoff_t next_pgofs; | ||
728 | loff_t isize; | 743 | loff_t isize; |
729 | u64 logical = 0, phys = 0, size = 0; | 744 | u64 logical = 0, phys = 0, size = 0; |
730 | u32 flags = 0; | 745 | u32 flags = 0; |
@@ -760,14 +775,15 @@ next: | |||
760 | map_bh.b_size = len; | 775 | map_bh.b_size = len; |
761 | 776 | ||
762 | ret = get_data_block(inode, start_blk, &map_bh, 0, | 777 | ret = get_data_block(inode, start_blk, &map_bh, 0, |
763 | F2FS_GET_BLOCK_FIEMAP); | 778 | F2FS_GET_BLOCK_FIEMAP, &next_pgofs); |
764 | if (ret) | 779 | if (ret) |
765 | goto out; | 780 | goto out; |
766 | 781 | ||
767 | /* HOLE */ | 782 | /* HOLE */ |
768 | if (!buffer_mapped(&map_bh)) { | 783 | if (!buffer_mapped(&map_bh)) { |
784 | start_blk = next_pgofs; | ||
769 | /* Go through holes util pass the EOF */ | 785 | /* Go through holes util pass the EOF */ |
770 | if (blk_to_logical(inode, start_blk++) < isize) | 786 | if (blk_to_logical(inode, start_blk) < isize) |
771 | goto prep_next; | 787 | goto prep_next; |
772 | /* Found a hole beyond isize means no more extents. | 788 | /* Found a hole beyond isize means no more extents. |
773 | * Note that the premise is that filesystems don't | 789 | * Note that the premise is that filesystems don't |
@@ -835,6 +851,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping, | |||
835 | map.m_lblk = 0; | 851 | map.m_lblk = 0; |
836 | map.m_len = 0; | 852 | map.m_len = 0; |
837 | map.m_flags = 0; | 853 | map.m_flags = 0; |
854 | map.m_next_pgofs = NULL; | ||
838 | 855 | ||
839 | for (page_idx = 0; nr_pages; page_idx++, nr_pages--) { | 856 | for (page_idx = 0; nr_pages; page_idx++, nr_pages--) { |
840 | 857 | ||
@@ -873,7 +890,7 @@ static int f2fs_mpage_readpages(struct address_space *mapping, | |||
873 | map.m_len = last_block - block_in_file; | 890 | map.m_len = last_block - block_in_file; |
874 | 891 | ||
875 | if (f2fs_map_blocks(inode, &map, 0, | 892 | if (f2fs_map_blocks(inode, &map, 0, |
876 | F2FS_GET_BLOCK_READ)) | 893 | F2FS_GET_BLOCK_READ)) |
877 | goto set_error_page; | 894 | goto set_error_page; |
878 | } | 895 | } |
879 | got_it: | 896 | got_it: |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d86b52169d6e..469a1f49a3cd 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -383,6 +383,7 @@ struct f2fs_map_blocks { | |||
383 | block_t m_lblk; | 383 | block_t m_lblk; |
384 | unsigned int m_len; | 384 | unsigned int m_len; |
385 | unsigned int m_flags; | 385 | unsigned int m_flags; |
386 | pgoff_t *m_next_pgofs; /* point next possible non-hole pgofs */ | ||
386 | }; | 387 | }; |
387 | 388 | ||
388 | /* for flag in get_data_block */ | 389 | /* for flag in get_data_block */ |
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 8c51fc7d9396..50fa296efa67 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -1647,7 +1647,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, | |||
1647 | struct f2fs_defragment *range) | 1647 | struct f2fs_defragment *range) |
1648 | { | 1648 | { |
1649 | struct inode *inode = file_inode(filp); | 1649 | struct inode *inode = file_inode(filp); |
1650 | struct f2fs_map_blocks map; | 1650 | struct f2fs_map_blocks map = { .m_next_pgofs = NULL }; |
1651 | struct extent_info ei; | 1651 | struct extent_info ei; |
1652 | pgoff_t pg_start, pg_end; | 1652 | pgoff_t pg_start, pg_end; |
1653 | unsigned int blk_per_seg = sbi->blocks_per_seg; | 1653 | unsigned int blk_per_seg = sbi->blocks_per_seg; |