LCOV - code coverage report
Current view: top level - fs/ext4 - extents_status.h (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 22 24 91.7 %
Date: 2023-07-31 20:08:22 Functions: 3 3 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  *  fs/ext4/extents_status.h
       4             :  *
       5             :  * Written by Yongqiang Yang <xiaoqiangnk@gmail.com>
       6             :  * Modified by
       7             :  *      Allison Henderson <achender@linux.vnet.ibm.com>
       8             :  *      Zheng Liu <wenqing.lz@taobao.com>
       9             :  *
      10             :  */
      11             : 
      12             : #ifndef _EXT4_EXTENTS_STATUS_H
      13             : #define _EXT4_EXTENTS_STATUS_H
      14             : 
      15             : /*
      16             :  * Turn on ES_DEBUG__ to get lots of info about extent status operations.
      17             :  */
      18             : #ifdef ES_DEBUG__
      19             : #define es_debug(fmt, ...)      printk(fmt, ##__VA_ARGS__)
      20             : #else
      21             : #define es_debug(fmt, ...)      no_printk(fmt, ##__VA_ARGS__)
      22             : #endif
      23             : 
      24             : /*
      25             :  * With ES_AGGRESSIVE_TEST defined, the result of es caching will be
      26             :  * checked with old map_block's result.
      27             :  */
      28             : #define ES_AGGRESSIVE_TEST__
      29             : 
      30             : /*
      31             :  * These flags live in the high bits of extent_status.es_pblk
      32             :  */
      33             : enum {
      34             :         ES_WRITTEN_B,
      35             :         ES_UNWRITTEN_B,
      36             :         ES_DELAYED_B,
      37             :         ES_HOLE_B,
      38             :         ES_REFERENCED_B,
      39             :         ES_FLAGS
      40             : };
      41             : 
      42             : #define ES_SHIFT (sizeof(ext4_fsblk_t)*8 - ES_FLAGS)
      43             : #define ES_MASK (~((ext4_fsblk_t)0) << ES_SHIFT)
      44             : 
      45             : #define EXTENT_STATUS_WRITTEN   (1 << ES_WRITTEN_B)
      46             : #define EXTENT_STATUS_UNWRITTEN (1 << ES_UNWRITTEN_B)
      47             : #define EXTENT_STATUS_DELAYED   (1 << ES_DELAYED_B)
      48             : #define EXTENT_STATUS_HOLE      (1 << ES_HOLE_B)
      49             : #define EXTENT_STATUS_REFERENCED        (1 << ES_REFERENCED_B)
      50             : 
      51             : #define ES_TYPE_MASK    ((ext4_fsblk_t)(EXTENT_STATUS_WRITTEN | \
      52             :                           EXTENT_STATUS_UNWRITTEN | \
      53             :                           EXTENT_STATUS_DELAYED | \
      54             :                           EXTENT_STATUS_HOLE) << ES_SHIFT)
      55             : 
      56             : struct ext4_sb_info;
      57             : struct ext4_extent;
      58             : 
      59             : struct extent_status {
      60             :         struct rb_node rb_node;
      61             :         ext4_lblk_t es_lblk;    /* first logical block extent covers */
      62             :         ext4_lblk_t es_len;     /* length of extent in block */
      63             :         ext4_fsblk_t es_pblk;   /* first physical block */
      64             : };
      65             : 
      66             : struct ext4_es_tree {
      67             :         struct rb_root root;
      68             :         struct extent_status *cache_es; /* recently accessed extent */
      69             : };
      70             : 
      71             : struct ext4_es_stats {
      72             :         unsigned long es_stats_shrunk;
      73             :         struct percpu_counter es_stats_cache_hits;
      74             :         struct percpu_counter es_stats_cache_misses;
      75             :         u64 es_stats_scan_time;
      76             :         u64 es_stats_max_scan_time;
      77             :         struct percpu_counter es_stats_all_cnt;
      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;
     124             : };
     125             : 
     126             : extern int __init ext4_init_es(void);
     127             : extern void ext4_exit_es(void);
     128             : extern void ext4_es_init_tree(struct ext4_es_tree *tree);
     129             : 
     130             : extern void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
     131             :                                   ext4_lblk_t len, ext4_fsblk_t pblk,
     132             :                                   unsigned int status);
     133             : extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk,
     134             :                                  ext4_lblk_t len, ext4_fsblk_t pblk,
     135             :                                  unsigned int status);
     136             : extern void ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk,
     137             :                                   ext4_lblk_t len);
     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);
     142             : extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk,
     143             :                                  ext4_lblk_t *next_lblk,
     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);
     151             : 
     152             : static inline unsigned int ext4_es_status(struct extent_status *es)
     153             : {
     154    98444468 :         return es->es_pblk >> ES_SHIFT;
     155             : }
     156             : 
     157             : static inline unsigned int ext4_es_type(struct extent_status *es)
     158             : {
     159   301836317 :         return (es->es_pblk & ES_TYPE_MASK) >> ES_SHIFT;
     160             : }
     161             : 
     162             : static inline int ext4_es_is_written(struct extent_status *es)
     163             : {
     164   130332994 :         return (ext4_es_type(es) & EXTENT_STATUS_WRITTEN) != 0;
     165             : }
     166             : 
     167             : static inline int ext4_es_is_unwritten(struct extent_status *es)
     168             : {
     169   123572162 :         return (ext4_es_type(es) & EXTENT_STATUS_UNWRITTEN) != 0;
     170             : }
     171             : 
     172     7260264 : static inline int ext4_es_is_delayed(struct extent_status *es)
     173             : {
     174    88401950 :         return (ext4_es_type(es) & EXTENT_STATUS_DELAYED) != 0;
     175             : }
     176             : 
     177             : static inline int ext4_es_is_hole(struct extent_status *es)
     178             : {
     179    85741504 :         return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0;
     180             : }
     181             : 
     182        8194 : static inline int ext4_es_is_mapped(struct extent_status *es)
     183             : {
     184        8194 :         return (ext4_es_is_written(es) || ext4_es_is_unwritten(es));
     185             : }
     186             : 
     187      131127 : static inline int ext4_es_is_delonly(struct extent_status *es)
     188             : {
     189    12256346 :         return (ext4_es_is_delayed(es) && !ext4_es_is_unwritten(es));
     190             : }
     191             : 
     192             : static inline void ext4_es_set_referenced(struct extent_status *es)
     193             : {
     194     5607155 :         es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT;
     195     5607155 : }
     196             : 
     197             : static inline void ext4_es_clear_referenced(struct extent_status *es)
     198             : {
     199       25690 :         es->es_pblk &= ~(((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT);
     200             : }
     201             : 
     202             : static inline int ext4_es_is_referenced(struct extent_status *es)
     203             : {
     204    98444468 :         return (ext4_es_status(es) & EXTENT_STATUS_REFERENCED) != 0;
     205             : }
     206             : 
     207             : static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es)
     208             : {
     209    45737677 :         return es->es_pblk & ~ES_MASK;
     210             : }
     211             : 
     212             : static inline ext4_fsblk_t ext4_es_show_pblock(struct extent_status *es)
     213             : {
     214           0 :         ext4_fsblk_t pblock = ext4_es_pblock(es);
     215           0 :         return pblock == ~ES_MASK ? 0 : pblock;
     216             : }
     217             : 
     218             : static inline void ext4_es_store_pblock(struct extent_status *es,
     219             :                                         ext4_fsblk_t pb)
     220             : {
     221     1576778 :         ext4_fsblk_t block;
     222             : 
     223     1576778 :         block = (pb & ~ES_MASK) | (es->es_pblk & ES_MASK);
     224     1576778 :         es->es_pblk = block;
     225     1576778 : }
     226             : 
     227             : static inline void ext4_es_store_status(struct extent_status *es,
     228             :                                         unsigned int status)
     229             : {
     230             :         es->es_pblk = (((ext4_fsblk_t)status << ES_SHIFT) & ES_MASK) |
     231             :                       (es->es_pblk & ~ES_MASK);
     232             : }
     233             : 
     234             : static inline void ext4_es_store_pblock_status(struct extent_status *es,
     235             :                                                ext4_fsblk_t pb,
     236             :                                                unsigned int status)
     237             : {
     238    24349206 :         es->es_pblk = (((ext4_fsblk_t)status << ES_SHIFT) & ES_MASK) |
     239    15973668 :                       (pb & ~ES_MASK);
     240             : }
     241             : 
     242             : extern int ext4_es_register_shrinker(struct ext4_sb_info *sbi);
     243             : extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi);
     244             : 
     245             : extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v);
     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 void 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             : 
     258             : #endif /* _EXT4_EXTENTS_STATUS_H */

Generated by: LCOV version 1.14