]> git.karo-electronics.de Git - linux-beck.git/blobdiff - fs/f2fs/node.c
f2fs: return -EIO when node id is not matched
[linux-beck.git] / fs / f2fs / node.c
index c618fad3e6c39565f20b7a58eecc5434a9e3aa2a..065cd99cc72329bd5b2faae2287f09e5602f9905 100644 (file)
 static struct kmem_cache *nat_entry_slab;
 static struct kmem_cache *free_nid_slab;
 
+static inline bool available_free_memory(struct f2fs_nm_info *nm_i, int type)
+{
+       struct sysinfo val;
+       unsigned long mem_size = 0;
+
+       si_meminfo(&val);
+       if (type == FREE_NIDS)
+               mem_size = nm_i->fcnt * sizeof(struct free_nid);
+       else if (type == NAT_ENTRIES)
+               mem_size += nm_i->nat_cnt * sizeof(struct nat_entry);
+       mem_size >>= 12;
+
+       /* give 50:50 memory for free nids and nat caches respectively */
+       return (mem_size < ((val.totalram * nm_i->ram_thresh) >> 11));
+}
+
 static void clear_node_page_dirty(struct page *page)
 {
        struct address_space *mapping = page->mapping;
@@ -117,6 +133,20 @@ int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
        return is_cp;
 }
 
+bool fsync_mark_done(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct nat_entry *e;
+       bool fsync_done = false;
+
+       read_lock(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, nid);
+       if (e)
+               fsync_done = e->fsync_done;
+       read_unlock(&nm_i->nat_tree_lock);
+       return fsync_done;
+}
+
 static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
 {
        struct nat_entry *new;
@@ -157,7 +187,7 @@ retry:
 }
 
 static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
-                       block_t new_blkaddr)
+                       block_t new_blkaddr, bool fsync_done)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct nat_entry *e;
@@ -201,6 +231,11 @@ retry:
        /* change address */
        nat_set_blkaddr(e, new_blkaddr);
        __set_nat_cache_dirty(nm_i, e);
+
+       /* update fsync_mark if its inode nat entry is still alive */
+       e = __lookup_nat_cache(nm_i, ni->ino);
+       if (e)
+               e->fsync_done = fsync_done;
        write_unlock(&nm_i->nat_tree_lock);
 }
 
@@ -208,7 +243,7 @@ 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 <= NM_WOUT_THRESHOLD)
+       if (available_free_memory(nm_i, NAT_ENTRIES))
                return 0;
 
        write_lock(&nm_i->nat_tree_lock);
@@ -467,7 +502,7 @@ static void truncate_node(struct dnode_of_data *dn)
        /* Deallocate node address */
        invalidate_blocks(sbi, ni.blk_addr);
        dec_valid_node_count(sbi, dn->inode);
-       set_node_addr(sbi, &ni, NULL_ADDR);
+       set_node_addr(sbi, &ni, NULL_ADDR, false);
 
        if (dn->nid == dn->inode->i_ino) {
                remove_orphan_inode(sbi, dn->nid);
@@ -725,7 +760,7 @@ skip_partial:
                                f2fs_put_page(page, 1);
                                goto restart;
                        }
-                       wait_on_page_writeback(page);
+                       f2fs_wait_on_page_writeback(page, NODE);
                        ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
                        set_page_dirty(page);
                        unlock_page(page);
@@ -814,7 +849,8 @@ struct page *new_node_page(struct dnode_of_data *dn,
        if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)))
                return ERR_PTR(-EPERM);
 
-       page = grab_cache_page(NODE_MAPPING(sbi), dn->nid);
+       page = grab_cache_page_write_begin(NODE_MAPPING(sbi),
+                                       dn->nid, AOP_FLAG_NOFS);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -829,14 +865,14 @@ struct page *new_node_page(struct dnode_of_data *dn,
        f2fs_bug_on(old_ni.blk_addr != NULL_ADDR);
        new_ni = old_ni;
        new_ni.ino = dn->inode->i_ino;
-       set_node_addr(sbi, &new_ni, NEW_ADDR);
+       set_node_addr(sbi, &new_ni, NEW_ADDR, false);
 
        fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
        set_cold_node(dn->inode, page);
        SetPageUptodate(page);
        set_page_dirty(page);
 
-       if (ofs == XATTR_NODE_OFFSET)
+       if (f2fs_has_xattr_block(ofs))
                F2FS_I(dn->inode)->i_xattr_nid = dn->nid;
 
        dn->node_page = page;
@@ -910,7 +946,8 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
        struct page *page;
        int err;
 repeat:
-       page = grab_cache_page(NODE_MAPPING(sbi), nid);
+       page = grab_cache_page_write_begin(NODE_MAPPING(sbi),
+                                       nid, AOP_FLAG_NOFS);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -921,7 +958,7 @@ repeat:
                goto got_it;
 
        lock_page(page);
-       if (unlikely(!PageUptodate(page))) {
+       if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) {
                f2fs_put_page(page, 1);
                return ERR_PTR(-EIO);
        }
@@ -930,7 +967,6 @@ repeat:
                goto repeat;
        }
 got_it:
-       f2fs_bug_on(nid != nid_of_node(page));
        mark_page_accessed(page);
        return page;
 }
@@ -1130,7 +1166,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
                                continue;
 
                        if (ino && ino_of_node(page) == ino) {
-                               wait_on_page_writeback(page);
+                               f2fs_wait_on_page_writeback(page, NODE);
                                if (TestClearPageError(page))
                                        ret = -EIO;
                        }
