]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/f2fs/checkpoint.c
f2fs: introduce NODE_MAPPING for code consistency
[karo-tx-linux.git] / fs / f2fs / checkpoint.c
index 5716e5eb4e8ec7ab2c63c69079259e2c5d772918..293d0486a40f7e8560b25d012a7a2398ef4e955c 100644 (file)
@@ -30,7 +30,7 @@ static struct kmem_cache *inode_entry_slab;
  */
 struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
 {
-       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       struct address_space *mapping = META_MAPPING(sbi);
        struct page *page = NULL;
 repeat:
        page = grab_cache_page(mapping, index);
@@ -50,7 +50,7 @@ repeat:
  */
 struct page *get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
 {
-       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       struct address_space *mapping = META_MAPPING(sbi);
        struct page *page;
 repeat:
        page = grab_cache_page(mapping, index);
@@ -61,11 +61,12 @@ repeat:
        if (PageUptodate(page))
                goto out;
 
-       if (f2fs_readpage(sbi, page, index, READ_SYNC))
+       if (f2fs_submit_page_bio(sbi, page, index,
+                               READ_SYNC | REQ_META | REQ_PRIO))
                goto repeat;
 
        lock_page(page);
-       if (page->mapping != mapping) {
+       if (unlikely(page->mapping != mapping)) {
                f2fs_put_page(page, 1);
                goto repeat;
        }
@@ -81,13 +82,12 @@ static int f2fs_write_meta_page(struct page *page,
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
 
        /* Should not write any meta pages, if any IO error was occurred */
-       if (wbc->for_reclaim || sbi->por_doing ||
-                       is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)) {
-               dec_page_count(sbi, F2FS_DIRTY_META);
-               wbc->pages_skipped++;
-               set_page_dirty(page);
-               return AOP_WRITEPAGE_ACTIVATE;
-       }
+       if (unlikely(sbi->por_doing ||
+                       is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
+               goto redirty_out;
+
+       if (wbc->for_reclaim)
+               goto redirty_out;
 
        wait_on_page_writeback(page);
 
@@ -95,24 +95,31 @@ static int f2fs_write_meta_page(struct page *page,
        dec_page_count(sbi, F2FS_DIRTY_META);
        unlock_page(page);
        return 0;
+
+redirty_out:
+       dec_page_count(sbi, F2FS_DIRTY_META);
+       wbc->pages_skipped++;
+       set_page_dirty(page);
+       return AOP_WRITEPAGE_ACTIVATE;
 }
 
 static int f2fs_write_meta_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;
+       int nrpages = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
        long written;
 
        if (wbc->for_kupdate)
                return 0;
 
-       if (get_pages(sbi, F2FS_DIRTY_META) == 0)
+       /* collect a number of dirty meta pages and write together */
+       if (get_pages(sbi, F2FS_DIRTY_META) < nrpages)
                return 0;
 
        /* if mounting is failed, skip writing node pages */
        mutex_lock(&sbi->cp_mutex);
-       written = sync_meta_pages(sbi, META, bio_get_nr_vecs(bdev));
+       written = sync_meta_pages(sbi, META, nrpages);
        mutex_unlock(&sbi->cp_mutex);
        wbc->nr_to_write -= written;
        return 0;
@@ -121,7 +128,7 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
 long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
                                                long nr_to_write)
 {
-       struct address_space *mapping = sbi->meta_inode->i_mapping;
+       struct address_space *mapping = META_MAPPING(sbi);
        pgoff_t index = 0, end = LONG_MAX;
        struct pagevec pvec;
        long nwritten = 0;
@@ -136,7 +143,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
                nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,
                                PAGECACHE_TAG_DIRTY,
                                min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1);
-               if (nr_pages == 0)
+               if (unlikely(nr_pages == 0))
                        break;
 
                for (i = 0; i < nr_pages; i++) {
@@ -149,7 +156,8 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
                                unlock_page(page);
                                break;
                        }
-                       if (nwritten++ >= nr_to_write)
+                       nwritten++;
+                       if (unlikely(nwritten >= nr_to_write))
                                break;
                }
                pagevec_release(&pvec);
@@ -157,7 +165,7 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
        }
 
        if (nwritten)
-               f2fs_submit_bio(sbi, type, nr_to_write == LONG_MAX);
+               f2fs_submit_merged_bio(sbi, type, WRITE);
 
        return nwritten;
 }
@@ -186,31 +194,24 @@ const struct address_space_operations f2fs_meta_aops = {
 
 int acquire_orphan_inode(struct f2fs_sb_info *sbi)
 {
-       unsigned int max_orphans;
        int err = 0;
 
-       /*
-        * considering 512 blocks in a segment 5 blocks are needed for cp
-        * and log segment summaries. Remaining blocks are used to keep
-        * orphan entries with the limitation one reserved segment
-        * for cp pack we can have max 1020*507 orphan entries
-        */
-       max_orphans = (sbi->blocks_per_seg - 5) * F2FS_ORPHANS_PER_BLOCK;
-       mutex_lock(&sbi->orphan_inode_mutex);
-       if (sbi->n_orphans >= max_orphans)
+       spin_lock(&sbi->orphan_inode_lock);
+       if (unlikely(sbi->n_orphans >= sbi->max_orphans))
                err = -ENOSPC;
        else
                sbi->n_orphans++;
-       mutex_unlock(&sbi->orphan_inode_mutex);
+       spin_unlock(&sbi->orphan_inode_lock);
+
        return err;
 }
 
 void release_orphan_inode(struct f2fs_sb_info *sbi)
 {
-       mutex_lock(&sbi->orphan_inode_mutex);
+       spin_lock(&sbi->orphan_inode_lock);
        f2fs_bug_on(sbi->n_orphans == 0);
        sbi->n_orphans--;
-       mutex_unlock(&sbi->orphan_inode_mutex);
+       spin_unlock(&sbi->orphan_inode_lock);
 }
 
 void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
@@ -218,27 +219,30 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
        struct list_head *head, *this;
        struct orphan_inode_entry *new = NULL, *orphan = NULL;
 
-       mutex_lock(&sbi->orphan_inode_mutex);
+       new = f2fs_kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
+       new->ino = ino;
+
+       spin_lock(&sbi->orphan_inode_lock);
        head = &sbi->orphan_inode_list;
        list_for_each(this, head) {
                orphan = list_entry(this, struct orphan_inode_entry, list);
-               if (orphan->ino == ino)
-                       goto out;
+               if (orphan->ino == ino) {
+                       spin_unlock(&sbi->orphan_inode_lock);
+                       kmem_cache_free(orphan_entry_slab, new);
+                       return;
+               }
+
                if (orphan->ino > ino)
                        break;
                orphan = NULL;
        }
 
-       new = f2fs_kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
-       new->ino = ino;
-
        /* add new_oentry into list which is sorted by inode number */
        if (orphan)
                list_add(&new->list, this->prev);
        else
                list_add_tail(&new->list, head);
-out:
-       mutex_unlock(&sbi->orphan_inode_mutex);
+       spin_unlock(&sbi->orphan_inode_lock);
 }
 
 void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
@@ -246,7 +250,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
        struct list_head *head;
        struct orphan_inode_entry *orphan;
 
-       mutex_lock(&sbi->orphan_inode_mutex);
+       spin_lock(&sbi->orphan_inode_lock);
        head = &sbi->orphan_inode_list;
        list_for_each_entry(orphan, head, list) {
                if (orphan->ino == ino) {
@@ -257,7 +261,7 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
                        break;
                }
        }
-       mutex_unlock(&sbi->orphan_inode_mutex);
+       spin_unlock(&sbi->orphan_inode_lock);
 }
 
 static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
