[PATCH 18/19] f2fs: introduce discard_map for f2fs_trim_fs
This patch adds a bitmap for discard issues from f2fs_trim_fs. There-in rule is to issue discard commands only for invalidated blocks after mount. Once mount is done, f2fs_trim_fs trims out whole invalid area. After ehn, it will not issue and discrads redundantly. Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 2 +- fs/f2fs/f2fs.h| 21 + fs/f2fs/segment.c | 52 +++- fs/f2fs/segment.h | 1 + 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index f5388f3..f50acbc 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -143,7 +143,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) si->base_mem += sizeof(struct sit_info); si->base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); si->base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); - si->base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); + si->base_mem += 3 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); si->base_mem += SIT_VBLOCK_MAP_SIZE; if (sbi->segs_per_sec > 1) si->base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 78a4300..98fc719 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -117,6 +117,8 @@ enum { #define DEF_BATCHED_TRIM_SECTIONS 32 #define BATCHED_TRIM_SEGMENTS(sbi) \ (SM_I(sbi)->trim_sections * (sbi)->segs_per_sec) +#define BATCHED_TRIM_BLOCKS(sbi) \ + (BATCHED_TRIM_SEGMENTS(sbi) << (sbi)->log_blocks_per_seg) struct cp_control { int reason; @@ -698,6 +700,7 @@ struct f2fs_sb_info { block_t user_block_count; /* # of user blocks */ block_t total_valid_block_count;/* # of valid blocks */ block_t alloc_valid_block_count;/* # of allocated blocks */ + block_t discard_blks; /* discard command candidats */ block_t last_valid_block_count; /* for recovery */ u32 s_next_generation; /* for NFS support */ atomic_t nr_pages[NR_COUNT_TYPE]; /* # of pages, see count_type */ @@ -1225,6 +1228,24 @@ static inline int f2fs_test_bit(unsigned int nr, char *addr) return mask & *addr; } +static inline void f2fs_set_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + *addr |= mask; +} + +static inline void f2fs_clear_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr >> 3); + mask = 1 << (7 - (nr & 0x07)); + *addr &= ~mask; +} + static inline int f2fs_test_and_set_bit(unsigned int nr, char *addr) { int mask; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index df8bce5..5a4ec01 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -483,10 +483,12 @@ void discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr) } static void __add_discard_entry(struct f2fs_sb_info *sbi, - struct cp_control *cpc, unsigned int start, unsigned int end) + struct cp_control *cpc, struct seg_entry *se, + unsigned int start, unsigned int end) { struct list_head *head = _I(sbi)->discard_list; struct discard_entry *new, *last; + unsigned int i; if (!list_empty(head)) { last = list_last_entry(head, struct discard_entry, list); @@ -504,6 +506,10 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi, list_add_tail(>list, head); done: SM_I(sbi)->nr_discards += end - start; + for (i = start; i < end; i++) { + f2fs_set_bit(i, se->discard_map); + sbi->discard_blks--; + } cpc->trimmed += end - start; } @@ -514,6 +520,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start); unsigned long *cur_map = (unsigned long *)se->cur_valid_map; unsigned long *ckpt_map = (unsigned long *)se->ckpt_valid_map; + unsigned long *discard_map = (unsigned long *)se->discard_map; unsigned long *dmap = SIT_I(sbi)->tmp_map; unsigned int start = 0, end = -1; bool force = (cpc->reason == CP_DISCARD); @@ -523,8 +530,11 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards)) return; - if (force && !se->valid_blocks) { + if (!se->valid_blocks) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + if (!force) + return; /* * if this segment is registered in the prefree list, then * we should skip adding a discard candidate, and let the @@ -537,18 +547,14 @@ static void add_discard_addrs(struct f2fs_sb_info
[PATCH 18/19] f2fs: introduce discard_map for f2fs_trim_fs
This patch adds a bitmap for discard issues from f2fs_trim_fs. There-in rule is to issue discard commands only for invalidated blocks after mount. Once mount is done, f2fs_trim_fs trims out whole invalid area. After ehn, it will not issue and discrads redundantly. Signed-off-by: Jaegeuk Kim jaeg...@kernel.org --- fs/f2fs/debug.c | 2 +- fs/f2fs/f2fs.h| 21 + fs/f2fs/segment.c | 52 +++- fs/f2fs/segment.h | 1 + 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index f5388f3..f50acbc 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -143,7 +143,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi) si-base_mem += sizeof(struct sit_info); si-base_mem += MAIN_SEGS(sbi) * sizeof(struct seg_entry); si-base_mem += f2fs_bitmap_size(MAIN_SEGS(sbi)); - si-base_mem += 2 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); + si-base_mem += 3 * SIT_VBLOCK_MAP_SIZE * MAIN_SEGS(sbi); si-base_mem += SIT_VBLOCK_MAP_SIZE; if (sbi-segs_per_sec 1) si-base_mem += MAIN_SECS(sbi) * sizeof(struct sec_entry); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 78a4300..98fc719 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -117,6 +117,8 @@ enum { #define DEF_BATCHED_TRIM_SECTIONS 32 #define BATCHED_TRIM_SEGMENTS(sbi) \ (SM_I(sbi)-trim_sections * (sbi)-segs_per_sec) +#define BATCHED_TRIM_BLOCKS(sbi) \ + (BATCHED_TRIM_SEGMENTS(sbi) (sbi)-log_blocks_per_seg) struct cp_control { int reason; @@ -698,6 +700,7 @@ struct f2fs_sb_info { block_t user_block_count; /* # of user blocks */ block_t total_valid_block_count;/* # of valid blocks */ block_t alloc_valid_block_count;/* # of allocated blocks */ + block_t discard_blks; /* discard command candidats */ block_t last_valid_block_count; /* for recovery */ u32 s_next_generation; /* for NFS support */ atomic_t nr_pages[NR_COUNT_TYPE]; /* # of pages, see count_type */ @@ -1225,6 +1228,24 @@ static inline int f2fs_test_bit(unsigned int nr, char *addr) return mask *addr; } +static inline void f2fs_set_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr 3); + mask = 1 (7 - (nr 0x07)); + *addr |= mask; +} + +static inline void f2fs_clear_bit(unsigned int nr, char *addr) +{ + int mask; + + addr += (nr 3); + mask = 1 (7 - (nr 0x07)); + *addr = ~mask; +} + static inline int f2fs_test_and_set_bit(unsigned int nr, char *addr) { int mask; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index df8bce5..5a4ec01 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -483,10 +483,12 @@ void discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr) } static void __add_discard_entry(struct f2fs_sb_info *sbi, - struct cp_control *cpc, unsigned int start, unsigned int end) + struct cp_control *cpc, struct seg_entry *se, + unsigned int start, unsigned int end) { struct list_head *head = SM_I(sbi)-discard_list; struct discard_entry *new, *last; + unsigned int i; if (!list_empty(head)) { last = list_last_entry(head, struct discard_entry, list); @@ -504,6 +506,10 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi, list_add_tail(new-list, head); done: SM_I(sbi)-nr_discards += end - start; + for (i = start; i end; i++) { + f2fs_set_bit(i, se-discard_map); + sbi-discard_blks--; + } cpc-trimmed += end - start; } @@ -514,6 +520,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) struct seg_entry *se = get_seg_entry(sbi, cpc-trim_start); unsigned long *cur_map = (unsigned long *)se-cur_valid_map; unsigned long *ckpt_map = (unsigned long *)se-ckpt_valid_map; + unsigned long *discard_map = (unsigned long *)se-discard_map; unsigned long *dmap = SIT_I(sbi)-tmp_map; unsigned int start = 0, end = -1; bool force = (cpc-reason == CP_DISCARD); @@ -523,8 +530,11 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc) SM_I(sbi)-nr_discards = SM_I(sbi)-max_discards)) return; - if (force !se-valid_blocks) { + if (!se-valid_blocks) { struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); + + if (!force) + return; /* * if this segment is registered in the prefree list, then * we should skip adding a discard candidate, and let the @@ -537,18 +547,14 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control