mirror of
https://gitee.com/openharmony/third_party_f2fs-tools
synced 2024-11-23 18:19:43 +00:00
c0ce8e646c
When fsck needs to assign a new area to a curreng segment, it calls find_next_free_block() function to find a new block to assign. For zoned block devices, fsck checks write pointer consistency with current segments' positions. In case a curseg is inconsistent with the write pointer of the zone it points to, fsck should assign not a new free block but a new free zone/section with write pointer at the zone start, so that next write to the current segment succeeds without error. To extend find_next_free_block() function's capability to find not only a block but also a zone/section, add new_sec flag to find_next_free_block() function. When new_sec flag is true, skip check for each block's availability so that the check is done with unit of section. Note that it is ensured that one zone has one section for f2fs on zoned block devices. Then the logic to find a new free section is good to find a new free zone. When fsck target devices have ZONED_HM model, set new_sec flag true to call find_next_free_block() from move_curseg_info(). Set curseg's alloc_type not SSR but LFS for the devices with ZONED_HM model, because SSR block allocation is not allowed for zoned block devices. Also skip relocate_curseg_offset() for the devices with ZONED_HM model for the same reason. Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com> Reviewed-by: Chao Yu <yuchao0@huawei.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
103 lines
2.4 KiB
C
103 lines
2.4 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, 0, 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, false)) {
|
|
MSG(0, "Not enough space to migrate blocks");
|
|
return -1;
|
|
}
|
|
|
|
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, left);
|
|
zero_journal_entries(sbi);
|
|
write_curseg_info(sbi);
|
|
|
|
/* flush dirty sit entries */
|
|
flush_sit_entries(sbi);
|
|
|
|
write_checkpoint(sbi);
|
|
|
|
return 0;
|
|
}
|