diff options
-rw-r--r-- | fs/ext4/extents.c | 23 | ||||
-rw-r--r-- | fs/ext4/extents_status.c | 51 | ||||
-rw-r--r-- | fs/ext4/inode.c | 7 |
3 files changed, 60 insertions, 21 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 7097b0f680e6..a61873808f76 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
@@ -2835,6 +2835,9 @@ again: | |||
2835 | err = -EIO; | 2835 | err = -EIO; |
2836 | break; | 2836 | break; |
2837 | } | 2837 | } |
2838 | /* Yield here to deal with large extent trees. | ||
2839 | * Should be a no-op if we did IO above. */ | ||
2840 | cond_resched(); | ||
2838 | if (WARN_ON(i + 1 > depth)) { | 2841 | if (WARN_ON(i + 1 > depth)) { |
2839 | err = -EIO; | 2842 | err = -EIO; |
2840 | break; | 2843 | break; |
@@ -4261,8 +4264,8 @@ got_allocated_blocks: | |||
4261 | /* not a good idea to call discard here directly, | 4264 | /* not a good idea to call discard here directly, |
4262 | * but otherwise we'd need to call it every free() */ | 4265 | * but otherwise we'd need to call it every free() */ |
4263 | ext4_discard_preallocations(inode); | 4266 | ext4_discard_preallocations(inode); |
4264 | ext4_free_blocks(handle, inode, NULL, ext4_ext_pblock(&newex), | 4267 | ext4_free_blocks(handle, inode, NULL, newblock, |
4265 | ext4_ext_get_actual_len(&newex), fb_flags); | 4268 | EXT4_C2B(sbi, allocated_clusters), fb_flags); |
4266 | goto out2; | 4269 | goto out2; |
4267 | } | 4270 | } |
4268 | 4271 | ||
@@ -4382,8 +4385,9 @@ out2: | |||
4382 | } | 4385 | } |
4383 | 4386 | ||
4384 | out3: | 4387 | out3: |
4385 | trace_ext4_ext_map_blocks_exit(inode, flags, map, err ? err : allocated); | 4388 | trace_ext4_ext_map_blocks_exit(inode, flags, map, |
4386 | 4389 | err ? err : allocated); | |
4390 | ext4_es_lru_add(inode); | ||
4387 | return err ? err : allocated; | 4391 | return err ? err : allocated; |
4388 | } | 4392 | } |
4389 | 4393 | ||
@@ -4405,9 +4409,20 @@ void ext4_ext_truncate(handle_t *handle, struct inode *inode) | |||
4405 | 4409 | ||
4406 | last_block = (inode->i_size + sb->s_blocksize - 1) | 4410 | last_block = (inode->i_size + sb->s_blocksize - 1) |
4407 | >> EXT4_BLOCK_SIZE_BITS(sb); | 4411 | >> EXT4_BLOCK_SIZE_BITS(sb); |
4412 | retry: | ||
4408 | err = ext4_es_remove_extent(inode, last_block, | 4413 | err = ext4_es_remove_extent(inode, last_block, |
4409 | EXT_MAX_BLOCKS - last_block); | 4414 | EXT_MAX_BLOCKS - last_block); |
4415 | if (err == ENOMEM) { | ||
4416 | cond_resched(); | ||
4417 | congestion_wait(BLK_RW_ASYNC, HZ/50); | ||
4418 | goto retry; | ||
4419 | } | ||
4420 | if (err) { | ||
4421 | ext4_std_error(inode->i_sb, err); | ||
4422 | return; | ||
4423 | } | ||
4410 | err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); | 4424 | err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); |
4425 | ext4_std_error(inode->i_sb, err); | ||
4411 | } | 4426 | } |
4412 | 4427 | ||
4413 | static void ext4_falloc_update_inode(struct inode *inode, | 4428 | static void ext4_falloc_update_inode(struct inode *inode, |
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 4b8df7fbb10a..91cb110da1b4 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
@@ -148,6 +148,8 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
148 | ext4_lblk_t end); | 148 | ext4_lblk_t end); |
149 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, | 149 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, |
150 | int nr_to_scan); | 150 | int nr_to_scan); |
151 | static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, | ||
152 | struct ext4_inode_info *locked_ei); | ||
151 | 153 | ||
152 | int __init ext4_init_es(void) | 154 | int __init ext4_init_es(void) |
153 | { | 155 | { |
@@ -665,7 +667,13 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, | |||
665 | err = __es_remove_extent(inode, lblk, end); | 667 | err = __es_remove_extent(inode, lblk, end); |
666 | if (err != 0) | 668 | if (err != 0) |
667 | goto error; | 669 | goto error; |
670 | retry: | ||
668 | err = __es_insert_extent(inode, &newes); | 671 | err = __es_insert_extent(inode, &newes); |
672 | if (err == -ENOMEM && __ext4_es_shrink(EXT4_SB(inode->i_sb), 1, | ||
673 | EXT4_I(inode))) | ||
674 | goto retry; | ||
675 | if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) | ||
676 | err = 0; | ||
669 | 677 | ||
670 | error: | 678 | error: |
671 | write_unlock(&EXT4_I(inode)->i_es_lock); | 679 | write_unlock(&EXT4_I(inode)->i_es_lock); |
@@ -744,8 +752,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
744 | struct extent_status orig_es; | 752 | struct extent_status orig_es; |
745 | ext4_lblk_t len1, len2; | 753 | ext4_lblk_t len1, len2; |
746 | ext4_fsblk_t block; | 754 | ext4_fsblk_t block; |
747 | int err = 0; | 755 | int err; |
748 | 756 | ||
757 | retry: | ||
758 | err = 0; | ||
749 | es = __es_tree_search(&tree->root, lblk); | 759 | es = __es_tree_search(&tree->root, lblk); |
750 | if (!es) | 760 | if (!es) |
751 | goto out; | 761 | goto out; |
@@ -780,6 +790,10 @@ static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | |||
780 | if (err) { | 790 | if (err) { |
781 | es->es_lblk = orig_es.es_lblk; | 791 | es->es_lblk = orig_es.es_lblk; |
782 | es->es_len = orig_es.es_len; | 792 | es->es_len = orig_es.es_len; |
793 | if ((err == -ENOMEM) && | ||
794 | __ext4_es_shrink(EXT4_SB(inode->i_sb), 1, | ||
795 | EXT4_I(inode))) | ||
796 | goto retry; | ||
783 | goto out; | 797 | goto out; |
784 | } | 798 | } |
785 | } else { | 799 | } else { |
@@ -889,22 +903,14 @@ static int ext4_inode_touch_time_cmp(void *priv, struct list_head *a, | |||
889 | return -1; | 903 | return -1; |
890 | } | 904 | } |
891 | 905 | ||
892 | static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | 906 | static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, |
907 | struct ext4_inode_info *locked_ei) | ||
893 | { | 908 | { |
894 | struct ext4_sb_info *sbi = container_of(shrink, | ||
895 | struct ext4_sb_info, s_es_shrinker); | ||
896 | struct ext4_inode_info *ei; | 909 | struct ext4_inode_info *ei; |
897 | struct list_head *cur, *tmp; | 910 | struct list_head *cur, *tmp; |
898 | LIST_HEAD(skiped); | 911 | LIST_HEAD(skiped); |
899 | int nr_to_scan = sc->nr_to_scan; | ||
900 | int ret, nr_shrunk = 0; | 912 | int ret, nr_shrunk = 0; |
901 | 913 | ||
902 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | ||
903 | trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | ||
904 | |||
905 | if (!nr_to_scan) | ||
906 | return ret; | ||
907 | |||
908 | spin_lock(&sbi->s_es_lru_lock); | 914 | spin_lock(&sbi->s_es_lru_lock); |
909 | 915 | ||
910 | /* | 916 | /* |
@@ -933,7 +939,7 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | |||
933 | continue; | 939 | continue; |
934 | } | 940 | } |
935 | 941 | ||
936 | if (ei->i_es_lru_nr == 0) | 942 | if (ei->i_es_lru_nr == 0 || ei == locked_ei) |
937 | continue; | 943 | continue; |
938 | 944 | ||
939 | write_lock(&ei->i_es_lock); | 945 | write_lock(&ei->i_es_lock); |
@@ -952,6 +958,27 @@ static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | |||
952 | list_splice_tail(&skiped, &sbi->s_es_lru); | 958 | list_splice_tail(&skiped, &sbi->s_es_lru); |
953 | spin_unlock(&sbi->s_es_lru_lock); | 959 | spin_unlock(&sbi->s_es_lru_lock); |
954 | 960 | ||
961 | if (locked_ei && nr_shrunk == 0) | ||
962 | nr_shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan); | ||
963 | |||
964 | return nr_shrunk; | ||
965 | } | ||
966 | |||
967 | static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) | ||
968 | { | ||
969 | struct ext4_sb_info *sbi = container_of(shrink, | ||
970 | struct ext4_sb_info, s_es_shrinker); | ||
971 | int nr_to_scan = sc->nr_to_scan; | ||
972 | int ret, nr_shrunk; | ||
973 | |||
974 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | ||
975 | trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | ||
976 | |||
977 | if (!nr_to_scan) | ||
978 | return ret; | ||
979 | |||
980 | nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL); | ||
981 | |||
955 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | 982 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); |
956 | trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret); | 983 | trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret); |
957 | return ret; | 984 | return ret; |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 98b9bff92a8a..ba33c67d6e48 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -514,10 +514,9 @@ int ext4_map_blocks(handle_t *handle, struct inode *inode, | |||
514 | "logical block %lu\n", inode->i_ino, flags, map->m_len, | 514 | "logical block %lu\n", inode->i_ino, flags, map->m_len, |
515 | (unsigned long) map->m_lblk); | 515 | (unsigned long) map->m_lblk); |
516 | 516 | ||
517 | ext4_es_lru_add(inode); | ||
518 | |||
519 | /* Lookup extent status tree firstly */ | 517 | /* Lookup extent status tree firstly */ |
520 | if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { | 518 | if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { |
519 | ext4_es_lru_add(inode); | ||
521 | if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { | 520 | if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { |
522 | map->m_pblk = ext4_es_pblock(&es) + | 521 | map->m_pblk = ext4_es_pblock(&es) + |
523 | map->m_lblk - es.es_lblk; | 522 | map->m_lblk - es.es_lblk; |
@@ -1529,11 +1528,9 @@ static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, | |||
1529 | "logical block %lu\n", inode->i_ino, map->m_len, | 1528 | "logical block %lu\n", inode->i_ino, map->m_len, |
1530 | (unsigned long) map->m_lblk); | 1529 | (unsigned long) map->m_lblk); |
1531 | 1530 | ||
1532 | ext4_es_lru_add(inode); | ||
1533 | |||
1534 | /* Lookup extent status tree firstly */ | 1531 | /* Lookup extent status tree firstly */ |
1535 | if (ext4_es_lookup_extent(inode, iblock, &es)) { | 1532 | if (ext4_es_lookup_extent(inode, iblock, &es)) { |
1536 | 1533 | ext4_es_lru_add(inode); | |
1537 | if (ext4_es_is_hole(&es)) { | 1534 | if (ext4_es_is_hole(&es)) { |
1538 | retval = 0; | 1535 | retval = 0; |
1539 | down_read((&EXT4_I(inode)->i_data_sem)); | 1536 | down_read((&EXT4_I(inode)->i_data_sem)); |