diff options
Diffstat (limited to 'fs/ext4/extents_status.c')
-rw-r--r-- | fs/ext4/extents_status.c | 200 |
1 files changed, 182 insertions, 18 deletions
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 0b7e28e7eaa4..94e7855ae71b 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
@@ -11,6 +11,8 @@ | |||
11 | */ | 11 | */ |
12 | #include <linux/rbtree.h> | 12 | #include <linux/rbtree.h> |
13 | #include <linux/list_sort.h> | 13 | #include <linux/list_sort.h> |
14 | #include <linux/proc_fs.h> | ||
15 | #include <linux/seq_file.h> | ||
14 | #include "ext4.h" | 16 | #include "ext4.h" |
15 | #include "extents_status.h" | 17 | #include "extents_status.h" |
16 | 18 | ||
@@ -313,19 +315,27 @@ ext4_es_alloc_extent(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len, | |||
313 | */ | 315 | */ |
314 | if (!ext4_es_is_delayed(es)) { | 316 | if (!ext4_es_is_delayed(es)) { |
315 | EXT4_I(inode)->i_es_lru_nr++; | 317 | EXT4_I(inode)->i_es_lru_nr++; |
316 | percpu_counter_inc(&EXT4_SB(inode->i_sb)->s_extent_cache_cnt); | 318 | percpu_counter_inc(&EXT4_SB(inode->i_sb)-> |
319 | s_es_stats.es_stats_lru_cnt); | ||
317 | } | 320 | } |
318 | 321 | ||
322 | EXT4_I(inode)->i_es_all_nr++; | ||
323 | percpu_counter_inc(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt); | ||
324 | |||
319 | return es; | 325 | return es; |
320 | } | 326 | } |
321 | 327 | ||
322 | static void ext4_es_free_extent(struct inode *inode, struct extent_status *es) | 328 | static void ext4_es_free_extent(struct inode *inode, struct extent_status *es) |
323 | { | 329 | { |
330 | EXT4_I(inode)->i_es_all_nr--; | ||
331 | percpu_counter_dec(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt); | ||
332 | |||
324 | /* Decrease the lru counter when this es is not delayed */ | 333 | /* Decrease the lru counter when this es is not delayed */ |
325 | if (!ext4_es_is_delayed(es)) { | 334 | if (!ext4_es_is_delayed(es)) { |
326 | BUG_ON(EXT4_I(inode)->i_es_lru_nr == 0); | 335 | BUG_ON(EXT4_I(inode)->i_es_lru_nr == 0); |
327 | EXT4_I(inode)->i_es_lru_nr--; | 336 | EXT4_I(inode)->i_es_lru_nr--; |
328 | percpu_counter_dec(&EXT4_SB(inode->i_sb)->s_extent_cache_cnt); | 337 | percpu_counter_dec(&EXT4_SB(inode->i_sb)-> |
338 | s_es_stats.es_stats_lru_cnt); | ||
329 | } | 339 | } |
330 | 340 | ||
331 | kmem_cache_free(ext4_es_cachep, es); | 341 | kmem_cache_free(ext4_es_cachep, es); |
@@ -426,7 +436,7 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, | |||
426 | unsigned short ee_len; | 436 | unsigned short ee_len; |
427 | int depth, ee_status, es_status; | 437 | int depth, ee_status, es_status; |
428 | 438 | ||
429 | path = ext4_ext_find_extent(inode, es->es_lblk, NULL, EXT4_EX_NOCACHE); | 439 | path = ext4_find_extent(inode, es->es_lblk, NULL, EXT4_EX_NOCACHE); |
430 | if (IS_ERR(path)) | 440 | if (IS_ERR(path)) |
431 | return; | 441 | return; |
432 | 442 | ||
@@ -499,10 +509,8 @@ static void ext4_es_insert_extent_ext_check(struct inode *inode, | |||
499 | } | 509 | } |
500 | } | 510 | } |
501 | out: | 511 | out: |
502 | if (path) { | 512 | ext4_ext_drop_refs(path); |
503 | ext4_ext_drop_refs(path); | 513 | kfree(path); |
504 | kfree(path); | ||
505 | } | ||
506 | } | 514 | } |
507 | 515 | ||
508 | static void ext4_es_insert_extent_ind_check(struct inode *inode, | 516 | static void ext4_es_insert_extent_ind_check(struct inode *inode, |
@@ -731,6 +739,7 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, | |||
731 | struct extent_status *es) | 739 | struct extent_status *es) |
732 | { | 740 | { |
733 | struct ext4_es_tree *tree; | 741 | struct ext4_es_tree *tree; |
742 | struct ext4_es_stats *stats; | ||
734 | struct extent_status *es1 = NULL; | 743 | struct extent_status *es1 = NULL; |
735 | struct rb_node *node; | 744 | struct rb_node *node; |
736 | int found = 0; | 745 | int found = 0; |
@@ -767,11 +776,15 @@ int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, | |||
767 | } | 776 | } |
768 | 777 | ||
769 | out: | 778 | out: |
779 | stats = &EXT4_SB(inode->i_sb)->s_es_stats; | ||
770 | if (found) { | 780 | if (found) { |
771 | BUG_ON(!es1); | 781 | BUG_ON(!es1); |
772 | es->es_lblk = es1->es_lblk; | 782 | es->es_lblk = es1->es_lblk; |
773 | es->es_len = es1->es_len; | 783 | es->es_len = es1->es_len; |
774 | es->es_pblk = es1->es_pblk; | 784 | es->es_pblk = es1->es_pblk; |
785 | stats->es_stats_cache_hits++; | ||
786 | } else { | ||
787 | stats->es_stats_cache_misses++; | ||
775 | } | 788 | } |
776 | 789 | ||
777 | read_unlock(&EXT4_I(inode)->i_es_lock); | 790 | read_unlock(&EXT4_I(inode)->i_es_lock); |
@@ -933,11 +946,16 @@ static int __ext4_es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, | |||
933 | struct ext4_inode_info *locked_ei) | 946 | struct ext4_inode_info *locked_ei) |
934 | { | 947 | { |
935 | struct ext4_inode_info *ei; | 948 | struct ext4_inode_info *ei; |
949 | struct ext4_es_stats *es_stats; | ||
936 | struct list_head *cur, *tmp; | 950 | struct list_head *cur, *tmp; |
937 | LIST_HEAD(skipped); | 951 | LIST_HEAD(skipped); |
952 | ktime_t start_time; | ||
953 | u64 scan_time; | ||
938 | int nr_shrunk = 0; | 954 | int nr_shrunk = 0; |
939 | int retried = 0, skip_precached = 1, nr_skipped = 0; | 955 | int retried = 0, skip_precached = 1, nr_skipped = 0; |
940 | 956 | ||
957 | es_stats = &sbi->s_es_stats; | ||
958 | start_time = ktime_get(); | ||
941 | spin_lock(&sbi->s_es_lru_lock); | 959 | spin_lock(&sbi->s_es_lru_lock); |
942 | 960 | ||
943 | retry: | 961 | retry: |
@@ -948,7 +966,8 @@ retry: | |||
948 | * If we have already reclaimed all extents from extent | 966 | * If we have already reclaimed all extents from extent |
949 | * status tree, just stop the loop immediately. | 967 | * status tree, just stop the loop immediately. |
950 | */ | 968 | */ |
951 | if (percpu_counter_read_positive(&sbi->s_extent_cache_cnt) == 0) | 969 | if (percpu_counter_read_positive( |
970 | &es_stats->es_stats_lru_cnt) == 0) | ||
952 | break; | 971 | break; |
953 | 972 | ||
954 | ei = list_entry(cur, struct ext4_inode_info, i_es_lru); | 973 | ei = list_entry(cur, struct ext4_inode_info, i_es_lru); |
@@ -958,7 +977,7 @@ retry: | |||
958 | * time. Normally we try hard to avoid shrinking | 977 | * time. Normally we try hard to avoid shrinking |
959 | * precached inodes, but we will as a last resort. | 978 | * precached inodes, but we will as a last resort. |
960 | */ | 979 | */ |
961 | if ((sbi->s_es_last_sorted < ei->i_touch_when) || | 980 | if ((es_stats->es_stats_last_sorted < ei->i_touch_when) || |
962 | (skip_precached && ext4_test_inode_state(&ei->vfs_inode, | 981 | (skip_precached && ext4_test_inode_state(&ei->vfs_inode, |
963 | EXT4_STATE_EXT_PRECACHED))) { | 982 | EXT4_STATE_EXT_PRECACHED))) { |
964 | nr_skipped++; | 983 | nr_skipped++; |
@@ -992,7 +1011,7 @@ retry: | |||
992 | if ((nr_shrunk == 0) && nr_skipped && !retried) { | 1011 | if ((nr_shrunk == 0) && nr_skipped && !retried) { |
993 | retried++; | 1012 | retried++; |
994 | list_sort(NULL, &sbi->s_es_lru, ext4_inode_touch_time_cmp); | 1013 | list_sort(NULL, &sbi->s_es_lru, ext4_inode_touch_time_cmp); |
995 | sbi->s_es_last_sorted = jiffies; | 1014 | es_stats->es_stats_last_sorted = jiffies; |
996 | ei = list_first_entry(&sbi->s_es_lru, struct ext4_inode_info, | 1015 | ei = list_first_entry(&sbi->s_es_lru, struct ext4_inode_info, |
997 | i_es_lru); | 1016 | i_es_lru); |
998 | /* | 1017 | /* |
@@ -1010,6 +1029,22 @@ retry: | |||
1010 | if (locked_ei && nr_shrunk == 0) | 1029 | if (locked_ei && nr_shrunk == 0) |
1011 | nr_shrunk = __es_try_to_reclaim_extents(locked_ei, nr_to_scan); | 1030 | nr_shrunk = __es_try_to_reclaim_extents(locked_ei, nr_to_scan); |
1012 | 1031 | ||
1032 | scan_time = ktime_to_ns(ktime_sub(ktime_get(), start_time)); | ||
1033 | if (likely(es_stats->es_stats_scan_time)) | ||
1034 | es_stats->es_stats_scan_time = (scan_time + | ||
1035 | es_stats->es_stats_scan_time*3) / 4; | ||
1036 | else | ||
1037 | es_stats->es_stats_scan_time = scan_time; | ||
1038 | if (scan_time > es_stats->es_stats_max_scan_time) | ||
1039 | es_stats->es_stats_max_scan_time = scan_time; | ||
1040 | if (likely(es_stats->es_stats_shrunk)) | ||
1041 | es_stats->es_stats_shrunk = (nr_shrunk + | ||
1042 | es_stats->es_stats_shrunk*3) / 4; | ||
1043 | else | ||
1044 | es_stats->es_stats_shrunk = nr_shrunk; | ||
1045 | |||
1046 | trace_ext4_es_shrink(sbi->s_sb, nr_shrunk, scan_time, skip_precached, | ||
1047 | nr_skipped, retried); | ||
1013 | return nr_shrunk; | 1048 | return nr_shrunk; |
1014 | } | 1049 | } |
1015 | 1050 | ||
@@ -1020,8 +1055,8 @@ static unsigned long ext4_es_count(struct shrinker *shrink, | |||
1020 | struct ext4_sb_info *sbi; | 1055 | struct ext4_sb_info *sbi; |
1021 | 1056 | ||
1022 | sbi = container_of(shrink, struct ext4_sb_info, s_es_shrinker); | 1057 | sbi = container_of(shrink, struct ext4_sb_info, s_es_shrinker); |
1023 | nr = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | 1058 | nr = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_lru_cnt); |
1024 | trace_ext4_es_shrink_enter(sbi->s_sb, sc->nr_to_scan, nr); | 1059 | trace_ext4_es_shrink_count(sbi->s_sb, sc->nr_to_scan, nr); |
1025 | return nr; | 1060 | return nr; |
1026 | } | 1061 | } |
1027 | 1062 | ||
@@ -1033,31 +1068,160 @@ static unsigned long ext4_es_scan(struct shrinker *shrink, | |||
1033 | int nr_to_scan = sc->nr_to_scan; | 1068 | int nr_to_scan = sc->nr_to_scan; |
1034 | int ret, nr_shrunk; | 1069 | int ret, nr_shrunk; |
1035 | 1070 | ||
1036 | ret = percpu_counter_read_positive(&sbi->s_extent_cache_cnt); | 1071 | ret = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_lru_cnt); |
1037 | trace_ext4_es_shrink_enter(sbi->s_sb, nr_to_scan, ret); | 1072 | trace_ext4_es_shrink_scan_enter(sbi->s_sb, nr_to_scan, ret); |
1038 | 1073 | ||
1039 | if (!nr_to_scan) | 1074 | if (!nr_to_scan) |
1040 | return ret; | 1075 | return ret; |
1041 | 1076 | ||
1042 | nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL); | 1077 | nr_shrunk = __ext4_es_shrink(sbi, nr_to_scan, NULL); |
1043 | 1078 | ||
1044 | trace_ext4_es_shrink_exit(sbi->s_sb, nr_shrunk, ret); | 1079 | trace_ext4_es_shrink_scan_exit(sbi->s_sb, nr_shrunk, ret); |
1045 | return nr_shrunk; | 1080 | return nr_shrunk; |
1046 | } | 1081 | } |
1047 | 1082 | ||
1048 | void ext4_es_register_shrinker(struct ext4_sb_info *sbi) | 1083 | static void *ext4_es_seq_shrinker_info_start(struct seq_file *seq, loff_t *pos) |
1049 | { | 1084 | { |
1085 | return *pos ? NULL : SEQ_START_TOKEN; | ||
1086 | } | ||
1087 | |||
1088 | static void * | ||
1089 | ext4_es_seq_shrinker_info_next(struct seq_file *seq, void *v, loff_t *pos) | ||
1090 | { | ||
1091 | return NULL; | ||
1092 | } | ||
1093 | |||
1094 | static int ext4_es_seq_shrinker_info_show(struct seq_file *seq, void *v) | ||
1095 | { | ||
1096 | struct ext4_sb_info *sbi = seq->private; | ||
1097 | struct ext4_es_stats *es_stats = &sbi->s_es_stats; | ||
1098 | struct ext4_inode_info *ei, *max = NULL; | ||
1099 | unsigned int inode_cnt = 0; | ||
1100 | |||
1101 | if (v != SEQ_START_TOKEN) | ||
1102 | return 0; | ||
1103 | |||
1104 | /* here we just find an inode that has the max nr. of objects */ | ||
1105 | spin_lock(&sbi->s_es_lru_lock); | ||
1106 | list_for_each_entry(ei, &sbi->s_es_lru, i_es_lru) { | ||
1107 | inode_cnt++; | ||
1108 | if (max && max->i_es_all_nr < ei->i_es_all_nr) | ||
1109 | max = ei; | ||
1110 | else if (!max) | ||
1111 | max = ei; | ||
1112 | } | ||
1113 | spin_unlock(&sbi->s_es_lru_lock); | ||
1114 | |||
1115 | seq_printf(seq, "stats:\n %lld objects\n %lld reclaimable objects\n", | ||
1116 | percpu_counter_sum_positive(&es_stats->es_stats_all_cnt), | ||
1117 | percpu_counter_sum_positive(&es_stats->es_stats_lru_cnt)); | ||
1118 | seq_printf(seq, " %lu/%lu cache hits/misses\n", | ||
1119 | es_stats->es_stats_cache_hits, | ||
1120 | es_stats->es_stats_cache_misses); | ||
1121 | if (es_stats->es_stats_last_sorted != 0) | ||
1122 | seq_printf(seq, " %u ms last sorted interval\n", | ||
1123 | jiffies_to_msecs(jiffies - | ||
1124 | es_stats->es_stats_last_sorted)); | ||
1125 | if (inode_cnt) | ||
1126 | seq_printf(seq, " %d inodes on lru list\n", inode_cnt); | ||
1127 | |||
1128 | seq_printf(seq, "average:\n %llu us scan time\n", | ||
1129 | div_u64(es_stats->es_stats_scan_time, 1000)); | ||
1130 | seq_printf(seq, " %lu shrunk objects\n", es_stats->es_stats_shrunk); | ||
1131 | if (inode_cnt) | ||
1132 | seq_printf(seq, | ||
1133 | "maximum:\n %lu inode (%u objects, %u reclaimable)\n" | ||
1134 | " %llu us max scan time\n", | ||
1135 | max->vfs_inode.i_ino, max->i_es_all_nr, max->i_es_lru_nr, | ||
1136 | div_u64(es_stats->es_stats_max_scan_time, 1000)); | ||
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | static void ext4_es_seq_shrinker_info_stop(struct seq_file *seq, void *v) | ||
1142 | { | ||
1143 | } | ||
1144 | |||
1145 | static const struct seq_operations ext4_es_seq_shrinker_info_ops = { | ||
1146 | .start = ext4_es_seq_shrinker_info_start, | ||
1147 | .next = ext4_es_seq_shrinker_info_next, | ||
1148 | .stop = ext4_es_seq_shrinker_info_stop, | ||
1149 | .show = ext4_es_seq_shrinker_info_show, | ||
1150 | }; | ||
1151 | |||
1152 | static int | ||
1153 | ext4_es_seq_shrinker_info_open(struct inode *inode, struct file *file) | ||
1154 | { | ||
1155 | int ret; | ||
1156 | |||
1157 | ret = seq_open(file, &ext4_es_seq_shrinker_info_ops); | ||
1158 | if (!ret) { | ||
1159 | struct seq_file *m = file->private_data; | ||
1160 | m->private = PDE_DATA(inode); | ||
1161 | } | ||
1162 | |||
1163 | return ret; | ||
1164 | } | ||
1165 | |||
1166 | static int | ||
1167 | ext4_es_seq_shrinker_info_release(struct inode *inode, struct file *file) | ||
1168 | { | ||
1169 | return seq_release(inode, file); | ||
1170 | } | ||
1171 | |||
1172 | static const struct file_operations ext4_es_seq_shrinker_info_fops = { | ||
1173 | .owner = THIS_MODULE, | ||
1174 | .open = ext4_es_seq_shrinker_info_open, | ||
1175 | .read = seq_read, | ||
1176 | .llseek = seq_lseek, | ||
1177 | .release = ext4_es_seq_shrinker_info_release, | ||
1178 | }; | ||
1179 | |||
1180 | int ext4_es_register_shrinker(struct ext4_sb_info *sbi) | ||
1181 | { | ||
1182 | int err; | ||
1183 | |||
1050 | INIT_LIST_HEAD(&sbi->s_es_lru); | 1184 | INIT_LIST_HEAD(&sbi->s_es_lru); |
1051 | spin_lock_init(&sbi->s_es_lru_lock); | 1185 | spin_lock_init(&sbi->s_es_lru_lock); |
1052 | sbi->s_es_last_sorted = 0; | 1186 | sbi->s_es_stats.es_stats_last_sorted = 0; |
1187 | sbi->s_es_stats.es_stats_shrunk = 0; | ||
1188 | sbi->s_es_stats.es_stats_cache_hits = 0; | ||
1189 | sbi->s_es_stats.es_stats_cache_misses = 0; | ||
1190 | sbi->s_es_stats.es_stats_scan_time = 0; | ||
1191 | sbi->s_es_stats.es_stats_max_scan_time = 0; | ||
1192 | err = percpu_counter_init(&sbi->s_es_stats.es_stats_all_cnt, 0, GFP_KERNEL); | ||
1193 | if (err) | ||
1194 | return err; | ||
1195 | err = percpu_counter_init(&sbi->s_es_stats.es_stats_lru_cnt, 0, GFP_KERNEL); | ||
1196 | if (err) | ||
1197 | goto err1; | ||
1198 | |||
1053 | sbi->s_es_shrinker.scan_objects = ext4_es_scan; | 1199 | sbi->s_es_shrinker.scan_objects = ext4_es_scan; |
1054 | sbi->s_es_shrinker.count_objects = ext4_es_count; | 1200 | sbi->s_es_shrinker.count_objects = ext4_es_count; |
1055 | sbi->s_es_shrinker.seeks = DEFAULT_SEEKS; | 1201 | sbi->s_es_shrinker.seeks = DEFAULT_SEEKS; |
1056 | register_shrinker(&sbi->s_es_shrinker); | 1202 | err = register_shrinker(&sbi->s_es_shrinker); |
1203 | if (err) | ||
1204 | goto err2; | ||
1205 | |||
1206 | if (sbi->s_proc) | ||
1207 | proc_create_data("es_shrinker_info", S_IRUGO, sbi->s_proc, | ||
1208 | &ext4_es_seq_shrinker_info_fops, sbi); | ||
1209 | |||
1210 | return 0; | ||
1211 | |||
1212 | err2: | ||
1213 | percpu_counter_destroy(&sbi->s_es_stats.es_stats_lru_cnt); | ||
1214 | err1: | ||
1215 | percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt); | ||
1216 | return err; | ||
1057 | } | 1217 | } |
1058 | 1218 | ||
1059 | void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi) | 1219 | void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi) |
1060 | { | 1220 | { |
1221 | if (sbi->s_proc) | ||
1222 | remove_proc_entry("es_shrinker_info", sbi->s_proc); | ||
1223 | percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt); | ||
1224 | percpu_counter_destroy(&sbi->s_es_stats.es_stats_lru_cnt); | ||
1061 | unregister_shrinker(&sbi->s_es_shrinker); | 1225 | unregister_shrinker(&sbi->s_es_shrinker); |
1062 | } | 1226 | } |
1063 | 1227 | ||