]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
f2fs: fix to propagate error from __get_meta_page()
authorChao Yu <yuchao0@huawei.com>
Mon, 16 Jul 2018 16:02:17 +0000 (00:02 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 1 Aug 2018 18:52:36 +0000 (11:52 -0700)
If caller of __get_meta_page() can handle error, let's propagate error
from __get_meta_page().

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/gc.c
fs/f2fs/inline.c
fs/f2fs/inode.c
fs/f2fs/node.c
fs/f2fs/recovery.c
fs/f2fs/segment.c

index b766f78b05f90c003e2325344bf2f3f1608789a5..c5fd318c06d20c7607666d732b36f1237cbbbbdb 100644 (file)
@@ -71,6 +71,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
                .encrypted_page = NULL,
                .is_meta = is_meta,
        };
+       int err;
 
        if (unlikely(!is_meta))
                fio.op_flags &= ~REQ_META;
@@ -85,11 +86,10 @@ repeat:
 
        fio.page = page;
 
-       if (f2fs_submit_page_bio(&fio)) {
-               memset(page_address(page), 0, PAGE_SIZE);
-               f2fs_stop_checkpoint(sbi, false);
-               f2fs_bug_on(sbi, 1);
-               return page;
+       err = f2fs_submit_page_bio(&fio);
+       if (err) {
+               f2fs_put_page(page, 1);
+               return ERR_PTR(err);
        }
 
        lock_page(page);
@@ -98,14 +98,9 @@ repeat:
                goto repeat;
        }
 
-       /*
-        * if there is any IO error when accessing device, make our filesystem
-        * readonly and make sure do not write checkpoint with non-uptodate
-        * meta page.
-        */
        if (unlikely(!PageUptodate(page))) {
-               memset(page_address(page), 0, PAGE_SIZE);
-               f2fs_stop_checkpoint(sbi, false);
+               f2fs_put_page(page, 1);
+               return ERR_PTR(-EIO);
        }
 out:
        return page;
@@ -116,6 +111,25 @@ struct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
        return __get_meta_page(sbi, index, true);
 }
 
