[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <57e1dbb2f348ab61cbc82be7161d788a08b5fbed.1726024117.git.bo.wu@vivo.com>
Date: Tue, 10 Sep 2024 21:57:26 -0600
From: Wu Bo <bo.wu@...o.com>
To: linux-kernel@...r.kernel.org
Cc: Jaegeuk Kim <jaegeuk@...nel.org>,
Chao Yu <chao@...nel.org>,
linux-f2fs-devel@...ts.sourceforge.net,
Wu Bo <wubo.oduw@...il.com>,
Wu Bo <bo.wu@...o.com>
Subject: [PATCH v2 13/13] f2fs: implement inline tail forward recovery
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@...o.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
Powered by blists - more mailing lists