Home | History | Annotate | Download | only in fsck
      1 /**
      2  * defrag.c
      3  *
      4  * Copyright (c) 2015 Jaegeuk Kim <jaegeuk (at) 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)) {
     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