f2fs: recover wrong pino after checkpoint during fsync
authorJaegeuk Kim <jaegeuk.kim@samsung.com>
Thu, 13 Jun 2013 23:52:35 +0000 (08:52 +0900)
committerJaegeuk Kim <jaegeuk.kim@samsung.com>
Fri, 14 Jun 2013 00:04:45 +0000 (09:04 +0900)
If a file is linked, f2fs loose its parent inode number so that fsync calls
for the linked file should do checkpoint all the time.
But, if we can recover its parent inode number after the checkpoint, we can
adjust roll-forward mechanism for the further fsync calls, which is able to
improve the fsync performance significatly.

Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
fs/f2fs/dir.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/namei.c
fs/f2fs/node.h
fs/f2fs/segment.c

index 69ca049b51685bd03964afbb3d582ab5838e2288..4f21452f929daa27b91dfabeb80ee5cfe4afdcca 100644 (file)
@@ -356,7 +356,7 @@ static struct page *init_inode_metadata(struct inode *inode,
         * We lost i_pino from now on.
         */
        if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK)) {
-               set_cp_file(inode);
+               file_lost_pino(inode);
                inc_nlink(inode);
        }
        return page;
index 3e7cb33b64d3b1ce74aa7becda1fa1cc7046f90f..863a5e91d84a50509275f46043867689727d80a1 100644 (file)
@@ -151,7 +151,7 @@ struct extent_info {
  * i_advise uses FADVISE_XXX_BIT. We can add additional hints later.
  */
 #define FADVISE_COLD_BIT       0x01
-#define FADVISE_CP_BIT         0x02
+#define FADVISE_LOST_PINO_BIT  0x02
 
 struct f2fs_inode_info {
        struct inode vfs_inode;         /* serve a vfs inode */
index fda226ff1849c324507231ef37551ef4a2dcece4..d2d2b7dbdcc12b348ca89899f500748716c2104c 100644 (file)
@@ -102,6 +102,24 @@ static const struct vm_operations_struct f2fs_file_vm_ops = {
        .remap_pages    = generic_file_remap_pages,
 };
 
+static int get_parent_ino(struct inode *inode, nid_t *pino)
+{
+       struct dentry *dentry;
+
+       inode = igrab(inode);
+       dentry = d_find_any_alias(inode);
+       iput(inode);
+       if (!dentry)
+               return 0;
+
+       inode = igrab(dentry->d_parent->d_inode);
+       dput(dentry);
+
+       *pino = inode->i_ino;
+       iput(inode);
+       return 1;
+}
+
 int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
@@ -134,7 +152,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 
        if (!S_ISREG(inode->i_mode) || inode->i_nlink != 1)
                need_cp = true;
-       else if (is_cp_file(inode))
+       else if (file_wrong_pino(inode))
                need_cp = true;
        else if (!space_for_roll_forward(sbi))
                need_cp = true;
@@ -142,8 +160,19 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                need_cp = true;
 
        if (need_cp) {
+               nid_t pino;
+
                /* all the dirty node pages should be flushed for POR */
                ret = f2fs_sync_fs(inode->i_sb, 1);
+               if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
+                                       get_parent_ino(inode, &pino)) {
+                       F2FS_I(inode)->i_pino = pino;
+                       file_got_pino(inode);
+                       mark_inode_dirty_sync(inode);
+                       ret = f2fs_write_inode(inode, NULL);
+                       if (ret)
+                               goto out;
+               }
        } else {
                /* if there is no written node page, write its inode page */
                while (!sync_node_pages(sbi, inode->i_ino, &wbc)) {
index 810444ee6b5e56388393d619e7aaa592167335c9..64c07169df050b4b358186540031365bd67f4b56 100644 (file)
@@ -112,7 +112,7 @@ static inline void set_cold_files(struct f2fs_sb_info *sbi, struct inode *inode,
        int count = le32_to_cpu(sbi->raw_super->extension_count);
        for (i = 0; i < count; i++) {
                if (is_multimedia_file(name, extlist[i])) {
-                       set_cold_file(inode);
+                       file_set_cold(inode);
                        break;
                }
        }
index a503661307db4b7667902e0de6965f294d9ee1ca..c65fb4f4230f699ba7647c820b328942b43b8490 100644 (file)
@@ -285,10 +285,17 @@ static inline void set_file(struct inode *inode, int type)
        F2FS_I(inode)->i_advise |= type;
 }
 
-#define is_cold_file(inode)    is_file(inode, FADVISE_COLD_BIT)
-#define is_cp_file(inode)      is_file(inode, FADVISE_CP_BIT)
-#define set_cold_file(inode)   set_file(inode, FADVISE_COLD_BIT)
-#define set_cp_file(inode)     set_file(inode, FADVISE_CP_BIT)
+static inline void clear_file(struct inode *inode, int type)
+{
+       F2FS_I(inode)->i_advise &= ~type;
+}
+
+#define file_is_cold(inode)    is_file(inode, FADVISE_COLD_BIT)
+#define file_wrong_pino(inode) is_file(inode, FADVISE_LOST_PINO_BIT)
+#define file_set_cold(inode)   set_file(inode, FADVISE_COLD_BIT)
+#define file_lost_pino(inode)  set_file(inode, FADVISE_LOST_PINO_BIT)
+#define file_clear_cold(inode) clear_file(inode, FADVISE_COLD_BIT)
+#define file_got_pino(inode)   clear_file(inode, FADVISE_LOST_PINO_BIT)
 
 static inline int is_cold_data(struct page *page)
 {
index b15debcccc23bc1bd8b679dc5ce3327c655afb61..0e1a60a4eb3fd0efa691d95c87fb77a9160455fc 100644 (file)
@@ -796,7 +796,7 @@ static int __get_segment_type_6(struct page *page, enum page_type p_type)
 
                if (S_ISDIR(inode->i_mode))
                        return CURSEG_HOT_DATA;
-               else if (is_cold_data(page) || is_cold_file(inode))
+               else if (is_cold_data(page) || file_is_cold(inode))
                        return CURSEG_COLD_DATA;
                else
                        return CURSEG_WARM_DATA;