xref: /aosp_15_r20/external/f2fs-tools/fsck/defrag.c (revision 59bfda1f02d633cd6b8b69f31eee485d40f6eef6)
1 /**
2  * defrag.c
3  *
4  * Copyright (c) 2015 Jaegeuk Kim <[email protected]>
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 
migrate_block(struct f2fs_sb_info * sbi,u64 from,u64 to)12 static int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to)
13 {
14 	void *raw = calloc(F2FS_BLKSIZE, 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 	/* get segment type */
27 	se = get_seg_entry(sbi, GET_SEGNO(sbi, from));
28 	/* write to */
29 	ret = dev_write_block(raw, to, f2fs_io_type_to_rw_hint(se->type));
30 	ASSERT(ret >= 0);
31 
32 	/* update sit bitmap & valid_blocks && se->type */
33 	offset = OFFSET_IN_SEG(sbi, from);
34 	type = se->type;
35 	se->valid_blocks--;
36 	f2fs_clear_bit(offset, (char *)se->cur_valid_map);
37 	se->dirty = 1;
38 
39 	se = get_seg_entry(sbi, GET_SEGNO(sbi, to));
40 	offset = OFFSET_IN_SEG(sbi, to);
41 	se->type = type;
42 	se->valid_blocks++;
43 	f2fs_set_bit(offset, (char *)se->cur_valid_map);
44 	se->dirty = 1;
45 
46 	/* read/write SSA */
47 	get_sum_entry(sbi, from, &sum);
48 	update_sum_entry(sbi, to, &sum);
49 
50 	/* if data block, read node and update node block */
51 	if (IS_DATASEG(type))
52 		update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
53 				le16_to_cpu(sum.ofs_in_node), to, NULL);
54 	else
55 		update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), to);
56 
57 	DBG(1, "Migrate %s block %"PRIx64" -> %"PRIx64"\n",
58 					IS_DATASEG(type) ? "data" : "node",
59 					from, to);
60 	free(raw);
61 	return 0;
62 }
63 
f2fs_defragment(struct f2fs_sb_info * sbi,u64 from,u64 len,u64 to,int left)64 int f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int left)
65 {
66 	struct seg_entry *se;
67 	u64 idx, offset;
68 
69 	/* flush NAT/SIT journal entries */
70 	flush_journal_entries(sbi);
71 
72 	for (idx = from; idx < from + len; idx++) {
73 		u64 target = to;
74 
75 		se = get_seg_entry(sbi, GET_SEGNO(sbi, idx));
76 		offset = OFFSET_IN_SEG(sbi, idx);
77 
78 		if (!f2fs_test_bit(offset, (const char *)se->cur_valid_map))
79 			continue;
80 
81 		if (find_next_free_block(sbi, &target, left, se->type, false)) {
82 			MSG(0, "Not enough space to migrate blocks");
83 			return -1;
84 		}
85 
86 		if (migrate_block(sbi, idx, target)) {
87 			ASSERT_MSG("Found inconsistency: please run FSCK");
88 			return -1;
89 		}
90 	}
91 
92 	/* update curseg info; can update sit->types */
93 	move_curseg_info(sbi, to, left);
94 	zero_journal_entries(sbi);
95 	write_curseg_info(sbi);
96 
97 	/* flush dirty sit entries */
98 	flush_sit_entries(sbi);
99 
100 	write_checkpoint(sbi);
101 
102 	return 0;
103 }
104