aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/extents.c23
-rw-r--r--fs/ext4/extents_status.c51
-rw-r--r--fs/ext4/inode.c7
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
4384out3: 4387out3:
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);
4412retry:
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
4413static void ext4_falloc_update_inode(struct inode *inode, 4428static 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);
149static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, 149static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei,
150 int nr_to_scan); 150 int nr_to_scan);
151static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan,
152 struct ext4_inode_info *locked_ei);
151 153
152int __init ext4_init_es(void) 154int __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;
670retry:
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
670error: 678error:
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
757retry:
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
892static int ext4_es_shrink(struct shrinker *shrink, struct shrink_control *sc) 906static 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
967static 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));