You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
102 lines
2.4 KiB
102 lines
2.4 KiB
/** |
|
* 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)) { |
|
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); |
|
zero_journal_entries(sbi); |
|
write_curseg_info(sbi); |
|
|
|
/* flush dirty sit entries */ |
|
flush_sit_entries(sbi); |
|
|
|
write_checkpoint(sbi); |
|
|
|
return 0; |
|
}
|
|
|