]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/f2fs/checkpoint.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[karo-tx-linux.git] / fs / f2fs / checkpoint.c
index 1f52b70ff9d19575b18d8ea24f80ec9023490e43..4aa521aa9bc3a794fbe52625e689b93140ed38a5 100644 (file)
@@ -33,14 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
        struct address_space *mapping = META_MAPPING(sbi);
        struct page *page = NULL;
 repeat:
-       page = grab_cache_page(mapping, index);
+       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
        if (!page) {
                cond_resched();
                goto repeat;
        }
 
-       /* We wait writeback only inside grab_meta_page() */
-       wait_on_page_writeback(page);
        SetPageUptodate(page);
        return page;
 }
@@ -168,7 +166,7 @@ static int f2fs_write_meta_page(struct page *page,
        if (unlikely(is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
                goto no_write;
 
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, META);
        write_meta_page(sbi, page);
 no_write:
        dec_page_count(sbi, F2FS_DIRTY_META);
@@ -187,21 +185,23 @@ 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);
-       int nrpages = nr_pages_to_skip(sbi, META);
-       long written;
-
-       if (wbc->for_kupdate)
-               return 0;
+       long diff, written;
 
        /* collect a number of dirty meta pages and write together */
-       if (get_pages(sbi, F2FS_DIRTY_META) < nrpages)
-               return 0;
+       if (wbc->for_kupdate ||
+               get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
+               goto skip_write;
 
        /* if mounting is failed, skip writing node pages */
        mutex_lock(&sbi->cp_mutex);
-       written = sync_meta_pages(sbi, META, nrpages);
+       diff = nr_pages_to_write(sbi, META, wbc);
+       written = sync_meta_pages(sbi, META, wbc->nr_to_write);
        mutex_unlock(&sbi->cp_mutex);
-       wbc->nr_to_write -= written;
+       wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
+       return 0;
+
+skip_write:
+       wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META);
        return 0;
 }
 
@@ -308,16 +308,15 @@ void release_orphan_inode(struct f2fs_sb_info *sbi)
 
 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;
+       struct list_head *head;
+       struct orphan_inode_entry *new, *orphan;
 
        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);
+       list_for_each_entry(orphan, head, list) {
                if (orphan->ino == ino) {
                        spin_unlock(&sbi->orphan_inode_lock);
                        kmem_cache_free(orphan_entry_slab, new);
@@ -326,14 +325,10 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 
                if (orphan->ino > ino)
                        break;
-               orphan = NULL;
        }
 
-       /* 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);
+       /* add new orphan entry into list which is sorted by inode number */
+       list_add_tail(&new->list, &orphan->list);
        spin_unlock(&sbi->orphan_inode_lock);
 }
 
@@ -347,10 +342,11 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
        list_for_each_entry(orphan, head, list) {
                if (orphan->ino == ino) {
                        list_del(&orphan->list);
-                       kmem_cache_free(orphan_entry_slab, orphan);
                        f2fs_bug_on(sbi->n_orphans == 0);
                        sbi->n_orphans--;
-                       break;
+                       spin_unlock(&sbi->orphan_inode_lock);
+                       kmem_cache_free(orphan_entry_slab, orphan);
+                       return;
                }
        }
        spin_unlock(&sbi->orphan_inode_lock);
@@ -560,14 +556,12 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct list_head *head = &sbi->dir_inode_list;
-       struct list_head *this;
+       struct dir_inode_entry *entry;
 
-       list_for_each(this, head) {
-               struct dir_inode_entry *entry;
-               entry = list_entry(this, struct dir_inode_entry, list);
+       list_for_each_entry(entry, head, list)
                if (unlikely(entry->inode == inode))
                        return -EEXIST;
-       }
+
        list_add_tail(&new->list, head);
        stat_inc_dirty_dir(sbi);
        return 0;
@@ -577,6 +571,7 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct dir_inode_entry *new;
+       int ret = 0;
 
        if (!S_ISDIR(inode->i_mode))
                return;
@@ -586,12 +581,13 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
        INIT_LIST_HEAD(&new->list);
 
        spin_lock(&sbi->dir_inode_lock);
-       if (__add_dirty_inode(inode, new))
-               kmem_cache_free(inode_entry_slab, new);
-
+       ret = __add_dirty_inode(inode, new);
        inode_inc_dirty_dents(inode);
        SetPagePrivate(page);
        spin_unlock(&sbi->dir_inode_lock);
+
+       if (ret)
+               kmem_cache_free(inode_entry_slab, new);
 }
 
 void add_dirty_dir_inode(struct inode *inode)
@@ -599,21 +595,24 @@ void add_dirty_dir_inode(struct inode *inode)
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct dir_inode_entry *new =
                        f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
+       int ret = 0;
 
        new->inode = inode;
        INIT_LIST_HEAD(&new->list);
 
        spin_lock(&sbi->dir_inode_lock);
-       if (__add_dirty_inode(inode, new))
-               kmem_cache_free(inode_entry_slab, new);
+       ret = __add_dirty_inode(inode, new);
        spin_unlock(&sbi->dir_inode_lock);
+
+       if (ret)
+               kmem_cache_free(inode_entry_slab, new);
 }
 
 void remove_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-
-       struct list_head *this, *head;
+       struct list_head *head;
+       struct dir_inode_entry *entry;
 
        if (!S_ISDIR(inode->i_mode))
                return;
@@ -625,18 +624,18 @@ void remove_dirty_dir_inode(struct inode *inode)
        }
 
        head = &sbi->dir_inode_list;
-       list_for_each(this, head) {
-               struct dir_inode_entry *entry;
-               entry = list_entry(this, struct dir_inode_entry, list);
+       list_for_each_entry(entry, head, list) {
                if (entry->inode == inode) {
                        list_del(&entry->list);
-                       kmem_cache_free(inode_entry_slab, entry);
                        stat_dec_dirty_dir(sbi);
-                       break;
+                       spin_unlock(&sbi->dir_inode_lock);
+                       kmem_cache_free(inode_entry_slab, entry);
+                       goto done;
                }
        }
        spin_unlock(&sbi->dir_inode_lock);
 
+done:
        /* Only from the recovery routine */
        if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
                clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
@@ -647,15 +646,14 @@ 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 *this, *head;
+       struct list_head *head;
        struct inode *inode = NULL;
+       struct dir_inode_entry *entry;
 
        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);
+       list_for_each_entry(entry, head, list) {
                if (entry->inode->i_ino == ino) {
                        inode = entry->inode;
                        break;