]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/f2fs/node.c
Merge remote-tracking branch 'regulator/fix/doc' into regulator-linus
[karo-tx-linux.git] / fs / f2fs / node.c
index aede91071f715e4e1418cfd83752aeb0d2f81b66..3df43b4efd89e96e971263e61369dee5d3e39b87 100644 (file)
@@ -244,7 +244,7 @@ static int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
 
-       if (nm_i->nat_cnt < 2 * NM_WOUT_THRESHOLD)
+       if (nm_i->nat_cnt <= NM_WOUT_THRESHOLD)
                return 0;
 
        write_lock(&nm_i->nat_tree_lock);
@@ -674,6 +674,7 @@ fail:
 int truncate_inode_blocks(struct inode *inode, pgoff_t from)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       struct address_space *node_mapping = sbi->node_inode->i_mapping;
        int err = 0, cont = 1;
        int level, offset[4], noffset[4];
        unsigned int nofs = 0;
@@ -684,7 +685,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
        trace_f2fs_truncate_inode_blocks_enter(inode, from);
 
        level = get_node_path(from, offset, noffset);
-
+restart:
        page = get_node_page(sbi, inode->i_ino);
        if (IS_ERR(page)) {
                trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page));
@@ -748,6 +749,10 @@ skip_partial:
                if (offset[1] == 0 &&
                                rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK]) {
                        lock_page(page);
+                       if (page->mapping != node_mapping) {
+                               f2fs_put_page(page, 1);
+                               goto restart;
+                       }
                        wait_on_page_writeback(page);
                        rn->i.i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
                        set_page_dirty(page);
@@ -916,7 +921,7 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
        struct address_space *mapping = sbi->node_inode->i_mapping;
        struct page *page;
        int err;
-
+repeat:
        page = grab_cache_page(mapping, nid);
        if (!page)
                return ERR_PTR(-ENOMEM);
@@ -932,6 +937,10 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
                f2fs_put_page(page, 1);
                return ERR_PTR(-EIO);
        }
+       if (page->mapping != mapping) {
+               f2fs_put_page(page, 1);
+               goto repeat;
+       }
 got_it:
        BUG_ON(nid != nid_of_node(page));
        mark_page_accessed(page);
@@ -955,7 +964,7 @@ struct page *get_node_page_ra(struct page *parent, int start)
        nid = get_nid(parent, start, false);
        if (!nid)
                return ERR_PTR(-ENOENT);
-
+repeat:
        page = grab_cache_page(mapping, nid);
        if (!page)
                return ERR_PTR(-ENOMEM);
@@ -981,7 +990,10 @@ struct page *get_node_page_ra(struct page *parent, int start)
        blk_finish_plug(&plug);
 
        lock_page(page);
