return __get_meta_page(sbi, index, false);
 }
 
+static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
+                                                       int type)
+{
+       struct seg_entry *se;
+       unsigned int segno, offset;
+       bool exist;
+
+       if (type != DATA_GENERIC_ENHANCE && type != DATA_GENERIC_ENHANCE_READ)
+               return true;
+
+       segno = GET_SEGNO(sbi, blkaddr);
+       offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
+       se = get_seg_entry(sbi, segno);
+
+       exist = f2fs_test_bit(offset, se->cur_valid_map);
+       if (!exist && type == DATA_GENERIC_ENHANCE) {
+               f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
+                       "blkaddr:%u, sit bitmap:%d", blkaddr, exist);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               WARN_ON(1);
+       }
+       return exist;
+}
+
 bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type)
 {
                        return false;
                break;
        case META_POR:
+               if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+                       blkaddr < MAIN_BLKADDR(sbi)))
+                       return false;
+               break;
        case DATA_GENERIC:
+       case DATA_GENERIC_ENHANCE:
+       case DATA_GENERIC_ENHANCE_READ:
                if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
-                       blkaddr < MAIN_BLKADDR(sbi))) {
-                       if (type == DATA_GENERIC) {
-                               f2fs_msg(sbi->sb, KERN_WARNING,
-                                       "access invalid blkaddr:%u", blkaddr);
-                               WARN_ON(1);
-                       }
+                               blkaddr < MAIN_BLKADDR(sbi))) {
+                       f2fs_msg(sbi->sb, KERN_WARNING,
+                               "access invalid blkaddr:%u", blkaddr);
+                       set_sbi_flag(sbi, SBI_NEED_FSCK);
+                       WARN_ON(1);
                        return false;
+               } else {
+                       return __is_bitmap_valid(sbi, blkaddr, type);
                }
                break;
        case META_GENERIC:
 
                        fio->encrypted_page : fio->page;
 
        if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
-                       fio->is_por ? META_POR :
-                       (__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)))
+                       fio->is_por ? META_POR : (__is_meta_io(fio) ?
+                       META_GENERIC : DATA_GENERIC_ENHANCE)))
                return -EFAULT;
 
        trace_f2fs_submit_page_bio(page, fio);
                spin_unlock(&io->io_lock);
        }
 
-       if (__is_valid_data_blkaddr(fio->old_blkaddr))
-               verify_block_addr(fio, fio->old_blkaddr);
-       verify_block_addr(fio, fio->new_blkaddr);
+       verify_fio_blkaddr(fio);
 
        bio_page = fio->encrypted_page ? fio->encrypted_page : fio->page;
 
        struct bio_post_read_ctx *ctx;
        unsigned int post_read_steps = 0;
 
-       if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
-               return ERR_PTR(-EFAULT);
-
        bio = f2fs_bio_alloc(sbi, min_t(int, nr_pages, BIO_MAX_PAGES), false);
        if (!bio)
                return ERR_PTR(-ENOMEM);
 static int f2fs_submit_page_read(struct inode *inode, struct page *page,
                                                        block_t blkaddr)
 {
-       struct bio *bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0);
+       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct bio *bio;
 
+       bio = f2fs_grab_read_bio(inode, blkaddr, 1, 0);
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
                return -EFAULT;
        }
        ClearPageError(page);
-       inc_page_count(F2FS_I_SB(inode), F2FS_RD_DATA);
-       __submit_bio(F2FS_I_SB(inode), bio, DATA);
+       inc_page_count(sbi, F2FS_RD_DATA);
+       __submit_bio(sbi, bio, DATA);
        return 0;
 }
 
 
        if (f2fs_lookup_extent_cache(inode, index, &ei)) {
                dn.data_blkaddr = ei.blk + index - ei.fofs;
+               if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
+                                               DATA_GENERIC_ENHANCE_READ)) {
+                       err = -EFAULT;
+                       goto put_err;
+               }
                goto got_it;
        }
 
                err = -ENOENT;
                goto put_err;
        }
+       if (dn.data_blkaddr != NEW_ADDR &&
+                       !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
+                                               dn.data_blkaddr,
+                                               DATA_GENERIC_ENHANCE)) {
+               err = -EFAULT;
+               goto put_err;
+       }
 got_it:
        if (PageUptodate(page)) {
                unlock_page(page);
        blkaddr = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
 
        if (__is_valid_data_blkaddr(blkaddr) &&
-               !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC)) {
+               !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
                err = -EFAULT;
                goto sync_out;
        }
 
-       if (is_valid_data_blkaddr(sbi, blkaddr)) {
+       if (__is_valid_data_blkaddr(blkaddr)) {
                /* use out-place-update for driect IO under LFS mode */
                if (test_opt(sbi, LFS) && flag == F2FS_GET_BLOCK_DIO &&
                                                        map->m_may_create) {
                }
 
                if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
-                                                       DATA_GENERIC)) {
+                                               DATA_GENERIC_ENHANCE_READ)) {
                        ret = -EFAULT;
                        goto out;
                }
                fio->old_blkaddr = ei.blk + page->index - ei.fofs;
 
                if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
