f2fs: fix to stop filesystem update once CP failed
[linux-2.6-microblaze.git] / fs / f2fs / segment.c
index 51dc79f..ca9876a 100644 (file)
@@ -186,10 +186,7 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page)
 {
        struct inmem_pages *new;
 
-       if (PagePrivate(page))
-               set_page_private(page, (unsigned long)ATOMIC_WRITTEN_PAGE);
-       else
-               f2fs_set_page_private(page, ATOMIC_WRITTEN_PAGE);
+       set_page_private_atomic(page);
 
        new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS);
 
@@ -272,9 +269,10 @@ next:
                /* we don't need to invalidate this in the sccessful status */
                if (drop || recover) {
                        ClearPageUptodate(page);
-                       clear_cold_data(page);
+                       clear_page_private_gcing(page);
                }
-               f2fs_clear_page_private(page);
+               detach_page_private(page);
+               set_page_private(page, 0);
                f2fs_put_page(page, 1);
 
                list_del(&cur->list);
@@ -357,7 +355,7 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
        struct list_head *head = &fi->inmem_pages;
        struct inmem_pages *cur = NULL;
 
-       f2fs_bug_on(sbi, !IS_ATOMIC_WRITTEN_PAGE(page));
+       f2fs_bug_on(sbi, !page_private_atomic(page));
 
        mutex_lock(&fi->inmem_lock);
        list_for_each_entry(cur, head, list) {
@@ -373,9 +371,12 @@ void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
        kmem_cache_free(inmem_entry_slab, cur);
 
        ClearPageUptodate(page);
-       f2fs_clear_page_private(page);
+       clear_page_private_atomic(page);
        f2fs_put_page(page, 0);
 
+       detach_page_private(page);
+       set_page_private(page, 0);
+
        trace_f2fs_commit_inmem_page(page, INMEM_INVALIDATE);
 }
 
@@ -775,11 +776,22 @@ int f2fs_flush_device_cache(struct f2fs_sb_info *sbi)
                return 0;
 
        for (i = 1; i < sbi->s_ndevs; i++) {
+               int count = DEFAULT_RETRY_IO_COUNT;
+
                if (!f2fs_test_bit(i, (char *)&sbi->dirty_device))
                        continue;
-               ret = __submit_flush_wait(sbi, FDEV(i).bdev);
-               if (ret)
+
+               do {
+                       ret = __submit_flush_wait(sbi, FDEV(i).bdev);
+                       if (ret)
+                               congestion_wait(BLK_RW_ASYNC,
+                                               DEFAULT_IO_TIMEOUT);
+               } while (ret && --count);
+
+               if (ret) {
+                       f2fs_stop_checkpoint(sbi, false);
                        break;
+               }
 
                spin_lock(&sbi->dev_lock);
                f2fs_clear_bit(i, (char *)&sbi->dirty_device);
@@ -1892,7 +1904,8 @@ static int f2fs_issue_discard(struct f2fs_sb_info *sbi,
                se = get_seg_entry(sbi, GET_SEGNO(sbi, i));
                offset = GET_BLKOFF_FROM_SEG0(sbi, i);
 
-               if (!f2fs_test_and_set_bit(offset, se->discard_map))
+               if (f2fs_block_unit_discard(sbi) &&
+                               !f2fs_test_and_set_bit(offset, se->discard_map))
                        sbi->discard_blks--;
        }
 
@@ -1917,7 +1930,8 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
        struct list_head *head = &SM_I(sbi)->dcc_info->entry_list;
        int i;
 
-       if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi))
+       if (se->valid_blocks == max_blocks || !f2fs_hw_support_discard(sbi) ||
+                       !f2fs_block_unit_discard(sbi))
                return false;
 
        if (!force) {
@@ -2002,14 +2016,18 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
        unsigned int start = 0, end = -1;
        unsigned int secno, start_segno;
        bool force = (cpc->reason & CP_DISCARD);
-       bool need_align = f2fs_lfs_mode(sbi) && __is_large_section(sbi);
+       bool section_alignment = F2FS_OPTION(sbi).discard_unit ==
+                                               DISCARD_UNIT_SECTION;
+
+       if (f2fs_lfs_mode(sbi) && __is_large_section(sbi))
+               section_alignment = true;
 
        mutex_lock(&dirty_i->seglist_lock);
 
        while (1) {
                int i;
 
-               if (need_align && end != -1)
+               if (section_alignment && end != -1)
                        end--;
                start = find_next_bit(prefree_map, MAIN_SEGS(sbi), end + 1);
                if (start >= MAIN_SEGS(sbi))
@@ -2017,7 +2035,7 @@ void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi,
                end = find_next_zero_bit(prefree_map, MAIN_SEGS(sbi),
                                                                start + 1);
 
-               if (need_align) {
+               if (section_alignment) {
                        start = rounddown(start, sbi->segs_per_sec);
                        end = roundup(end, sbi->segs_per_sec);
                }
@@ -2055,6 +2073,9 @@ next:
        }
        mutex_unlock(&dirty_i->seglist_lock);
 
+       if (!f2fs_block_unit_discard(sbi))
+               goto wakeup;
+
        /* send small discards */
        list_for_each_entry_safe(entry, this, head, list) {
                unsigned int cur_pos = 0, next_pos, len, total_len = 0;
@@ -2088,6 +2109,7 @@ skip:
                dcc->nr_discards -= total_len;
        }
 
+wakeup:
        wake_up_discard_thread(sbi, false);
 }
 
@@ -2107,6 +2129,11 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi)
                return -ENOMEM;
 
        dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY;
+       if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT)
+               dcc->discard_granularity = sbi->blocks_per_seg;
+       else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION)
+               dcc->discard_granularity = BLKS_PER_SEC(sbi);
+
        INIT_LIST_HEAD(&dcc->entry_list);
        for (i = 0; i < MAX_PLIST_NUM; i++)
                INIT_LIST_HEAD(&dcc->pend_list[i]);
@@ -2254,7 +2281,8 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                        del = 0;
                }
 
-               if (!f2fs_test_and_set_bit(offset, se->discard_map))
+               if (f2fs_block_unit_discard(sbi) &&
+                               !f2fs_test_and_set_bit(offset, se->discard_map))
                        sbi->discard_blks--;
 
                /*
@@ -2296,7 +2324,8 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                        }
                }
 
-               if (f2fs_test_and_clear_bit(offset, se->discard_map))
+               if (f2fs_block_unit_discard(sbi) &&
+                       f2fs_test_and_clear_bit(offset, se->discard_map))
                        sbi->discard_blks++;
        }
        if (!f2fs_test_bit(offset, se->ckpt_valid_map))
@@ -2321,6 +2350,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
                return;
 
        invalidate_mapping_pages(META_MAPPING(sbi), addr, addr);
+       f2fs_invalidate_compress_page(sbi, addr);
 
        /* add it into sit main buffer */
        down_write(&sit_i->sentry_lock);
