.. | .. |
---|
70 | 70 | |
---|
71 | 71 | struct ext4_es_stats { |
---|
72 | 72 | unsigned long es_stats_shrunk; |
---|
73 | | - unsigned long es_stats_cache_hits; |
---|
74 | | - unsigned long es_stats_cache_misses; |
---|
| 73 | + struct percpu_counter es_stats_cache_hits; |
---|
| 74 | + struct percpu_counter es_stats_cache_misses; |
---|
75 | 75 | u64 es_stats_scan_time; |
---|
76 | 76 | u64 es_stats_max_scan_time; |
---|
77 | 77 | struct percpu_counter es_stats_all_cnt; |
---|
78 | 78 | struct percpu_counter es_stats_shk_cnt; |
---|
| 79 | +}; |
---|
| 80 | + |
---|
| 81 | +/* |
---|
| 82 | + * Pending cluster reservations for bigalloc file systems |
---|
| 83 | + * |
---|
| 84 | + * A cluster with a pending reservation is a logical cluster shared by at |
---|
| 85 | + * least one extent in the extents status tree with delayed and unwritten |
---|
| 86 | + * status and at least one other written or unwritten extent. The |
---|
| 87 | + * reservation is said to be pending because a cluster reservation would |
---|
| 88 | + * have to be taken in the event all blocks in the cluster shared with |
---|
| 89 | + * written or unwritten extents were deleted while the delayed and |
---|
| 90 | + * unwritten blocks remained. |
---|
| 91 | + * |
---|
| 92 | + * The set of pending cluster reservations is an auxiliary data structure |
---|
| 93 | + * used with the extents status tree to implement reserved cluster/block |
---|
| 94 | + * accounting for bigalloc file systems. The set is kept in memory and |
---|
| 95 | + * records all pending cluster reservations. |
---|
| 96 | + * |
---|
| 97 | + * Its primary function is to avoid the need to read extents from the |
---|
| 98 | + * disk when invalidating pages as a result of a truncate, punch hole, or |
---|
| 99 | + * collapse range operation. Page invalidation requires a decrease in the |
---|
| 100 | + * reserved cluster count if it results in the removal of all delayed |
---|
| 101 | + * and unwritten extents (blocks) from a cluster that is not shared with a |
---|
| 102 | + * written or unwritten extent, and no decrease otherwise. Determining |
---|
| 103 | + * whether the cluster is shared can be done by searching for a pending |
---|
| 104 | + * reservation on it. |
---|
| 105 | + * |
---|
| 106 | + * Secondarily, it provides a potentially faster method for determining |
---|
| 107 | + * whether the reserved cluster count should be increased when a physical |
---|
| 108 | + * cluster is deallocated as a result of a truncate, punch hole, or |
---|
| 109 | + * collapse range operation. The necessary information is also present |
---|
| 110 | + * in the extents status tree, but might be more rapidly accessed in |
---|
| 111 | + * the pending reservation set in many cases due to smaller size. |
---|
| 112 | + * |
---|
| 113 | + * The pending cluster reservation set is implemented as a red-black tree |
---|
| 114 | + * with the goal of minimizing per page search time overhead. |
---|
| 115 | + */ |
---|
| 116 | + |
---|
| 117 | +struct pending_reservation { |
---|
| 118 | + struct rb_node rb_node; |
---|
| 119 | + ext4_lblk_t lclu; |
---|
| 120 | +}; |
---|
| 121 | + |
---|
| 122 | +struct ext4_pending_tree { |
---|
| 123 | + struct rb_root root; |
---|
79 | 124 | }; |
---|
80 | 125 | |
---|
81 | 126 | extern int __init ext4_init_es(void); |
---|
.. | .. |
---|
90 | 135 | unsigned int status); |
---|
91 | 136 | extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk, |
---|
92 | 137 | ext4_lblk_t len); |
---|
93 | | -extern void ext4_es_find_delayed_extent_range(struct inode *inode, |
---|
94 | | - ext4_lblk_t lblk, ext4_lblk_t end, |
---|
95 | | - struct extent_status *es); |
---|
| 138 | +extern void ext4_es_find_extent_range(struct inode *inode, |
---|
| 139 | + int (*match_fn)(struct extent_status *es), |
---|
| 140 | + ext4_lblk_t lblk, ext4_lblk_t end, |
---|
| 141 | + struct extent_status *es); |
---|
96 | 142 | extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, |
---|
| 143 | + ext4_lblk_t *next_lblk, |
---|
97 | 144 | struct extent_status *es); |
---|
| 145 | +extern bool ext4_es_scan_range(struct inode *inode, |
---|
| 146 | + int (*matching_fn)(struct extent_status *es), |
---|
| 147 | + ext4_lblk_t lblk, ext4_lblk_t end); |
---|
| 148 | +extern bool ext4_es_scan_clu(struct inode *inode, |
---|
| 149 | + int (*matching_fn)(struct extent_status *es), |
---|
| 150 | + ext4_lblk_t lblk); |
---|
98 | 151 | |
---|
99 | 152 | static inline unsigned int ext4_es_status(struct extent_status *es) |
---|
100 | 153 | { |
---|
.. | .. |
---|
126 | 179 | return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0; |
---|
127 | 180 | } |
---|
128 | 181 | |
---|
| 182 | +static inline int ext4_es_is_mapped(struct extent_status *es) |
---|
| 183 | +{ |
---|
| 184 | + return (ext4_es_is_written(es) || ext4_es_is_unwritten(es)); |
---|
| 185 | +} |
---|
| 186 | + |
---|
| 187 | +static inline int ext4_es_is_delonly(struct extent_status *es) |
---|
| 188 | +{ |
---|
| 189 | + return (ext4_es_is_delayed(es) && !ext4_es_is_unwritten(es)); |
---|
| 190 | +} |
---|
| 191 | + |
---|
129 | 192 | static inline void ext4_es_set_referenced(struct extent_status *es) |
---|
130 | 193 | { |
---|
131 | 194 | es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT; |
---|
.. | .. |
---|
144 | 207 | static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es) |
---|
145 | 208 | { |
---|
146 | 209 | return es->es_pblk & ~ES_MASK; |
---|
| 210 | +} |
---|
| 211 | + |
---|
| 212 | +static inline ext4_fsblk_t ext4_es_show_pblock(struct extent_status *es) |
---|
| 213 | +{ |
---|
| 214 | + ext4_fsblk_t pblock = ext4_es_pblock(es); |
---|
| 215 | + return pblock == ~ES_MASK ? 0 : pblock; |
---|
147 | 216 | } |
---|
148 | 217 | |
---|
149 | 218 | static inline void ext4_es_store_pblock(struct extent_status *es, |
---|
.. | .. |
---|
175 | 244 | |
---|
176 | 245 | extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v); |
---|
177 | 246 | |
---|
| 247 | +extern int __init ext4_init_pending(void); |
---|
| 248 | +extern void ext4_exit_pending(void); |
---|
| 249 | +extern void ext4_init_pending_tree(struct ext4_pending_tree *tree); |
---|
| 250 | +extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); |
---|
| 251 | +extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); |
---|
| 252 | +extern int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, |
---|
| 253 | + bool allocated); |
---|
| 254 | +extern unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, |
---|
| 255 | + ext4_lblk_t len); |
---|
| 256 | +extern void ext4_clear_inode_es(struct inode *inode); |
---|
| 257 | + |
---|
178 | 258 | #endif /* _EXT4_EXTENTS_STATUS_H */ |
---|