return CAP_BLKS_PER_SEC(sbi) - get_ckpt_valid_blocks(sbi, segno, true);
}
-static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi,
- unsigned int node_blocks, unsigned int data_blocks,
- unsigned int dent_blocks)
+static inline void get_additional_blocks_required(struct f2fs_sb_info *sbi,
+ unsigned int *total_node_blocks, unsigned int *total_data_blocks,
+ unsigned int *total_dent_blocks, bool separate_dent)
{
- unsigned int segno, left_blocks, blocks;
+ unsigned int segno, left_blocks;
int i;
+ unsigned int min_free_node_blocks = CAP_BLKS_PER_SEC(sbi);
+ unsigned int min_free_dent_blocks = CAP_BLKS_PER_SEC(sbi);
+ unsigned int min_free_data_blocks = CAP_BLKS_PER_SEC(sbi);
/* check current data/node sections in the worst case. */
for (i = CURSEG_HOT_DATA; i < NR_PERSISTENT_LOG; i++) {
segno = CURSEG_I(sbi, i)->segno;
if (unlikely(segno == NULL_SEGNO))
- return false;
+ return;
left_blocks = get_left_section_blocks(sbi, i, segno);
- blocks = i <= CURSEG_COLD_DATA ? data_blocks : node_blocks;
- if (blocks > left_blocks)
- return false;
+ if (i > CURSEG_COLD_DATA)
+ min_free_node_blocks = min(min_free_node_blocks, left_blocks);
+ else if (i == CURSEG_HOT_DATA && separate_dent)
+ min_free_dent_blocks = left_blocks;
+ else
+ min_free_data_blocks = min(min_free_data_blocks, left_blocks);
}
- /* check current data section for dentry blocks. */
- segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno;
-
- if (unlikely(segno == NULL_SEGNO))
- return false;
-
- left_blocks = get_left_section_blocks(sbi, CURSEG_HOT_DATA, segno);
-
- if (dent_blocks > left_blocks)
- return false;
- return true;
+ *total_node_blocks = (*total_node_blocks > min_free_node_blocks) ?
+ *total_node_blocks - min_free_node_blocks : 0;
+ *total_dent_blocks = (*total_dent_blocks > min_free_dent_blocks) ?
+ *total_dent_blocks - min_free_dent_blocks : 0;
+ *total_data_blocks = (*total_data_blocks > min_free_data_blocks) ?
+ *total_data_blocks - min_free_data_blocks : 0;
}
/*
- * calculate needed sections for dirty node/dentry and call
- * has_curseg_enough_space, please note that, it needs to account
- * dirty data as well in lfs mode when checkpoint is disabled.
+ * call get_additional_blocks_required to calculate dirty blocks
+ * needing to be placed in free sections, please note that, it
+ * needs to account dirty data as well in lfs mode when checkpoint
+ * is disabled.
*/
-static inline void __get_secs_required(struct f2fs_sb_info *sbi,
- unsigned int *lower_p, unsigned int *upper_p, bool *curseg_p)
+static inline int __get_secs_required(struct f2fs_sb_info *sbi)
{
unsigned int total_node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) +
get_pages(sbi, F2FS_DIRTY_DENTS) +
get_pages(sbi, F2FS_DIRTY_IMETA);
unsigned int total_dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS);
unsigned int total_data_blocks = 0;
- unsigned int node_secs = total_node_blocks / CAP_BLKS_PER_SEC(sbi);
- unsigned int dent_secs = total_dent_blocks / CAP_BLKS_PER_SEC(sbi);
- unsigned int data_secs = 0;
- unsigned int node_blocks = total_node_blocks % CAP_BLKS_PER_SEC(sbi);
- unsigned int dent_blocks = total_dent_blocks % CAP_BLKS_PER_SEC(sbi);
- unsigned int data_blocks = 0;
+ bool separate_dent = true;
- if (f2fs_lfs_mode(sbi)) {
+ if (f2fs_lfs_mode(sbi))
total_data_blocks = get_pages(sbi, F2FS_DIRTY_DATA);
- data_secs = total_data_blocks / CAP_BLKS_PER_SEC(sbi);
- data_blocks = total_data_blocks % CAP_BLKS_PER_SEC(sbi);
+
+ /*
+ * When active_logs != 4, dentry blocks and data blocks can be
+ * mixed in the same logs, so check their space together.
+ */
+ if (F2FS_OPTION(sbi).active_logs != 4) {
+ total_data_blocks += total_dent_blocks;
+ total_dent_blocks = 0;
+ separate_dent = false;
}
- if (lower_p)
- *lower_p = node_secs + dent_secs + data_secs;
- if (upper_p)
- *upper_p = node_secs + dent_secs + data_secs +
- (node_blocks ? 1 : 0) + (dent_blocks ? 1 : 0) +
- (data_blocks ? 1 : 0);
- if (curseg_p)
- *curseg_p = has_curseg_enough_space(sbi,
- node_blocks, data_blocks, dent_blocks);
+ get_additional_blocks_required(sbi, &total_node_blocks, &total_dent_blocks,
+ &total_data_blocks, separate_dent);
+
+ return DIV_ROUND_UP(total_node_blocks, CAP_BLKS_PER_SEC(sbi)) +
+ DIV_ROUND_UP(total_dent_blocks, CAP_BLKS_PER_SEC(sbi)) +
+ DIV_ROUND_UP(total_data_blocks, CAP_BLKS_PER_SEC(sbi));
}
static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi,
int freed, int needed)
{
- unsigned int free_secs, lower_secs, upper_secs;
- bool curseg_space;
+ unsigned int free_secs, required_secs;
if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
return false;
- __get_secs_required(sbi, &lower_secs, &upper_secs, &curseg_space);
-
free_secs = free_sections(sbi) + freed;
- lower_secs += needed + reserved_sections(sbi);
- upper_secs += needed + reserved_sections(sbi);
+ required_secs = needed + reserved_sections(sbi) +
+ __get_secs_required(sbi);
- if (free_secs > upper_secs)
- return false;
- if (free_secs <= lower_secs)
- return true;
- return !curseg_space;
+ return free_secs < required_secs;
}
static inline bool has_enough_free_secs(struct f2fs_sb_info *sbi,