+struct page *f2fs_get_meta_page_nofail(struct f2fs_sb_info *sbi, pgoff_t index)
+{
+       struct page *page;
+       int count = 0;
+
+retry:
+       page = __get_meta_page(sbi, index, true);
+       if (IS_ERR(page)) {
+               if (PTR_ERR(page) == -EIO &&
+                               ++count <= DEFAULT_RETRY_IO_COUNT)
+                       goto retry;
+
+               f2fs_stop_checkpoint(sbi, false);
+               f2fs_bug_on(sbi, 1);
+       }
+
+       return page;
+}
+
 /* for POR only */
 struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index)
 {
@@ -607,7 +621,9 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
        /* truncate all the data during iput */
        iput(inode);
 
-       f2fs_get_node_info(sbi, ino, &ni);
+       err = f2fs_get_node_info(sbi, ino, &ni);
+       if (err)
+               goto err_out;
 
        /* ENOMEM was fully retried in f2fs_evict_inode. */
        if (ni.blk_addr != NULL_ADDR) {
@@ -655,9 +671,15 @@ int f2fs_recover_orphan_inodes(struct f2fs_sb_info *sbi)
        f2fs_ra_meta_pages(sbi, start_blk, orphan_blocks, META_CP, true);
 
        for (i = 0; i < orphan_blocks; i++) {
-               struct page *page = f2fs_get_meta_page(sbi, start_blk + i);
+               struct page *page;
                struct f2fs_orphan_block *orphan_blk;
 
+               page = f2fs_get_meta_page(sbi, start_blk + i);
+               if (IS_ERR(page)) {
+                       err = PTR_ERR(page);
+                       goto out;
+               }
+
                orphan_blk = (struct f2fs_orphan_block *)page_address(page);
                for (j = 0; j < le32_to_cpu(orphan_blk->entry_count); j++) {
                        nid_t ino = le32_to_cpu(orphan_blk->ino[j]);
@@ -748,6 +770,9 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
        __u32 crc = 0;
 
        *cp_page = f2fs_get_meta_page(sbi, cp_addr);
+       if (IS_ERR(*cp_page))
+               return PTR_ERR(*cp_page);
+
        *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
 
        crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
@@ -873,6 +898,8 @@ int f2fs_get_valid_checkpoint(struct f2fs_sb_info *sbi)
                unsigned char *ckpt = (unsigned char *)sbi->ckpt;
 
                cur_page = f2fs_get_meta_page(sbi, cp_blk_no + i);
+               if (IS_ERR(cur_page))
+                       goto free_fail_no_cp;
                sit_bitmap_ptr = page_address(cur_page);
                memcpy(ckpt + i * blk_size, sit_bitmap_ptr, blk_size);
                f2fs_put_page(cur_page, 1);
index 2b28f0a6f75115068239af9cffe739dac9831785..7f860405cd6ee26e6e017f68d51255fe0d0739d0 100644 (file)
@@ -879,6 +879,10 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
        if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
                return -EPERM;
 
+       err = f2fs_get_node_info(sbi, dn->nid, &ni);
+       if (err)
+               return err;
+
        dn->data_blkaddr = datablock_addr(dn->inode,
                                dn->node_page, dn->ofs_in_node);
        if (dn->data_blkaddr == NEW_ADDR)
@@ -888,7 +892,6 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)
                return err;
 
 alloc:
-       f2fs_get_node_info(sbi, dn->nid, &ni);
        set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
 
        f2fs_allocate_data_block(sbi, NULL, dn->data_blkaddr, &dn->data_blkaddr,
@@ -1291,7 +1294,11 @@ static int f2fs_xattr_fiemap(struct inode *inode,
                if (!page)
                        return -ENOMEM;
 
-               f2fs_get_node_info(sbi, inode->i_ino, &ni);
+               err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
+               if (err) {
+                       f2fs_put_page(page, 1);
+                       return err;
+               }
 
                phys = (__u64)blk_to_logical(inode, ni.blk_addr);
                offset = offsetof(struct f2fs_inode, i_addr) +
@@ -1318,7 +1325,11 @@ static int f2fs_xattr_fiemap(struct inode *inode,
                if (!page)
                        return -ENOMEM;
 
-               f2fs_get_node_info(sbi, xnid, &ni);
+               err = f2fs_get_node_info(sbi, xnid, &ni);
+               if (err) {
+                       f2fs_put_page(page, 1);
+                       return err;
+               }
 
                phys = (__u64)blk_to_logical(inode, ni.blk_addr);
                len = inode->i_sb->s_blocksize;
@@ -1705,6 +1716,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
        struct inode *inode = page->mapping->host;
        struct dnode_of_data dn;
        struct extent_info ei = {0,0,0};
+       struct node_info ni;
        bool ipu_force = false;
        int err = 0;
 
@@ -1773,6 +1785,12 @@ got_it:
                fio->need_lock = LOCK_REQ;
        }
 
+       err = f2fs_get_node_info(fio->sbi, dn.nid, &ni);
+       if (err)
+               goto out_writepage;
+
+       fio->version = ni.version;
+
        err = encrypt_one_page(fio);
        if (err)
                goto out_writepage;
index 9e6b27596b2686b19ec5a6ef206d5ac56ca55748..1f692f1445d796a70e669c7331ebcb5ec0e1620a 100644 (file)
@@ -513,6 +513,8 @@ enum {
                                         */
 };
 
+#define DEFAULT_RETRY_IO_COUNT 8       /* maximum retry read IO count */
+
 #define F2FS_LINK_MAX  0xffffffff      /* maximum link count per file */
 
 #define MAX_DIR_RA_PAGES       4       /* maximum ra pages of dir */
@@ -1020,6 +1022,7 @@ struct f2fs_io_info {
        bool retry;             /* need to reallocate block address */
        enum iostat_type io_type;       /* io type */
        struct writeback_control *io_wbc; /* writeback control */
+       unsigned char version;          /* version of the node */
 };
 
 #define is_read_io(rw) ((rw) == READ)
@@ -2823,7 +2826,7 @@ bool f2fs_available_free_memory(struct f2fs_sb_info *sbi, int type);
 int f2fs_need_dentry_mark(struct f2fs_sb_info *sbi, nid_t nid);
 bool f2fs_is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid);
 bool f2fs_need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino);
-void f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
+int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
                                                struct node_info *ni);
 pgoff_t f2fs_get_next_page_offset(struct dnode_of_data *dn, pgoff_t pgofs);
 int f2fs_get_dnode_of_data(struct dnode_of_data *dn, pgoff_t index, int mode);
@@ -2850,7 +2853,7 @@ int f2fs_try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink);
 void f2fs_recover_inline_xattr(struct inode *inode, struct page *page);
 int f2fs_recover_xattr_data(struct inode *inode, struct page *page);
 int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page);
