#define GC_THREAD_MIN_WB_PAGES 1
#define DEF_GC_THREAD_URGENT_SLEEP_TIME 500
#define DEF_GC_THREAD_MIN_SLEEP_TIME 30000
#define DEF_GC_THREAD_MAX_SLEEP_TIME 60000
#define DEF_GC_THREAD_NOGC_SLEEP_TIME 300000
#define DEF_GC_THREAD_MIN_SLEEP_TIME_ZONED 10
#define DEF_GC_THREAD_MAX_SLEEP_TIME_ZONED 20
#define DEF_GC_THREAD_NOGC_SLEEP_TIME_ZONED 60000
#define DEF_GC_THREAD_AGE_THRESHOLD (60 * 60 * 24 * 7)
#define DEF_GC_THREAD_CANDIDATE_RATIO 20
#define DEF_GC_THREAD_MAX_CANDIDATE_COUNT 10
#define DEF_GC_THREAD_AGE_WEIGHT 60
#define DEF_GC_THREAD_VALID_THRESH_RATIO 80
#define DEFAULT_ACCURACY_CLASS 10000
#define LIMIT_INVALID_BLOCK 40
#define LIMIT_FREE_BLOCK 40
#define LIMIT_NO_ZONED_GC 60
#define LIMIT_BOOST_ZONED_GC 25
#define DEF_MIGRATION_WINDOW_GRANULARITY_ZONED 3
#define BOOST_GC_MULTIPLE 5
#define ZONED_PIN_SEC_REQUIRED_COUNT 1
#define DEF_GC_FAILED_PINNED_FILES 2048
#define MAX_GC_FAILED_PINNED_FILES USHRT_MAX
#define DEF_MAX_VICTIM_SEARCH 4096
#define NR_GC_CHECKPOINT_SECS (3)
struct f2fs_gc_kthread {
struct task_struct *f2fs_gc_task;
wait_queue_head_t gc_wait_queue_head;
unsigned int urgent_sleep_time;
unsigned int min_sleep_time;
unsigned int max_sleep_time;
unsigned int no_gc_sleep_time;
bool gc_wake;
wait_queue_head_t fggc_wq;
unsigned int no_zoned_gc_percent;
unsigned int boost_zoned_gc_percent;
unsigned int valid_thresh_ratio;
unsigned int boost_gc_multiple;
unsigned int boost_gc_greedy;
};
struct gc_inode_list {
struct list_head ilist;
struct radix_tree_root iroot;
};
struct victim_entry {
struct rb_node rb_node;
unsigned long long mtime;
unsigned int segno;
struct list_head list;
};
static inline block_t free_segs_blk_count_zoned(struct f2fs_sb_info *sbi)
{
block_t free_seg_blks = 0;
struct free_segmap_info *free_i = FREE_I(sbi);
int j;
spin_lock(&free_i->segmap_lock);
for (j = 0; j < MAIN_SEGS(sbi); j++)
if (!test_bit(j, free_i->free_segmap))
free_seg_blks += f2fs_usable_blks_in_seg(sbi, j);
spin_unlock(&free_i->segmap_lock);
return free_seg_blks;
}
static inline block_t free_segs_blk_count(struct f2fs_sb_info *sbi)
{
if (f2fs_sb_has_blkzoned(sbi))
return free_segs_blk_count_zoned(sbi);
return SEGS_TO_BLKS(sbi, free_segments(sbi));
}
static inline block_t free_user_blocks(struct f2fs_sb_info *sbi)
{
block_t free_blks, ovp_blks;
free_blks = free_segs_blk_count(sbi);
ovp_blks = SEGS_TO_BLKS(sbi, overprovision_segments(sbi));
if (free_blks < ovp_blks)
return 0;
return free_blks - ovp_blks;
}
static inline block_t limit_invalid_user_blocks(block_t user_block_count)
{
return (long)(user_block_count * LIMIT_INVALID_BLOCK) / 100;
}
static inline block_t limit_free_user_blocks(block_t reclaimable_user_blocks)
{
return (long)(reclaimable_user_blocks * LIMIT_FREE_BLOCK) / 100;
}
static inline void increase_sleep_time(struct f2fs_gc_kthread *gc_th,
unsigned int *wait)
{
unsigned int min_time = gc_th->min_sleep_time;
unsigned int max_time = gc_th->max_sleep_time;
if (*wait == gc_th->no_gc_sleep_time)
return;
if ((long long)*wait + (long long)min_time > (long long)max_time)
*wait = max_time;
else
*wait += min_time;
}
static inline void decrease_sleep_time(struct f2fs_gc_kthread *gc_th,
unsigned int *wait)
{
unsigned int min_time = gc_th->min_sleep_time;
if (*wait == gc_th->no_gc_sleep_time)
*wait = gc_th->max_sleep_time;
if ((long long)*wait - (long long)min_time < (long long)min_time)
*wait = min_time;
else
*wait -= min_time;
}
static inline bool has_enough_free_blocks(struct f2fs_sb_info *sbi,
unsigned int limit_perc)
{
return free_sections(sbi) > ((sbi->total_sections * limit_perc) / 100);
}
static inline bool has_enough_invalid_blocks(struct f2fs_sb_info *sbi)
{
block_t user_block_count = sbi->user_block_count;
block_t invalid_user_blocks = user_block_count -
written_block_count(sbi);
return (invalid_user_blocks >
limit_invalid_user_blocks(user_block_count) &&
free_user_blocks(sbi) <
limit_free_user_blocks(invalid_user_blocks));
}
static inline bool need_to_boost_gc(struct f2fs_sb_info *sbi)
{
if (f2fs_sb_has_blkzoned(sbi))
return !has_enough_free_blocks(sbi,
sbi->gc_thread->boost_zoned_gc_percent);
return has_enough_invalid_blocks(sbi);
}