@@ -3289,7 +3319,10 @@ static int __get_segment_type_6(struct f2fs_io_info *fio)
        if (fio->type == DATA) {
                struct inode *inode = fio->page->mapping->host;
 
-               if (is_cold_data(fio->page)) {
+               if (is_inode_flag_set(inode, FI_ALIGNED_WRITE))
+                       return CURSEG_COLD_DATA_PINNED;
+
+               if (page_private_gcing(fio->page)) {
                        if (fio->sbi->am.atgc_enabled &&
                                (fio->io_type == FS_DATA_IO) &&
                                (fio->sbi->gc_mode != GC_URGENT_HIGH))
@@ -3468,9 +3501,11 @@ static void do_write_page(struct f2fs_summary *sum, struct f2fs_io_info *fio)
 reallocate:
        f2fs_allocate_data_block(fio->sbi, fio->page, fio->old_blkaddr,
                        &fio->new_blkaddr, sum, type, fio);
-       if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO)
+       if (GET_SEGNO(fio->sbi, fio->old_blkaddr) != NULL_SEGNO) {
                invalidate_mapping_pages(META_MAPPING(fio->sbi),
                                        fio->old_blkaddr, fio->old_blkaddr);
+               f2fs_invalidate_compress_page(fio->sbi, fio->old_blkaddr);
+       }
 
        /* writeout dirty page into bdev */
        f2fs_submit_page_write(fio);
@@ -3556,7 +3591,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
                goto drop_bio;
        }
 
-       if (is_sbi_flag_set(sbi, SBI_NEED_FSCK) || f2fs_cp_error(sbi)) {
+       if (f2fs_cp_error(sbi)) {
                err = -EIO;
                goto drop_bio;
        }
@@ -3660,6 +3695,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
        if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) {
                invalidate_mapping_pages(META_MAPPING(sbi),
                                        old_blkaddr, old_blkaddr);
+               f2fs_invalidate_compress_page(sbi, old_blkaddr);
                if (!from_gc)
                        update_segment_mtime(sbi, old_blkaddr, 0);
                update_sit_entry(sbi, old_blkaddr, -1);
@@ -3919,7 +3955,7 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
        /* sanity check for summary blocks */
        if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES ||
                        sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) {
-               f2fs_err(sbi, "invalid journal entries nats %u sits %u\n",
+               f2fs_err(sbi, "invalid journal entries nats %u sits %u",
                         nats_in_cursum(nat_j), sits_in_cursum(sit_j));
                return -EINVAL;
        }
@@ -4274,6 +4310,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        unsigned int sit_segs, start;
        char *src_bitmap, *bitmap;
        unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size;
+       unsigned int discard_map = f2fs_block_unit_discard(sbi) ? 1 : 0;
 
        /* allocate memory for SIT information */
        sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
@@ -4296,9 +4333,9 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
                return -ENOMEM;
 
 #ifdef CONFIG_F2FS_CHECK_FS
-       bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 4;
+       bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (3 + discard_map);
 #else
-       bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 3;
+       bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * (2 + discard_map);
 #endif
        sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
        if (!sit_i->bitmap)
@@ -4318,8 +4355,10 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
                bitmap += SIT_VBLOCK_MAP_SIZE;
 #endif
 
-               sit_i->sentries[start].discard_map = bitmap;
-               bitmap += SIT_VBLOCK_MAP_SIZE;
+               if (discard_map) {
+                       sit_i->sentries[start].discard_map = bitmap;
+                       bitmap += SIT_VBLOCK_MAP_SIZE;
+               }
        }
 
        sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
@@ -4481,17 +4520,19 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
                        if (IS_NODESEG(se->type))
                                total_node_blocks += se->valid_blocks;
 
-                       /* build discard map only one time */
-                       if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
-                               memset(se->discard_map, 0xff,
-                                       SIT_VBLOCK_MAP_SIZE);
-                       } else {
-                               memcpy(se->discard_map,
-                                       se->cur_valid_map,
-                                       SIT_VBLOCK_MAP_SIZE);
-                               sbi->discard_blks +=
-                                       sbi->blocks_per_seg -
-                                       se->valid_blocks;
+                       if (f2fs_block_unit_discard(sbi)) {
+                               /* build discard map only one time */
+                               if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+                                       memset(se->discard_map, 0xff,
+                                               SIT_VBLOCK_MAP_SIZE);
+                               } else {
+                                       memcpy(se->discard_map,
+                                               se->cur_valid_map,
+                                               SIT_VBLOCK_MAP_SIZE);
+                                       sbi->discard_blks +=
+                                               sbi->blocks_per_seg -
+                                               se->valid_blocks;
+                               }
                        }
 
                        if (__is_large_section(sbi))
@@ -4527,13 +4568,15 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
                if (IS_NODESEG(se->type))
                        total_node_blocks += se->valid_blocks;
 
-               if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
-                       memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE);
-               } else {
-                       memcpy(se->discard_map, se->cur_valid_map,
-                                               SIT_VBLOCK_MAP_SIZE);
-                       sbi->discard_blks += old_valid_blocks;
-                       sbi->discard_blks -= se->valid_blocks;
+               if (f2fs_block_unit_discard(sbi)) {
+                       if (is_set_ckpt_flags(sbi, CP_TRIMMED_FLAG)) {
+                               memset(se->discard_map, 0xff, SIT_VBLOCK_MAP_SIZE);
+                       } else {
+                               memcpy(se->discard_map, se->cur_valid_map,
+                                                       SIT_VBLOCK_MAP_SIZE);
+                               sbi->discard_blks += old_valid_blocks;
+                               sbi->discard_blks -= se->valid_blocks;
+                       }
                }
 
                if (__is_large_section(sbi)) {
@@ -4682,6 +4725,10 @@ static int sanity_check_curseg(struct f2fs_sb_info *sbi)
                struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
                unsigned int blkofs = curseg->next_blkoff;
 
+               if (f2fs_sb_has_readonly(sbi) &&
+                       i != CURSEG_HOT_DATA && i != CURSEG_HOT_NODE)
+                       continue;
+
                sanity_check_seg_type(sbi, curseg->seg_type);
 
                if (f2fs_test_bit(blkofs, se->cur_valid_map))
@@ -5147,7 +5194,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
                sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC;
        sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
        sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
-       sm_info->min_seq_blocks = sbi->blocks_per_seg * sbi->segs_per_sec;
+       sm_info->min_seq_blocks = sbi->blocks_per_seg;
        sm_info->min_hot_blocks = DEF_MIN_HOT_BLOCKS;
        sm_info->min_ssr_sections = reserved_sections(sbi);