-void f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
+int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
                        unsigned int segno, struct f2fs_summary_block *sum);
 void f2fs_flush_nat_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc);
 int f2fs_build_node_manager(struct f2fs_sb_info *sbi);
@@ -2928,6 +2931,7 @@ enum rw_hint f2fs_io_type_to_rw_hint(struct f2fs_sb_info *sbi,
 void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io);
 struct page *f2fs_grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
 struct page *f2fs_get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index);
+struct page *f2fs_get_meta_page_nofail(struct f2fs_sb_info *sbi, pgoff_t index);
 struct page *f2fs_get_tmp_page(struct f2fs_sb_info *sbi, pgoff_t index);
 bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
                                        block_t blkaddr, int type);
index 5e29d40537489bcdbff486fb7df4ec4a9f480e5a..d41f2138b2a9ef8b599c203d7124a1f94cae75fb 100644 (file)
@@ -1067,7 +1067,12 @@ static int __clone_blkaddrs(struct inode *src_inode, struct inode *dst_inode,
                        if (ret)
                                return ret;
 
-                       f2fs_get_node_info(sbi, dn.nid, &ni);
+                       ret = f2fs_get_node_info(sbi, dn.nid, &ni);
+                       if (ret) {
+                               f2fs_put_dnode(&dn);
+                               return ret;
+                       }
+
                        ilen = min((pgoff_t)
                                ADDRS_PER_PAGE(dn.node_page, dst_inode) -
                                                dn.ofs_in_node, len - i);
index 37ab2d10a872d831fb2389fa80cceb277945cccb..e352fbd33848ef4c2ab5db017d0d9d657819e9ed 100644 (file)
@@ -517,7 +517,11 @@ next_step:
                        continue;
                }
 
