mirror of
https://gitee.com/openharmony/third_party_f2fs-tools
synced 2024-11-23 10:10:00 +00:00
2c1ebe237a
This tool tries to move the valid blocks ranging from blkaddr to blkaddr + len to targeted blkaddr with a direction like expand or shrink. The option includes: -d debug level [default:0] -s start block address [default: main_blkaddr] -l length [default:512 (2MB)] -t target block address [default: main_blkaddr + 2MB] -i set direction as shrink [default: expand] For example, # defrag.f2fs -s 0x100 -l 0x10 -t 0x4000 /dev/sdb1 This will move data blocks between 0x100 and 0x110 to the right side of 0x4000 space. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
102 lines
2.3 KiB
C
102 lines
2.3 KiB
C
/**
|
|
* defrag.c
|
|
*
|
|
* Copyright (c) 2015 Jaegeuk Kim <jaegeuk@kernel.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*/
|
|
#include "fsck.h"
|
|
|
|
static int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to)
|
|
{
|
|
void *raw = calloc(BLOCK_SZ, 1);
|
|
struct seg_entry *se;
|
|
struct f2fs_summary sum;
|
|
u64 offset;
|
|
int ret, type;
|
|
|
|
ASSERT(raw != NULL);
|
|
|
|
/* read from */
|
|
ret = dev_read_block(raw, from);
|
|
ASSERT(ret >= 0);
|
|
|
|
/* write to */
|
|
ret = dev_write_block(raw, to);
|
|
ASSERT(ret >= 0);
|
|
|
|
/* update sit bitmap & valid_blocks && se->type */
|
|
se = get_seg_entry(sbi, GET_SEGNO(sbi, from));
|
|
offset = OFFSET_IN_SEG(sbi, from);
|
|
type = se->type;
|
|
se->valid_blocks--;
|
|
f2fs_clear_bit(offset, (char *)se->cur_valid_map);
|
|
se->dirty = 1;
|
|
|
|
se = get_seg_entry(sbi, GET_SEGNO(sbi, to));
|
|
offset = OFFSET_IN_SEG(sbi, to);
|
|
se->type = type;
|
|
se->valid_blocks++;
|
|
f2fs_set_bit(offset, (char *)se->cur_valid_map);
|
|
se->dirty = 1;
|
|
|
|
/* read/write SSA */
|
|
get_sum_entry(sbi, from, &sum);
|
|
update_sum_entry(sbi, to, &sum);
|
|
|
|
/* if data block, read node and update node block */
|
|
if (IS_DATASEG(type))
|
|
update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
|
|
le16_to_cpu(sum.ofs_in_node), to);
|
|
else
|
|
update_nat_blkaddr(sbi, le32_to_cpu(sum.nid), to);
|
|
|
|
DBG(0, "Migrate %s block %"PRIx64" -> %"PRIx64"\n",
|
|
IS_DATASEG(type) ? "data" : "node",
|
|
from, to);
|
|
free(raw);
|
|
return 0;
|
|
}
|
|
|
|
int f2fs_defragment(struct f2fs_sb_info *sbi, u64 from, u64 len, u64 to, int left)
|
|
{
|
|
struct seg_entry *se;
|
|
u64 idx, offset;
|
|
|
|
/* flush NAT/SIT journal entries */
|
|
flush_journal_entries(sbi);
|
|
|
|
for (idx = from; idx < from + len; idx++) {
|
|
u64 target = to;
|
|
|
|
se = get_seg_entry(sbi, GET_SEGNO(sbi, idx));
|
|
offset = OFFSET_IN_SEG(sbi, idx);
|
|
|
|
if (!f2fs_test_bit(offset, (const char *)se->cur_valid_map))
|
|
continue;
|
|
|
|
if (find_next_free_block(sbi, &target, left, se->type)) {
|
|
ASSERT_MSG("Not enough space to migrate blocks");
|
|
break;
|
|
}
|
|
|
|
if (migrate_block(sbi, idx, target)) {
|
|
ASSERT_MSG("Found inconsistency: please run FSCK");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* update curseg info; can update sit->types */
|
|
move_curseg_info(sbi, to);
|
|
write_curseg_info(sbi);
|
|
|
|
/* flush dirty sit entries */
|
|
flush_sit_entries(sbi);
|
|
|
|
write_checkpoint(sbi);
|
|
|
|
return 0;
|
|
}
|