1f5166768STheodore Ts'o // SPDX-License-Identifier: GPL-2.0 2c0677e6dSZheng Liu /* 3c0677e6dSZheng Liu * fs/ext4/extents_status.h 4c0677e6dSZheng Liu * 5c0677e6dSZheng Liu * Written by Yongqiang Yang <xiaoqiangnk@gmail.com> 6c0677e6dSZheng Liu * Modified by 7c0677e6dSZheng Liu * Allison Henderson <achender@linux.vnet.ibm.com> 8c0677e6dSZheng Liu * Zheng Liu <wenqing.lz@taobao.com> 9c0677e6dSZheng Liu * 10c0677e6dSZheng Liu */ 11c0677e6dSZheng Liu 12c0677e6dSZheng Liu #ifndef _EXT4_EXTENTS_STATUS_H 13c0677e6dSZheng Liu #define _EXT4_EXTENTS_STATUS_H 14c0677e6dSZheng Liu 15654598beSZheng Liu /* 16654598beSZheng Liu * Turn on ES_DEBUG__ to get lots of info about extent status operations. 17654598beSZheng Liu */ 18654598beSZheng Liu #ifdef ES_DEBUG__ 19654598beSZheng Liu #define es_debug(fmt, ...) printk(fmt, ##__VA_ARGS__) 20654598beSZheng Liu #else 21654598beSZheng Liu #define es_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__) 22654598beSZheng Liu #endif 23654598beSZheng Liu 248e919d13STheodore Ts'o /* 25921f266bSDmitry Monakhov * With ES_AGGRESSIVE_TEST defined, the result of es caching will be 26921f266bSDmitry Monakhov * checked with old map_block's result. 27921f266bSDmitry Monakhov */ 28921f266bSDmitry Monakhov #define ES_AGGRESSIVE_TEST__ 29921f266bSDmitry Monakhov 30921f266bSDmitry Monakhov /* 318e919d13STheodore Ts'o * These flags live in the high bits of extent_status.es_pblk 328e919d13STheodore Ts'o */ 33624d0f1dSJan Kara enum { 34624d0f1dSJan Kara ES_WRITTEN_B, 35624d0f1dSJan Kara ES_UNWRITTEN_B, 36624d0f1dSJan Kara ES_DELAYED_B, 37624d0f1dSJan Kara ES_HOLE_B, 382be12de9SJan Kara ES_REFERENCED_B, 39624d0f1dSJan Kara ES_FLAGS 40624d0f1dSJan Kara }; 413be78c73STheodore Ts'o 42624d0f1dSJan Kara #define ES_SHIFT (sizeof(ext4_fsblk_t)*8 - ES_FLAGS) 43624d0f1dSJan Kara #define ES_MASK (~((ext4_fsblk_t)0) << ES_SHIFT) 44fdc0212eSZheng Liu 45624d0f1dSJan Kara #define EXTENT_STATUS_WRITTEN (1 << ES_WRITTEN_B) 46624d0f1dSJan Kara #define EXTENT_STATUS_UNWRITTEN (1 << ES_UNWRITTEN_B) 47624d0f1dSJan Kara #define EXTENT_STATUS_DELAYED (1 << ES_DELAYED_B) 48624d0f1dSJan Kara #define EXTENT_STATUS_HOLE (1 << ES_HOLE_B) 492be12de9SJan Kara #define EXTENT_STATUS_REFERENCED (1 << ES_REFERENCED_B) 502be12de9SJan Kara 512be12de9SJan Kara #define ES_TYPE_MASK ((ext4_fsblk_t)(EXTENT_STATUS_WRITTEN | \ 522be12de9SJan Kara EXTENT_STATUS_UNWRITTEN | \ 532be12de9SJan Kara EXTENT_STATUS_DELAYED | \ 542be12de9SJan Kara EXTENT_STATUS_HOLE) << ES_SHIFT) 553be78c73STheodore Ts'o 56d3922a77SZheng Liu struct ext4_sb_info; 57adb23551SZheng Liu struct ext4_extent; 58adb23551SZheng Liu 59c0677e6dSZheng Liu struct extent_status { 60c0677e6dSZheng Liu struct rb_node rb_node; 6106b0c886SZheng Liu ext4_lblk_t es_lblk; /* first logical block extent covers */ 6206b0c886SZheng Liu ext4_lblk_t es_len; /* length of extent in block */ 63fdc0212eSZheng Liu ext4_fsblk_t es_pblk; /* first physical block */ 64c0677e6dSZheng Liu }; 65c0677e6dSZheng Liu 66c0677e6dSZheng Liu struct ext4_es_tree { 67c0677e6dSZheng Liu struct rb_root root; 68c0677e6dSZheng Liu struct extent_status *cache_es; /* recently accessed extent */ 69c0677e6dSZheng Liu }; 70c0677e6dSZheng Liu 71eb68d0e2SZheng Liu struct ext4_es_stats { 72eb68d0e2SZheng Liu unsigned long es_stats_shrunk; 73eb68d0e2SZheng Liu unsigned long es_stats_cache_hits; 74eb68d0e2SZheng Liu unsigned long es_stats_cache_misses; 75eb68d0e2SZheng Liu u64 es_stats_scan_time; 76eb68d0e2SZheng Liu u64 es_stats_max_scan_time; 77eb68d0e2SZheng Liu struct percpu_counter es_stats_all_cnt; 78edaa53caSZheng Liu struct percpu_counter es_stats_shk_cnt; 79eb68d0e2SZheng Liu }; 80eb68d0e2SZheng Liu 811dc0aa46SEric Whitney /* 821dc0aa46SEric Whitney * Pending cluster reservations for bigalloc file systems 831dc0aa46SEric Whitney * 841dc0aa46SEric Whitney * A cluster with a pending reservation is a logical cluster shared by at 851dc0aa46SEric Whitney * least one extent in the extents status tree with delayed and unwritten 861dc0aa46SEric Whitney * status and at least one other written or unwritten extent. The 871dc0aa46SEric Whitney * reservation is said to be pending because a cluster reservation would 881dc0aa46SEric Whitney * have to be taken in the event all blocks in the cluster shared with 891dc0aa46SEric Whitney * written or unwritten extents were deleted while the delayed and 901dc0aa46SEric Whitney * unwritten blocks remained. 911dc0aa46SEric Whitney * 921dc0aa46SEric Whitney * The set of pending cluster reservations is an auxiliary data structure 931dc0aa46SEric Whitney * used with the extents status tree to implement reserved cluster/block 941dc0aa46SEric Whitney * accounting for bigalloc file systems. The set is kept in memory and 951dc0aa46SEric Whitney * records all pending cluster reservations. 961dc0aa46SEric Whitney * 971dc0aa46SEric Whitney * Its primary function is to avoid the need to read extents from the 981dc0aa46SEric Whitney * disk when invalidating pages as a result of a truncate, punch hole, or 991dc0aa46SEric Whitney * collapse range operation. Page invalidation requires a decrease in the 1001dc0aa46SEric Whitney * reserved cluster count if it results in the removal of all delayed 1011dc0aa46SEric Whitney * and unwritten extents (blocks) from a cluster that is not shared with a 1021dc0aa46SEric Whitney * written or unwritten extent, and no decrease otherwise. Determining 1031dc0aa46SEric Whitney * whether the cluster is shared can be done by searching for a pending 1041dc0aa46SEric Whitney * reservation on it. 1051dc0aa46SEric Whitney * 1061dc0aa46SEric Whitney * Secondarily, it provides a potentially faster method for determining 1071dc0aa46SEric Whitney * whether the reserved cluster count should be increased when a physical 1081dc0aa46SEric Whitney * cluster is deallocated as a result of a truncate, punch hole, or 1091dc0aa46SEric Whitney * collapse range operation. The necessary information is also present 1101dc0aa46SEric Whitney * in the extents status tree, but might be more rapidly accessed in 1111dc0aa46SEric Whitney * the pending reservation set in many cases due to smaller size. 1121dc0aa46SEric Whitney * 1131dc0aa46SEric Whitney * The pending cluster reservation set is implemented as a red-black tree 1141dc0aa46SEric Whitney * with the goal of minimizing per page search time overhead. 1151dc0aa46SEric Whitney */ 1161dc0aa46SEric Whitney 1171dc0aa46SEric Whitney struct pending_reservation { 1181dc0aa46SEric Whitney struct rb_node rb_node; 1191dc0aa46SEric Whitney ext4_lblk_t lclu; 1201dc0aa46SEric Whitney }; 1211dc0aa46SEric Whitney 1221dc0aa46SEric Whitney struct ext4_pending_tree { 1231dc0aa46SEric Whitney struct rb_root root; 1241dc0aa46SEric Whitney }; 1251dc0aa46SEric Whitney 126654598beSZheng Liu extern int __init ext4_init_es(void); 127654598beSZheng Liu extern void ext4_exit_es(void); 128654598beSZheng Liu extern void ext4_es_init_tree(struct ext4_es_tree *tree); 129654598beSZheng Liu 13006b0c886SZheng Liu extern int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, 131fdc0212eSZheng Liu ext4_lblk_t len, ext4_fsblk_t pblk, 1323be78c73STheodore Ts'o unsigned int status); 133107a7bd3STheodore Ts'o extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk, 134107a7bd3STheodore Ts'o ext4_lblk_t len, ext4_fsblk_t pblk, 135107a7bd3STheodore Ts'o unsigned int status); 13606b0c886SZheng Liu extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk, 137654598beSZheng Liu ext4_lblk_t len); 138ad431025SEric Whitney extern void ext4_es_find_extent_range(struct inode *inode, 139ad431025SEric Whitney int (*match_fn)(struct extent_status *es), 140e30b5dcaSYan, Zheng ext4_lblk_t lblk, ext4_lblk_t end, 141654598beSZheng Liu struct extent_status *es); 142d100eef2SZheng Liu extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, 143d100eef2SZheng Liu struct extent_status *es); 144ad431025SEric Whitney extern bool ext4_es_scan_range(struct inode *inode, 145ad431025SEric Whitney int (*matching_fn)(struct extent_status *es), 146ad431025SEric Whitney ext4_lblk_t lblk, ext4_lblk_t end); 147ad431025SEric Whitney extern bool ext4_es_scan_clu(struct inode *inode, 148ad431025SEric Whitney int (*matching_fn)(struct extent_status *es), 149ad431025SEric Whitney ext4_lblk_t lblk); 150654598beSZheng Liu 151624d0f1dSJan Kara static inline unsigned int ext4_es_status(struct extent_status *es) 152624d0f1dSJan Kara { 153624d0f1dSJan Kara return es->es_pblk >> ES_SHIFT; 154624d0f1dSJan Kara } 155624d0f1dSJan Kara 1562be12de9SJan Kara static inline unsigned int ext4_es_type(struct extent_status *es) 1572be12de9SJan Kara { 1582be12de9SJan Kara return (es->es_pblk & ES_TYPE_MASK) >> ES_SHIFT; 1592be12de9SJan Kara } 1602be12de9SJan Kara 161fdc0212eSZheng Liu static inline int ext4_es_is_written(struct extent_status *es) 162fdc0212eSZheng Liu { 1632be12de9SJan Kara return (ext4_es_type(es) & EXTENT_STATUS_WRITTEN) != 0; 164fdc0212eSZheng Liu } 165fdc0212eSZheng Liu 166fdc0212eSZheng Liu static inline int ext4_es_is_unwritten(struct extent_status *es) 167fdc0212eSZheng Liu { 1682be12de9SJan Kara return (ext4_es_type(es) & EXTENT_STATUS_UNWRITTEN) != 0; 169fdc0212eSZheng Liu } 170fdc0212eSZheng Liu 171fdc0212eSZheng Liu static inline int ext4_es_is_delayed(struct extent_status *es) 172fdc0212eSZheng Liu { 1732be12de9SJan Kara return (ext4_es_type(es) & EXTENT_STATUS_DELAYED) != 0; 174fdc0212eSZheng Liu } 175fdc0212eSZheng Liu 176fdc0212eSZheng Liu static inline int ext4_es_is_hole(struct extent_status *es) 177fdc0212eSZheng Liu { 1782be12de9SJan Kara return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0; 1792be12de9SJan Kara } 1802be12de9SJan Kara 1810b02f4c0SEric Whitney static inline int ext4_es_is_mapped(struct extent_status *es) 1820b02f4c0SEric Whitney { 1830b02f4c0SEric Whitney return (ext4_es_is_written(es) || ext4_es_is_unwritten(es)); 1840b02f4c0SEric Whitney } 1850b02f4c0SEric Whitney 1860b02f4c0SEric Whitney static inline int ext4_es_is_delonly(struct extent_status *es) 1870b02f4c0SEric Whitney { 1880b02f4c0SEric Whitney return (ext4_es_is_delayed(es) && !ext4_es_is_unwritten(es)); 1890b02f4c0SEric Whitney } 1900b02f4c0SEric Whitney 1912be12de9SJan Kara static inline void ext4_es_set_referenced(struct extent_status *es) 1922be12de9SJan Kara { 1932be12de9SJan Kara es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT; 1942be12de9SJan Kara } 1952be12de9SJan Kara 1962be12de9SJan Kara static inline void ext4_es_clear_referenced(struct extent_status *es) 1972be12de9SJan Kara { 1982be12de9SJan Kara es->es_pblk &= ~(((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT); 1992be12de9SJan Kara } 2002be12de9SJan Kara 2012be12de9SJan Kara static inline int ext4_es_is_referenced(struct extent_status *es) 2022be12de9SJan Kara { 2032be12de9SJan Kara return (ext4_es_status(es) & EXTENT_STATUS_REFERENCED) != 0; 204fdc0212eSZheng Liu } 205fdc0212eSZheng Liu 206fdc0212eSZheng Liu static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es) 207fdc0212eSZheng Liu { 2083be78c73STheodore Ts'o return es->es_pblk & ~ES_MASK; 209fdc0212eSZheng Liu } 210fdc0212eSZheng Liu 211fdc0212eSZheng Liu static inline void ext4_es_store_pblock(struct extent_status *es, 212fdc0212eSZheng Liu ext4_fsblk_t pb) 213fdc0212eSZheng Liu { 214fdc0212eSZheng Liu ext4_fsblk_t block; 215fdc0212eSZheng Liu 2163be78c73STheodore Ts'o block = (pb & ~ES_MASK) | (es->es_pblk & ES_MASK); 217fdc0212eSZheng Liu es->es_pblk = block; 218fdc0212eSZheng Liu } 219fdc0212eSZheng Liu 220fdc0212eSZheng Liu static inline void ext4_es_store_status(struct extent_status *es, 2213be78c73STheodore Ts'o unsigned int status) 222fdc0212eSZheng Liu { 223624d0f1dSJan Kara es->es_pblk = (((ext4_fsblk_t)status << ES_SHIFT) & ES_MASK) | 224624d0f1dSJan Kara (es->es_pblk & ~ES_MASK); 225fdc0212eSZheng Liu } 226fdc0212eSZheng Liu 2279a6633b1STheodore Ts'o static inline void ext4_es_store_pblock_status(struct extent_status *es, 2289a6633b1STheodore Ts'o ext4_fsblk_t pb, 2299a6633b1STheodore Ts'o unsigned int status) 2309a6633b1STheodore Ts'o { 231624d0f1dSJan Kara es->es_pblk = (((ext4_fsblk_t)status << ES_SHIFT) & ES_MASK) | 232624d0f1dSJan Kara (pb & ~ES_MASK); 2339a6633b1STheodore Ts'o } 2349a6633b1STheodore Ts'o 235eb68d0e2SZheng Liu extern int ext4_es_register_shrinker(struct ext4_sb_info *sbi); 236d3922a77SZheng Liu extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi); 23774cd15cdSZheng Liu 238ebd173beSTheodore Ts'o extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v); 239ebd173beSTheodore Ts'o 2401dc0aa46SEric Whitney extern int __init ext4_init_pending(void); 2411dc0aa46SEric Whitney extern void ext4_exit_pending(void); 2421dc0aa46SEric Whitney extern void ext4_init_pending_tree(struct ext4_pending_tree *tree); 2431dc0aa46SEric Whitney extern void ext4_remove_pending(struct inode *inode, ext4_lblk_t lblk); 2441dc0aa46SEric Whitney extern bool ext4_is_pending(struct inode *inode, ext4_lblk_t lblk); 2450b02f4c0SEric Whitney extern int ext4_es_insert_delayed_block(struct inode *inode, ext4_lblk_t lblk, 2460b02f4c0SEric Whitney bool allocated); 247b6bf9171SEric Whitney extern unsigned int ext4_es_delayed_clu(struct inode *inode, ext4_lblk_t lblk, 248b6bf9171SEric Whitney ext4_lblk_t len); 249b6bf9171SEric Whitney extern void ext4_es_remove_blks(struct inode *inode, ext4_lblk_t lblk, 250b6bf9171SEric Whitney ext4_lblk_t len); 251b0c013e2STheodore Ts'o extern void ext4_clear_inode_es(struct inode *inode); 2521dc0aa46SEric Whitney 253c0677e6dSZheng Liu #endif /* _EXT4_EXTENTS_STATUS_H */ 254