-               f2fs_get_node_info(sbi, nid, &ni);
+               if (f2fs_get_node_info(sbi, nid, &ni)) {
+                       f2fs_put_page(node_page, 1);
+                       continue;
+               }
+
                if (ni.blk_addr != start_addr + off) {
                        f2fs_put_page(node_page, 1);
                        continue;
@@ -576,7 +580,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
        if (IS_ERR(node_page))
                return false;
 
-       f2fs_get_node_info(sbi, nid, dni);
+       if (f2fs_get_node_info(sbi, nid, dni)) {
+               f2fs_put_page(node_page, 1);
+               return false;
+       }
 
        if (sum->version != dni->version) {
                f2fs_msg(sbi->sb, KERN_WARNING,
@@ -655,7 +662,10 @@ static void move_data_block(struct inode *inode, block_t bidx,
         */
        f2fs_wait_on_page_writeback(page, DATA, true);
 
-       f2fs_get_node_info(fio.sbi, dn.nid, &ni);
+       err = f2fs_get_node_info(fio.sbi, dn.nid, &ni);
+       if (err)
+               goto put_out;
+
        set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version);
 
        /* read page */
index 2bcb2d36f024ed269652f674fc69bcf52bd854ce..115dc219344b15be987905121b38961b8fdcd630 100644 (file)
@@ -121,6 +121,7 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
                .encrypted_page = NULL,
                .io_type = FS_DATA_IO,
        };
+       struct node_info ni;
        int dirty, err;
 
        if (!f2fs_exist_data(dn->inode))
@@ -130,6 +131,14 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
        if (err)
                return err;
 
+       err = f2fs_get_node_info(fio.sbi, dn->nid, &ni);
+       if (err) {
+               f2fs_put_dnode(dn);
+               return err;
+       }
+
+       fio.version = ni.version;
+
        if (unlikely(dn->data_blkaddr != NEW_ADDR)) {
                f2fs_put_dnode(dn);
                set_sbi_flag(fio.sbi, SBI_NEED_FSCK);
@@ -690,7 +699,10 @@ int f2fs_inline_data_fiemap(struct inode *inode,
                ilen = start + len;
        ilen -= start;
 
-       f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
+       err = f2fs_get_node_info(F2FS_I_SB(inode), inode->i_ino, &ni);
+       if (err)
+               goto out;
+
        byteaddr = (__u64)ni.blk_addr << inode->i_sb->s_blocksize_bits;
        byteaddr += (char *)inline_data_addr(inode, ipage) -
                                        (char *)F2FS_INODE(ipage);
index 740988bc250de206c30c66d426d4f1f0e40dda90..35d49528b2c185de1778637fb493fb98285f9242 100644 (file)
@@ -699,6 +699,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct node_info ni;
+       int err;
 
        /*
         * clear nlink of inode in order to release resource of inode
@@ -721,10 +722,16 @@ void f2fs_handle_failed_inode(struct inode *inode)
         * so we can prevent losing this orphan when encoutering checkpoint
         * and following suddenly power-off.
         */
-       f2fs_get_node_info(sbi, inode->i_ino, &ni);
+       err = f2fs_get_node_info(sbi, inode->i_ino, &ni);
+       if (err) {
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "May loss orphan inode, run fsck to fix.");
+               goto out;
+       }
 
        if (ni.blk_addr != NULL_ADDR) {
-               int err = f2fs_acquire_orphan_inode(sbi);
+               err = f2fs_acquire_orphan_inode(sbi);
                if (err) {
                        set_sbi_flag(sbi, SBI_NEED_FSCK);
                        f2fs_msg(sbi->sb, KERN_WARNING,
@@ -737,6 +744,7 @@ void f2fs_handle_failed_inode(struct inode *inode)
                set_inode_flag(inode, FI_FREE_NID);
        }
 
+out:
        f2fs_unlock_op(sbi);
 
        /* iput will drop the inode object */
index b18b7522c4d55b082eac9d990035ef375abf95a6..69d0ac1b6cacffc00ab27a0d9efd15d2c6e35d91 100644 (file)
@@ -113,7 +113,7 @@ static void clear_node_page_dirty(struct page *page)
 static struct page *get_current_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
 {
        pgoff_t index = current_nat_addr(sbi, nid);
-       return f2fs_get_meta_page(sbi, index);
+       return f2fs_get_meta_page_nofail(sbi, index);
 }
 
 static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
@@ -419,7 +419,7 @@ int f2fs_try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 /*
  * This function always returns success
  */
-void f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
+int f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
                                                struct node_info *ni)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
@@ -443,7 +443,7 @@ void f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
                ni->blk_addr = nat_get_blkaddr(e);
                ni->version = nat_get_version(e);
                up_read(&nm_i->nat_tree_lock);
-               return;
+               return 0;
        }
 
        memset(&ne, 0, sizeof(struct f2fs_nat_entry));
@@ -466,6 +466,9 @@ void f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
        up_read(&nm_i->nat_tree_lock);
 
        page = f2fs_get_meta_page(sbi, index);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
+
        nat_blk = (struct f2fs_nat_block *)page_address(page);
        ne = nat_blk->entries[nid - start_nid];
        node_info_from_raw_nat(ni, &ne);
@@ -473,6 +476,7 @@ void f2fs_get_node_info(struct f2fs_sb_info *sbi, nid_t nid,
 cache:
        /* cache nat entry */
        cache_nat_entry(sbi, nid, &ne);
+       return 0;
 }
 
 /*
@@ -722,12 +726,15 @@ release_out:
        return err;
 }
 
-static void truncate_node(struct dnode_of_data *dn)
+static int truncate_node(struct dnode_of_data *dn)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode);
        struct node_info ni;
+       int err;
 
-       f2fs_get_node_info(sbi, dn->nid, &ni);
+       err = f2fs_get_node_info(sbi, dn->nid, &ni);
+       if (err)
+               return err;
 
        /* Deallocate node address */
        f2fs_invalidate_blocks(sbi, ni.blk_addr);
@@ -750,11 +757,14 @@ static void truncate_node(struct dnode_of_data *dn)
 
        dn->node_page = NULL;
        trace_f2fs_truncate_node(dn->inode, dn->nid, ni.blk_addr);
+
+       return 0;
 }
 
 static int truncate_dnode(struct dnode_of_data *dn)
 {
        struct page *page;
+       int err;
 
        if (dn->nid == 0)
                return 1;
@@ -770,7 +780,10 @@ static int truncate_dnode(struct dnode_of_data *dn)
        dn->node_page = page;
        dn->ofs_in_node = 0;
        f2fs_truncate_data_blocks(dn);
-       truncate_node(dn);
+       err = truncate_node(dn);
+       if (err)
+               return err;
+
        return 1;
 }
 
@@ -835,7 +848,9 @@ static int truncate_nodes(struct dnode_of_data *dn, unsigned int nofs,
        if (!ofs) {
                /* remove current indirect node */
                dn->node_page = page;
-               truncate_node(dn);
+               ret = truncate_node(dn);
+               if (ret)
+                       goto out_err;
                freed++;
        } else {
                f2fs_put_page(page, 1);
@@ -893,7 +908,9 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
        if (offset[idx + 1] == 0) {
                dn->node_page = pages[idx];
                dn->nid = nid[idx];
-               truncate_node(dn);
+               err = truncate_node(dn);
+               if (err)
+                       goto fail;
        } else {
                f2fs_put_page(pages[idx], 1);
        }
@@ -1014,6 +1031,7 @@ int f2fs_truncate_xattr_node(struct inode *inode)
        nid_t nid = F2FS_I(inode)->i_xattr_nid;
        struct dnode_of_data dn;
        struct page *npage;
+       int err;
 
        if (!nid)
                return 0;
@@ -1022,10 +1040,15 @@ int f2fs_truncate_xattr_node(struct inode *inode)
        if (IS_ERR(npage))
                return PTR_ERR(npage);
 
+       set_new_dnode(&dn, inode, NULL, npage, nid);
+       err = truncate_node(&dn);
+       if (err) {
+               f2fs_put_page(npage, 1);
+               return err;
+       }
+
        f2fs_i_xnid_write(inode, 0);
 
-       set_new_dnode(&dn, inode, NULL, npage, nid);
-       truncate_node(&dn);
        return 0;
 }
 
@@ -1059,7 +1082,11 @@ int f2fs_remove_inode_page(struct inode *inode)
                        inode->i_blocks != 0 && inode->i_blocks != 8);
 
        /* will put inode & node pages */
-       truncate_node(&dn);
+       err = truncate_node(&dn);
+       if (err) {
+               f2fs_put_dnode(&dn);
+               return err;
+       }
        return 0;
 }
 
@@ -1092,7 +1119,11 @@ struct page *f2fs_new_node_page(struct dnode_of_data *dn, unsigned int ofs)
                goto fail;
 
 #ifdef CONFIG_F2FS_CHECK_FS
-       f2fs_get_node_info(sbi, dn->nid, &new_ni);
+       err = f2fs_get_node_info(sbi, dn->nid, &new_ni);
+       if (err) {
+               dec_valid_node_count(sbi, dn->inode, !ofs);
+               goto fail;
+       }
        f2fs_bug_on(sbi, new_ni.blk_addr != NULL_ADDR);
 #endif
        new_ni.nid = dn->nid;
@@ -1140,6 +1171,7 @@ static int read_node_page(struct page *page, int op_flags)
                .page = page,
                .encrypted_page = NULL,
        };
