The recovery logic is similar to that of inline data, except that the inline tail may require recovery of some blocks. This is because the inline tail has a 16-size block address array, whereas inline data does not.
Signed-off-by: Wu Bo <bo...@vivo.com> --- fs/f2fs/f2fs.h | 1 + fs/f2fs/inline.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/recovery.c | 9 +++++++- 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f889d97209c7..7d5348e2127b 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4217,6 +4217,7 @@ int f2fs_clear_inline_tail(struct inode *inode, bool force); int f2fs_try_convert_inline_dir(struct inode *dir, struct dentry *dentry); int f2fs_write_inline_data(struct inode *inode, struct page *page); int f2fs_recover_inline_data(struct inode *inode, struct page *npage); +int f2fs_recover_inline_tail(struct inode *inode, struct page *npage); struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, const struct f2fs_filename *fname, struct page **res_page); diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index c2f84f3dde67..76e0ff62be51 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -414,6 +414,57 @@ int f2fs_recover_inline_data(struct inode *inode, struct page *npage) return 0; } +int f2fs_recover_inline_tail(struct inode *inode, struct page *npage) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode *ri = NULL; + void *src_addr, *dst_addr; + struct page *ipage; + + if (IS_INODE(npage)) + ri = F2FS_INODE(npage); + + if (f2fs_has_inline_tail(inode) && + ri && (le32_to_cpu(ri->i_flags) & F2FS_INLINE_TAIL)) { +process_inline: + if (!(ri->i_inline & F2FS_DATA_EXIST)) + return 0; + + ipage = f2fs_get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) + return PTR_ERR(ipage); + + f2fs_wait_on_page_writeback(ipage, NODE, true, true); + + src_addr = inline_data_addr(inode, npage); + dst_addr = inline_data_addr(inode, ipage); + memcpy(dst_addr, src_addr, MAX_INLINE_DATA(inode)); + + set_inode_flag(inode, FI_DATA_EXIST); + + set_page_dirty(ipage); + f2fs_put_page(ipage, 1); + return 0; + } + + if (f2fs_has_inline_tail(inode)) { + ipage = f2fs_get_node_page(sbi, inode->i_ino); + if (IS_ERR(ipage)) + return PTR_ERR(ipage); + f2fs_truncate_inline_inode(inode, ipage, 0); + clear_inode_flag(inode, FI_INLINE_TAIL); + f2fs_put_page(ipage, 1); + } else if (ri && (le32_to_cpu(ri->i_inline) & F2FS_INLINE_TAIL)) { + int ret; + + ret = f2fs_truncate_blocks(inode, + COMPACT_ADDRS_PER_INODE >> PAGE_SHIFT, false); + if (ret) + return ret; + goto process_inline; + } + return 0; +} struct f2fs_dir_entry *f2fs_find_in_inline_dir(struct inode *dir, const struct f2fs_filename *fname, struct page **res_page) diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 9756f0f2b7f7..d73a557b82d9 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c @@ -645,9 +645,16 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, goto out; } + err = f2fs_recover_inline_tail(inode, page); + if (err) + goto out; + /* step 3: recover data indices */ start = f2fs_start_bidx_of_node(ofs_of_node(page), inode); - end = start + ADDRS_PER_PAGE(page, inode); + if (f2fs_has_inline_tail(inode)) + end = COMPACT_ADDRS_PER_INODE; + else + end = start + ADDRS_PER_PAGE(page, inode); set_new_dnode(&dn, inode, NULL, NULL, 0); retry_dn: -- 2.35.3 _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel