fs: use mapping_set_error instead of opencoded set_bit
[cascardo/linux.git] / fs / f2fs / checkpoint.c
index 9c6439b..7e9b504 100644 (file)
@@ -28,7 +28,7 @@ struct kmem_cache *inode_entry_slab;
 
 void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io)
 {
-       set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+       set_ckpt_flags(sbi, CP_ERROR_FLAG);
        sbi->sb->s_flags |= MS_RDONLY;
        if (!end_io)
                f2fs_flush_merged_bios(sbi);
@@ -267,7 +267,6 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
                                struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
-       struct blk_plug plug;
        long diff, written;
 
        /* collect a number of dirty meta pages and write together */
@@ -280,9 +279,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
        /* if mounting is failed, skip writing node pages */
        mutex_lock(&sbi->cp_mutex);
        diff = nr_pages_to_write(sbi, META, wbc);
-       blk_start_plug(&plug);
        written = sync_meta_pages(sbi, META, wbc->nr_to_write);
-       blk_finish_plug(&plug);
        mutex_unlock(&sbi->cp_mutex);
        wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
        return 0;
@@ -388,6 +385,9 @@ const struct address_space_operations f2fs_meta_aops = {
        .set_page_dirty = f2fs_set_meta_page_dirty,
        .invalidatepage = f2fs_invalidate_page,
        .releasepage    = f2fs_release_page,
+#ifdef CONFIG_MIGRATION
+       .migratepage    = f2fs_migrate_page,
+#endif
 };
 
 static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -491,7 +491,7 @@ int acquire_orphan_inode(struct f2fs_sb_info *sbi)
        spin_lock(&im->ino_lock);
 
 #ifdef CONFIG_F2FS_FAULT_INJECTION
-       if (time_to_inject(FAULT_ORPHAN)) {
+       if (time_to_inject(sbi, FAULT_ORPHAN)) {
                spin_unlock(&im->ino_lock);
                return -ENOSPC;
        }
@@ -532,6 +532,17 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
        struct inode *inode;
        struct node_info ni;
+       int err = acquire_orphan_inode(sbi);
+
+       if (err) {
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                               "%s: orphan failed (ino=%x), run fsck to fix.",
+                               __func__, ino);
+               return err;
+       }
+
+       __add_ino_entry(sbi, ino, ORPHAN_INO);
 
        inode = f2fs_iget_retry(sbi->sb, ino);
        if (IS_ERR(inode)) {
@@ -552,17 +563,13 @@ static int recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 
        /* ENOMEM was fully retried in f2fs_evict_inode. */
        if (ni.blk_addr != NULL_ADDR) {
-               int err = acquire_orphan_inode(sbi);
-
-               if (err) {
-                       set_sbi_flag(sbi, SBI_NEED_FSCK);
-                       f2fs_msg(sbi->sb, KERN_WARNING,
-                               "%s: orphan failed (ino=%x), run fsck to fix.",
-                                       __func__, ino);
-                       return err;
-               }
-               __add_ino_entry(sbi, ino, ORPHAN_INO);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "%s: orphan failed (ino=%x), run fsck to fix.",
+                               __func__, ino);
+               return -EIO;
        }
+       __remove_ino_entry(sbi, ino, ORPHAN_INO);
        return 0;
 }
 
@@ -571,7 +578,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
        block_t start_blk, orphan_blocks, i, j;
        int err;
 
-       if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
+       if (!is_set_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG))
                return 0;
 
        start_blk = __start_cp_addr(sbi) + 1 + __cp_payload(sbi);
@@ -595,7 +602,7 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
                f2fs_put_page(page, 1);
        }
        /* clear Orphan Flag */
-       clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
+       clear_ckpt_flags(sbi, CP_ORPHAN_PRESENT_FLAG);
        return 0;
 }
 
@@ -656,45 +663,55 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
        }
 }
 
-static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
-                               block_t cp_addr, unsigned long long *version)
+static int get_checkpoint_version(struct f2fs_sb_info *sbi, block_t cp_addr,
+               struct f2fs_checkpoint **cp_block, struct page **cp_page,
+               unsigned long long *version)
 {
-       struct page *cp_page_1, *cp_page_2 = NULL;
        unsigned long blk_size = sbi->blocksize;
-       struct f2fs_checkpoint *cp_block;
-       unsigned long long cur_version = 0, pre_version = 0;
-       size_t crc_offset;
+       size_t crc_offset = 0;
        __u32 crc = 0;
 
-       /* Read the 1st cp block in this CP pack */
-       cp_page_1 = get_meta_page(sbi, cp_addr);
+       *cp_page = get_meta_page(sbi, cp_addr);
+       *cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
 
-       /* get the version number */
-       cp_block = (struct f2fs_checkpoint *)page_address(cp_page_1);
-       crc_offset = le32_to_cpu(cp_block->checksum_offset);
-       if (crc_offset >= blk_size)
-               goto invalid_cp1;
+       crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
+       if (crc_offset >= blk_size) {
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                       "invalid crc_offset: %zu", crc_offset);
+               return -EINVAL;
+       }
 