+       int err;
 
        if (PageUptodate(page)) {
 #ifdef CONFIG_F2FS_CHECK_FS
@@ -1148,7 +1180,9 @@ static int read_node_page(struct page *page, int op_flags)
                return LOCKED_PAGE;
        }
 
-       f2fs_get_node_info(sbi, page->index, &ni);
+       err = f2fs_get_node_info(sbi, page->index, &ni);
+       if (err)
+               return err;
 
        if (unlikely(ni.blk_addr == NULL_ADDR) ||
                        is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN)) {
@@ -1383,6 +1417,9 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
        nid = nid_of_node(page);
        f2fs_bug_on(sbi, page->index != nid);
 
+       if (f2fs_get_node_info(sbi, nid, &ni))
+               goto redirty_out;
+
        if (wbc->for_reclaim) {
                if (!down_read_trylock(&sbi->node_write))
                        goto redirty_out;
@@ -1390,8 +1427,6 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
                down_read(&sbi->node_write);
        }
 
-       f2fs_get_node_info(sbi, nid, &ni);
-
        /* This page is already truncated */
        if (unlikely(ni.blk_addr == NULL_ADDR)) {
                ClearPageUptodate(page);
@@ -2311,12 +2346,16 @@ int f2fs_recover_xattr_data(struct inode *inode, struct page *page)
        struct dnode_of_data dn;
        struct node_info ni;
        struct page *xpage;
+       int err;
 
        if (!prev_xnid)
                goto recover_xnid;
 
        /* 1: invalidate the previous xattr nid */
-       f2fs_get_node_info(sbi, prev_xnid, &ni);
+       err = f2fs_get_node_info(sbi, prev_xnid, &ni);
+       if (err)
+               return err;
+
        f2fs_invalidate_blocks(sbi, ni.blk_addr);
        dec_valid_node_count(sbi, inode, false);
        set_node_addr(sbi, &ni, NULL_ADDR, false);
@@ -2351,8 +2390,11 @@ int f2fs_recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
        nid_t ino = ino_of_node(page);
        struct node_info old_ni, new_ni;
        struct page *ipage;
+       int err;
 
-       f2fs_get_node_info(sbi, ino, &old_ni);
+       err = f2fs_get_node_info(sbi, ino, &old_ni);
+       if (err)
+               return err;
 
        if (unlikely(old_ni.blk_addr != NULL_ADDR))
                return -EINVAL;
@@ -2406,7 +2448,7 @@ retry:
        return 0;
 }
 
-void f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
+int f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
                        unsigned int segno, struct f2fs_summary_block *sum)
 {
        struct f2fs_node *rn;
@@ -2428,6 +2470,9 @@ void f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
                for (idx = addr; idx < addr + nrpages; idx++) {
                        struct page *page = f2fs_get_tmp_page(sbi, idx);
 
+                       if (IS_ERR(page))
+                               return PTR_ERR(page);
+
                        rn = F2FS_NODE(page);
                        sum_entry->nid = rn->footer.nid;
                        sum_entry->version = 0;
@@ -2439,6 +2484,7 @@ void f2fs_restore_node_summary(struct f2fs_sb_info *sbi,
                invalidate_mapping_pages(META_MAPPING(sbi), addr,
                                                        addr + nrpages);
        }
+       return 0;
 }
 
 static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
@@ -2675,7 +2721,13 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
        nat_bits_addr = __start_cp_addr(sbi) + sbi->blocks_per_seg -
                                                nm_i->nat_bits_blocks;
        for (i = 0; i < nm_i->nat_bits_blocks; i++) {
-               struct page *page = f2fs_get_meta_page(sbi, nat_bits_addr++);
+               struct page *page;
+
+               page = f2fs_get_meta_page(sbi, nat_bits_addr++);
+               if (IS_ERR(page)) {
+                       disable_nat_bits(sbi, true);
+                       return PTR_ERR(page);
+               }
 
                memcpy(nm_i->nat_bits + (i << F2FS_BLKSIZE_BITS),
                                        page_address(page), F2FS_BLKSIZE);
index 0d927ae26c48e15d5d953ba98246bf1600760248..956f34c87082c89a32ac50eb5df05816ffacbff3 100644 (file)
@@ -256,6 +256,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head,
                        return 0;
 
                page = f2fs_get_tmp_page(sbi, blkaddr);
+               if (IS_ERR(page)) {
+                       err = PTR_ERR(page);
+                       break;
+               }
 
                if (!is_recoverable_dnode(page))
                        break;
@@ -471,7 +475,10 @@ retry_dn:
 
        f2fs_wait_on_page_writeback(dn.node_page, NODE, true);
 
-       f2fs_get_node_info(sbi, dn.nid, &ni);
+       err = f2fs_get_node_info(sbi, dn.nid, &ni);
+       if (err)
+               goto err;
+
        f2fs_bug_on(sbi, ni.ino != ino_of_node(page));
        f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page));
 
