[PATCH v2 13/13] f2fs: implement inline tail forward recovery

From: Wu Bo
Date: Tue Sep 10 2024 - 23:46:07 EST


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.wu@xxxxxxxx>
---
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