| .. | .. |
|---|
| 16 | 16 | #define DEF_MAX_RECLAIM_PREFREE_SEGMENTS 4096 /* 8GB in maximum */ |
|---|
| 17 | 17 | |
|---|
| 18 | 18 | #define F2FS_MIN_SEGMENTS 9 /* SB + 2 (CP + SIT + NAT) + SSA + MAIN */ |
|---|
| 19 | +#define F2FS_MIN_META_SEGMENTS 8 /* SB + 2 (CP + SIT + NAT) + SSA */ |
|---|
| 19 | 20 | |
|---|
| 20 | 21 | /* L: Logical segment # in volume, R: Relative segment # in main area */ |
|---|
| 21 | 22 | #define GET_L2R_SEGNO(free_i, segno) ((segno) - (free_i)->start_segno) |
|---|
| 22 | 23 | #define GET_R2L_SEGNO(free_i, segno) ((segno) + (free_i)->start_segno) |
|---|
| 23 | 24 | |
|---|
| 24 | 25 | #define IS_DATASEG(t) ((t) <= CURSEG_COLD_DATA) |
|---|
| 25 | | -#define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE) |
|---|
| 26 | +#define IS_NODESEG(t) ((t) >= CURSEG_HOT_NODE && (t) <= CURSEG_COLD_NODE) |
|---|
| 27 | +#define SE_PAGETYPE(se) ((IS_NODESEG((se)->type) ? NODE : DATA)) |
|---|
| 28 | + |
|---|
| 29 | +static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, |
|---|
| 30 | + unsigned short seg_type) |
|---|
| 31 | +{ |
|---|
| 32 | + f2fs_bug_on(sbi, seg_type >= NR_PERSISTENT_LOG); |
|---|
| 33 | +} |
|---|
| 26 | 34 | |
|---|
| 27 | 35 | #define IS_HOT(t) ((t) == CURSEG_HOT_NODE || (t) == CURSEG_HOT_DATA) |
|---|
| 28 | 36 | #define IS_WARM(t) ((t) == CURSEG_WARM_NODE || (t) == CURSEG_WARM_DATA) |
|---|
| .. | .. |
|---|
| 34 | 42 | ((seg) == CURSEG_I(sbi, CURSEG_COLD_DATA)->segno) || \ |
|---|
| 35 | 43 | ((seg) == CURSEG_I(sbi, CURSEG_HOT_NODE)->segno) || \ |
|---|
| 36 | 44 | ((seg) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno) || \ |
|---|
| 37 | | - ((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno)) |
|---|
| 45 | + ((seg) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno) || \ |
|---|
| 46 | + ((seg) == CURSEG_I(sbi, CURSEG_COLD_DATA_PINNED)->segno) || \ |
|---|
| 47 | + ((seg) == CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC)->segno)) |
|---|
| 38 | 48 | |
|---|
| 39 | 49 | #define IS_CURSEC(sbi, secno) \ |
|---|
| 40 | 50 | (((secno) == CURSEG_I(sbi, CURSEG_HOT_DATA)->segno / \ |
|---|
| .. | .. |
|---|
| 48 | 58 | ((secno) == CURSEG_I(sbi, CURSEG_WARM_NODE)->segno / \ |
|---|
| 49 | 59 | (sbi)->segs_per_sec) || \ |
|---|
| 50 | 60 | ((secno) == CURSEG_I(sbi, CURSEG_COLD_NODE)->segno / \ |
|---|
| 51 | | - (sbi)->segs_per_sec)) \ |
|---|
| 61 | + (sbi)->segs_per_sec) || \ |
|---|
| 62 | + ((secno) == CURSEG_I(sbi, CURSEG_COLD_DATA_PINNED)->segno / \ |
|---|
| 63 | + (sbi)->segs_per_sec) || \ |
|---|
| 64 | + ((secno) == CURSEG_I(sbi, CURSEG_ALL_DATA_ATGC)->segno / \ |
|---|
| 65 | + (sbi)->segs_per_sec)) |
|---|
| 52 | 66 | |
|---|
| 53 | 67 | #define MAIN_BLKADDR(sbi) \ |
|---|
| 54 | 68 | (SM_I(sbi) ? SM_I(sbi)->main_blkaddr : \ |
|---|
| .. | .. |
|---|
| 132 | 146 | * In the victim_sel_policy->alloc_mode, there are two block allocation modes. |
|---|
| 133 | 147 | * LFS writes data sequentially with cleaning operations. |
|---|
| 134 | 148 | * SSR (Slack Space Recycle) reuses obsolete space without cleaning operations. |
|---|
| 149 | + * AT_SSR (Age Threshold based Slack Space Recycle) merges fragments into |
|---|
| 150 | + * fragmented segment which has similar aging degree. |
|---|
| 135 | 151 | */ |
|---|
| 136 | 152 | enum { |
|---|
| 137 | 153 | LFS = 0, |
|---|
| 138 | | - SSR |
|---|
| 154 | + SSR, |
|---|
| 155 | + AT_SSR, |
|---|
| 139 | 156 | }; |
|---|
| 140 | 157 | |
|---|
| 141 | 158 | /* |
|---|
| 142 | 159 | * In the victim_sel_policy->gc_mode, there are two gc, aka cleaning, modes. |
|---|
| 143 | 160 | * GC_CB is based on cost-benefit algorithm. |
|---|
| 144 | 161 | * GC_GREEDY is based on greedy algorithm. |
|---|
| 162 | + * GC_AT is based on age-threshold algorithm. |
|---|
| 145 | 163 | */ |
|---|
| 146 | 164 | enum { |
|---|
| 147 | 165 | GC_CB = 0, |
|---|
| 148 | 166 | GC_GREEDY, |
|---|
| 167 | + GC_AT, |
|---|
| 149 | 168 | ALLOC_NEXT, |
|---|
| 150 | 169 | FLUSH_DEVICE, |
|---|
| 151 | 170 | MAX_GC_POLICY, |
|---|
| .. | .. |
|---|
| 154 | 173 | /* |
|---|
| 155 | 174 | * BG_GC means the background cleaning job. |
|---|
| 156 | 175 | * FG_GC means the on-demand cleaning job. |
|---|
| 157 | | - * FORCE_FG_GC means on-demand cleaning job in background. |
|---|
| 158 | 176 | */ |
|---|
| 159 | 177 | enum { |
|---|
| 160 | 178 | BG_GC = 0, |
|---|
| 161 | 179 | FG_GC, |
|---|
| 162 | | - FORCE_FG_GC, |
|---|
| 163 | 180 | }; |
|---|
| 164 | 181 | |
|---|
| 165 | 182 | /* for a function parameter to select a victim segment */ |
|---|
| 166 | 183 | struct victim_sel_policy { |
|---|
| 167 | 184 | int alloc_mode; /* LFS or SSR */ |
|---|
| 168 | 185 | int gc_mode; /* GC_CB or GC_GREEDY */ |
|---|
| 169 | | - unsigned long *dirty_segmap; /* dirty segment bitmap */ |
|---|
| 170 | | - unsigned int max_search; /* maximum # of segments to search */ |
|---|
| 186 | + unsigned long *dirty_bitmap; /* dirty segment/section bitmap */ |
|---|
| 187 | + unsigned int max_search; /* |
|---|
| 188 | + * maximum # of segments/sections |
|---|
| 189 | + * to search |
|---|
| 190 | + */ |
|---|
| 171 | 191 | unsigned int offset; /* last scanned bitmap offset */ |
|---|
| 172 | 192 | unsigned int ofs_unit; /* bitmap search unit */ |
|---|
| 173 | 193 | unsigned int min_cost; /* minimum cost */ |
|---|
| 194 | + unsigned long long oldest_age; /* oldest age of segments having the same min cost */ |
|---|
| 174 | 195 | unsigned int min_segno; /* segment # having min. cost */ |
|---|
| 196 | + unsigned long long age; /* mtime of GCed section*/ |
|---|
| 197 | + unsigned long long age_threshold;/* age threshold */ |
|---|
| 175 | 198 | }; |
|---|
| 176 | 199 | |
|---|
| 177 | 200 | struct seg_entry { |
|---|
| .. | .. |
|---|
| 184 | 207 | unsigned char *cur_valid_map_mir; /* mirror of current valid bitmap */ |
|---|
| 185 | 208 | #endif |
|---|
| 186 | 209 | /* |
|---|
| 187 | | - * # of valid blocks and the validity bitmap stored in the the last |
|---|
| 210 | + * # of valid blocks and the validity bitmap stored in the last |
|---|
| 188 | 211 | * checkpoint pack. This information is used by the SSR mode. |
|---|
| 189 | 212 | */ |
|---|
| 190 | 213 | unsigned char *ckpt_valid_map; /* validity bitmap of blocks last cp */ |
|---|
| .. | .. |
|---|
| 237 | 260 | unsigned long long mounted_time; /* mount time */ |
|---|
| 238 | 261 | unsigned long long min_mtime; /* min. modification time */ |
|---|
| 239 | 262 | unsigned long long max_mtime; /* max. modification time */ |
|---|
| 263 | + unsigned long long dirty_min_mtime; /* rerange candidates in GC_AT */ |
|---|
| 264 | + unsigned long long dirty_max_mtime; /* rerange candidates in GC_AT */ |
|---|
| 240 | 265 | |
|---|
| 241 | 266 | unsigned int last_victim[MAX_GC_POLICY]; /* last victim segment # */ |
|---|
| 242 | 267 | }; |
|---|
| .. | .. |
|---|
| 266 | 291 | struct dirty_seglist_info { |
|---|
| 267 | 292 | const struct victim_selection *v_ops; /* victim selction operation */ |
|---|
| 268 | 293 | unsigned long *dirty_segmap[NR_DIRTY_TYPE]; |
|---|
| 294 | + unsigned long *dirty_secmap; |
|---|
| 269 | 295 | struct mutex seglist_lock; /* lock for segment bitmaps */ |
|---|
| 270 | 296 | int nr_dirty[NR_DIRTY_TYPE]; /* # of dirty segments */ |
|---|
| 271 | 297 | unsigned long *victim_secmap; /* background GC victims */ |
|---|
| .. | .. |
|---|
| 274 | 300 | /* victim selection function for cleaning and SSR */ |
|---|
| 275 | 301 | struct victim_selection { |
|---|
| 276 | 302 | int (*get_victim)(struct f2fs_sb_info *, unsigned int *, |
|---|
| 277 | | - int, int, char); |
|---|
| 303 | + int, int, char, unsigned long long); |
|---|
| 278 | 304 | }; |
|---|
| 279 | 305 | |
|---|
| 280 | 306 | /* for active log information */ |
|---|
| .. | .. |
|---|
| 284 | 310 | struct rw_semaphore journal_rwsem; /* protect journal area */ |
|---|
| 285 | 311 | struct f2fs_journal *journal; /* cached journal info */ |
|---|
| 286 | 312 | unsigned char alloc_type; /* current allocation type */ |
|---|
| 313 | + unsigned short seg_type; /* segment type like CURSEG_XXX_TYPE */ |
|---|
| 287 | 314 | unsigned int segno; /* current segment number */ |
|---|
| 288 | 315 | unsigned short next_blkoff; /* next block offset to write */ |
|---|
| 289 | 316 | unsigned int zone; /* current zone number */ |
|---|
| 290 | 317 | unsigned int next_segno; /* preallocated segment */ |
|---|
| 318 | + bool inited; /* indicate inmem log is inited */ |
|---|
| 291 | 319 | }; |
|---|
| 292 | 320 | |
|---|
| 293 | 321 | struct sit_entry_set { |
|---|
| .. | .. |
|---|
| 301 | 329 | */ |
|---|
| 302 | 330 | static inline struct curseg_info *CURSEG_I(struct f2fs_sb_info *sbi, int type) |
|---|
| 303 | 331 | { |
|---|
| 304 | | - if (type == CURSEG_COLD_DATA_PINNED) |
|---|
| 305 | | - type = CURSEG_COLD_DATA; |
|---|
| 306 | 332 | return (struct curseg_info *)(SM_I(sbi)->curseg_array + type); |
|---|
| 307 | 333 | } |
|---|
| 308 | 334 | |
|---|
| .. | .. |
|---|
| 334 | 360 | } |
|---|
| 335 | 361 | |
|---|
| 336 | 362 | static inline unsigned int get_ckpt_valid_blocks(struct f2fs_sb_info *sbi, |
|---|
| 337 | | - unsigned int segno) |
|---|
| 363 | + unsigned int segno, bool use_section) |
|---|
| 338 | 364 | { |
|---|
| 365 | + if (use_section && __is_large_section(sbi)) { |
|---|
| 366 | + unsigned int start_segno = START_SEGNO(segno); |
|---|
| 367 | + unsigned int blocks = 0; |
|---|
| 368 | + int i; |
|---|
| 369 | + |
|---|
| 370 | + for (i = 0; i < sbi->segs_per_sec; i++, start_segno++) { |
|---|
| 371 | + struct seg_entry *se = get_seg_entry(sbi, start_segno); |
|---|
| 372 | + |
|---|
| 373 | + blocks += se->ckpt_valid_blocks; |
|---|
| 374 | + } |
|---|
| 375 | + return blocks; |
|---|
| 376 | + } |
|---|
| 339 | 377 | return get_seg_entry(sbi, segno)->ckpt_valid_blocks; |
|---|
| 340 | 378 | } |
|---|
| 341 | 379 | |
|---|
| .. | .. |
|---|
| 407 | 445 | unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); |
|---|
| 408 | 446 | unsigned int start_segno = GET_SEG_FROM_SEC(sbi, secno); |
|---|
| 409 | 447 | unsigned int next; |
|---|
| 448 | + unsigned int usable_segs = f2fs_usable_segs_in_sec(sbi, segno); |
|---|
| 410 | 449 | |
|---|
| 411 | 450 | spin_lock(&free_i->segmap_lock); |
|---|
| 412 | 451 | clear_bit(segno, free_i->free_segmap); |
|---|
| .. | .. |
|---|
| 414 | 453 | |
|---|
| 415 | 454 | next = find_next_bit(free_i->free_segmap, |
|---|
| 416 | 455 | start_segno + sbi->segs_per_sec, start_segno); |
|---|
| 417 | | - if (next >= start_segno + sbi->segs_per_sec) { |
|---|
| 456 | + if (next >= start_segno + usable_segs) { |
|---|
| 418 | 457 | clear_bit(secno, free_i->free_secmap); |
|---|
| 419 | 458 | free_i->free_sections++; |
|---|
| 420 | 459 | } |
|---|
| .. | .. |
|---|
| 434 | 473 | } |
|---|
| 435 | 474 | |
|---|
| 436 | 475 | static inline void __set_test_and_free(struct f2fs_sb_info *sbi, |
|---|
| 437 | | - unsigned int segno) |
|---|
| 476 | + unsigned int segno, bool inmem) |
|---|
| 438 | 477 | { |
|---|
| 439 | 478 | struct free_segmap_info *free_i = FREE_I(sbi); |
|---|
| 440 | 479 | unsigned int secno = GET_SEC_FROM_SEG(sbi, segno); |
|---|
| 441 | 480 | unsigned int start_segno = GET_SEG_FROM_SEC(sbi, secno); |
|---|
| 442 | 481 | unsigned int next; |
|---|
| 482 | + unsigned int usable_segs = f2fs_usable_segs_in_sec(sbi, segno); |
|---|
| 443 | 483 | |
|---|
| 444 | 484 | spin_lock(&free_i->segmap_lock); |
|---|
| 445 | 485 | if (test_and_clear_bit(segno, free_i->free_segmap)) { |
|---|
| 446 | 486 | free_i->free_segments++; |
|---|
| 447 | 487 | |
|---|
| 448 | | - if (IS_CURSEC(sbi, secno)) |
|---|
| 488 | + if (!inmem && IS_CURSEC(sbi, secno)) |
|---|
| 449 | 489 | goto skip_free; |
|---|
| 450 | 490 | next = find_next_bit(free_i->free_segmap, |
|---|
| 451 | 491 | start_segno + sbi->segs_per_sec, start_segno); |
|---|
| 452 | | - if (next >= start_segno + sbi->segs_per_sec) { |
|---|
| 492 | + if (next >= start_segno + usable_segs) { |
|---|
| 453 | 493 | if (test_and_clear_bit(secno, free_i->free_secmap)) |
|---|
| 454 | 494 | free_i->free_sections++; |
|---|
| 455 | 495 | } |
|---|
| .. | .. |
|---|
| 496 | 536 | return FREE_I(sbi)->free_segments; |
|---|
| 497 | 537 | } |
|---|
| 498 | 538 | |
|---|
| 499 | | -static inline int reserved_segments(struct f2fs_sb_info *sbi) |
|---|
| 539 | +static inline unsigned int reserved_segments(struct f2fs_sb_info *sbi) |
|---|
| 500 | 540 | { |
|---|
| 501 | | - return SM_I(sbi)->reserved_segments; |
|---|
| 541 | + return SM_I(sbi)->reserved_segments + |
|---|
| 542 | + SM_I(sbi)->additional_reserved_segments; |
|---|
| 502 | 543 | } |
|---|
| 503 | 544 | |
|---|
| 504 | 545 | static inline unsigned int free_sections(struct f2fs_sb_info *sbi) |
|---|
| .. | .. |
|---|
| 528 | 569 | |
|---|
| 529 | 570 | static inline int reserved_sections(struct f2fs_sb_info *sbi) |
|---|
| 530 | 571 | { |
|---|
| 531 | | - return GET_SEC_FROM_SEG(sbi, (unsigned int)reserved_segments(sbi)); |
|---|
| 572 | + return GET_SEC_FROM_SEG(sbi, reserved_segments(sbi)); |
|---|
| 532 | 573 | } |
|---|
| 533 | 574 | |
|---|
| 534 | | -static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi) |
|---|
| 575 | +static inline bool has_curseg_enough_space(struct f2fs_sb_info *sbi, |
|---|
| 576 | + unsigned int node_blocks, unsigned int dent_blocks) |
|---|
| 535 | 577 | { |
|---|
| 536 | | - unsigned int node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) + |
|---|
| 537 | | - get_pages(sbi, F2FS_DIRTY_DENTS); |
|---|
| 538 | | - unsigned int dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS); |
|---|
| 578 | + |
|---|
| 539 | 579 | unsigned int segno, left_blocks; |
|---|
| 540 | 580 | int i; |
|---|
| 541 | 581 | |
|---|
| 542 | 582 | /* check current node segment */ |
|---|
| 543 | 583 | for (i = CURSEG_HOT_NODE; i <= CURSEG_COLD_NODE; i++) { |
|---|
| 544 | 584 | segno = CURSEG_I(sbi, i)->segno; |
|---|
| 545 | | - left_blocks = sbi->blocks_per_seg - |
|---|
| 546 | | - get_seg_entry(sbi, segno)->ckpt_valid_blocks; |
|---|
| 585 | + left_blocks = f2fs_usable_blks_in_seg(sbi, segno) - |
|---|
| 586 | + get_seg_entry(sbi, segno)->ckpt_valid_blocks; |
|---|
| 547 | 587 | |
|---|
| 548 | 588 | if (node_blocks > left_blocks) |
|---|
| 549 | 589 | return false; |
|---|
| .. | .. |
|---|
| 551 | 591 | |
|---|
| 552 | 592 | /* check current data segment */ |
|---|
| 553 | 593 | segno = CURSEG_I(sbi, CURSEG_HOT_DATA)->segno; |
|---|
| 554 | | - left_blocks = sbi->blocks_per_seg - |
|---|
| 594 | + left_blocks = f2fs_usable_blks_in_seg(sbi, segno) - |
|---|
| 555 | 595 | get_seg_entry(sbi, segno)->ckpt_valid_blocks; |
|---|
| 556 | 596 | if (dent_blocks > left_blocks) |
|---|
| 557 | 597 | return false; |
|---|
| .. | .. |
|---|
| 561 | 601 | static inline bool has_not_enough_free_secs(struct f2fs_sb_info *sbi, |
|---|
| 562 | 602 | int freed, int needed) |
|---|
| 563 | 603 | { |
|---|
| 564 | | - int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); |
|---|
| 565 | | - int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); |
|---|
| 566 | | - int imeta_secs = get_blocktype_secs(sbi, F2FS_DIRTY_IMETA); |
|---|
| 604 | + unsigned int total_node_blocks = get_pages(sbi, F2FS_DIRTY_NODES) + |
|---|
| 605 | + get_pages(sbi, F2FS_DIRTY_DENTS) + |
|---|
| 606 | + get_pages(sbi, F2FS_DIRTY_IMETA); |
|---|
| 607 | + unsigned int total_dent_blocks = get_pages(sbi, F2FS_DIRTY_DENTS); |
|---|
| 608 | + unsigned int node_secs = total_node_blocks / BLKS_PER_SEC(sbi); |
|---|
| 609 | + unsigned int dent_secs = total_dent_blocks / BLKS_PER_SEC(sbi); |
|---|
| 610 | + unsigned int node_blocks = total_node_blocks % BLKS_PER_SEC(sbi); |
|---|
| 611 | + unsigned int dent_blocks = total_dent_blocks % BLKS_PER_SEC(sbi); |
|---|
| 612 | + unsigned int free, need_lower, need_upper; |
|---|
| 567 | 613 | |
|---|
| 568 | 614 | if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING))) |
|---|
| 569 | 615 | return false; |
|---|
| 570 | 616 | |
|---|
| 571 | | - if (free_sections(sbi) + freed == reserved_sections(sbi) + needed && |
|---|
| 572 | | - has_curseg_enough_space(sbi)) |
|---|
| 617 | + free = free_sections(sbi) + freed; |
|---|
| 618 | + need_lower = node_secs + dent_secs + reserved_sections(sbi) + needed; |
|---|
| 619 | + need_upper = need_lower + (node_blocks ? 1 : 0) + (dent_blocks ? 1 : 0); |
|---|
| 620 | + |
|---|
| 621 | + if (free > need_upper) |
|---|
| 573 | 622 | return false; |
|---|
| 574 | | - return (free_sections(sbi) + freed) <= |
|---|
| 575 | | - (node_secs + 2 * dent_secs + imeta_secs + |
|---|
| 576 | | - reserved_sections(sbi) + needed); |
|---|
| 623 | + else if (free <= need_lower) |
|---|
| 624 | + return true; |
|---|
| 625 | + return !has_curseg_enough_space(sbi, node_blocks, dent_blocks); |
|---|
| 577 | 626 | } |
|---|
| 578 | 627 | |
|---|
| 579 | 628 | static inline bool f2fs_is_checkpoint_ready(struct f2fs_sb_info *sbi) |
|---|
| .. | .. |
|---|
| 610 | 659 | * pages over min_fsync_blocks. (=default option) |
|---|
| 611 | 660 | * F2FS_IPU_ASYNC - do IPU given by asynchronous write requests. |
|---|
| 612 | 661 | * F2FS_IPU_NOCACHE - disable IPU bio cache. |
|---|
| 613 | | - * F2FS_IPUT_DISABLE - disable IPU. (=default option in LFS mode) |
|---|
| 662 | + * F2FS_IPU_HONOR_OPU_WRITE - use OPU write prior to IPU write if inode has |
|---|
| 663 | + * FI_OPU_WRITE flag. |
|---|
| 664 | + * F2FS_IPU_DISABLE - disable IPU. (=default option in LFS mode) |
|---|
| 614 | 665 | */ |
|---|
| 615 | 666 | #define DEF_MIN_IPU_UTIL 70 |
|---|
| 616 | 667 | #define DEF_MIN_FSYNC_BLOCKS 8 |
|---|
| .. | .. |
|---|
| 626 | 677 | F2FS_IPU_FSYNC, |
|---|
| 627 | 678 | F2FS_IPU_ASYNC, |
|---|
| 628 | 679 | F2FS_IPU_NOCACHE, |
|---|
| 680 | + F2FS_IPU_HONOR_OPU_WRITE, |
|---|
| 629 | 681 | }; |
|---|
| 630 | 682 | |
|---|
| 631 | 683 | static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, |
|---|
| .. | .. |
|---|
| 673 | 725 | bool is_valid = test_bit_le(0, raw_sit->valid_map) ? true : false; |
|---|
| 674 | 726 | int valid_blocks = 0; |
|---|
| 675 | 727 | int cur_pos = 0, next_pos; |
|---|
| 728 | + unsigned int usable_blks_per_seg = f2fs_usable_blks_in_seg(sbi, segno); |
|---|
| 676 | 729 | |
|---|
| 677 | 730 | /* check bitmap with valid block count */ |
|---|
| 678 | 731 | do { |
|---|
| 679 | 732 | if (is_valid) { |
|---|
| 680 | 733 | next_pos = find_next_zero_bit_le(&raw_sit->valid_map, |
|---|
| 681 | | - sbi->blocks_per_seg, |
|---|
| 734 | + usable_blks_per_seg, |
|---|
| 682 | 735 | cur_pos); |
|---|
| 683 | 736 | valid_blocks += next_pos - cur_pos; |
|---|
| 684 | 737 | } else |
|---|
| 685 | 738 | next_pos = find_next_bit_le(&raw_sit->valid_map, |
|---|
| 686 | | - sbi->blocks_per_seg, |
|---|
| 739 | + usable_blks_per_seg, |
|---|
| 687 | 740 | cur_pos); |
|---|
| 688 | 741 | cur_pos = next_pos; |
|---|
| 689 | 742 | is_valid = !is_valid; |
|---|
| 690 | | - } while (cur_pos < sbi->blocks_per_seg); |
|---|
| 743 | + } while (cur_pos < usable_blks_per_seg); |
|---|
| 691 | 744 | |
|---|
| 692 | 745 | if (unlikely(GET_SIT_VBLOCKS(raw_sit) != valid_blocks)) { |
|---|
| 693 | 746 | f2fs_err(sbi, "Mismatch valid blocks %d vs. %d", |
|---|
| .. | .. |
|---|
| 696 | 749 | return -EFSCORRUPTED; |
|---|
| 697 | 750 | } |
|---|
| 698 | 751 | |
|---|
| 752 | + if (usable_blks_per_seg < sbi->blocks_per_seg) |
|---|
| 753 | + f2fs_bug_on(sbi, find_next_bit_le(&raw_sit->valid_map, |
|---|
| 754 | + sbi->blocks_per_seg, |
|---|
| 755 | + usable_blks_per_seg) != sbi->blocks_per_seg); |
|---|
| 756 | + |
|---|
| 699 | 757 | /* check segment usage, and check boundary of a given segment number */ |
|---|
| 700 | | - if (unlikely(GET_SIT_VBLOCKS(raw_sit) > sbi->blocks_per_seg |
|---|
| 758 | + if (unlikely(GET_SIT_VBLOCKS(raw_sit) > usable_blks_per_seg |
|---|
| 701 | 759 | || segno > TOTAL_SEGS(sbi) - 1)) { |
|---|
| 702 | 760 | f2fs_err(sbi, "Wrong valid blocks %d or segno %u", |
|---|
| 703 | 761 | GET_SIT_VBLOCKS(raw_sit), segno); |
|---|