f2fs: add inline_data recovery routine
authorJaegeuk Kim <jaegeuk.kim@samsung.com>
Thu, 26 Dec 2013 03:49:48 +0000 (12:49 +0900)
committerJaegeuk Kim <jaegeuk.kim@samsung.com>
Mon, 6 Jan 2014 07:42:20 +0000 (16:42 +0900)
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>
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/inline.c
fs/f2fs/recovery.c
include/linux/f2fs_fs.h

index 0b6bada..07a7ae0 100644 (file)
@@ -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
index 68dd7bf..c77ad4d 100644 (file)
@@ -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;
index 3c9261c..2a756e5 100644 (file)
@@ -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;
+}
index 96e690b..655791e 100644 (file)
@@ -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);
index aea5eed..da74d87 100644 (file)
@@ -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 */