@@ -574,6 +581,10 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
                f2fs_ra_meta_pages_cond(sbi, blkaddr);
 
                page = f2fs_get_tmp_page(sbi, blkaddr);
+               if (IS_ERR(page)) {
+                       err = PTR_ERR(page);
+                       break;
+               }
 
                if (!is_recoverable_dnode(page)) {
                        f2fs_put_page(page, 1);
index f5f04aabe338b64c0be6a4822235166b25b07ebd..65dcde1d4fb83fac6f8a7c06bfc6f0cedd0f004c 100644 (file)
@@ -250,7 +250,13 @@ retry:
                                err = -EAGAIN;
                                goto next;
                        }
-                       f2fs_get_node_info(sbi, dn.nid, &ni);
+
+                       err = f2fs_get_node_info(sbi, dn.nid, &ni);
+                       if (err) {
+                               f2fs_put_dnode(&dn);
+                               return err;
+                       }
+
                        if (cur->old_addr == NEW_ADDR) {
                                f2fs_invalidate_blocks(sbi, dn.data_blkaddr);
                                f2fs_update_data_blkaddr(&dn, NEW_ADDR);
@@ -2051,7 +2057,7 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra)
  */
 struct page *f2fs_get_sum_page(struct f2fs_sb_info *sbi, unsigned int segno)
 {
-       return f2fs_get_meta_page(sbi, GET_SUM_BLOCK(sbi, segno));
+       return f2fs_get_meta_page_nofail(sbi, GET_SUM_BLOCK(sbi, segno));
 }
 
 void f2fs_update_meta_page(struct f2fs_sb_info *sbi,
@@ -2911,11 +2917,9 @@ void f2fs_outplace_write_data(struct dnode_of_data *dn,
 {
        struct f2fs_sb_info *sbi = fio->sbi;
        struct f2fs_summary sum;
-       struct node_info ni;
 
        f2fs_bug_on(sbi, dn->data_blkaddr == NULL_ADDR);
-       f2fs_get_node_info(sbi, dn->nid, &ni);
-       set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
+       set_summary(&sum, dn->nid, dn->ofs_in_node, fio->version);
        do_write_page(&sum, fio);
        f2fs_update_data_blkaddr(dn, fio->new_blkaddr);
 
@@ -3077,7 +3081,7 @@ void f2fs_wait_on_block_writeback(struct f2fs_sb_info *sbi, block_t blkaddr)
        }
 }
 
-static void read_compacted_summaries(struct f2fs_sb_info *sbi)
+static int read_compacted_summaries(struct f2fs_sb_info *sbi)
 {
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
        struct curseg_info *seg_i;
@@ -3089,6 +3093,8 @@ static void read_compacted_summaries(struct f2fs_sb_info *sbi)
        start = start_sum_block(sbi);
 
        page = f2fs_get_meta_page(sbi, start++);
+       if (IS_ERR(page))
+               return PTR_ERR(page);
        kaddr = (unsigned char *)page_address(page);
 
        /* Step 1: restore nat cache */
@@ -3129,11 +3135,14 @@ static void read_compacted_summaries(struct f2fs_sb_info *sbi)
                        page = NULL;
 
                        page = f2fs_get_meta_page(sbi, start++);
+                       if (IS_ERR(page))
+                               return PTR_ERR(page);
                        kaddr = (unsigned char *)page_address(page);
                        offset = 0;
                }
        }
        f2fs_put_page(page, 1);
