Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[firefly-linux-kernel-4.4.55.git] / fs / f2fs / node.c
index 7dd63b794bfb5a04ae0d203c9ed2c8e739f0eb08..27d1a74dd6f34f9aed56f72942106e62e1a7c999 100644 (file)
@@ -159,7 +159,7 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
 
        head = radix_tree_lookup(&nm_i->nat_set_root, set);
        if (!head) {
-               head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_ATOMIC);
+               head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_NOFS);
 
                INIT_LIST_HEAD(&head->entry_list);
                INIT_LIST_HEAD(&head->set_list);
@@ -246,7 +246,7 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
 {
        struct nat_entry *new;
 
-       new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC);
+       new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_NOFS);
        f2fs_radix_tree_insert(&nm_i->nat_root, nid, new);
        memset(new, 0, sizeof(struct nat_entry));
        nat_set_nid(new, nid);
@@ -306,6 +306,10 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
        if (nat_get_blkaddr(e) != NEW_ADDR && new_blkaddr == NULL_ADDR) {
                unsigned char version = nat_get_version(e);
                nat_set_version(e, inc_node_version(version));
+
+               /* in order to reuse the nid */
+               if (nm_i->next_scan_nid > ni->nid)
+                       nm_i->next_scan_nid = ni->nid;
        }
 
        /* change address */
@@ -328,11 +332,11 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
 int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
+       int nr = nr_shrink;
 
-       if (available_free_memory(sbi, NAT_ENTRIES))
+       if (!down_write_trylock(&nm_i->nat_tree_lock))
                return 0;
 
-       down_write(&nm_i->nat_tree_lock);
        while (nr_shrink && !list_empty(&nm_i->nat_entries)) {
                struct nat_entry *ne;
                ne = list_first_entry(&nm_i->nat_entries,
@@ -341,7 +345,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
                nr_shrink--;
        }
        up_write(&nm_i->nat_tree_lock);
-       return nr_shrink;
+       return nr - nr_shrink;
 }
 
 /*
@@ -898,17 +902,20 @@ int truncate_xattr_node(struct inode *inode, struct page *page)
  * Caller should grab and release a rwsem by calling f2fs_lock_op() and
  * f2fs_unlock_op().
  */
-void remove_inode_page(struct inode *inode)
+int remove_inode_page(struct inode *inode)
 {
        struct dnode_of_data dn;
+       int err;
 
        set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino);
-       if (get_dnode_of_data(&dn, 0, LOOKUP_NODE))
-               return;
+       err = get_dnode_of_data(&dn, 0, LOOKUP_NODE);
+       if (err)
+               return err;
 
-       if (truncate_xattr_node(inode, dn.inode_page)) {
+       err = truncate_xattr_node(inode, dn.inode_page);
+       if (err) {
                f2fs_put_dnode(&dn);
-               return;
+               return err;
        }
 
        /* remove potential inline_data blocks */
@@ -922,6 +929,7 @@ void remove_inode_page(struct inode *inode)
 
        /* will put inode & node pages */
        truncate_node(&dn);
+       return 0;
 }
 
 struct page *new_inode_page(struct inode *inode)
@@ -991,8 +999,7 @@ fail:
 /*
  * Caller should do after getting the following values.
  * 0: f2fs_put_page(page, 0)
- * LOCKED_PAGE: f2fs_put_page(page, 1)
- * error: nothing
+ * LOCKED_PAGE or error: f2fs_put_page(page, 1)
  */
 static int read_node_page(struct page *page, int rw)
 {
@@ -1010,7 +1017,6 @@ static int read_node_page(struct page *page, int rw)
 
        if (unlikely(ni.blk_addr == NULL_ADDR)) {
                ClearPageUptodate(page);
-               f2fs_put_page(page, 1);
                return -ENOENT;
        }
 
@@ -1041,10 +1047,7 @@ void ra_node_page(struct f2fs_sb_info *sbi, nid_t nid)
                return;
 
        err = read_node_page(apage, READA);
-       if (err == 0)
-               f2fs_put_page(apage, 0);
-       else if (err == LOCKED_PAGE)
-               f2fs_put_page(apage, 1);
+       f2fs_put_page(apage, err ? 1 : 0);
 }
 
 struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
@@ -1057,10 +1060,12 @@ repeat:
                return ERR_PTR(-ENOMEM);
 
        err = read_node_page(page, READ_SYNC);
-       if (err < 0)
+       if (err < 0) {
+               f2fs_put_page(page, 1);
                return ERR_PTR(err);
-       else if (err != LOCKED_PAGE)
+       } else if (err != LOCKED_PAGE) {
                lock_page(page);
+       }
 
        if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) {
                ClearPageUptodate(page);
@@ -1096,10 +1101,12 @@ repeat:
                return ERR_PTR(-ENOMEM);
 
        err = read_node_page(page, READ_SYNC);
-       if (err < 0)
+       if (err < 0) {
+               f2fs_put_page(page, 1);
                return ERR_PTR(err);
-       else if (err == LOCKED_PAGE)
+       } else if (err == LOCKED_PAGE) {
                goto page_hit;
+       }
 
        blk_start_plug(&plug);
 
@@ -1533,7 +1540,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
                if (unlikely(nid >= nm_i->max_nid))
                        nid = 0;
 
-               if (i++ == FREE_NID_PAGES)
+               if (++i >= FREE_NID_PAGES)
                        break;
        }
 
@@ -1570,6 +1577,8 @@ retry:
 
        /* We should not use stale free nids created by build_free_nids */
        if (nm_i->fcnt && !on_build_free_nids(nm_i)) {
+               struct node_info ni;
+
                f2fs_bug_on(sbi, list_empty(&nm_i->free_nid_list));
                list_for_each_entry(i, &nm_i->free_nid_list, list)
                        if (i->state == NID_NEW)
@@ -1580,6 +1589,13 @@ retry:
                i->state = NID_ALLOC;
                nm_i->fcnt--;
                spin_unlock(&nm_i->free_nid_list_lock);
+
+               /* check nid is allocated already */
+               get_node_info(sbi, *nid, &ni);
+               if (ni.blk_addr != NULL_ADDR) {
+                       alloc_nid_done(sbi, *nid);
+                       goto retry;
+               }
                return true;
        }
        spin_unlock(&nm_i->free_nid_list_lock);
@@ -1636,6 +1652,32 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
                kmem_cache_free(free_nid_slab, i);
 }
 
+int 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 (!mutex_trylock(&nm_i->build_lock))
+               return 0;
+
+       spin_lock(&nm_i->free_nid_list_lock);
+       list_for_each_entry_safe(i, next, &nm_i->free_nid_list, list) {
+               if (nr_shrink <= 0 || nm_i->fcnt <= NAT_ENTRY_PER_BLOCK)
+                       break;
+               if (i->state == NID_ALLOC)
+                       continue;
+               __del_from_free_nid_list(nm_i, i);
+               kmem_cache_free(free_nid_slab, i);
+               nm_i->fcnt--;
+               nr_shrink--;
+       }
+       spin_unlock(&nm_i->free_nid_list_lock);
+       mutex_unlock(&nm_i->build_lock);
+
+       return nr - nr_shrink;
+}
+
 void recover_inline_xattr(struct inode *inode, struct page *page)
 {
        void *src_addr, *dst_addr;