aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-03-31 00:26:03 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-04-03 04:27:49 -0400
commit5ec4e49f9bd753e2a6857a96e01f8ae5ff00b459 (patch)
tree25938d3e5e3e5c9bbb37de1ee6c2cd6ad23071a8 /fs/f2fs
parent33afa7fde0defbb362328233e600e052d0a22cd5 (diff)
f2fs: change GC bitmaps to apply the section granularity
This patch removes a bitmap for victim segments selected by foreground GC, and modifies the other bitmap for victim segments selected by background GC. 1) foreground GC bitmap : We don't need to manage this, since we just only one previous victim section number instead of the whole victim history. The f2fs uses the victim section number in order not to allocate currently GC'ed section to current active logs. 2) background GC bitmap : This bitmap is used to avoid selecting victims repeatedly by background GCs. In addition, the victims are able to be selected by foreground GCs, since there is no need to read victim blocks during foreground GCs. By the fact that the foreground GC reclaims segments in a section unit, it'd be better to manage this bitmap based on the section granularity. Reviewed-by: Namjae Jeon <namjae.jeon@samsung.com> Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/checkpoint.c2
-rw-r--r--fs/f2fs/debug.c2
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/gc.c43
-rw-r--r--fs/f2fs/segment.c66
-rw-r--r--fs/f2fs/segment.h10
-rw-r--r--fs/f2fs/super.c2
7 files changed, 68 insertions, 59 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index d947e66ee8a8..93fd57d491ac 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -748,8 +748,6 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
748 flush_nat_entries(sbi); 748 flush_nat_entries(sbi);
749 flush_sit_entries(sbi); 749 flush_sit_entries(sbi);
750 750
751 reset_victim_segmap(sbi);
752
753 /* unlock all the fs_lock[] in do_checkpoint() */ 751 /* unlock all the fs_lock[] in do_checkpoint() */
754 do_checkpoint(sbi, is_umount); 752 do_checkpoint(sbi, is_umount);
755 753
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 20b8794ec8f6..c3bf343b0b82 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -153,7 +153,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
153 /* build dirty segmap */ 153 /* build dirty segmap */
154 si->base_mem += sizeof(struct dirty_seglist_info); 154 si->base_mem += sizeof(struct dirty_seglist_info);
155 si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi)); 155 si->base_mem += NR_DIRTY_TYPE * f2fs_bitmap_size(TOTAL_SEGS(sbi));
156 si->base_mem += 2 * f2fs_bitmap_size(TOTAL_SEGS(sbi)); 156 si->base_mem += f2fs_bitmap_size(TOTAL_SECS(sbi));
157 157
158 /* buld nm */ 158 /* buld nm */
159 si->base_mem += sizeof(struct f2fs_nm_info); 159 si->base_mem += sizeof(struct f2fs_nm_info);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 77e2eb061bfa..71eacd373916 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -410,6 +410,7 @@ struct f2fs_sb_info {
410 /* for cleaning operations */ 410 /* for cleaning operations */
411 struct mutex gc_mutex; /* mutex for GC */ 411 struct mutex gc_mutex; /* mutex for GC */
412 struct f2fs_gc_kthread *gc_thread; /* GC thread */ 412 struct f2fs_gc_kthread *gc_thread; /* GC thread */
413 unsigned int cur_victim_sec; /* current victim section num */
413 414
414 /* 415 /*
415 * for stat information. 416 * for stat information.
@@ -979,7 +980,6 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *,
979 int, unsigned int, int); 980 int, unsigned int, int);
980void flush_sit_entries(struct f2fs_sb_info *); 981void flush_sit_entries(struct f2fs_sb_info *);
981int build_segment_manager(struct f2fs_sb_info *); 982int build_segment_manager(struct f2fs_sb_info *);
982void reset_victim_segmap(struct f2fs_sb_info *);
983void destroy_segment_manager(struct f2fs_sb_info *); 983void destroy_segment_manager(struct f2fs_sb_info *);
984 984
985/* 985/*
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 2e3eb2d4fc30..09b8a907400b 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -160,18 +160,21 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
160static unsigned int check_bg_victims(struct f2fs_sb_info *sbi) 160static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
161{ 161{
162 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 162 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
163 unsigned int segno; 163 unsigned int hint = 0;
164 unsigned int secno;
164 165
165 /* 166 /*
166 * If the gc_type is FG_GC, we can select victim segments 167 * If the gc_type is FG_GC, we can select victim segments
167 * selected by background GC before. 168 * selected by background GC before.
168 * Those segments guarantee they have small valid blocks. 169 * Those segments guarantee they have small valid blocks.
169 */ 170 */
170 segno = find_next_bit(dirty_i->victim_segmap[BG_GC], 171next:
171 TOTAL_SEGS(sbi), 0); 172 secno = find_next_bit(dirty_i->victim_secmap, TOTAL_SECS(sbi), hint++);
172 if (segno < TOTAL_SEGS(sbi)) { 173 if (secno < TOTAL_SECS(sbi)) {
173 clear_bit(segno, dirty_i->victim_segmap[BG_GC]); 174 if (sec_usage_check(sbi, secno))
174 return segno; 175 goto next;
176 clear_bit(secno, dirty_i->victim_secmap);
177 return secno * sbi->segs_per_sec;
175 } 178 }
176 return NULL_SEGNO; 179 return NULL_SEGNO;
177} 180}
@@ -234,7 +237,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
234{ 237{
235 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 238 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
236 struct victim_sel_policy p; 239 struct victim_sel_policy p;
237 unsigned int segno; 240 unsigned int secno;
238 int nsearched = 0; 241 int nsearched = 0;
239 242
240 p.alloc_mode = alloc_mode; 243 p.alloc_mode = alloc_mode;
@@ -253,6 +256,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
253 256
254 while (1) { 257 while (1) {
255 unsigned long cost; 258 unsigned long cost;
259 unsigned int segno;
256 260
257 segno = find_next_bit(p.dirty_segmap, 261 segno = find_next_bit(p.dirty_segmap,
258 TOTAL_SEGS(sbi), p.offset); 262 TOTAL_SEGS(sbi), p.offset);
@@ -265,13 +269,11 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
265 break; 269 break;
266 } 270 }
267 p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit; 271 p.offset = ((segno / p.ofs_unit) * p.ofs_unit) + p.ofs_unit;
272 secno = GET_SECNO(sbi, segno);
268 273
269 if (test_bit(segno, dirty_i->victim_segmap[FG_GC])) 274 if (sec_usage_check(sbi, secno))
270 continue; 275 continue;
271 if (gc_type == BG_GC && 276 if (gc_type == BG_GC && test_bit(secno, dirty_i->victim_secmap))
272 test_bit(segno, dirty_i->victim_segmap[BG_GC]))
273 continue;
274 if (IS_CURSEC(sbi, GET_SECNO(sbi, segno)))
275 continue; 277 continue;
276 278
277 cost = get_gc_cost(sbi, segno, &p); 279 cost = get_gc_cost(sbi, segno, &p);
@@ -291,13 +293,14 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
291 } 293 }
292got_it: 294got_it:
293 if (p.min_segno != NULL_SEGNO) { 295 if (p.min_segno != NULL_SEGNO) {
294 *result = (p.min_segno / p.ofs_unit) * p.ofs_unit;
295 if (p.alloc_mode == LFS) { 296 if (p.alloc_mode == LFS) {
296 int i; 297 secno = GET_SECNO(sbi, p.min_segno);
297 for (i = 0; i < p.ofs_unit; i++) 298 if (gc_type == FG_GC)
298 set_bit(*result + i, 299 sbi->cur_victim_sec = secno;
299 dirty_i->victim_segmap[gc_type]); 300 else
301 set_bit(secno, dirty_i->victim_secmap);
300 } 302 }
303 *result = (p.min_segno / p.ofs_unit) * p.ofs_unit;
301 } 304 }
302 mutex_unlock(&dirty_i->seglist_lock); 305 mutex_unlock(&dirty_i->seglist_lock);
303 306
@@ -662,9 +665,11 @@ gc_more:
662 for (i = 0; i < sbi->segs_per_sec; i++) 665 for (i = 0; i < sbi->segs_per_sec; i++)
663 do_garbage_collect(sbi, segno + i, &ilist, gc_type); 666 do_garbage_collect(sbi, segno + i, &ilist, gc_type);
664 667
665 if (gc_type == FG_GC && 668 if (gc_type == FG_GC) {
666 get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0) 669 sbi->cur_victim_sec = NULL_SEGNO;
667 nfree++; 670 nfree++;
671 WARN_ON(get_valid_blocks(sbi, segno, sbi->segs_per_sec));
672 }
668 673
669 if (has_not_enough_free_secs(sbi, nfree)) 674 if (has_not_enough_free_secs(sbi, nfree))
670 goto gc_more; 675 goto gc_more;
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index b3486f34af78..d5244f6765a9 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -69,8 +69,9 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
69 if (test_and_clear_bit(segno, 69 if (test_and_clear_bit(segno,
70 dirty_i->dirty_segmap[dirty_type])) 70 dirty_i->dirty_segmap[dirty_type]))
71 dirty_i->nr_dirty[dirty_type]--; 71 dirty_i->nr_dirty[dirty_type]--;
72 clear_bit(segno, dirty_i->victim_segmap[FG_GC]); 72 if (get_valid_blocks(sbi, segno, sbi->segs_per_sec) == 0)
73 clear_bit(segno, dirty_i->victim_segmap[BG_GC]); 73 clear_bit(GET_SECNO(sbi, segno),
74 dirty_i->victim_secmap);
74 } 75 }
75} 76}
76 77
@@ -296,13 +297,12 @@ static void write_sum_page(struct f2fs_sb_info *sbi,
296 f2fs_put_page(page, 1); 297 f2fs_put_page(page, 1);
297} 298}
298 299
299static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, 300static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi, int type)
300 int ofs_unit, int type)
301{ 301{
302 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 302 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
303 unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE]; 303 unsigned long *prefree_segmap = dirty_i->dirty_segmap[PRE];
304 unsigned int segno, next_segno, i; 304 unsigned int segno;
305 int ofs = 0; 305 unsigned int ofs = 0;
306 306
307 /* 307 /*
308 * If there is not enough reserved sections, 308 * If there is not enough reserved sections,
@@ -318,23 +318,30 @@ static unsigned int check_prefree_segments(struct f2fs_sb_info *sbi,
318 if (IS_NODESEG(type)) 318 if (IS_NODESEG(type))
319 return NULL_SEGNO; 319 return NULL_SEGNO;
320next: 320next:
321 segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs++); 321 segno = find_next_bit(prefree_segmap, TOTAL_SEGS(sbi), ofs);
322 ofs = ((segno / ofs_unit) * ofs_unit) + ofs_unit; 322 ofs += sbi->segs_per_sec;
323
323 if (segno < TOTAL_SEGS(sbi)) { 324 if (segno < TOTAL_SEGS(sbi)) {
325 int i;
326
324 /* skip intermediate segments in a section */ 327 /* skip intermediate segments in a section */
325 if (segno % ofs_unit) 328 if (segno % sbi->segs_per_sec)
326 goto next; 329 goto next;
327 330
328 /* skip if whole section is not prefree */ 331 /* skip if the section is currently used */
329 next_segno = find_next_zero_bit(prefree_segmap, 332 if (sec_usage_check(sbi, GET_SECNO(sbi, segno)))
330 TOTAL_SEGS(sbi), segno + 1);
331 if (next_segno - segno < ofs_unit)
332 goto next; 333 goto next;
333 334
335 /* skip if whole section is not prefree */
336 for (i = 1; i < sbi->segs_per_sec; i++)
337 if (!test_bit(segno + i, prefree_segmap))
338 goto next;
339
334 /* skip if whole section was not free at the last checkpoint */ 340 /* skip if whole section was not free at the last checkpoint */
335 for (i = 0; i < ofs_unit; i++) 341 for (i = 0; i < sbi->segs_per_sec; i++)
336 if (get_seg_entry(sbi, segno)->ckpt_valid_blocks) 342 if (get_seg_entry(sbi, segno + i)->ckpt_valid_blocks)
337 goto next; 343 goto next;
344
338 return segno; 345 return segno;
339 } 346 }
340 return NULL_SEGNO; 347 return NULL_SEGNO;
@@ -561,15 +568,13 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
561 int type, bool force) 568 int type, bool force)
562{ 569{
563 struct curseg_info *curseg = CURSEG_I(sbi, type); 570 struct curseg_info *curseg = CURSEG_I(sbi, type);
564 unsigned int ofs_unit;
565 571
566 if (force) { 572 if (force) {
567 new_curseg(sbi, type, true); 573 new_curseg(sbi, type, true);
568 goto out; 574 goto out;
569 } 575 }
570 576
571 ofs_unit = need_SSR(sbi) ? 1 : sbi->segs_per_sec; 577 curseg->next_segno = check_prefree_segments(sbi, type);
572 curseg->next_segno = check_prefree_segments(sbi, ofs_unit, type);
573 578
574 if (curseg->next_segno != NULL_SEGNO) 579 if (curseg->next_segno != NULL_SEGNO)
575 change_curseg(sbi, type, false); 580 change_curseg(sbi, type, false);
@@ -1558,14 +1563,13 @@ static void init_dirty_segmap(struct f2fs_sb_info *sbi)
1558 } 1563 }
1559} 1564}
1560 1565
1561static int init_victim_segmap(struct f2fs_sb_info *sbi) 1566static int init_victim_secmap(struct f2fs_sb_info *sbi)
1562{ 1567{
1563 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 1568 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
1564 unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi)); 1569 unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SECS(sbi));
1565 1570
1566 dirty_i->victim_segmap[FG_GC] = kzalloc(bitmap_size, GFP_KERNEL); 1571 dirty_i->victim_secmap = kzalloc(bitmap_size, GFP_KERNEL);
1567 dirty_i->victim_segmap[BG_GC] = kzalloc(bitmap_size, GFP_KERNEL); 1572 if (!dirty_i->victim_secmap)
1568 if (!dirty_i->victim_segmap[FG_GC] || !dirty_i->victim_segmap[BG_GC])
1569 return -ENOMEM; 1573 return -ENOMEM;
1570 return 0; 1574 return 0;
1571} 1575}
@@ -1592,7 +1596,7 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
1592 } 1596 }
1593 1597
1594 init_dirty_segmap(sbi); 1598 init_dirty_segmap(sbi);
1595 return init_victim_segmap(sbi); 1599 return init_victim_secmap(sbi);
1596} 1600}
1597 1601
1598/* 1602/*
@@ -1679,18 +1683,10 @@ static void discard_dirty_segmap(struct f2fs_sb_info *sbi,
1679 mutex_unlock(&dirty_i->seglist_lock); 1683 mutex_unlock(&dirty_i->seglist_lock);
1680} 1684}
1681 1685
1682void reset_victim_segmap(struct f2fs_sb_info *sbi) 1686static void destroy_victim_secmap(struct f2fs_sb_info *sbi)
1683{
1684 unsigned int bitmap_size = f2fs_bitmap_size(TOTAL_SEGS(sbi));
1685 memset(DIRTY_I(sbi)->victim_segmap[FG_GC], 0, bitmap_size);
1686}
1687
1688static void destroy_victim_segmap(struct f2fs_sb_info *sbi)
1689{ 1687{
1690 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); 1688 struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
1691 1689 kfree(dirty_i->victim_secmap);
1692 kfree(dirty_i->victim_segmap[FG_GC]);
1693 kfree(dirty_i->victim_segmap[BG_GC]);
1694} 1690}
1695 1691
1696static void destroy_dirty_segmap(struct f2fs_sb_info *sbi) 1692static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
@@ -1705,7 +1701,7 @@ static void destroy_dirty_segmap(struct f2fs_sb_info *sbi)
1705 for (i = 0; i < NR_DIRTY_TYPE; i++) 1701 for (i = 0; i < NR_DIRTY_TYPE; i++)
1706 discard_dirty_segmap(sbi, i); 1702 discard_dirty_segmap(sbi, i);
1707 1703
1708 destroy_victim_segmap(sbi); 1704 destroy_victim_secmap(sbi);
1709 SM_I(sbi)->dirty_info = NULL; 1705 SM_I(sbi)->dirty_info = NULL;
1710 kfree(dirty_i); 1706 kfree(dirty_i);
1711} 1707}
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index fea9245d4774..994bb7bd7b70 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -10,6 +10,7 @@
10 */ 10 */
11/* constant macro */ 11/* constant macro */
12#define NULL_SEGNO ((unsigned int)(~0)) 12#define NULL_SEGNO ((unsigned int)(~0))
13#define NULL_SECNO ((unsigned int)(~0))
13 14
14/* V: Logical segment # in volume, R: Relative segment # in main area */ 15/* V: Logical segment # in volume, R: Relative segment # in main area */
15#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno) 16#define GET_L2R_SEGNO(free_i, segno) (segno - free_i->start_segno)
@@ -214,7 +215,7 @@ struct dirty_seglist_info {
214 unsigned long *dirty_segmap[NR_DIRTY_TYPE]; 215 unsigned long *dirty_segmap[NR_DIRTY_TYPE];
215 struct mutex seglist_lock; /* lock for segment bitmaps */ 216 struct mutex seglist_lock; /* lock for segment bitmaps */
216 int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */ 217 int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */
217 unsigned long *victim_segmap[2]; /* BG_GC, FG_GC */ 218 unsigned long *victim_secmap; /* background GC victims */
218}; 219};
219 220
220/* victim selection function for cleaning and SSR */ 221/* victim selection function for cleaning and SSR */
@@ -616,3 +617,10 @@ static inline block_t sum_blk_addr(struct f2fs_sb_info *sbi, int base, int type)
616 le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count) 617 le32_to_cpu(F2FS_CKPT(sbi)->cp_pack_total_block_count)
617 - (base + 1) + type; 618 - (base + 1) + type;
618} 619}
620
621static inline bool sec_usage_check(struct f2fs_sb_info *sbi, unsigned int secno)
622{
623 if (IS_CURSEC(sbi, secno) || (sbi->cur_victim_sec == secno))
624 return true;
625 return false;
626}
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 252890ef8dbc..728c20a8e456 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -26,6 +26,7 @@
26 26
27#include "f2fs.h" 27#include "f2fs.h"
28#include "node.h" 28#include "node.h"
29#include "segment.h"
29#include "xattr.h" 30#include "xattr.h"
30 31
31static struct kmem_cache *f2fs_inode_cachep; 32static struct kmem_cache *f2fs_inode_cachep;
@@ -458,6 +459,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
458 sbi->root_ino_num = le32_to_cpu(raw_super->root_ino); 459 sbi->root_ino_num = le32_to_cpu(raw_super->root_ino);
459 sbi->node_ino_num = le32_to_cpu(raw_super->node_ino); 460 sbi->node_ino_num = le32_to_cpu(raw_super->node_ino);
460 sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino); 461 sbi->meta_ino_num = le32_to_cpu(raw_super->meta_ino);
462 sbi->cur_victim_sec = NULL_SECNO;
461 463
462 for (i = 0; i < NR_COUNT_TYPE; i++) 464 for (i = 0; i < NR_COUNT_TYPE; i++)
463 atomic_set(&sbi->nr_pages[i], 0); 465 atomic_set(&sbi->nr_pages[i], 0);