f2fs: avoid wrong decrypted data from disk
[GitHub/MotorolaMobilityLLC/kernel-slsi.git] / fs / f2fs / segment.c
index 40ae4a9216f820a2391de09eba77527d9a37694c..842c29e516d3ba180eb468563fbc9daa1cd2eebb 100644 (file)
@@ -1892,7 +1892,7 @@ bool is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr)
        struct seg_entry *se;
        bool is_cp = false;
 
-       if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
+       if (!is_valid_data_blkaddr(sbi, blkaddr))
                return true;
 
        down_read(&sit_i->sentry_lock);
@@ -2949,11 +2949,15 @@ void f2fs_wait_on_page_writeback(struct page *page,
        }
 }
 
-void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
+void f2fs_wait_on_block_writeback(struct inode *inode, block_t blkaddr)
 {
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct page *cpage;
 
-       if (blkaddr == NEW_ADDR || blkaddr == NULL_ADDR)
+       if (!f2fs_post_read_required(inode))
+               return;
+
+       if (!is_valid_data_blkaddr(sbi, blkaddr))
                return;
 
        cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
@@ -3618,6 +3622,7 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
        unsigned int i, start, end;
        unsigned int readed, start_blk = 0;
        int err = 0;
+       block_t total_node_blocks = 0;
 
        do {
                readed = ra_meta_pages(sbi, start_blk, BIO_MAX_PAGES,
@@ -3640,6 +3645,8 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
                        if (err)
                                return err;
                        seg_info_from_raw_sit(se, &sit);
+                       if (IS_NODESEG(se->type))
+                               total_node_blocks += se->valid_blocks;
 
                        /* build discard map only one time */
                        if (f2fs_discard_en(sbi)) {
@@ -3668,15 +3675,28 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
                unsigned int old_valid_blocks;
 
                start = le32_to_cpu(segno_in_journal(journal, i));
+               if (start >= MAIN_SEGS(sbi)) {
+                       f2fs_msg(sbi->sb, KERN_ERR,
+                                       "Wrong journal entry on segno %u",
+                                       start);
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
+                       err = -EINVAL;
+                       break;
+               }
+
                se = &sit_i->sentries[start];
                sit = sit_in_journal(journal, i);
 
                old_valid_blocks = se->valid_blocks;
+               if (IS_NODESEG(se->type))
+                       total_node_blocks -= old_valid_blocks;
 
                err = check_block_count(sbi, start, &sit);
                if (err)
                        break;
                seg_info_from_raw_sit(se, &sit);
+               if (IS_NODESEG(se->type))
+                       total_node_blocks += se->valid_blocks;
 
                if (f2fs_discard_en(sbi)) {
                        if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
@@ -3695,6 +3715,15 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
                                se->valid_blocks - old_valid_blocks;
        }
        up_read(&curseg->journal_rwsem);
+
+       if (!err && total_node_blocks != valid_node_count(sbi)) {
+               f2fs_msg(sbi->sb, KERN_ERR,
+                       "SIT is corrupted node# %u vs %u",
+                       total_node_blocks, valid_node_count(sbi));
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               err = -EINVAL;
+       }
+
        return err;
 }