@@ -270,12 +274,12 @@ static void recover_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
        iput(inode);
 }
 
-int recover_orphan_inodes(struct f2fs_sb_info *sbi)
+void recover_orphan_inodes(struct f2fs_sb_info *sbi)
 {
        block_t start_blk, orphan_blkaddr, i, j;
 
        if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG))
-               return 0;
+               return;
 
        sbi->por_doing = true;
        start_blk = __start_cp_addr(sbi) + 1;
@@ -295,29 +299,39 @@ int recover_orphan_inodes(struct f2fs_sb_info *sbi)
        /* clear Orphan Flag */
        clear_ckpt_flags(F2FS_CKPT(sbi), CP_ORPHAN_PRESENT_FLAG);
        sbi->por_doing = false;
-       return 0;
+       return;
 }
 
 static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
 {
-       struct list_head *head, *this, *next;
+       struct list_head *head;
        struct f2fs_orphan_block *orphan_blk = NULL;
-       struct page *page = NULL;
        unsigned int nentries = 0;
-       unsigned short index = 1;
-       unsigned short orphan_blocks;
-
-       orphan_blocks = (unsigned short)((sbi->n_orphans +
+       unsigned short index;
+       unsigned short orphan_blocks = (unsigned short)((sbi->n_orphans +
                (F2FS_ORPHANS_PER_BLOCK - 1)) / F2FS_ORPHANS_PER_BLOCK);
+       struct page *page = NULL;
+       struct orphan_inode_entry *orphan = NULL;
+
+       for (index = 0; index < orphan_blocks; index++)
+               grab_meta_page(sbi, start_blk + index);
 
-       mutex_lock(&sbi->orphan_inode_mutex);
+       index = 1;
+       spin_lock(&sbi->orphan_inode_lock);
        head = &sbi->orphan_inode_list;
 
        /* loop for each orphan inode entry and write them in Jornal block */
-       list_for_each_safe(this, next, head) {
-               struct orphan_inode_entry *orphan;
+       list_for_each_entry(orphan, head, list) {
+               if (!page) {
+                       page = find_get_page(META_MAPPING(sbi), start_blk++);
+                       f2fs_bug_on(!page);
+                       orphan_blk =
+                               (struct f2fs_orphan_block *)page_address(page);
+                       memset(orphan_blk, 0, sizeof(*orphan_blk));
+                       f2fs_put_page(page, 0);
+               }
 
-               orphan = list_entry(this, struct orphan_inode_entry, list);
+               orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino);
 
                if (nentries == F2FS_ORPHANS_PER_BLOCK) {
                        /*
@@ -331,29 +345,20 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
                        set_page_dirty(page);
                        f2fs_put_page(page, 1);
                        index++;
-                       start_blk++;
                        nentries = 0;
                        page = NULL;
                }
-               if (page)
-                       goto page_exist;
+       }
 
-               page = grab_meta_page(sbi, start_blk);
-               orphan_blk = (struct f2fs_orphan_block *)page_address(page);
-               memset(orphan_blk, 0, sizeof(*orphan_blk));
-page_exist:
-               orphan_blk->ino[nentries++] = cpu_to_le32(orphan->ino);
+       if (page) {
+               orphan_blk->blk_addr = cpu_to_le16(index);
+               orphan_blk->blk_count = cpu_to_le16(orphan_blocks);
+               orphan_blk->entry_count = cpu_to_le32(nentries);
+               set_page_dirty(page);
+               f2fs_put_page(page, 1);
        }
-       if (!page)
-               goto end;
 
-       orphan_blk->blk_addr = cpu_to_le16(index);
-       orphan_blk->blk_count = cpu_to_le16(orphan_blocks);
-       orphan_blk->entry_count = cpu_to_le32(nentries);
-       set_page_dirty(page);
-       f2fs_put_page(page, 1);
-end:
-       mutex_unlock(&sbi->orphan_inode_mutex);
+       spin_unlock(&sbi->orphan_inode_lock);
 }
 
 static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
@@ -428,7 +433,8 @@ int get_valid_checkpoint(struct f2fs_sb_info *sbi)
        cp1 = validate_checkpoint(sbi, cp_start_blk_no, &cp1_version);
 
        /* The second checkpoint pack should start at the next segment */
-       cp_start_blk_no += 1 << le32_to_cpu(fsb->log_blocks_per_seg);
+       cp_start_blk_no += ((unsigned long long)1) <<
+                               le32_to_cpu(fsb->log_blocks_per_seg);
        cp2 = validate_checkpoint(sbi, cp_start_blk_no, &cp2_version);
 
        if (cp1 && cp2) {
@@ -465,7 +471,7 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
        list_for_each(this, head) {
                struct dir_inode_entry *entry;
                entry = list_entry(this, struct dir_inode_entry, list);
-               if (entry->inode == inode)
+               if (unlikely(entry->inode == inode))
                        return -EEXIST;
        }
        list_add_tail(&new->list, head);
@@ -513,8 +519,8 @@ void add_dirty_dir_inode(struct inode *inode)
 void remove_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       struct list_head *head = &sbi->dir_inode_list;
-       struct list_head *this;
+
+       struct list_head *this, *head;
 
        if (!S_ISDIR(inode->i_mode))
                return;
@@ -525,6 +531,7 @@ void remove_dirty_dir_inode(struct inode *inode)
                return;
        }
 
+       head = &sbi->dir_inode_list;
        list_for_each(this, head) {
                struct dir_inode_entry *entry;
                entry = list_entry(this, struct dir_inode_entry, list);
@@ -546,11 +553,13 @@ void remove_dirty_dir_inode(struct inode *inode)
 
 struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
-       struct list_head *head = &sbi->dir_inode_list;
-       struct list_head *this;
+
+       struct list_head *this, *head;
        struct inode *inode = NULL;
 
        spin_lock(&sbi->dir_inode_lock);
+
+       head = &sbi->dir_inode_list;
        list_for_each(this, head) {
                struct dir_inode_entry *entry;
                entry = list_entry(this, struct dir_inode_entry, list);
@@ -565,11 +574,13 @@ struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
 
 void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
 {
-       struct list_head *head = &sbi->dir_inode_list;
+       struct list_head *head;
        struct dir_inode_entry *entry;
        struct inode *inode;
 retry:
        spin_lock(&sbi->dir_inode_lock);
+
+       head = &sbi->dir_inode_list;
        if (list_empty(head)) {
                spin_unlock(&sbi->dir_inode_lock);
                return;
@@ -585,7 +596,7 @@ retry:
                 * We should submit bio, since it exists several
                 * wribacking dentry pages in the freeing inode.
                 */
-               f2fs_submit_bio(sbi, DATA, true);
+               f2fs_submit_merged_bio(sbi, DATA, WRITE);
        }
        goto retry;
 }
@@ -760,8 +771,8 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        /* wait for previous submitted node/meta pages writeback */
        wait_on_all_pages_writeback(sbi);
 
-       filemap_fdatawait_range(sbi->node_inode->i_mapping, 0, LONG_MAX);
-       filemap_fdatawait_range(sbi->meta_inode->i_mapping, 0, LONG_MAX);
+       filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX);
+       filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX);
 
        /* update user_block_counts */
        sbi->last_valid_block_count = sbi->total_valid_block_count;
@@ -770,7 +781,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        /* Here, we only have one bio having CP pack */
        sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
 
-       if (!is_set_ckpt_flags(ckpt, CP_ERROR_FLAG)) {
+       if (unlikely(!is_set_ckpt_flags(ckpt, CP_ERROR_FLAG))) {
                clear_prefree_segments(sbi);
                F2FS_RESET_SB_DIRT(sbi);
        }
@@ -791,9 +802,9 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
 
        trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish block_ops");
 
-       f2fs_submit_bio(sbi, DATA, true);
-       f2fs_submit_bio(sbi, NODE, true);
-       f2fs_submit_bio(sbi, META, true);
+       f2fs_submit_merged_bio(sbi, DATA, WRITE);
+       f2fs_submit_merged_bio(sbi, NODE, WRITE);
+       f2fs_submit_merged_bio(sbi, META, WRITE);
 
        /*
         * update checkpoint pack index
@@ -818,20 +829,28 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
 
 void init_orphan_info(struct f2fs_sb_info *sbi)
 {
-       mutex_init(&sbi->orphan_inode_mutex);
+       spin_lock_init(&sbi->orphan_inode_lock);
        INIT_LIST_HEAD(&sbi->orphan_inode_list);
        sbi->n_orphans = 0;
+       /*
+        * considering 512 blocks in a segment 8 blocks are needed for cp
+        * and log segment summaries. Remaining blocks are used to keep
+        * orphan entries with the limitation one reserved segment
+        * for cp pack we can have max 1020*504 orphan entries
+        */
+       sbi->max_orphans = (sbi->blocks_per_seg - 2 - NR_CURSEG_TYPE)
+                               * F2FS_ORPHANS_PER_BLOCK;
 }
 
 int __init create_checkpoint_caches(void)
 {
        orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry",
                        sizeof(struct orphan_inode_entry), NULL);
-       if (unlikely(!orphan_entry_slab))
+       if (!orphan_entry_slab)
                return -ENOMEM;
        inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry",
                        sizeof(struct dir_inode_entry), NULL);
-       if (unlikely(!inode_entry_slab)) {
+       if (!inode_entry_slab) {
                kmem_cache_destroy(orphan_entry_slab);
                return -ENOMEM;
        }