aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);