f2fs: invalidate temporary meta page
authorChao Yu <chao2.yu@samsung.com>
Tue, 28 Jul 2015 10:36:47 +0000 (18:36 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 5 Aug 2015 15:19:21 +0000 (08:19 -0700)
To avoid meeting garbage data in next free node block at the end of warm
node chain when doing recovery, we will try to zero out that invalid block.

If the device is not support discard, our way for zeroing out block is:
grabbing a temporary zeroed page in meta inode, then, issue write request
with this page.

But, we forget to release that temporary page, so our memory usage will
increase without gaining any hit ratio benefit, so it's better to free it
for saving memory.

Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/f2fs.h
fs/f2fs/recovery.c
fs/f2fs/segment.c

index 9c1acf69bfbbea7da3005201eb55ceadbc0c2339..c3111769d382ed48244136ad59b4fb78a54ebdf9 100644 (file)
@@ -896,12 +896,15 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        __u32 crc32 = 0;
        int i;
        int cp_payload_blks = __cp_payload(sbi);
+       block_t discard_blk = NEXT_FREE_BLKADDR(sbi, curseg);
+       bool invalidate = false;
 
        /*
         * This avoids to conduct wrong roll-forward operations and uses
         * metapages, so should be called prior to sync_meta_pages below.
         */
-       discard_next_dnode(sbi, NEXT_FREE_BLKADDR(sbi, curseg));
+       if (discard_next_dnode(sbi, discard_blk))
+               invalidate = true;
 
        /* Flush all the NAT/SIT pages */
        while (get_pages(sbi, F2FS_DIRTY_META)) {
@@ -1030,6 +1033,14 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        /* wait for previous submitted meta pages writeback */
        wait_on_all_pages_writeback(sbi);
 
+       /*
+        * invalidate meta page which is used temporarily for zeroing out
+        * block at the end of warm node chain.
+        */
+       if (invalidate)
+               invalidate_mapping_pages(META_MAPPING(sbi), discard_blk,
+                                                               discard_blk);
+
        release_dirty_inode(sbi);
 
        if (unlikely(f2fs_cp_error(sbi)))
index 58b05b541a4e0af9effbe5e30e9cc33d1c812ba2..34a524d007ec9a8417d5cc055c33f0849f42c028 100644 (file)
@@ -1707,7 +1707,7 @@ void invalidate_blocks(struct f2fs_sb_info *, block_t);
 void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
 void clear_prefree_segments(struct f2fs_sb_info *, struct cp_control *);
 void release_discard_addrs(struct f2fs_sb_info *);
-void discard_next_dnode(struct f2fs_sb_info *, block_t);
+bool discard_next_dnode(struct f2fs_sb_info *, block_t);
 int npages_for_summary_flush(struct f2fs_sb_info *, bool);
 void allocate_new_segments(struct f2fs_sb_info *);
 int f2fs_trim_fs(struct f2fs_sb_info *, struct fstrim_range *);
index 24a8c1d4f45f288914b61f60c1ea0a6d583b6175..07a36e413ace422766dd8847df6ff74b5c51d8c9 100644 (file)
@@ -561,11 +561,20 @@ out:
 
        clear_sbi_flag(sbi, SBI_POR_DOING);
        if (err) {
-               discard_next_dnode(sbi, blkaddr);
+               bool invalidate = false;
+
+               if (discard_next_dnode(sbi, blkaddr))
+                       invalidate = true;
 
                /* Flush all the NAT/SIT pages */
                while (get_pages(sbi, F2FS_DIRTY_META))
                        sync_meta_pages(sbi, META, LONG_MAX);
+
+               /* invalidate temporary meta page */
+               if (invalidate)
+                       invalidate_mapping_pages(META_MAPPING(sbi),
+                                                       blkaddr, blkaddr);
+
                set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
                mutex_unlock(&sbi->cp_mutex);
        } else if (need_writecp) {
index 509a2c4bb7d3eaa2df3cfcea3c975a135e685c75..1f1200487c4411e2bdeb06bbdbfb40d2d2e6b2e3 100644 (file)
@@ -514,7 +514,7 @@ static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
        return blkdev_issue_discard(sbi->sb->s_bdev, start, len, GFP_NOFS, 0);
 }
 
-void discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
+bool discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
 {
        int err = -ENOTSUPP;
 
@@ -524,13 +524,16 @@ void discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
                unsigned int offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
 
                if (f2fs_test_bit(offset, se->discard_map))
-                       return;
+                       return false;
 
                err = f2fs_issue_discard(sbi, blkaddr, 1);
        }
 
-       if (err)
+       if (err) {
                update_meta_page(sbi, NULL, blkaddr);
+               return true;
+       }
+       return false;
 }
 
 static void __add_discard_entry(struct f2fs_sb_info *sbi,