Skip to content

Commit

Permalink
f2fs-tools: do not reuse corrupted quota inodes
Browse files Browse the repository at this point in the history
When we detect quota inode corruption, we better deallocate the current
space and allocate new ones for a clean start.

Signed-off-by: Daeho Jeong <[email protected]>
Signed-off-by: Jaegeuk Kim <[email protected]>
  • Loading branch information
Daeho Jeong authored and Jaegeuk Kim committed Oct 20, 2023
1 parent 24c565e commit 56a5bbf
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 44 deletions.
148 changes: 106 additions & 42 deletions fsck/fsck.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ int f2fs_set_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap);
}

static inline int f2fs_clear_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);

return f2fs_clear_bit(BLKOFF_FROM_MAIN(sbi, blk),
fsck->sit_area_bitmap);
}

static int add_into_hard_link_list(struct f2fs_sb_info *sbi,
u32 nid, u32 link_cnt)
{
Expand Down Expand Up @@ -2150,6 +2158,9 @@ int fsck_chk_quota_node(struct f2fs_sb_info *sbi)
return ret;
}

static void fsck_disconnect_file(struct f2fs_sb_info *sbi, nid_t ino,
bool dealloc);

int fsck_chk_quota_files(struct f2fs_sb_info *sbi)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
Expand Down Expand Up @@ -2181,6 +2192,8 @@ int fsck_chk_quota_files(struct f2fs_sb_info *sbi)
if (c.fix_on) {
DBG(0, "Fixing Quota file ([%3d] ino [0x%x])\n",
qtype, ino);
fsck_disconnect_file(sbi, ino, true);
f2fs_rebuild_qf_inode(sbi, qtype);
f2fs_filesize_update(sbi, ino, 0);
ret = quota_write_inode(sbi, qtype);
if (!ret) {
Expand Down Expand Up @@ -2852,10 +2865,53 @@ static int fsck_do_reconnect_file(struct f2fs_sb_info *sbi,
return 0;
}

static void fsck_failed_reconnect_file_dnode(struct f2fs_sb_info *sbi,
struct f2fs_inode *inode, nid_t nid)
static inline void release_inode_cnt(struct f2fs_sb_info *sbi, bool dealloc)
{
F2FS_FSCK(sbi)->chk.valid_inode_cnt--;
if (dealloc)
sbi->total_valid_inode_count--;
}

static inline void release_node_cnt(struct f2fs_sb_info *sbi, bool dealloc)
{
F2FS_FSCK(sbi)->chk.valid_node_cnt--;
if (dealloc)
sbi->total_valid_node_count--;
}

static inline void release_block_cnt(struct f2fs_sb_info *sbi, bool dealloc)
{
F2FS_FSCK(sbi)->chk.valid_blk_cnt--;
if (dealloc)
sbi->total_valid_block_count--;
}

static inline void release_block(struct f2fs_sb_info *sbi, u64 blkaddr,
bool dealloc)
{
f2fs_clear_main_bitmap(sbi, blkaddr);
if (dealloc) {
struct seg_entry *se;
u64 offset;

se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
offset = OFFSET_IN_SEG(sbi, blkaddr);
se->valid_blocks--;
f2fs_clear_bit(offset, (char *)se->cur_valid_map);
se->dirty = 1;
f2fs_clear_sit_bitmap(sbi, blkaddr);
}
}

static inline void release_nat_entry(struct f2fs_sb_info *sbi, u32 nid)
{
nullify_nat_entry(sbi, nid);
F2FS_FSCK(sbi)->chk.valid_nat_entry_cnt--;
}

static void fsck_disconnect_file_dnode(struct f2fs_sb_info *sbi,
struct f2fs_inode *inode, nid_t nid, bool dealloc)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
u32 addr;
Expand All @@ -2868,27 +2924,29 @@ static void fsck_failed_reconnect_file_dnode(struct f2fs_sb_info *sbi,
err = dev_read_block(node, ni.blk_addr);
ASSERT(err >= 0);

fsck->chk.valid_node_cnt--;
fsck->chk.valid_blk_cnt--;
f2fs_clear_main_bitmap(sbi, ni.blk_addr);
release_node_cnt(sbi, dealloc);
release_block_cnt(sbi, dealloc);
release_block(sbi, ni.blk_addr, dealloc);

for (i = 0; i < ADDRS_PER_BLOCK(inode); i++) {
addr = le32_to_cpu(node->dn.addr[i]);
if (!addr)
continue;
fsck->chk.valid_blk_cnt--;
release_block_cnt(sbi, dealloc);
if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
continue;
f2fs_clear_main_bitmap(sbi, addr);
release_block(sbi, addr, dealloc);
}

if (dealloc)
release_nat_entry(sbi, nid);

free(node);
}

static void fsck_failed_reconnect_file_idnode(struct f2fs_sb_info *sbi,
struct f2fs_inode *inode, nid_t nid)
static void fsck_disconnect_file_idnode(struct f2fs_sb_info *sbi,
struct f2fs_inode *inode, nid_t nid, bool dealloc)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
nid_t tmp;
Expand All @@ -2901,24 +2959,26 @@ static void fsck_failed_reconnect_file_idnode(struct f2fs_sb_info *sbi,
err = dev_read_block(node, ni.blk_addr);
ASSERT(err >= 0);

fsck->chk.valid_node_cnt--;
fsck->chk.valid_blk_cnt--;
f2fs_clear_main_bitmap(sbi, ni.blk_addr);
release_node_cnt(sbi, dealloc);
release_block_cnt(sbi, dealloc);
release_block(sbi, ni.blk_addr, dealloc);

for (i = 0; i < NIDS_PER_BLOCK; i++) {
tmp = le32_to_cpu(node->in.nid[i]);
if (!tmp)
continue;
fsck_failed_reconnect_file_dnode(sbi, inode, tmp);
fsck_disconnect_file_dnode(sbi, inode, tmp, dealloc);
}

if (dealloc)
release_nat_entry(sbi, nid);

free(node);
}

static void fsck_failed_reconnect_file_didnode(struct f2fs_sb_info *sbi,
struct f2fs_inode *inode, nid_t nid)
static void fsck_disconnect_file_didnode(struct f2fs_sb_info *sbi,
struct f2fs_inode *inode, nid_t nid, bool dealloc)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
nid_t tmp;
Expand All @@ -2931,28 +2991,26 @@ static void fsck_failed_reconnect_file_didnode(struct f2fs_sb_info *sbi,
err = dev_read_block(node, ni.blk_addr);
ASSERT(err >= 0);

fsck->chk.valid_node_cnt--;
fsck->chk.valid_blk_cnt--;
f2fs_clear_main_bitmap(sbi, ni.blk_addr);
release_node_cnt(sbi, dealloc);
release_block_cnt(sbi, dealloc);
release_block(sbi, ni.blk_addr, dealloc);

for (i = 0; i < NIDS_PER_BLOCK; i++) {
tmp = le32_to_cpu(node->in.nid[i]);
if (!tmp)
continue;
fsck_failed_reconnect_file_idnode(sbi, inode, tmp);
fsck_disconnect_file_idnode(sbi, inode, tmp, dealloc);
}

if (dealloc)
release_nat_entry(sbi, nid);

free(node);
}

/*
* Counters and main_area_bitmap are already changed during checking
* inode block, so clear them. There is no need to clear new blocks
* allocted to lost+found.
*/
static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
static void fsck_disconnect_file(struct f2fs_sb_info *sbi, nid_t ino,
bool dealloc)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_node *node;
struct node_info ni;
nid_t nid;
Expand All @@ -2966,18 +3024,18 @@ static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
ASSERT(err >= 0);

/* clear inode counters */
fsck->chk.valid_inode_cnt--;
fsck->chk.valid_node_cnt--;
fsck->chk.valid_blk_cnt--;
f2fs_clear_main_bitmap(sbi, ni.blk_addr);
release_inode_cnt(sbi, dealloc);
release_node_cnt(sbi, dealloc);
release_block_cnt(sbi, dealloc);
release_block(sbi, ni.blk_addr, dealloc);

/* clear xnid counters */
if (node->i.i_xattr_nid) {
nid = le32_to_cpu(node->i.i_xattr_nid);
fsck->chk.valid_node_cnt--;
fsck->chk.valid_blk_cnt--;
release_node_cnt(sbi, dealloc);
release_block_cnt(sbi, dealloc);
get_node_info(sbi, nid, &ni);
f2fs_clear_main_bitmap(sbi, ni.blk_addr);
release_block(sbi, ni.blk_addr, dealloc);
}

/* clear data counters */
Expand All @@ -2987,10 +3045,10 @@ static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
block_t addr = le32_to_cpu(node->i.i_addr[ofs + i]);
if (!addr)
continue;
fsck->chk.valid_blk_cnt--;
release_block_cnt(sbi, dealloc);
if (addr == NEW_ADDR || addr == COMPRESS_ADDR)
continue;
f2fs_clear_main_bitmap(sbi, addr);
release_block(sbi, addr, dealloc);
}
}

