Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1e1bb4ba authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

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: default avatarJaegeuk Kim <jaegeuk.kim@samsung.com>
parent 0dbdc2ae
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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;
+48 −0
Original line number Diff line number Diff line
@@ -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;
}
+6 −2
Original line number Diff line number Diff line
@@ -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);
+1 −2
Original line number Diff line number Diff line
@@ -155,7 +155,6 @@ 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))