diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 5 | ||||
-rw-r--r-- | fs/ext4/extents_status.c | 91 | ||||
-rw-r--r-- | fs/ext4/super.c | 1 |
3 files changed, 64 insertions, 33 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index ab6caf55f5bf..4186ec84f835 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -881,6 +881,9 @@ struct ext4_inode_info { | |||
881 | struct list_head i_es_list; | 881 | struct list_head i_es_list; |
882 | unsigned int i_es_all_nr; /* protected by i_es_lock */ | 882 | unsigned int i_es_all_nr; /* protected by i_es_lock */ |
883 | unsigned int i_es_shk_nr; /* protected by i_es_lock */ | 883 | unsigned int i_es_shk_nr; /* protected by i_es_lock */ |
884 | ext4_lblk_t i_es_shrink_lblk; /* Offset where we start searching for | ||
885 | extents to shrink. Protected by | ||
886 | i_es_lock */ | ||
884 | 887 | ||
885 | /* ialloc */ | 888 | /* ialloc */ |
886 | ext4_group_t i_last_alloc_group; | 889 | ext4_group_t i_last_alloc_group; |
@@ -1321,7 +1324,7 @@ struct ext4_sb_info { | |||
1321 | 1324 | ||
1322 | /* Reclaim extents from extent status tree */ | 1325 | /* Reclaim extents from extent status tree */ |
1323 | struct shrinker s_es_shrinker; | 1326 | struct shrinker s_es_shrinker; |
1324 | struct list_head s_es_list; | 1327 | struct list_head s_es_list; /* List of inodes with reclaimable extents */ |
1325 | long s_es_nr_inode; | 1328 | long s_es_nr_inode; |
1326 | struct ext4_es_stats s_es_stats; | 1329 | struct ext4_es_stats s_es_stats; |
1327 | struct mb_cache *s_mb_cache; | 1330 | struct mb_cache *s_mb_cache; |
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index de2d9d8bf22f..8f2aac4006d2 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
@@ -147,8 +147,7 @@ static struct kmem_cache *ext4_es_cachep; | |||
147 | static int __es_insert_extent(struct inode *inode, struct extent_status *newes); | 147 | static int __es_insert_extent(struct inode *inode, struct extent_status *newes); |
148 | static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, | 148 | static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, |
149 | ext4_lblk_t end); | 149 | ext4_lblk_t end); |
150 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, | 150 | static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan); |
151 | int nr_to_scan); | ||
152 | static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, | 151 | static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, |
153 | struct ext4_inode_info *locked_ei); | 152 | struct ext4_inode_info *locked_ei); |
154 | 153 | ||
@@ -716,7 +715,7 @@ int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, | |||
716 | retry: | 715 | retry: |
717 | err = __es_insert_extent(inode, &newes); | 716 | err = __es_insert_extent(inode, &newes); |
718 | if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb), | 717 | if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb), |
719 | 1, EXT4_I(inode))) | 718 | 128, EXT4_I(inode))) |
720 | goto retry; | 719 | goto retry; |
721 | if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) | 720 | if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) |
722 | err = 0; | 721 | err = 0; |
@@ -874,7 +873,7 @@ retry: | |||
874 | es->es_len = orig_es.es_len; | 873 | es->es_len = orig_es.es_len; |
875 | if ((err == -ENOMEM) && | 874 | if ((err == -ENOMEM) && |
876 | __es_shrink(EXT4_SB(inode->i_sb), | 875 | __es_shrink(EXT4_SB(inode->i_sb), |
877 | 1, EXT4_I(inode))) | 876 | 128, EXT4_I(inode))) |
878 | goto retry; | 877 | goto retry; |
879 | goto out; | 878 | goto out; |
880 | } | 879 | } |
@@ -976,8 +975,6 @@ retry: | |||
976 | spin_lock(&sbi->s_es_lock); | 975 | spin_lock(&sbi->s_es_lock); |
977 | nr_to_walk = sbi->s_es_nr_inode; | 976 | nr_to_walk = sbi->s_es_nr_inode; |
978 | while (nr_to_walk-- > 0) { | 977 | while (nr_to_walk-- > 0) { |
979 | int shrunk; | ||
980 | |||
981 | if (list_empty(&sbi->s_es_list)) { | 978 | if (list_empty(&sbi->s_es_list)) { |
982 | spin_unlock(&sbi->s_es_lock); | 979 | spin_unlock(&sbi->s_es_lock); |
983 | goto out; | 980 | goto out; |
@@ -985,7 +982,7 @@ retry: | |||
985 | ei = list_first_entry(&sbi->s_es_list, struct ext4_inode_info, | 982 | ei = list_first_entry(&sbi->s_es_list, struct ext4_inode_info, |
986 | i_es_list); | 983 | i_es_list); |
987 | /* Move the inode to the tail */ | 984 | /* Move the inode to the tail */ |
988 | list_move(&ei->i_es_list, sbi->s_es_list.prev); | 985 | list_move_tail(&ei->i_es_list, &sbi->s_es_list); |
989 | 986 | ||
990 | /* | 987 | /* |
991 | * Normally we try hard to avoid shrinking precached inodes, | 988 | * Normally we try hard to avoid shrinking precached inodes, |
@@ -1007,13 +1004,10 @@ retry: | |||
1007 | */ | 1004 | */ |
1008 | spin_unlock(&sbi->s_es_lock); | 1005 | spin_unlock(&sbi->s_es_lock); |
1009 | 1006 | ||
1010 | shrunk = __es_try_to_reclaim_extents(ei, nr_to_scan); | 1007 | nr_shrunk += es_reclaim_extents(ei, &nr_to_scan); |
1011 | write_unlock(&ei->i_es_lock); | 1008 | write_unlock(&ei->i_es_lock); |
1012 | 1009 | ||
1013 | nr_shrunk += shrunk; | 1010 | if (nr_to_scan <= 0) |
1014 | nr_to_scan -= shrunk; | ||
1015 | |||
1016 | if (nr_to_scan == 0) | ||
1017 | goto out; | 1011 | goto out; |
1018 | spin_lock(&sbi->s_es_lock); | 1012 | spin_lock(&sbi->s_es_lock); |
1019 | } | 1013 | } |
@@ -1029,7 +1023,7 @@ retry: | |||
1029 | } | 1023 | } |
1030 | 1024 | ||
1031 | if (locked_ei && nr_shrunk == 0) | 1025 | if (locked_ei && nr_shrunk == 0) |
1032 | nr_shrunk = __es_try_to_reclaim_extents(locked_ei, nr_to_scan); | 1026 | nr_shrunk = es_reclaim_extents(locked_ei, &nr_to_scan); |
1033 | 1027 | ||
1034 | out: | 1028 | out: |
1035 | scan_time = ktime_to_ns(ktime_sub(ktime_get(), start_time)); | 1029 | scan_time = ktime_to_ns(ktime_sub(ktime_get(), start_time)); |
@@ -1224,27 +1218,33 @@ void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi) | |||
1224 | unregister_shrinker(&sbi->s_es_shrinker); | 1218 | unregister_shrinker(&sbi->s_es_shrinker); |
1225 | } | 1219 | } |
1226 | 1220 | ||
1227 | static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, | 1221 | /* |
1228 | int nr_to_scan) | 1222 | * Shrink extents in given inode from ei->i_es_shrink_lblk till end. Scan at |
1223 | * most *nr_to_scan extents, update *nr_to_scan accordingly. | ||
1224 | * | ||
1225 | * Return 0 if we hit end of tree / interval, 1 if we exhausted nr_to_scan. | ||
1226 | * Increment *nr_shrunk by the number of reclaimed extents. Also update | ||
1227 | * ei->i_es_shrink_lblk to where we should continue scanning. | ||
1228 | */ | ||
1229 | static int es_do_reclaim_extents(struct ext4_inode_info *ei, ext4_lblk_t end, | ||
1230 | int *nr_to_scan, int *nr_shrunk) | ||
1229 | { | 1231 | { |
1230 | struct inode *inode = &ei->vfs_inode; | 1232 | struct inode *inode = &ei->vfs_inode; |
1231 | struct ext4_es_tree *tree = &ei->i_es_tree; | 1233 | struct ext4_es_tree *tree = &ei->i_es_tree; |
1232 | struct rb_node *node; | ||
1233 | struct extent_status *es; | 1234 | struct extent_status *es; |
1234 | unsigned long nr_shrunk = 0; | 1235 | struct rb_node *node; |
1235 | static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, | ||
1236 | DEFAULT_RATELIMIT_BURST); | ||
1237 | |||
1238 | if (ei->i_es_shk_nr == 0) | ||
1239 | return 0; | ||
1240 | 1236 | ||
1241 | if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED) && | 1237 | es = __es_tree_search(&tree->root, ei->i_es_shrink_lblk); |
1242 | __ratelimit(&_rs)) | 1238 | if (!es) |
1243 | ext4_warning(inode->i_sb, "forced shrink of precached extents"); | 1239 | goto out_wrap; |
1240 | node = &es->rb_node; | ||
1241 | while (*nr_to_scan > 0) { | ||
1242 | if (es->es_lblk > end) { | ||
1243 | ei->i_es_shrink_lblk = end + 1; | ||
1244 | return 0; | ||
1245 | } | ||
1244 | 1246 | ||
1245 | node = rb_first(&tree->root); | 1247 | (*nr_to_scan)--; |
1246 | while (node != NULL) { | ||
1247 | es = rb_entry(node, struct extent_status, rb_node); | ||
1248 | node = rb_next(&es->rb_node); | 1248 | node = rb_next(&es->rb_node); |
1249 | /* | 1249 | /* |
1250 | * We can't reclaim delayed extent from status tree because | 1250 | * We can't reclaim delayed extent from status tree because |
@@ -1253,11 +1253,38 @@ static int __es_try_to_reclaim_extents(struct ext4_inode_info *ei, | |||
1253 | if (!ext4_es_is_delayed(es)) { | 1253 | if (!ext4_es_is_delayed(es)) { |
1254 | rb_erase(&es->rb_node, &tree->root); | 1254 | rb_erase(&es->rb_node, &tree->root); |
1255 | ext4_es_free_extent(inode, es); | 1255 | ext4_es_free_extent(inode, es); |
1256 | nr_shrunk++; | 1256 | (*nr_shrunk)++; |
1257 | if (--nr_to_scan == 0) | ||
1258 | break; | ||
1259 | } | 1257 | } |
1258 | if (!node) | ||
1259 | goto out_wrap; | ||
1260 | es = rb_entry(node, struct extent_status, rb_node); | ||
1260 | } | 1261 | } |
1261 | tree->cache_es = NULL; | 1262 | ei->i_es_shrink_lblk = es->es_lblk; |
1263 | return 1; | ||
1264 | out_wrap: | ||
1265 | ei->i_es_shrink_lblk = 0; | ||
1266 | return 0; | ||
1267 | } | ||
1268 | |||
1269 | static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan) | ||
1270 | { | ||
1271 | struct inode *inode = &ei->vfs_inode; | ||
1272 | int nr_shrunk = 0; | ||
1273 | ext4_lblk_t start = ei->i_es_shrink_lblk; | ||
1274 | static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, | ||
1275 | DEFAULT_RATELIMIT_BURST); | ||
1276 | |||
1277 | if (ei->i_es_shk_nr == 0) | ||
1278 | return 0; | ||
1279 | |||
1280 | if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED) && | ||
1281 | __ratelimit(&_rs)) | ||
1282 | ext4_warning(inode->i_sb, "forced shrink of precached extents"); | ||
1283 | |||
1284 | if (!es_do_reclaim_extents(ei, EXT_MAX_BLOCKS, nr_to_scan, &nr_shrunk) && | ||
1285 | start != 0) | ||
1286 | es_do_reclaim_extents(ei, start - 1, nr_to_scan, &nr_shrunk); | ||
1287 | |||
1288 | ei->i_es_tree.cache_es = NULL; | ||
1262 | return nr_shrunk; | 1289 | return nr_shrunk; |
1263 | } | 1290 | } |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index e2a17f8b7adc..48318497e8e9 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -874,6 +874,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) | |||
874 | INIT_LIST_HEAD(&ei->i_es_list); | 874 | INIT_LIST_HEAD(&ei->i_es_list); |
875 | ei->i_es_all_nr = 0; | 875 | ei->i_es_all_nr = 0; |
876 | ei->i_es_shk_nr = 0; | 876 | ei->i_es_shk_nr = 0; |
877 | ei->i_es_shrink_lblk = 0; | ||
877 | ei->i_reserved_data_blocks = 0; | 878 | ei->i_reserved_data_blocks = 0; |
878 | ei->i_reserved_meta_blocks = 0; | 879 | ei->i_reserved_meta_blocks = 0; |
879 | ei->i_allocated_meta_blocks = 0; | 880 | ei->i_allocated_meta_blocks = 0; |