+       return 0;
 }
 
 static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
@@ -3145,6 +3154,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
        unsigned short blk_off;
        unsigned int segno = 0;
        block_t blk_addr = 0;
+       int err = 0;
 
        /* get segment number and block addr */
        if (IS_DATASEG(type)) {
@@ -3168,6 +3178,8 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
        }
 
        new = f2fs_get_meta_page(sbi, blk_addr);
+       if (IS_ERR(new))
+               return PTR_ERR(new);
        sum = (struct f2fs_summary_block *)page_address(new);
 
        if (IS_NODESEG(type)) {
@@ -3179,7 +3191,9 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
                                ns->ofs_in_node = 0;
                        }
                } else {
-                       f2fs_restore_node_summary(sbi, segno, sum);
+                       err = f2fs_restore_node_summary(sbi, segno, sum);
+                       if (err)
+                               goto out;
                }
        }
 
@@ -3199,8 +3213,9 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
        curseg->alloc_type = ckpt->alloc_type[type];
        curseg->next_blkoff = blk_off;
        mutex_unlock(&curseg->curseg_mutex);
+out:
        f2fs_put_page(new, 1);
-       return 0;
+       return err;
 }
 
 static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
@@ -3218,7 +3233,9 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
                                                        META_CP, true);
 
                /* restore for compacted data summary */
-               read_compacted_summaries(sbi);
+               err = read_compacted_summaries(sbi);
+               if (err)
+                       return err;
                type = CURSEG_HOT_NODE;
        }
 
@@ -3349,7 +3366,7 @@ int f2fs_lookup_journal_in_cursum(struct f2fs_journal *journal, int type,
 static struct page *get_current_sit_page(struct f2fs_sb_info *sbi,
                                        unsigned int segno)
 {
-       return f2fs_get_meta_page(sbi, current_sit_addr(sbi, segno));
+       return f2fs_get_meta_page_nofail(sbi, current_sit_addr(sbi, segno));
 }
 
 static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,