-                                                       DATA_GENERIC))
+                                               DATA_GENERIC_ENHANCE))
                        return -EFAULT;
 
                ipu_force = true;
 got_it:
        if (__is_valid_data_blkaddr(fio->old_blkaddr) &&
                !f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
-                                                       DATA_GENERIC)) {
+                                               DATA_GENERIC_ENHANCE)) {
                err = -EFAULT;
                goto out_writepage;
        }
         * If current allocation needs SSR,
         * it had better in-place writes for updated data.
         */
-       if (ipu_force || (is_valid_data_blkaddr(fio->sbi, fio->old_blkaddr) &&
+       if (ipu_force ||
+               (__is_valid_data_blkaddr(fio->old_blkaddr) &&
                                        need_inplace_update(fio))) {
                err = encrypt_one_page(fio);
                if (err)
                zero_user_segment(page, 0, PAGE_SIZE);
                SetPageUptodate(page);
        } else {
+               if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
+                               DATA_GENERIC_ENHANCE_READ)) {
+                       err = -EFAULT;
+                       goto fail;
+               }
                err = f2fs_submit_page_read(inode, page, blkaddr);
                if (err)
                        goto fail;
 
        META_SSA,
        META_MAX,
        META_POR,
-       DATA_GENERIC,
+       DATA_GENERIC,           /* check range only */
+       DATA_GENERIC_ENHANCE,   /* strong check on range and segment bitmap */
+       DATA_GENERIC_ENHANCE_READ,      /*
+                                        * strong check on range and segment
+                                        * bitmap but no warning due to race
+                                        * condition of read on truncated area
+                                        * by extent_cache
+                                        */
        META_GENERIC,
 };
 
        return true;
 }
 
-static inline bool is_valid_data_blkaddr(struct f2fs_sb_info *sbi,
-                                               block_t blkaddr)
-{
-       if (!__is_valid_data_blkaddr(blkaddr))
-               return false;
-       verify_blkaddr(sbi, blkaddr, DATA_GENERIC);
-       return true;
-}
-
 static inline void f2fs_set_page_private(struct page *page,
                                                unsigned long data)
 {
 
        switch (whence) {
        case SEEK_DATA:
                if ((blkaddr == NEW_ADDR && dirty == pgofs) ||
-                       is_valid_data_blkaddr(sbi, blkaddr))
+                       __is_valid_data_blkaddr(blkaddr))
                        return true;
                break;
        case SEEK_HOLE:
 
                        if (__is_valid_data_blkaddr(blkaddr) &&
                                !f2fs_is_valid_blkaddr(F2FS_I_SB(inode),
-                                               blkaddr, DATA_GENERIC)) {
+                                       blkaddr, DATA_GENERIC_ENHANCE)) {
                                f2fs_put_dnode(&dn);
                                goto fail;
                        }
                f2fs_set_data_blkaddr(dn);
 
                if (__is_valid_data_blkaddr(blkaddr) &&
-                       !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC))
+                       !f2fs_is_valid_blkaddr(sbi, blkaddr,
+                                       DATA_GENERIC_ENHANCE))
                        continue;
 
                f2fs_invalidate_blocks(sbi, blkaddr);
        for (i = 0; i < done; i++, blkaddr++, do_replace++, dn.ofs_in_node++) {
                *blkaddr = datablock_addr(dn.inode,
                                        dn.node_page, dn.ofs_in_node);
+
+               if (__is_valid_data_blkaddr(*blkaddr) &&
+                       !f2fs_is_valid_blkaddr(sbi, *blkaddr,
+                                       DATA_GENERIC_ENHANCE)) {
+                       f2fs_put_dnode(&dn);
+                       return -EFAULT;
+               }
+
                if (!f2fs_is_checkpointed_data(sbi, *blkaddr)) {
 
                        if (test_opt(sbi, LFS)) {
 
 
        if (f2fs_lookup_extent_cache(inode, index, &ei)) {
                dn.data_blkaddr = ei.blk + index - ei.fofs;
+               if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
+                                               DATA_GENERIC_ENHANCE_READ))) {
+                       err = -EFAULT;
+                       goto put_page;
+               }
                goto got_it;
        }
 
                goto put_page;
        f2fs_put_dnode(&dn);
 
+       if (!__is_valid_data_blkaddr(dn.data_blkaddr)) {
+               err = -ENOENT;
+               goto put_page;
+       }
        if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr,
-                                               DATA_GENERIC))) {
+                                               DATA_GENERIC_ENHANCE))) {
                err = -EFAULT;
                goto put_page;
        }
 
 
        if (!__is_valid_data_blkaddr(addr))
                return 1;
