diff options
| -rw-r--r-- | fs/ext4/extents_status.c | 22 | ||||
| -rw-r--r-- | fs/ext4/extents_status.h | 35 |
2 files changed, 48 insertions, 9 deletions
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c index 30596498ed0b..e04d45733976 100644 --- a/fs/ext4/extents_status.c +++ b/fs/ext4/extents_status.c | |||
| @@ -382,7 +382,7 @@ static void ext4_es_free_extent(struct inode *inode, struct extent_status *es) | |||
| 382 | static int ext4_es_can_be_merged(struct extent_status *es1, | 382 | static int ext4_es_can_be_merged(struct extent_status *es1, |
| 383 | struct extent_status *es2) | 383 | struct extent_status *es2) |
| 384 | { | 384 | { |
| 385 | if (ext4_es_status(es1) != ext4_es_status(es2)) | 385 | if (ext4_es_type(es1) != ext4_es_type(es2)) |
| 386 | return 0; | 386 | return 0; |
| 387 | 387 | ||
| 388 | if (((__u64) es1->es_len) + es2->es_len > EXT_MAX_BLOCKS) { | 388 | if (((__u64) es1->es_len) + es2->es_len > EXT_MAX_BLOCKS) { |
| @@ -425,6 +425,8 @@ ext4_es_try_to_merge_left(struct inode *inode, struct extent_status *es) | |||
| 425 | es1 = rb_entry(node, struct extent_status, rb_node); | 425 | es1 = rb_entry(node, struct extent_status, rb_node); |
| 426 | if (ext4_es_can_be_merged(es1, es)) { | 426 | if (ext4_es_can_be_merged(es1, es)) { |
| 427 | es1->es_len += es->es_len; | 427 | es1->es_len += es->es_len; |
| 428 | if (ext4_es_is_referenced(es)) | ||
| 429 | ext4_es_set_referenced(es1); | ||
| 428 | rb_erase(&es->rb_node, &tree->root); | 430 | rb_erase(&es->rb_node, &tree->root); |
| 429 | ext4_es_free_extent(inode, es); | 431 | ext4_es_free_extent(inode, es); |
| 430 | es = es1; | 432 | es = es1; |
| @@ -447,6 +449,8 @@ ext4_es_try_to_merge_right(struct inode *inode, struct extent_status *es) | |||
| 447 | es1 = rb_entry(node, struct extent_status, rb_node); | 449 | es1 = rb_entry(node, struct extent_status, rb_node); |
| 448 | if (ext4_es_can_be_merged(es, es1)) { | 450 | if (ext4_es_can_be_merged(es, es1)) { |
| 449 | es->es_len += es1->es_len; | 451 | es->es_len += es1->es_len; |
| 452 | if (ext4_es_is_referenced(es1)) | ||
| 453 | ext4_es_set_referenced(es); | ||
| 450 | rb_erase(node, &tree->root); | 454 | rb_erase(node, &tree->root); |
| 451 | ext4_es_free_extent(inode, es1); | 455 | ext4_es_free_extent(inode, es1); |
| 452 | } | 456 | } |
| @@ -813,6 +817,8 @@ out: | |||
| 813 | es->es_lblk = es1->es_lblk; | 817 | es->es_lblk = es1->es_lblk; |
| 814 | es->es_len = es1->es_len; | 818 | es->es_len = es1->es_len; |
| 815 | es->es_pblk = es1->es_pblk; | 819 | es->es_pblk = es1->es_pblk; |
| 820 | if (!ext4_es_is_referenced(es)) | ||
| 821 | ext4_es_set_referenced(es); | ||
| 816 | stats->es_stats_cache_hits++; | 822 | stats->es_stats_cache_hits++; |
| 817 | } else { | 823 | } else { |
| 818 | stats->es_stats_cache_misses++; | 824 | stats->es_stats_cache_misses++; |
| @@ -1252,11 +1258,17 @@ static int es_do_reclaim_extents(struct ext4_inode_info *ei, ext4_lblk_t end, | |||
| 1252 | * We can't reclaim delayed extent from status tree because | 1258 | * We can't reclaim delayed extent from status tree because |
| 1253 | * fiemap, bigallic, and seek_data/hole need to use it. | 1259 | * fiemap, bigallic, and seek_data/hole need to use it. |
| 1254 | */ | 1260 | */ |
| 1255 | if (!ext4_es_is_delayed(es)) { | 1261 | if (ext4_es_is_delayed(es)) |
| 1256 | rb_erase(&es->rb_node, &tree->root); | 1262 | goto next; |
| 1257 | ext4_es_free_extent(inode, es); | 1263 | if (ext4_es_is_referenced(es)) { |
| 1258 | (*nr_shrunk)++; | 1264 | ext4_es_clear_referenced(es); |
| 1265 | goto next; | ||
| 1259 | } | 1266 | } |
| 1267 | |||
| 1268 | rb_erase(&es->rb_node, &tree->root); | ||
| 1269 | ext4_es_free_extent(inode, es); | ||
| 1270 | (*nr_shrunk)++; | ||
| 1271 | next: | ||
| 1260 | if (!node) | 1272 | if (!node) |
| 1261 | goto out_wrap; | 1273 | goto out_wrap; |
| 1262 | es = rb_entry(node, struct extent_status, rb_node); | 1274 | es = rb_entry(node, struct extent_status, rb_node); |
diff --git a/fs/ext4/extents_status.h b/fs/ext4/extents_status.h index e86b1f34cfec..691b52613ce4 100644 --- a/fs/ext4/extents_status.h +++ b/fs/ext4/extents_status.h | |||
| @@ -34,6 +34,7 @@ enum { | |||
| 34 | ES_UNWRITTEN_B, | 34 | ES_UNWRITTEN_B, |
| 35 | ES_DELAYED_B, | 35 | ES_DELAYED_B, |
| 36 | ES_HOLE_B, | 36 | ES_HOLE_B, |
| 37 | ES_REFERENCED_B, | ||
| 37 | ES_FLAGS | 38 | ES_FLAGS |
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| @@ -44,6 +45,12 @@ enum { | |||
| 44 | #define EXTENT_STATUS_UNWRITTEN (1 << ES_UNWRITTEN_B) | 45 | #define EXTENT_STATUS_UNWRITTEN (1 << ES_UNWRITTEN_B) |
| 45 | #define EXTENT_STATUS_DELAYED (1 << ES_DELAYED_B) | 46 | #define EXTENT_STATUS_DELAYED (1 << ES_DELAYED_B) |
| 46 | #define EXTENT_STATUS_HOLE (1 << ES_HOLE_B) | 47 | #define EXTENT_STATUS_HOLE (1 << ES_HOLE_B) |
| 48 | #define EXTENT_STATUS_REFERENCED (1 << ES_REFERENCED_B) | ||
| 49 | |||
| 50 | #define ES_TYPE_MASK ((ext4_fsblk_t)(EXTENT_STATUS_WRITTEN | \ | ||
| 51 | EXTENT_STATUS_UNWRITTEN | \ | ||
| 52 | EXTENT_STATUS_DELAYED | \ | ||
| 53 | EXTENT_STATUS_HOLE) << ES_SHIFT) | ||
| 47 | 54 | ||
| 48 | struct ext4_sb_info; | 55 | struct ext4_sb_info; |
| 49 | struct ext4_extent; | 56 | struct ext4_extent; |
| @@ -93,24 +100,44 @@ static inline unsigned int ext4_es_status(struct extent_status *es) | |||
| 93 | return es->es_pblk >> ES_SHIFT; | 100 | return es->es_pblk >> ES_SHIFT; |
| 94 | } | 101 | } |
| 95 | 102 | ||
| 103 | static inline unsigned int ext4_es_type(struct extent_status *es) | ||
| 104 | { | ||
| 105 | return (es->es_pblk & ES_TYPE_MASK) >> ES_SHIFT; | ||
| 106 | } | ||
| 107 | |||
| 96 | static inline int ext4_es_is_written(struct extent_status *es) | 108 | static inline int ext4_es_is_written(struct extent_status *es) |
| 97 | { | 109 | { |
| 98 | return (ext4_es_status(es) & EXTENT_STATUS_WRITTEN) != 0; | 110 | return (ext4_es_type(es) & EXTENT_STATUS_WRITTEN) != 0; |
| 99 | } | 111 | } |
| 100 | 112 | ||
| 101 | static inline int ext4_es_is_unwritten(struct extent_status *es) | 113 | static inline int ext4_es_is_unwritten(struct extent_status *es) |
| 102 | { | 114 | { |
| 103 | return (ext4_es_status(es) & EXTENT_STATUS_UNWRITTEN) != 0; | 115 | return (ext4_es_type(es) & EXTENT_STATUS_UNWRITTEN) != 0; |
| 104 | } | 116 | } |
| 105 | 117 | ||
| 106 | static inline int ext4_es_is_delayed(struct extent_status *es) | 118 | static inline int ext4_es_is_delayed(struct extent_status *es) |
| 107 | { | 119 | { |
| 108 | return (ext4_es_status(es) & EXTENT_STATUS_DELAYED) != 0; | 120 | return (ext4_es_type(es) & EXTENT_STATUS_DELAYED) != 0; |
| 109 | } | 121 | } |
| 110 | 122 | ||
| 111 | static inline int ext4_es_is_hole(struct extent_status *es) | 123 | static inline int ext4_es_is_hole(struct extent_status *es) |
| 112 | { | 124 | { |
| 113 | return (ext4_es_status(es) & EXTENT_STATUS_HOLE) != 0; | 125 | return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0; |
| 126 | } | ||
| 127 | |||
| 128 | static inline void ext4_es_set_referenced(struct extent_status *es) | ||
| 129 | { | ||
| 130 | es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT; | ||
| 131 | } | ||
| 132 | |||
| 133 | static inline void ext4_es_clear_referenced(struct extent_status *es) | ||
| 134 | { | ||
| 135 | es->es_pblk &= ~(((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT); | ||
| 136 | } | ||
| 137 | |||
| 138 | static inline int ext4_es_is_referenced(struct extent_status *es) | ||
| 139 | { | ||
| 140 | return (ext4_es_status(es) & EXTENT_STATUS_REFERENCED) != 0; | ||
| 114 | } | 141 | } |
| 115 | 142 | ||
| 116 | static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es) | 143 | static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es) |