-
+       if (page->mapping != mapping) {
+               f2fs_put_page(page, 1);
+               goto repeat;
+       }
 page_hit:
        if (!PageUptodate(page)) {
                f2fs_put_page(page, 1);
@@ -1159,7 +1171,6 @@ static int f2fs_write_node_pages(struct address_space *mapping,
                            struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
-       struct block_device *bdev = sbi->sb->s_bdev;
        long nr_to_write = wbc->nr_to_write;
 
        /* First check balancing cached NAT entries */
@@ -1173,10 +1184,9 @@ static int f2fs_write_node_pages(struct address_space *mapping,
                return 0;
 
        /* if mounting is failed, skip writing node pages */
-       wbc->nr_to_write = bio_get_nr_vecs(bdev);
+       wbc->nr_to_write = max_hw_blocks(sbi);
        sync_node_pages(sbi, 0, wbc);
-       wbc->nr_to_write = nr_to_write -
-               (bio_get_nr_vecs(bdev) - wbc->nr_to_write);
+       wbc->nr_to_write = nr_to_write - (max_hw_blocks(sbi) - wbc->nr_to_write);
        return 0;
 }
 
@@ -1239,16 +1249,30 @@ static void __del_from_free_nid_list(struct free_nid *i)
        kmem_cache_free(free_nid_slab, i);
 }
 
-static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
+static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
 {
        struct free_nid *i;
+       struct nat_entry *ne;
+       bool allocated = false;
 
        if (nm_i->fcnt > 2 * MAX_FREE_NIDS)
-               return 0;
+               return -1;
 
        /* 0 nid should not be used */
        if (nid == 0)
                return 0;
+
+       if (!build)
+               goto retry;
+
+       /* do not add allocated nids */
+       read_lock(&nm_i->nat_tree_lock);
+       ne = __lookup_nat_cache(nm_i, nid);
+       if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
+               allocated = true;
+       read_unlock(&nm_i->nat_tree_lock);
+       if (allocated)
+               return 0;
 retry:
        i = kmem_cache_alloc(free_nid_slab, GFP_NOFS);
        if (!i) {
@@ -1282,34 +1306,35 @@ static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
        spin_unlock(&nm_i->free_nid_list_lock);
 }
 
-static int scan_nat_page(struct f2fs_nm_info *nm_i,
+static void scan_nat_page(struct f2fs_nm_info *nm_i,
                        struct page *nat_page, nid_t start_nid)
 {
        struct f2fs_nat_block *nat_blk = page_address(nat_page);
        block_t blk_addr;
-       int fcnt = 0;
        int i;
 
        i = start_nid % NAT_ENTRY_PER_BLOCK;
 
        for (; i < NAT_ENTRY_PER_BLOCK; i++, start_nid++) {
+
                if (start_nid >= nm_i->max_nid)
                        break;
-               blk_addr  = le32_to_cpu(nat_blk->entries[i].block_addr);
+
+               blk_addr = le32_to_cpu(nat_blk->entries[i].block_addr);
                BUG_ON(blk_addr == NEW_ADDR);
-               if (blk_addr == NULL_ADDR)
-                       fcnt += add_free_nid(nm_i, start_nid);
+               if (blk_addr == NULL_ADDR) {
+                       if (add_free_nid(nm_i, start_nid, true) < 0)
+                               break;
+               }
        }
-       return fcnt;
 }
 
 static void build_free_nids(struct f2fs_sb_info *sbi)
 {
-       struct free_nid *fnid, *next_fnid;
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
        struct f2fs_summary_block *sum = curseg->sum_blk;
-       int fcnt = 0, i = 0;
+       int i = 0;
        nid_t nid = nm_i->next_scan_nid;
 
        /* Enough entries */
@@ -1322,7 +1347,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
        while (1) {
                struct page *page = get_current_nat_page(sbi, nid);
 
-               fcnt += scan_nat_page(nm_i, page, nid);
+               scan_nat_page(nm_i, page, nid);
                f2fs_put_page(page, 1);
 
                nid += (NAT_ENTRY_PER_BLOCK - (nid % NAT_ENTRY_PER_BLOCK));
@@ -1342,22 +1367,11 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
                block_t addr = le32_to_cpu(nat_in_journal(sum, i).block_addr);
                nid = le32_to_cpu(nid_in_journal(sum, i));
                if (addr == NULL_ADDR)
-                       add_free_nid(nm_i, nid);
+                       add_free_nid(nm_i, nid, true);
                else
                        remove_free_nid(nm_i, nid);
        }
        mutex_unlock(&curseg->curseg_mutex);
-
-       /* remove the free nids from current allocated nids */
-       list_for_each_entry_safe(fnid, next_fnid, &nm_i->free_nid_list, list) {
-               struct nat_entry *ne;
-
-               read_lock(&nm_i->nat_tree_lock);
-               ne = __lookup_nat_cache(nm_i, fnid->nid);
-               if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
-                       remove_free_nid(nm_i, fnid->nid);
-               read_unlock(&nm_i->nat_tree_lock);
-       }
 }
 
 /*
@@ -1429,8 +1443,12 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
        spin_lock(&nm_i->free_nid_list_lock);
        i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
        BUG_ON(!i || i->state != NID_ALLOC);
-       i->state = NID_NEW;
-       nm_i->fcnt++;
+       if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
+               __del_from_free_nid_list(i);
+       } else {
+               i->state = NID_NEW;
+               nm_i->fcnt++;
+       }
        spin_unlock(&nm_i->free_nid_list_lock);
 }
 
@@ -1643,7 +1661,7 @@ flush_now:
                }
 
                if (nat_get_blkaddr(ne) == NULL_ADDR &&
-                                       !add_free_nid(NM_I(sbi), nid)) {
+                               add_free_nid(NM_I(sbi), nid, false) <= 0) {
                        write_lock(&nm_i->nat_tree_lock);
                        __del_from_nat_cache(nm_i, ne);
                        write_unlock(&nm_i->nat_tree_lock);