Merge tag 'trace-3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux...
[firefly-linux-kernel-4.4.55.git] / fs / f2fs / segment.c
index 923cb76fdc46e1e9f26b3a5014690e5c58d59fd0..42607a679923356c314d4b77399ff3e4b6cf8320 100644 (file)
@@ -178,17 +178,47 @@ void register_inmem_page(struct inode *inode, struct page *page)
 {
        struct f2fs_inode_info *fi = F2FS_I(inode);
        struct inmem_pages *new;
+       int err;
+
+       SetPagePrivate(page);
 
        new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS);
 
        /* add atomic page indices to the list */
        new->page = page;
        INIT_LIST_HEAD(&new->list);
-
+retry:
        /* increase reference count with clean state */
        mutex_lock(&fi->inmem_lock);
+       err = radix_tree_insert(&fi->inmem_root, page->index, new);
+       if (err == -EEXIST) {
+               mutex_unlock(&fi->inmem_lock);
+               kmem_cache_free(inmem_entry_slab, new);
+               return;
+       } else if (err) {
+               mutex_unlock(&fi->inmem_lock);
+               goto retry;
+       }
        get_page(page);
        list_add_tail(&new->list, &fi->inmem_pages);
+       inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
+       mutex_unlock(&fi->inmem_lock);
+}
+
+void invalidate_inmem_page(struct inode *inode, struct page *page)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       struct inmem_pages *cur;
+
+       mutex_lock(&fi->inmem_lock);
+       cur = radix_tree_lookup(&fi->inmem_root, page->index);
+       if (cur) {
+               radix_tree_delete(&fi->inmem_root, cur->page->index);
+               f2fs_put_page(cur->page, 0);
+               list_del(&cur->list);
+               kmem_cache_free(inmem_entry_slab, cur);
+               dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
+       }
        mutex_unlock(&fi->inmem_lock);
 }
 
@@ -203,7 +233,16 @@ void commit_inmem_pages(struct inode *inode, bool abort)
                .rw = WRITE_SYNC,
        };
 
-       f2fs_balance_fs(sbi);
+       /*
+        * The abort is true only when f2fs_evict_inode is called.
+        * Basically, the f2fs_evict_inode doesn't produce any data writes, so
+        * that we don't need to call f2fs_balance_fs.
+        * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this
+        * inode becomes free by iget_locked in f2fs_iget.
+        */
+       if (!abort)
+               f2fs_balance_fs(sbi);
+
        f2fs_lock_op(sbi);
 
        mutex_lock(&fi->inmem_lock);
@@ -216,9 +255,11 @@ void commit_inmem_pages(struct inode *inode, bool abort)
                        do_write_data_page(cur->page, &fio);
                        submit_bio = true;
                }
+               radix_tree_delete(&fi->inmem_root, cur->page->index);
                f2fs_put_page(cur->page, 1);
                list_del(&cur->list);
                kmem_cache_free(inmem_entry_slab, cur);
+               dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
        }
        if (submit_bio)
                f2fs_submit_merged_bio(sbi, DATA, WRITE);
@@ -248,7 +289,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
 {
        /* check the # of cached NAT entries and prefree segments */
        if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) ||
-                               excess_prefree_segs(sbi))
+                       excess_prefree_segs(sbi) ||
+                       available_free_memory(sbi, INO_ENTRIES))
                f2fs_sync_fs(sbi->sb, true);
 }
 
@@ -441,10 +483,33 @@ void discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
        }
 }
 
-static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+static void __add_discard_entry(struct f2fs_sb_info *sbi,
+               struct cp_control *cpc, unsigned int start, unsigned int end)
 {
        struct list_head *head = &SM_I(sbi)->discard_list;
-       struct discard_entry *new;
+       struct discard_entry *new, *last;
+
+       if (!list_empty(head)) {
+               last = list_last_entry(head, struct discard_entry, list);
+               if (START_BLOCK(sbi, cpc->trim_start) + start ==
+                                               last->blkaddr + last->len) {
+                       last->len += end - start;
+                       goto done;
+               }
+       }
+
+       new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
+       INIT_LIST_HEAD(&new->list);
+       new->blkaddr = START_BLOCK(sbi, cpc->trim_start) + start;
+       new->len = end - start;
+       list_add_tail(&new->list, head);
+done:
+       SM_I(sbi)->nr_discards += end - start;
+       cpc->trimmed += end - start;
+}
+
+static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+{
        int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
        int max_blocks = sbi->blocks_per_seg;
        struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start);
