[PATCH 18/19] f2fs: introduce discard_map for f2fs_trim_fs

2015-05-01 Thread Jaegeuk Kim
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

2015-05-01 Thread Jaegeuk Kim
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