Merge tag 'for-linus-5.8b-rc4-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / fs / f2fs / node.c
index ecbd6bd..03e24df 100644 (file)
@@ -1300,7 +1300,13 @@ static int read_node_page(struct page *page, int op_flags)
        }
 
        fio.new_blkaddr = fio.old_blkaddr = ni.blk_addr;
-       return f2fs_submit_page_bio(&fio);
+
+       err = f2fs_submit_page_bio(&fio);
+
+       if (!err)
+               f2fs_update_iostat(sbi, FS_NODE_READ_IO, F2FS_BLKSIZE);
+
+       return err;
 }
 
 /*
@@ -1514,8 +1520,15 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted,
 
        trace_f2fs_writepage(page, NODE);
 
-       if (unlikely(f2fs_cp_error(sbi)))
+       if (unlikely(f2fs_cp_error(sbi))) {
+               if (is_sbi_flag_set(sbi, SBI_IS_CLOSE)) {
+                       ClearPageUptodate(page);
+                       dec_page_count(sbi, F2FS_DIRTY_NODES);
+                       unlock_page(page);
+                       return 0;
+               }
                goto redirty_out;
+       }
 
        if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
                goto redirty_out;
@@ -1801,6 +1814,53 @@ static bool flush_dirty_inode(struct page *page)
        return true;
 }
 
+int f2fs_flush_inline_data(struct f2fs_sb_info *sbi)
+{
+       pgoff_t index = 0;
+       struct pagevec pvec;
+       int nr_pages;
+       int ret = 0;
+
+       pagevec_init(&pvec);
+
+       while ((nr_pages = pagevec_lookup_tag(&pvec,
+                       NODE_MAPPING(sbi), &index, PAGECACHE_TAG_DIRTY))) {
+               int i;
+
+               for (i = 0; i < nr_pages; i++) {
+                       struct page *page = pvec.pages[i];
+
+                       if (!IS_DNODE(page))
+                               continue;
+
+                       lock_page(page);
+
+                       if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
+continue_unlock:
+                               unlock_page(page);
+                               continue;
+                       }
+
+                       if (!PageDirty(page)) {
+                               /* someone wrote it for us */
+                               goto continue_unlock;
+                       }
+
+                       /* flush inline_data, if it's async context. */
+                       if (is_inline_node(page)) {
+                               clear_inline_node(page);
+                               unlock_page(page);
+                               flush_inline_data(sbi, ino_of_node(page));
+                               continue;
+                       }
+                       unlock_page(page);
+               }
+               pagevec_release(&pvec);
+               cond_resched();
+       }
+       return ret;
+}
+
 int f2fs_sync_node_pages(struct f2fs_sb_info *sbi,
                                struct writeback_control *wbc,
                                bool do_balance, enum iostat_type io_type)
@@ -1864,8 +1924,8 @@ continue_unlock:
                                goto continue_unlock;
                        }
 
-                       /* flush inline_data */
-                       if (is_inline_node(page)) {
+                       /* flush inline_data, if it's async context. */
+                       if (do_balance && is_inline_node(page)) {
                                clear_inline_node(page);
                                unlock_page(page);
                                flush_inline_data(sbi, ino_of_node(page));
@@ -2482,7 +2542,6 @@ void f2fs_alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
 int f2fs_try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
-       struct free_nid *i, *next;
        int nr = nr_shrink;
 
        if (nm_i->nid_cnt[FREE_NID] <= MAX_FREE_NIDS)
@@ -2491,17 +2550,23 @@ int f2fs_try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink)
        if (!mutex_trylock(&nm_i->build_lock))
                return 0;
 
-       spin_lock(&nm_i->nid_list_lock);
-       list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) {
-               if (nr_shrink <= 0 ||
-                               nm_i->nid_cnt[FREE_NID] <= MAX_FREE_NIDS)
-                       break;
+       while (nr_shrink && nm_i->nid_cnt[FREE_NID] > MAX_FREE_NIDS) {
+               struct free_nid *i, *next;
+               unsigned int batch = SHRINK_NID_BATCH_SIZE;
 
-               __remove_free_nid(sbi, i, FREE_NID);
-               kmem_cache_free(free_nid_slab, i);
-               nr_shrink--;
+               spin_lock(&nm_i->nid_list_lock);
+               list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) {
+                       if (!nr_shrink || !batch ||
+                               nm_i->nid_cnt[FREE_NID] <= MAX_FREE_NIDS)
+                               break;
+                       __remove_free_nid(sbi, i, FREE_NID);
+                       kmem_cache_free(free_nid_slab, i);
+                       nr_shrink--;
+                       batch--;
+               }
+               spin_unlock(&nm_i->nid_list_lock);
        }
-       spin_unlock(&nm_i->nid_list_lock);
+
        mutex_unlock(&nm_i->build_lock);
 
        return nr - nr_shrink;
@@ -2928,7 +2993,7 @@ static int __get_nat_bitmaps(struct f2fs_sb_info *sbi)
                return 0;
 
        nm_i->nat_bits_blocks = F2FS_BLK_ALIGN((nat_bits_bytes << 1) + 8);
-       nm_i->nat_bits = f2fs_kzalloc(sbi,
+       nm_i->nat_bits = f2fs_kvzalloc(sbi,
                        nm_i->nat_bits_blocks << F2FS_BLKSIZE_BITS, GFP_KERNEL);
        if (!nm_i->nat_bits)
                return -ENOMEM;
@@ -3061,9 +3126,9 @@ static int init_free_nid_cache(struct f2fs_sb_info *sbi)
        int i;
 
        nm_i->free_nid_bitmap =
-               f2fs_kzalloc(sbi, array_size(sizeof(unsigned char *),
-                                            nm_i->nat_blocks),
-                            GFP_KERNEL);
+               f2fs_kvzalloc(sbi, array_size(sizeof(unsigned char *),
+                                             nm_i->nat_blocks),
+                             GFP_KERNEL);
        if (!nm_i->free_nid_bitmap)
                return -ENOMEM;