-       crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
-       if (!f2fs_crc_valid(sbi, crc, cp_block, crc_offset))
-               goto invalid_cp1;
+       crc = le32_to_cpu(*((__le32 *)((unsigned char *)*cp_block
+                                                       + crc_offset)));
+       if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
+               f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
+               return -EINVAL;
+       }
 
-       pre_version = cur_cp_version(cp_block);
+       *version = cur_cp_version(*cp_block);
+       return 0;
+}
 
-       /* Read the 2nd cp block in this CP pack */
-       cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
-       cp_page_2 = get_meta_page(sbi, cp_addr);
+static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
+                               block_t cp_addr, unsigned long long *version)
+{
+       struct page *cp_page_1 = NULL, *cp_page_2 = NULL;
+       struct f2fs_checkpoint *cp_block = NULL;
+       unsigned long long cur_version = 0, pre_version = 0;
+       int err;
 
-       cp_block = (struct f2fs_checkpoint *)page_address(cp_page_2);
-       crc_offset = le32_to_cpu(cp_block->checksum_offset);
-       if (crc_offset >= blk_size)
-               goto invalid_cp2;
+       err = get_checkpoint_version(sbi, cp_addr, &cp_block,
+                                       &cp_page_1, version);
+       if (err)
+               goto invalid_cp1;
+       pre_version = *version;
 
-       crc = le32_to_cpu(*((__le32 *)((unsigned char *)cp_block + crc_offset)));
-       if (!f2fs_crc_valid(sbi, crc, cp_block, crc_offset))
+       cp_addr += le32_to_cpu(cp_block->cp_pack_total_block_count) - 1;
+       err = get_checkpoint_version(sbi, cp_addr, &cp_block,
+                                       &cp_page_2, version);
+       if (err)
                goto invalid_cp2;
-
-       cur_version = cur_cp_version(cp_block);
+       cur_version = *version;
 
        if (cur_version == pre_version) {
                *version = cur_version;
@@ -989,6 +1006,37 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
        finish_wait(&sbi->cp_wait, &wait);
 }
 
+static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+{
+       unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
+       struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+
+       spin_lock(&sbi->cp_lock);
+
+       if (cpc->reason == CP_UMOUNT)
+               __set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
+       else
+               __clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
+
+       if (cpc->reason == CP_FASTBOOT)
+               __set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
+       else
+               __clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
+
+       if (orphan_num)
+               __set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
+       else
+               __clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
+
+       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
+               __set_ckpt_flags(ckpt, CP_FSCK_FLAG);
+
+       /* set this flag to activate crc|cp_ver for recovery */
+       __set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
+
+       spin_unlock(&sbi->cp_lock);
+}
+
 static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
@@ -1043,10 +1091,12 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        /* 2 cp  + n data seg summary + orphan inode blocks */
        data_sum_blocks = npages_for_summary_flush(sbi, false);
+       spin_lock(&sbi->cp_lock);
        if (data_sum_blocks < NR_CURSEG_DATA_TYPE)
-               set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
+               __set_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
        else
-               clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
+               __clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
+       spin_unlock(&sbi->cp_lock);
 
        orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
        ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
@@ -1061,26 +1111,8 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                                cp_payload_blks + data_sum_blocks +
                                orphan_blocks);
 
-       if (cpc->reason == CP_UMOUNT)
-               set_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
-       else
-               clear_ckpt_flags(ckpt, CP_UMOUNT_FLAG);
-
-       if (cpc->reason == CP_FASTBOOT)
-               set_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
-       else
-               clear_ckpt_flags(ckpt, CP_FASTBOOT_FLAG);
-
-       if (orphan_num)
-               set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
-       else
-               clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
-
-       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK))
-               set_ckpt_flags(ckpt, CP_FSCK_FLAG);
-
-       /* set this flag to activate crc|cp_ver for recovery */
-       set_ckpt_flags(ckpt, CP_CRC_RECOVERY_FLAG);
+       /* update ckpt flag for checkpoint */
+       update_ckpt_flags(sbi, cpc);
 
        /* update SIT/NAT bitmap */
        get_sit_bitmap(sbi, __bitmap_ptr(sbi, SIT_BITMAP));