Expand All @@ -3002,18 +3060,24 @@ static void fsck_failed_reconnect_file(struct f2fs_sb_info *sbi, nid_t ino)
switch (i) {
case 0: /* direct node */
case 1:
fsck_failed_reconnect_file_dnode(sbi, &node->i, nid);
fsck_disconnect_file_dnode(sbi, &node->i, nid,
dealloc);
break;
case 2: /* indirect node */
case 3:
fsck_failed_reconnect_file_idnode(sbi, &node->i, nid);
fsck_disconnect_file_idnode(sbi, &node->i, nid,
dealloc);
break;
case 4: /* double indirect node */
fsck_failed_reconnect_file_didnode(sbi, &node->i, nid);
fsck_disconnect_file_didnode(sbi, &node->i, nid,
dealloc);
break;
}
}

if (dealloc)
release_nat_entry(sbi, ino);

free(node);
}

Expand Down Expand Up @@ -3099,7 +3163,7 @@ static int fsck_reconnect_file(struct f2fs_sb_info *sbi)
if (fsck_do_reconnect_file(sbi, lpf_node, node)) {
DBG(1, "Failed to reconnect inode [0x%x]\n",
nid);
fsck_failed_reconnect_file(sbi, nid);
fsck_disconnect_file(sbi, nid, false);
continue;
}

Expand Down
5 changes: 3 additions & 2 deletions fsck/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
ERR_MSG("Not enough space\n");
return -ENOSPC;
}
if (is_node && fsck->chk.valid_node_cnt >=
if (is_node && fsck->chk.valid_node_cnt >
sbi->total_valid_node_count) {
ERR_MSG("Not enough space for node block\n");
return -ENOSPC;
Expand Down Expand Up @@ -76,7 +76,7 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,

se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
offset = OFFSET_IN_SEG(sbi, blkaddr);
se->type = type;
se->type = se->orig_type = type;
if (se->valid_blocks == 0)
SM_I(sbi)->free_segments--;
se->valid_blocks++;
Expand All @@ -101,6 +101,7 @@ int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
if (c.func == FSCK) {
fsck->chk.valid_blk_cnt++;
if (is_node) {
fsck->chk.valid_nat_entry_cnt++;
fsck->chk.valid_node_cnt++;
if (is_inode)
fsck->chk.valid_inode_cnt++;
Expand Down

0 comments on commit 56a5bbf

Please sign in to comment.