2017-12-18 06:00:59 +03:00
// SPDX-License-Identifier: GPL-2.0
2012-11-09 00:18:54 +04:00
/*
* fs / ext4 / extents_status . h
*
* Written by Yongqiang Yang < xiaoqiangnk @ gmail . com >
* Modified by
* Allison Henderson < achender @ linux . vnet . ibm . com >
* Zheng Liu < wenqing . lz @ taobao . com >
*
*/
# ifndef _EXT4_EXTENTS_STATUS_H
# define _EXT4_EXTENTS_STATUS_H
2012-11-09 06:57:20 +04:00
/*
* Turn on ES_DEBUG__ to get lots of info about extent status operations .
*/
# ifdef ES_DEBUG__
# define es_debug(fmt, ...) printk(fmt, ##__VA_ARGS__)
# else
# define es_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
# endif
2013-03-11 05:01:03 +04:00
/*
* With ES_AGGRESSIVE_TEST defined , the result of es caching will be
* checked with old map_block ' s result .
*/
# define ES_AGGRESSIVE_TEST__
2013-02-27 23:54:37 +04:00
/*
* These flags live in the high bits of extent_status . es_pblk
*/
2014-11-25 19:53:47 +03:00
enum {
ES_WRITTEN_B ,
ES_UNWRITTEN_B ,
ES_DELAYED_B ,
ES_HOLE_B ,
2014-11-25 19:55:24 +03:00
ES_REFERENCED_B ,
2014-11-25 19:53:47 +03:00
ES_FLAGS
} ;
2013-02-18 09:26:51 +04:00
2014-11-25 19:53:47 +03:00
# define ES_SHIFT (sizeof(ext4_fsblk_t)*8 - ES_FLAGS)
# define ES_MASK (~((ext4_fsblk_t)0) << ES_SHIFT)
2013-08-17 05:22:41 +04:00
2014-11-25 19:53:47 +03:00
# define EXTENT_STATUS_WRITTEN (1 << ES_WRITTEN_B)
# define EXTENT_STATUS_UNWRITTEN (1 << ES_UNWRITTEN_B)
# define EXTENT_STATUS_DELAYED (1 << ES_DELAYED_B)
# define EXTENT_STATUS_HOLE (1 << ES_HOLE_B)
2014-11-25 19:55:24 +03:00
# define EXTENT_STATUS_REFERENCED (1 << ES_REFERENCED_B)
# define ES_TYPE_MASK ((ext4_fsblk_t)(EXTENT_STATUS_WRITTEN | \
EXTENT_STATUS_UNWRITTEN | \
EXTENT_STATUS_DELAYED | \
EXTENT_STATUS_HOLE ) < < ES_SHIFT )
2013-08-17 05:22:41 +04:00
2013-07-01 16:12:37 +04:00
struct ext4_sb_info ;
2013-03-11 05:13:05 +04:00
struct ext4_extent ;
2012-11-09 00:18:54 +04:00
struct extent_status {
struct rb_node rb_node ;
2013-02-18 09:26:51 +04:00
ext4_lblk_t es_lblk ; /* first logical block extent covers */
ext4_lblk_t es_len ; /* length of extent in block */
2013-02-18 09:26:51 +04:00
ext4_fsblk_t es_pblk ; /* first physical block */
2012-11-09 00:18:54 +04:00
} ;
struct ext4_es_tree {
struct rb_root root ;
struct extent_status * cache_es ; /* recently accessed extent */
} ;
2014-09-02 06:26:49 +04:00
struct ext4_es_stats {
unsigned long es_stats_shrunk ;
unsigned long es_stats_cache_hits ;
unsigned long es_stats_cache_misses ;
u64 es_stats_scan_time ;
u64 es_stats_max_scan_time ;
struct percpu_counter es_stats_all_cnt ;
2014-11-25 19:45:37 +03:00
struct percpu_counter es_stats_shk_cnt ;
2014-09-02 06:26:49 +04:00
} ;
2018-10-01 21:17:41 +03:00
/*
* Pending cluster reservations for bigalloc file systems
*
* A cluster with a pending reservation is a logical cluster shared by at
* least one extent in the extents status tree with delayed and unwritten
* status and at least one other written or unwritten extent . The
* reservation is said to be pending because a cluster reservation would
* have to be taken in the event all blocks in the cluster shared with
* written or unwritten extents were deleted while the delayed and
* unwritten blocks remained .
*
* The set of pending cluster reservations is an auxiliary data structure
* used with the extents status tree to implement reserved cluster / block
* accounting for bigalloc file systems . The set is kept in memory and
* records all pending cluster reservations .
*
* Its primary function is to avoid the need to read extents from the
* disk when invalidating pages as a result of a truncate , punch hole , or
* collapse range operation . Page invalidation requires a decrease in the
* reserved cluster count if it results in the removal of all delayed
* and unwritten extents ( blocks ) from a cluster that is not shared with a
* written or unwritten extent , and no decrease otherwise . Determining
* whether the cluster is shared can be done by searching for a pending
* reservation on it .
*
* Secondarily , it provides a potentially faster method for determining
* whether the reserved cluster count should be increased when a physical
* cluster is deallocated as a result of a truncate , punch hole , or
* collapse range operation . The necessary information is also present
* in the extents status tree , but might be more rapidly accessed in
* the pending reservation set in many cases due to smaller size .
*
* The pending cluster reservation set is implemented as a red - black tree
* with the goal of minimizing per page search time overhead .
*/
struct pending_reservation {
struct rb_node rb_node ;
ext4_lblk_t lclu ;
} ;
struct ext4_pending_tree {
struct rb_root root ;
} ;
2012-11-09 06:57:20 +04:00
extern int __init ext4_init_es ( void ) ;
extern void ext4_exit_es ( void ) ;
extern void ext4_es_init_tree ( struct ext4_es_tree * tree ) ;
2013-02-18 09:26:51 +04:00
extern int ext4_es_insert_extent ( struct inode * inode , ext4_lblk_t lblk ,
2013-02-18 09:26:51 +04:00
ext4_lblk_t len , ext4_fsblk_t pblk ,
2013-08-17 05:22:41 +04:00
unsigned int status ) ;
2013-08-17 05:23:41 +04:00
extern void ext4_es_cache_extent ( struct inode * inode , ext4_lblk_t lblk ,
ext4_lblk_t len , ext4_fsblk_t pblk ,
unsigned int status ) ;
2013-02-18 09:26:51 +04:00
extern int ext4_es_remove_extent ( struct inode * inode , ext4_lblk_t lblk ,
2012-11-09 06:57:20 +04:00
ext4_lblk_t len ) ;
2018-10-01 21:10:39 +03:00
extern void ext4_es_find_extent_range ( struct inode * inode ,
int ( * match_fn ) ( struct extent_status * es ) ,
ext4_lblk_t lblk , ext4_lblk_t end ,
struct extent_status * es ) ;
2013-02-18 09:29:59 +04:00
extern int ext4_es_lookup_extent ( struct inode * inode , ext4_lblk_t lblk ,
struct extent_status * es ) ;
2018-10-01 21:10:39 +03:00
extern bool ext4_es_scan_range ( struct inode * inode ,
int ( * matching_fn ) ( struct extent_status * es ) ,
ext4_lblk_t lblk , ext4_lblk_t end ) ;
extern bool ext4_es_scan_clu ( struct inode * inode ,
int ( * matching_fn ) ( struct extent_status * es ) ,
ext4_lblk_t lblk ) ;
2012-11-09 06:57:20 +04:00
2014-11-25 19:53:47 +03:00
static inline unsigned int ext4_es_status ( struct extent_status * es )
{
return es - > es_pblk > > ES_SHIFT ;
}
2014-11-25 19:55:24 +03:00
static inline unsigned int ext4_es_type ( struct extent_status * es )
{
return ( es - > es_pblk & ES_TYPE_MASK ) > > ES_SHIFT ;
}
2013-02-18 09:26:51 +04:00
static inline int ext4_es_is_written ( struct extent_status * es )
{
2014-11-25 19:55:24 +03:00
return ( ext4_es_type ( es ) & EXTENT_STATUS_WRITTEN ) ! = 0 ;
2013-02-18 09:26:51 +04:00
}
static inline int ext4_es_is_unwritten ( struct extent_status * es )
{
2014-11-25 19:55:24 +03:00
return ( ext4_es_type ( es ) & EXTENT_STATUS_UNWRITTEN ) ! = 0 ;
2013-02-18 09:26:51 +04:00
}
static inline int ext4_es_is_delayed ( struct extent_status * es )
{
2014-11-25 19:55:24 +03:00
return ( ext4_es_type ( es ) & EXTENT_STATUS_DELAYED ) ! = 0 ;
2013-02-18 09:26:51 +04:00
}
static inline int ext4_es_is_hole ( struct extent_status * es )
{
2014-11-25 19:55:24 +03:00
return ( ext4_es_type ( es ) & EXTENT_STATUS_HOLE ) ! = 0 ;
}
2018-10-01 21:19:37 +03:00
static inline int ext4_es_is_mapped ( struct extent_status * es )
{
return ( ext4_es_is_written ( es ) | | ext4_es_is_unwritten ( es ) ) ;
}
static inline int ext4_es_is_delonly ( struct extent_status * es )
{
return ( ext4_es_is_delayed ( es ) & & ! ext4_es_is_unwritten ( es ) ) ;
}
2014-11-25 19:55:24 +03:00
static inline void ext4_es_set_referenced ( struct extent_status * es )
{
es - > es_pblk | = ( ( ext4_fsblk_t ) EXTENT_STATUS_REFERENCED ) < < ES_SHIFT ;
}
static inline void ext4_es_clear_referenced ( struct extent_status * es )
{
es - > es_pblk & = ~ ( ( ( ext4_fsblk_t ) EXTENT_STATUS_REFERENCED ) < < ES_SHIFT ) ;
}
static inline int ext4_es_is_referenced ( struct extent_status * es )
{
return ( ext4_es_status ( es ) & EXTENT_STATUS_REFERENCED ) ! = 0 ;
2013-02-18 09:26:51 +04:00
}
static inline ext4_fsblk_t ext4_es_pblock ( struct extent_status * es )
{
2013-08-17 05:22:41 +04:00
return es - > es_pblk & ~ ES_MASK ;
2013-02-18 09:26:51 +04:00
}
static inline void ext4_es_store_pblock ( struct extent_status * es ,
ext4_fsblk_t pb )
{
ext4_fsblk_t block ;
2013-08-17 05:22:41 +04:00
block = ( pb & ~ ES_MASK ) | ( es - > es_pblk & ES_MASK ) ;
2013-02-18 09:26:51 +04:00
es - > es_pblk = block ;
}
static inline void ext4_es_store_status ( struct extent_status * es ,
2013-08-17 05:22:41 +04:00
unsigned int status )
2013-02-18 09:26:51 +04:00
{
2014-11-25 19:53:47 +03:00
es - > es_pblk = ( ( ( ext4_fsblk_t ) status < < ES_SHIFT ) & ES_MASK ) |
( es - > es_pblk & ~ ES_MASK ) ;
2013-02-18 09:26:51 +04:00
}
2014-02-20 05:15:15 +04:00
static inline void ext4_es_store_pblock_status ( struct extent_status * es ,
ext4_fsblk_t pb ,
unsigned int status )
{
2014-11-25 19:53:47 +03:00
es - > es_pblk = ( ( ( ext4_fsblk_t ) status < < ES_SHIFT ) & ES_MASK ) |
( pb & ~ ES_MASK ) ;
2014-02-20 05:15:15 +04:00
}
2014-09-02 06:26:49 +04:00
extern int ext4_es_register_shrinker ( struct ext4_sb_info * sbi ) ;
2013-07-01 16:12:37 +04:00
extern void ext4_es_unregister_shrinker ( struct ext4_sb_info * sbi ) ;
2013-02-18 09:32:55 +04:00
2015-09-23 19:46:17 +03:00
extern int ext4_seq_es_shrinker_info_show ( struct seq_file * seq , void * v ) ;
2018-10-01 21:17:41 +03:00
extern int __init ext4_init_pending ( void ) ;
extern void ext4_exit_pending ( void ) ;
extern void ext4_init_pending_tree ( struct ext4_pending_tree * tree ) ;
extern void ext4_remove_pending ( struct inode * inode , ext4_lblk_t lblk ) ;
extern bool ext4_is_pending ( struct inode * inode , ext4_lblk_t lblk ) ;
2018-10-01 21:19:37 +03:00
extern int ext4_es_insert_delayed_block ( struct inode * inode , ext4_lblk_t lblk ,
bool allocated ) ;
2018-10-01 21:24:08 +03:00
extern unsigned int ext4_es_delayed_clu ( struct inode * inode , ext4_lblk_t lblk ,
ext4_lblk_t len ) ;
extern void ext4_es_remove_blks ( struct inode * inode , ext4_lblk_t lblk ,
ext4_lblk_t len ) ;
2018-10-01 21:17:41 +03:00
2012-11-09 00:18:54 +04:00
# endif /* _EXT4_EXTENTS_STATUS_H */