-       if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC))
+       if (!f2fs_is_valid_blkaddr(sbi, addr, DATA_GENERIC_ENHANCE))
                return -EFAULT;
        return 0;
 }
                struct extent_info *ei = &F2FS_I(inode)->extent_tree->largest;
 
                if (ei->len &&
-                       (!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC) ||
+                       (!f2fs_is_valid_blkaddr(sbi, ei->blk,
+                                               DATA_GENERIC_ENHANCE) ||
                        !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1,
-                                                       DATA_GENERIC))) {
+                                               DATA_GENERIC_ENHANCE))) {
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        f2fs_msg(sbi->sb, KERN_WARNING,
                                "%s: inode (ino=%lx) extent info [%u, %u, %u] "
 
                        new_blkaddr == NULL_ADDR);
        f2fs_bug_on(sbi, nat_get_blkaddr(e) == NEW_ADDR &&
                        new_blkaddr == NEW_ADDR);
-       f2fs_bug_on(sbi, is_valid_data_blkaddr(sbi, nat_get_blkaddr(e)) &&
+       f2fs_bug_on(sbi, __is_valid_data_blkaddr(nat_get_blkaddr(e)) &&
                        new_blkaddr == NEW_ADDR);
 
        /* increment version no as node is removed */
 
        /* change address */
        nat_set_blkaddr(e, new_blkaddr);
-       if (!is_valid_data_blkaddr(sbi, new_blkaddr))
+       if (!__is_valid_data_blkaddr(new_blkaddr))
                set_nat_flag(e, IS_CHECKPOINTED, false);
        __set_nat_cache_dirty(nm_i, e);
 
        struct f2fs_nat_entry ne;
        struct nat_entry *e;
        pgoff_t index;
+       block_t blkaddr;
        int i;
 
        ni->nid = nid;
        node_info_from_raw_nat(ni, &ne);
        f2fs_put_page(page, 1);
 cache:
+       blkaddr = le32_to_cpu(ne.block_addr);
+       if (__is_valid_data_blkaddr(blkaddr) &&
+               !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE))
+               return -EFAULT;
+
        /* cache nat entry */
        cache_nat_entry(sbi, nid, &ne);
        return 0;
        }
 
        if (__is_valid_data_blkaddr(ni.blk_addr) &&
-               !f2fs_is_valid_blkaddr(sbi, ni.blk_addr, DATA_GENERIC)) {
+               !f2fs_is_valid_blkaddr(sbi, ni.blk_addr,
+                                       DATA_GENERIC_ENHANCE)) {
                up_read(&sbi->node_write);
                goto redirty_out;
        }
 
                src = datablock_addr(dn.inode, dn.node_page, dn.ofs_in_node);
                dest = datablock_addr(dn.inode, page, dn.ofs_in_node);
 
+               if (__is_valid_data_blkaddr(src) &&
+                       !f2fs_is_valid_blkaddr(sbi, src, META_POR)) {
+                       err = -EFAULT;
+                       goto err;
+               }
+
+               if (__is_valid_data_blkaddr(dest) &&
+                       !f2fs_is_valid_blkaddr(sbi, dest, META_POR)) {
+                       err = -EFAULT;
+                       goto err;
+               }
+
                /* skip recovering if dest is the same as src */
                if (src == dest)
                        continue;
 
        struct seg_entry *se;
        bool is_cp = false;
 
-       if (!is_valid_data_blkaddr(sbi, blkaddr))
+       if (!__is_valid_data_blkaddr(blkaddr))
                return true;
 
        down_read(&sit_i->sentry_lock);
        if (!f2fs_post_read_required(inode))
                return;
 
-       if (!is_valid_data_blkaddr(sbi, blkaddr))
+       if (!__is_valid_data_blkaddr(blkaddr))
                return;
 
        cpage = find_lock_page(META_MAPPING(sbi), blkaddr);
 
        (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1))
 
 #define GET_SEGNO(sbi, blk_addr)                                       \
-       ((!is_valid_data_blkaddr(sbi, blk_addr)) ?                      \
+       ((!__is_valid_data_blkaddr(blk_addr)) ?                 \
        NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
                GET_SEGNO_FROM_SEG0(sbi, blk_addr)))
 #define BLKS_PER_SEC(sbi)                                      \
        f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1);
 }
 
-static inline void verify_block_addr(struct f2fs_io_info *fio, block_t blk_addr)
+static inline void verify_fio_blkaddr(struct f2fs_io_info *fio)
 {
        struct f2fs_sb_info *sbi = fio->sbi;
 
-       if (__is_meta_io(fio))
-               verify_blkaddr(sbi, blk_addr, META_GENERIC);
-       else
-               verify_blkaddr(sbi, blk_addr, DATA_GENERIC);
+       if (__is_valid_data_blkaddr(fio->old_blkaddr))
+               verify_blkaddr(sbi, fio->old_blkaddr, __is_meta_io(fio) ?
+                                       META_GENERIC : DATA_GENERIC);
+       verify_blkaddr(sbi, fio->new_blkaddr, __is_meta_io(fio) ?
+                                       META_GENERIC : DATA_GENERIC_ENHANCE);
 }
 
 /*