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

Reply via email to