15e5c12b0Sopenharmony_ci/**
25e5c12b0Sopenharmony_ci * defrag.c
35e5c12b0Sopenharmony_ci *
45e5c12b0Sopenharmony_ci * Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org>
55e5c12b0Sopenharmony_ci *
65e5c12b0Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
75e5c12b0Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as
85e5c12b0Sopenharmony_ci * published by the Free Software Foundation.
95e5c12b0Sopenharmony_ci */
105e5c12b0Sopenharmony_ci#include "fsck.h"
115e5c12b0Sopenharmony_ci
125e5c12b0Sopenharmony_cistatic int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to)
135e5c12b0Sopenharmony_ci{
145e5c12b0Sopenharmony_ci	void *raw = calloc(BLOCK_SZ, 1);
155e5c12b0Sopenharmony_ci	struct seg_entry *se;
165e5c12b0Sopenharmony_ci	struct f2fs_summary sum;
175e5c12b0Sopenharmony_ci	u64 offset;
185e5c12b0Sopenharmony_ci	int ret, type;
195e5c12b0Sopenharmony_ci
205e5c12b0Sopenharmony_ci	ASSERT(raw != NULL);
215e5c12b0Sopenharmony_ci
225e5c12b0Sopenharmony_ci	/* read from */
235e5c12b0Sopenharmony_ci	ret = dev_read_block(raw, from);
245e5c12b0Sopenharmony_ci	ASSERT(ret >= 0);
255e5c12b0Sopenharmony_ci
265e5c12b0Sopenharmony_ci	/* write to */
275e5c12b0Sopenharmony_ci	ret = dev_write_block(raw, to);
285e5c12b0Sopenharmony_ci	ASSERT(ret >= 0);
295e5c12b0Sopenharmony_ci
305e5c12b0Sopenharmony_ci	/* update sit bitmap & valid_blocks && se->type */
315e5c12b0Sopenharmony_ci	se = get_seg_entry(sbi, GET_SEGNO(sbi, from));
325e5c12b0Sopenharmony_ci	offset = OFFSET_IN_SEG(sbi, from);
335e5c12b0Sopenharmony_ci	type = se->type;
345e5c12b0Sopenharmony_ci	se->valid_blocks--;
355e5c12b0Sopenharmony_ci	f2fs_clear_bit(offset, (char *)se->cur_valid_map);
365e5c12b0Sopenharmony_ci	se->dirty = 1;
375e5c12b0Sopenharmony_ci
385e5c12b0Sopenharmony_ci	se = get_seg_entry(sbi, GET_SEGNO(sbi, to));
395e5c12b0Sopenharmony_ci	offset = OFFSET_IN_SEG(sbi, to);
405e5c12b0Sopenharmony_ci	se->type = type;
415e5c12b0Sopenharmony_ci	se->valid_blocks++;
425e5c12b0Sopenharmony_ci	f2fs_set_bit(offset, (char *)se->cur_valid_map);
435e5c12b0Sopenharmony_ci	se->dirty = 1;
445e5c12b0Sopenharmony_ci
455e5c12b0Sopenharmony_ci	/* read/write SSA */
465e5c12b0Sopenharmony_ci	get_sum_entry(sbi, from, &sum);
475e5c12b0Sopenharmony_ci	update_sum_entry(sbi, to, &sum);
485e5c12b0Sopenharmony_ci
495e5c12b0Sopenharmony_ci	/* if data block, read node and update node block */
505e5c12b0Sopenharmony_ci	if (IS_DATASEG(type))
515e5c12b0Sopenharmony_ci		update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
525e5c12b0Sopenharmony_ci				le16_to_cpu(sum.ofs_in_node), to);
535e5c12b0Sopenharmony_ci	else
545e5c12b0Sopenharmony_ci		update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), to);
555e5c12b0Sopenharmony_ci
565e5c12b0Sopenharmony_ci	DBG(1, "Migrate %s block %"PRIx64" -> %"PRIx64"\n",
575e5c12b0Sopenharmony_ci					IS_DATASEG(type) ? "data" : "node",
585e5c12b0Sopenharmony_ci					from, to);
595e5c12b0Sopenharmony_ci	free(raw);
605e5c12b0Sopenharmony_ci	return 0;
615e5c12b0Sopenharmony_ci}
625e5c12b0Sopenharmony_ci
635e5c12b0Sopenharmony_ciint f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int left)
645e5c12b0Sopenharmony_ci{
655e5c12b0Sopenharmony_ci	struct seg_entry *se;
665e5c12b0Sopenharmony_ci	u64 idx, offset;
675e5c12b0Sopenharmony_ci
685e5c12b0Sopenharmony_ci	/* flush NAT/SIT journal entries */
695e5c12b0Sopenharmony_ci	flush_journal_entries(sbi);
705e5c12b0Sopenharmony_ci
715e5c12b0Sopenharmony_ci	for (idx = from; idx < from + len; idx++) {
725e5c12b0Sopenharmony_ci		u64 target = to;
735e5c12b0Sopenharmony_ci
745e5c12b0Sopenharmony_ci		se = get_seg_entry(sbi, GET_SEGNO(sbi, idx));
755e5c12b0Sopenharmony_ci		offset = OFFSET_IN_SEG(sbi, idx);
765e5c12b0Sopenharmony_ci
775e5c12b0Sopenharmony_ci		if (!f2fs_test_bit(offset, (const char *)se->cur_valid_map))
785e5c12b0Sopenharmony_ci			continue;
795e5c12b0Sopenharmony_ci
805e5c12b0Sopenharmony_ci		if (find_next_free_block(sbi, &target, left, se->type, false)) {
815e5c12b0Sopenharmony_ci			MSG(0, "Not enough space to migrate blocks");
825e5c12b0Sopenharmony_ci			return -1;
835e5c12b0Sopenharmony_ci		}
845e5c12b0Sopenharmony_ci
855e5c12b0Sopenharmony_ci		if (migrate_block(sbi, idx, target)) {
865e5c12b0Sopenharmony_ci			ASSERT_MSG("Found inconsistency: please run FSCK");
875e5c12b0Sopenharmony_ci			return -1;
885e5c12b0Sopenharmony_ci		}
895e5c12b0Sopenharmony_ci	}
905e5c12b0Sopenharmony_ci
915e5c12b0Sopenharmony_ci	/* update curseg info; can update sit->types */
925e5c12b0Sopenharmony_ci	move_curseg_info(sbi, to, left);
935e5c12b0Sopenharmony_ci	zero_journal_entries(sbi);
945e5c12b0Sopenharmony_ci	write_curseg_info(sbi);
955e5c12b0Sopenharmony_ci
965e5c12b0Sopenharmony_ci	/* flush dirty sit entries */
975e5c12b0Sopenharmony_ci	flush_sit_entries(sbi);
985e5c12b0Sopenharmony_ci
995e5c12b0Sopenharmony_ci	write_checkpoint(sbi);
1005e5c12b0Sopenharmony_ci
1015e5c12b0Sopenharmony_ci	return 0;
1025e5c12b0Sopenharmony_ci}
103