Re: [f2fs-dev] [RFC PATCH v2 7/7] fsck.f2fs: reconnect unreachable files to lost+found
On 02/26, Sheng Yong wrote: > Hi, Chao > > On 2018/2/26 16:23, Chao Yu wrote: > > On 2018/2/23 11:18, Sheng Yong wrote: > > > This patch introduces lost_found feature to fsck. If a file is found > > > unreachable by fsck. Fsck tries to reconnect the file to lost+found > > > directory: > > >1. Scan all unreachable file inodes, ignore non-inodes ones and > > > directories. > > >2. Check them and fix incorrupted data to make sure filesystem > > > metadata (mainly counters and main/nat bitmap) are all consistent. > > >3. Reconnect these files to lost+found. If lost+found does not exist, > > > create it first. During reconnecting, expand lost+found's dentry > > > block automatically. Reconnected files are renamed after its ino > > > number. > > >4. If reconnect fails drop the node and restore filesystem metadata. > > > > > > Signed-off-by: Sheng Yong > > > --- > > > fsck/dir.c | 19 ++- > > > fsck/fsck.c | 388 > > > ++- > > > fsck/fsck.h | 3 + > > > fsck/mount.c | 2 + > > > 4 files changed, 409 insertions(+), 3 deletions(-) > > > > > > diff --git a/fsck/dir.c b/fsck/dir.c > > > index b2ea18f..567a4e9 100644 > > > --- a/fsck/dir.c > > > +++ b/fsck/dir.c > > > @@ -176,6 +176,23 @@ static int f2fs_find_entry(struct f2fs_sb_info *sbi, > > > return 0; > > > } > [...] > > > + > > > +static int fsck_do_reconnect_file(struct f2fs_sb_info *sbi, > > > + struct f2fs_node *lpf, > > > + struct f2fs_node *fnode) > > > +{ > > > + char name[80]; > > > + size_t namelen; > > > + nid_t ino = le32_to_cpu(fnode->footer.ino); > > > + struct node_info ni; > > > + int ret; > > > + > > > + namelen = snprintf(name, 80, "%u", ino); > > > + if (namelen >= 80) > > > + /* ignore terminating '\0', should never happen */ > > > + namelen = 79; > > > + > > > + if (f2fs_lookup(sbi, lpf, (u8 *)name, namelen)) { > > > + ASSERT_MSG("Name %s already exist in lost+found", name); > > > + return -EEXIST; > > > + } > > > + > > > + get_node_info(sbi, le32_to_cpu(lpf->footer.ino), &ni); > > > + ret = f2fs_add_link(sbi, lpf, (unsigned char *)name, namelen, > > > + ino, F2FS_FT_REG_FILE, ni.blk_addr, 0); > > > > Need to change F2FS_FT_REG_FILE to ftype due to we expect to reconnect all > > kinds > > of inode except directory, right? > > > Right. My bad, will fix this in next version. Thanks. Hi Sheng, I merged this series except this patch. Please update this one only. :) Thanks, > > > > + if (ret) { > > > + ASSERT_MSG("Failed to add inode [0x%x] to lost+found", ino); > > > + return -EINVAL; > > > + } > > > + > > > + /* update fnode */ > > > + memcpy(fnode->i.i_name, name, namelen); > > > + fnode->i.i_namelen = cpu_to_le32(namelen); > > > + fnode->i.i_pino = c.lpf_ino; > > > + get_node_info(sbi, le32_to_cpu(fnode->footer.ino), &ni); > > > + ret = dev_write_block(fnode, ni.blk_addr); > > > + ASSERT(ret >= 0); > > > + > > > + DBG(1, "Reconnect inode [0x%x] to lost+found\n", ino); > > > + return 0; > > > +} > > > + > [...] > > > + > > > +/* > > > + * Scan unreachable nids and find only regular file inodes. If these > > > files > > > + * are not corrupted, reconnect them to lost+found. > > > + * > > > + * Since all unreachable nodes are already checked, we can allocate new > > > + * blocks safely. > > > + * > > > + * This function returns the number of files been reconnected. > > > + */ > > > +static int fsck_reconnect_file(struct f2fs_sb_info *sbi) > > > +{ > > > + struct f2fs_fsck *fsck = F2FS_FSCK(sbi); > > > + struct f2fs_node *lpf_node, *node; > > > + struct node_info ni; > > > + char *reconnect_bitmap; > > > + u32 blk_cnt; > > > + nid_t nid; > > > + int err, cnt = 0, ftype; > > > + > > > + node = calloc(F2FS_BLKSIZE, 1); > > > + ASSERT(node); > > > + > > > + reconnect_bitmap = calloc(fsck->nat_area_bitmap_sz, 1); > > > + ASSERT(reconnect_bitmap); > > > + > > > + for (nid = 0; nid < fsck->nr_nat_entries; nid++) { > > > + if (f2fs_test_bit(nid, fsck->nat_area_bitmap)) { > > > + if (is_qf_ino(F2FS_RAW_SUPER(sbi), nid)) { > > > + DBG(1, "Not support quota inode [0x%x]\n", > > > + nid); > > > + continue; > > > + } > > > + > > > + get_node_info(sbi, nid, &ni); > > > + err = dev_read_block(node, ni.blk_addr); > > > + ASSERT(err >= 0); > > > + > > > + /* reconnection will restore these nodes if needed */ > > > + if (node->footer.ino != node->footer.nid) { > > > + DBG(1, "Not support non-inode node [0x%x]\n", > > > + nid); > > > + continue; > > > + } > > > + > > > + if (S_ISDIR(le16_to_cpu(node->i.i_mode)
[f2fs-dev] [RFC PATCH v2 7/7] fsck.f2fs: reconnect unreachable files to lost+found
This patch introduces lost_found feature to fsck. If a file is found unreachable by fsck. Fsck tries to reconnect the file to lost+found directory: 1. Scan all unreachable file inodes, ignore non-inodes ones and directories. 2. Check them and fix incorrupted data to make sure filesystem metadata (mainly counters and main/nat bitmap) are all consistent. 3. Reconnect these files to lost+found. If lost+found does not exist, create it first. During reconnecting, expand lost+found's dentry block automatically. Reconnected files are renamed after its ino number. 4. If reconnect fails drop the node and restore filesystem metadata. Signed-off-by: Sheng Yong --- fsck/dir.c | 19 ++- fsck/fsck.c | 388 ++- fsck/fsck.h | 3 + fsck/mount.c | 2 + 4 files changed, 409 insertions(+), 3 deletions(-) diff --git a/fsck/dir.c b/fsck/dir.c index b2ea18f..567a4e9 100644 --- a/fsck/dir.c +++ b/fsck/dir.c @@ -176,6 +176,23 @@ static int f2fs_find_entry(struct f2fs_sb_info *sbi, return 0; } +/* return ino if file exists, otherwise return 0 */ +nid_t f2fs_lookup(struct f2fs_sb_info *sbi, struct f2fs_node *dir, + u8 *name, int len) +{ + int err; + struct dentry de = { + .name = name, + .len = len, + }; + + err = f2fs_find_entry(sbi, dir, &de); + if (err == 1) + return de.ino; + else + return 0; +} + static void f2fs_update_dentry(nid_t ino, int file_type, struct f2fs_dentry_ptr *d, const unsigned char *name, int len, f2fs_hash_t name_hash, @@ -199,7 +216,7 @@ static void f2fs_update_dentry(nid_t ino, int file_type, /* * f2fs_add_link - Add a new file(dir) to parent dir. */ -static int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent, +int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent, const unsigned char *name, int name_len, nid_t ino, int file_type, block_t p_blkaddr, int inc_link) { diff --git a/fsck/fsck.c b/fsck/fsck.c index f6391e9..9a822ef 100644 --- a/fsck/fsck.c +++ b/fsck/fsck.c @@ -10,6 +10,7 @@ */ #include "fsck.h" #include "quotaio.h" +#include char *tree_mark; uint32_t tree_mark_size = 256; @@ -43,6 +44,14 @@ static inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk) fsck->main_area_bitmap); } +static inline int f2fs_clear_main_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->main_area_bitmap); +} + static inline int f2fs_test_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk) { struct f2fs_fsck *fsck = F2FS_FSCK(sbi); @@ -453,9 +462,11 @@ static int sanity_check_nid(struct f2fs_sb_info *sbi, u32 nid, /* workaround to fix later */ if (ftype != F2FS_FT_ORPHAN || - f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0) + f2fs_test_bit(nid, fsck->nat_area_bitmap) != 0) { f2fs_clear_bit(nid, fsck->nat_area_bitmap); - else + /* avoid reusing nid when reconnecting files */ + f2fs_set_bit(nid, NM_I(sbi)->nid_bitmap); + } else ASSERT_MSG("orphan or xattr nid is duplicated [0x%x]\n", nid); @@ -2046,6 +2057,369 @@ int check_sit_types(struct f2fs_sb_info *sbi) return err; } +static struct f2fs_node *fsck_get_lpf(struct f2fs_sb_info *sbi) +{ + struct f2fs_node *node; + struct node_info ni; + nid_t lpf_ino; + int err; + + /* read root inode first */ + node = calloc(F2FS_BLKSIZE, 1); + ASSERT(node); + get_node_info(sbi, F2FS_ROOT_INO(sbi), &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + + /* lookup lost+found in root directory */ + lpf_ino = f2fs_lookup(sbi, node, (u8 *)LPF, strlen(LPF)); + if (lpf_ino) { /* found */ + get_node_info(sbi, lpf_ino, &ni); + err = dev_read_block(node, ni.blk_addr); + ASSERT(err >= 0); + DBG(1, "Found lost+found 0x%x at blkaddr [0x%x]\n", + lpf_ino, ni.blk_addr); + if (!S_ISDIR(le16_to_cpu(node->i.i_mode))) { + ASSERT_MSG("lost+found is not directory [0%o]\n", + le16_to_cpu(node->i.i_mode)); + /* FIXME: give up? */ + goto out; + } + } else { /* not found, create it */ + struct dentry de; + + memset(&de, 0, sizeof(de)); + de.name = (u8 *) LPF; + de.len = strlen(LPF); + de.mode