mirror of https://gitee.com/openkylin/linux.git
f2fs: add inline_data recovery routine
This patch adds a inline_data recovery routine with the following policy. [prev.] [next] of inline_data flag o o -> recover inline_data o x -> remove inline_data, and then recover data blocks x o -> remove inline_data, and then recover inline_data x x -> recover data blocks Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
This commit is contained in:
parent
0dbdc2ae9b
commit
1e1bb4baf1
|
@ -1015,6 +1015,7 @@ static inline int f2fs_readonly(struct super_block *sb)
|
|||
*/
|
||||
int f2fs_sync_file(struct file *, loff_t, loff_t, int);
|
||||
void truncate_data_blocks(struct dnode_of_data *);
|
||||
int truncate_blocks(struct inode *, u64);
|
||||
void f2fs_truncate(struct inode *);
|
||||
int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
|
||||
int f2fs_setattr(struct dentry *, struct iattr *);
|
||||
|
@ -1322,4 +1323,5 @@ bool f2fs_may_inline(struct inode *);
|
|||
int f2fs_read_inline_data(struct inode *, struct page *);
|
||||
int f2fs_convert_inline_data(struct inode *, pgoff_t);
|
||||
int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
|
||||
int recover_inline_data(struct inode *, struct page *);
|
||||
#endif
|
||||
|
|
|
@ -251,7 +251,7 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
|
|||
f2fs_put_page(page, 1);
|
||||
}
|
||||
|
||||
static int truncate_blocks(struct inode *inode, u64 from)
|
||||
int truncate_blocks(struct inode *inode, u64 from)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
unsigned int blocksize = inode->i_sb->s_blocksize;
|
||||
|
|
|
@ -169,3 +169,51 @@ int f2fs_write_inline_data(struct inode *inode,
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recover_inline_data(struct inode *inode, struct page *npage)
|
||||
{
|
||||
struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
|
||||
struct f2fs_inode *ri = NULL;
|
||||
void *src_addr, *dst_addr;
|
||||
struct page *ipage;
|
||||
|
||||
/*
|
||||
* The inline_data recovery policy is as follows.
|
||||
* [prev.] [next] of inline_data flag
|
||||
* o o -> recover inline_data
|
||||
* o x -> remove inline_data, and then recover data blocks
|
||||
* x o -> remove inline_data, and then recover inline_data
|
||||
* x x -> recover data blocks
|
||||
*/
|
||||
if (IS_INODE(npage))
|
||||
ri = F2FS_INODE(npage);
|
||||
|
||||
if (f2fs_has_inline_data(inode) &&
|
||||
ri && ri->i_inline & F2FS_INLINE_DATA) {
|
||||
process_inline:
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
f2fs_bug_on(IS_ERR(ipage));
|
||||
|
||||
src_addr = inline_data_addr(npage);
|
||||
dst_addr = inline_data_addr(ipage);
|
||||
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
|
||||
update_inode(inode, ipage);
|
||||
f2fs_put_page(ipage, 1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (f2fs_has_inline_data(inode)) {
|
||||
ipage = get_node_page(sbi, inode->i_ino);
|
||||
f2fs_bug_on(IS_ERR(ipage));
|
||||
zero_user_segment(ipage, INLINE_DATA_OFFSET,
|
||||
INLINE_DATA_OFFSET + MAX_INLINE_DATA);
|
||||
clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
|
||||
update_inode(inode, ipage);
|
||||
f2fs_put_page(ipage, 1);
|
||||
} else if (ri && ri->i_inline & F2FS_INLINE_DATA) {
|
||||
truncate_blocks(inode, 0);
|
||||
set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
|
||||
goto process_inline;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -298,6 +298,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
|||
struct node_info ni;
|
||||
int err = 0, recovered = 0;
|
||||
|
||||
if (recover_inline_data(inode, page))
|
||||
goto out;
|
||||
|
||||
start = start_bidx_of_node(ofs_of_node(page), fi);
|
||||
if (IS_INODE(page))
|
||||
end = start + ADDRS_PER_INODE(fi);
|
||||
|
@ -305,12 +308,13 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
|||
end = start + ADDRS_PER_BLOCK;
|
||||
|
||||
f2fs_lock_op(sbi);
|
||||
|
||||
set_new_dnode(&dn, inode, NULL, NULL, 0);
|
||||
|
||||
err = get_dnode_of_data(&dn, start, ALLOC_NODE);
|
||||
if (err) {
|
||||
f2fs_unlock_op(sbi);
|
||||
return err;
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait_on_page_writeback(dn.node_page);
|
||||
|
@ -361,7 +365,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
|
|||
err:
|
||||
f2fs_put_dnode(&dn);
|
||||
f2fs_unlock_op(sbi);
|
||||
|
||||
out:
|
||||
f2fs_msg(sbi->sb, KERN_NOTICE, "recover_data: ino = %lx, "
|
||||
"recovered_data = %d blocks, err = %d",
|
||||
inode->i_ino, recovered, err);
|
||||
|
|
|
@ -155,12 +155,11 @@ struct f2fs_extent {
|
|||
#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */
|
||||
#define F2FS_INLINE_DATA 0x02 /* file inline data flag */
|
||||
|
||||
|
||||
#define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
|
||||
F2FS_INLINE_XATTR_ADDRS - 1))
|
||||
|
||||
#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) \
|
||||
- sizeof(__le32)*(DEF_ADDRS_PER_INODE + 5 - 1))
|
||||
- sizeof(__le32) * (DEF_ADDRS_PER_INODE + 5 - 1))
|
||||
|
||||
struct f2fs_inode {
|
||||
__le16 i_mode; /* file mode */
|
||||
|
|
Loading…
Reference in New Issue