@@ -473,13 +538,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                }
                mutex_unlock(&dirty_i->seglist_lock);
 
-               new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
-               INIT_LIST_HEAD(&new->list);
-               new->blkaddr = START_BLOCK(sbi, cpc->trim_start);
-               new->len = sbi->blocks_per_seg;
-               list_add_tail(&new->list, head);
-               SM_I(sbi)->nr_discards += sbi->blocks_per_seg;
-               cpc->trimmed += sbi->blocks_per_seg;
+               __add_discard_entry(sbi, cpc, 0, sbi->blocks_per_seg);
                return;
        }
 
@@ -489,7 +548,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 
        /* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */
        for (i = 0; i < entries; i++)
-               dmap[i] = (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];
+               dmap[i] = ~(cur_map[i] | ckpt_map[i]);
 
        while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) {
                start = __find_rev_next_bit(dmap, max_blocks, end + 1);
@@ -501,14 +560,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                if (end - start < cpc->trim_minlen)
                        continue;
 
-               new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
-               INIT_LIST_HEAD(&new->list);
-               new->blkaddr = START_BLOCK(sbi, cpc->trim_start) + start;
-               new->len = end - start;
-               cpc->trimmed += end - start;
-
-               list_add_tail(&new->list, head);
-               SM_I(sbi)->nr_discards += end - start;
+               __add_discard_entry(sbi, cpc, start, end);
        }
 }
 
@@ -620,10 +672,10 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
 
        /* Update valid block bitmap */
        if (del > 0) {
-               if (f2fs_set_bit(offset, se->cur_valid_map))
+               if (f2fs_test_and_set_bit(offset, se->cur_valid_map))
                        f2fs_bug_on(sbi, 1);
        } else {
-               if (!f2fs_clear_bit(offset, se->cur_valid_map))
+               if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map))
                        f2fs_bug_on(sbi, 1);
        }
        if (!f2fs_test_bit(offset, se->ckpt_valid_map))
@@ -1004,6 +1056,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
                                                range->len < sbi->blocksize)
                return -EINVAL;
 
+       cpc.trimmed = 0;
        if (end <= MAIN_BLKADDR(sbi))
                goto out;
 
@@ -1015,10 +1068,11 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
        cpc.trim_start = start_segno;
        cpc.trim_end = end_segno;
        cpc.trim_minlen = range->minlen >> sbi->log_blocksize;
-       cpc.trimmed = 0;
 
        /* do checkpoint to issue discard commands safely */
+       mutex_lock(&sbi->gc_mutex);
        write_checkpoint(sbi, &cpc);
+       mutex_unlock(&sbi->gc_mutex);
 out:
        range->len = cpc.trimmed << sbi->log_blocksize;
        return 0;
@@ -1050,8 +1104,8 @@ static int __get_segment_type_4(struct page *page, enum page_type p_type)
                else
                        return CURSEG_COLD_DATA;
        } else {
-               if (IS_DNODE(page) && !is_cold_node(page))
-                       return CURSEG_HOT_NODE;
+               if (IS_DNODE(page) && is_cold_node(page))
+                       return CURSEG_WARM_NODE;
                else
                        return CURSEG_COLD_NODE;
        }
@@ -1524,17 +1578,7 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
 static struct page *get_current_sit_page(struct f2fs_sb_info *sbi,
                                        unsigned int segno)
 {
-       struct sit_info *sit_i = SIT_I(sbi);
-       unsigned int offset = SIT_BLOCK_OFFSET(segno);
-       block_t blk_addr = sit_i->sit_base_addr + offset;
-
-       check_seg_range(sbi, segno);
-
-       /* calculate sit block address */
-       if (f2fs_test_bit(offset, sit_i->sit_bitmap))
-               blk_addr += sit_i->sit_blocks;
-
-       return get_meta_page(sbi, blk_addr);
+       return get_meta_page(sbi, current_sit_addr(sbi, segno));
 }
 
 static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
@@ -1687,7 +1731,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
         * #2, flush sit entries to sit page.
         */
        list_for_each_entry_safe(ses, tmp, head, set_list) {
-               struct page *page;
+               struct page *page = NULL;
                struct f2fs_sit_block *raw_sit = NULL;
                unsigned int start_segno = ses->start_segno;
                unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
@@ -2200,7 +2244,7 @@ int __init create_segment_manager_caches(void)
                goto fail;
 
        sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set",
-                       sizeof(struct nat_entry_set));
+                       sizeof(struct sit_entry_set));
        if (!sit_entry_set_slab)
                goto destory_discard_entry;