1 /** 2 * defrag.c 3 * 4 * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 */ 10 #include "fsck.h" 11 12 static int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to) 13 { 14 void *raw = calloc(BLOCK_SZ, 1); 15 struct seg_entry *se; 16 struct f2fs_summary sum; 17 u64 offset; 18 int ret, type; 19 20 ASSERT(raw != NULL); 21 22 /* read from */ 23 ret = dev_read_block(raw, from); 24 ASSERT(ret >= 0); 25 26 /* write to */ 27 ret = dev_write_block(raw, to); 28 ASSERT(ret >= 0); 29 30 /* update sit bitmap & valid_blocks && se->type */ 31 se = get_seg_entry(sbi, GET_SEGNO(sbi, from)); 32 offset = OFFSET_IN_SEG(sbi, from); 33 type = se->type; 34 se->valid_blocks--; 35 f2fs_clear_bit(offset, (char *)se->cur_valid_map); 36 se->dirty = 1; 37 38 se = get_seg_entry(sbi, GET_SEGNO(sbi, to)); 39 offset = OFFSET_IN_SEG(sbi, to); 40 se->type = type; 41 se->valid_blocks++; 42 f2fs_set_bit(offset, (char *)se->cur_valid_map); 43 se->dirty = 1; 44 45 /* read/write SSA */ 46 get_sum_entry(sbi, from, &sum); 47 update_sum_entry(sbi, to, &sum); 48 49 /* if data block, read node and update node block */ 50 if (IS_DATASEG(type)) 51 update_data_blkaddr(sbi, le32_to_cpu(sum.nid), 52 le16_to_cpu(sum.ofs_in_node), to); 53 else 54 update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), to); 55 56 DBG(0, "Migrate %s block %"PRIx64" -> %"PRIx64"\n", 57 IS_DATASEG(type) ? "data" : "node", 58 from, to); 59 free(raw); 60 return 0; 61 } 62 63 int f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int left) 64 { 65 struct seg_entry *se; 66 u64 idx, offset; 67 68 /* flush NAT/SIT journal entries */ 69 flush_journal_entries(sbi); 70 71 for (idx = from; idx < from + len; idx++) { 72 u64 target = to; 73 74 se = get_seg_entry(sbi, GET_SEGNO(sbi, idx)); 75 offset = OFFSET_IN_SEG(sbi, idx); 76 77 if (!f2fs_test_bit(offset, (const char *)se->cur_valid_map)) 78 continue; 79 80 if (find_next_free_block(sbi, &target, left, se->type, false)) { 81 MSG(0, "Not enough space to migrate blocks"); 82 return -1; 83 } 84 85 if (migrate_block(sbi, idx, target)) { 86 ASSERT_MSG("Found inconsistency: please run FSCK"); 87 return -1; 88 } 89 } 90 91 /* update curseg info; can update sit->types */ 92 move_curseg_info(sbi, to, left); 93 zero_journal_entries(sbi); 94 write_curseg_info(sbi); 95 96 /* flush dirty sit entries */ 97 flush_sit_entries(sbi); 98 99 write_checkpoint(sbi); 100 101 return 0; 102 } 103