@@ -1163,7 +1199,7 @@ static int f2fs_write_node_page(struct page *page,
        if (unlikely(sbi->por_doing))
                goto redirty_out;
 
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, NODE);
 
        /* get old block addr of this node page */
        nid = nid_of_node(page);
@@ -1184,7 +1220,7 @@ static int f2fs_write_node_page(struct page *page,
        mutex_lock(&sbi->node_write);
        set_page_writeback(page);
        write_node_page(sbi, page, &fio, nid, ni.blk_addr, &new_addr);
-       set_node_addr(sbi, &ni, new_addr);
+       set_node_addr(sbi, &ni, new_addr, is_fsync_dnode(page));
        dec_page_count(sbi, F2FS_DIRTY_NODES);
        mutex_unlock(&sbi->node_write);
        unlock_page(page);
@@ -1198,31 +1234,27 @@ redirty_out:
        return AOP_WRITEPAGE_ACTIVATE;
 }
 
-/*
- * It is very important to gather dirty pages and write at once, so that we can
- * submit a big bio without interfering other data writes.
- * Be default, 512 pages (2MB) * 3 node types, is more reasonable.
- */
-#define COLLECT_DIRTY_NODES    1536
 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);
-       long nr_to_write = wbc->nr_to_write;
+       long diff;
 
        /* balancing f2fs's metadata in background */
        f2fs_balance_fs_bg(sbi);
 
        /* collect a number of dirty node pages and write together */
-       if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
-               return 0;
+       if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE))
+               goto skip_write;
 
-       /* if mounting is failed, skip writing node pages */
-       wbc->nr_to_write = 3 * max_hw_blocks(sbi);
+       diff = nr_pages_to_write(sbi, NODE, wbc);
        wbc->sync_mode = WB_SYNC_NONE;
        sync_node_pages(sbi, 0, wbc);
-       wbc->nr_to_write = nr_to_write - (3 * max_hw_blocks(sbi) -
-                                               wbc->nr_to_write);
+       wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
+       return 0;
+
+skip_write:
+       wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_NODES);
        return 0;
 }
 
@@ -1290,7 +1322,7 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
        struct nat_entry *ne;
        bool allocated = false;
 
-       if (nm_i->fcnt > 2 * MAX_FREE_NIDS)
+       if (!available_free_memory(nm_i, FREE_NIDS))
                return -1;
 
        /* 0 nid should not be used */
@@ -1475,7 +1507,7 @@ 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(nm_i, nid);
        f2fs_bug_on(!i || i->state != NID_ALLOC);
-       if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
+       if (!available_free_memory(nm_i, FREE_NIDS)) {
                __del_from_free_nid_list(nm_i, i);
        } else {
                i->state = NID_NEW;
@@ -1489,7 +1521,7 @@ void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
                block_t new_blkaddr)
 {
        rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr);
-       set_node_addr(sbi, ni, new_blkaddr);
+       set_node_addr(sbi, ni, new_blkaddr, false);
        clear_node_page_dirty(page);
 }
 
@@ -1533,7 +1565,7 @@ bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
 
        recover_inline_xattr(inode, page);
 
-       if (ofs_of_node(page) != XATTR_NODE_OFFSET)
+       if (!f2fs_has_xattr_block(ofs_of_node(page)))
                return false;
 
        /* 1: invalidate the previous xattr nid */
@@ -1545,7 +1577,7 @@ bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
        f2fs_bug_on(ni.blk_addr == NULL_ADDR);
        invalidate_blocks(sbi, ni.blk_addr);
        dec_valid_node_count(sbi, inode);
-       set_node_addr(sbi, &ni, NULL_ADDR);
+       set_node_addr(sbi, &ni, NULL_ADDR, false);
 
 recover_xnid:
        /* 2: allocate new xattr nid */
@@ -1555,12 +1587,12 @@ recover_xnid:
        remove_free_nid(NM_I(sbi), new_xnid);
        get_node_info(sbi, new_xnid, &ni);
        ni.ino = inode->i_ino;
-       set_node_addr(sbi, &ni, NEW_ADDR);
+       set_node_addr(sbi, &ni, NEW_ADDR, false);
        F2FS_I(inode)->i_xattr_nid = new_xnid;
 
        /* 3: update xattr blkaddr */
        refresh_sit_entry(sbi, NEW_ADDR, blkaddr);
-       set_node_addr(sbi, &ni, blkaddr);
+       set_node_addr(sbi, &ni, blkaddr, false);
 
        update_inode_page(inode);
        return true;
@@ -1598,7 +1630,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
 
        if (unlikely(!inc_valid_node_count(sbi, NULL)))
                WARN_ON(1);
-       set_node_addr(sbi, &new_ni, NEW_ADDR);
+       set_node_addr(sbi, &new_ni, NEW_ADDR, false);
        inc_valid_inode_count(sbi);
        f2fs_put_page(ipage, 1);
        return 0;
@@ -1816,9 +1848,6 @@ flush_now:
        if (!flushed)
                mutex_unlock(&curseg->curseg_mutex);
        f2fs_put_page(page, 1);
-
-       /* 2) shrink nat caches if necessary */
-       try_to_free_nats(sbi, nm_i->nat_cnt - NM_WOUT_THRESHOLD);
 }
 
 static int init_node_manager(struct f2fs_sb_info *sbi)
@@ -1838,6 +1867,7 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
        nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks - 3;
        nm_i->fcnt = 0;
        nm_i->nat_cnt = 0;
+       nm_i->ram_thresh = DEF_RAM_THRESHOLD;
 
        INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC);
        INIT_LIST_HEAD(&nm_i->free_nid_list);