diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ext4/extents_status.c | 51 |
1 files changed, 39 insertions, 12 deletions
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; |