]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/f2fs/checkpoint.c
ocfs2: return non-zero st_blocks for inline data
[karo-tx-linux.git] / fs / f2fs / checkpoint.c
index f661d80474be7ab8f91de74525fa65198cfa68f9..3842af954cd5bc127f2f0aad13d0ff52b743779d 100644 (file)
@@ -237,7 +237,7 @@ static int f2fs_write_meta_page(struct page *page,
        dec_page_count(sbi, F2FS_DIRTY_META);
        unlock_page(page);
 
-       if (wbc->for_reclaim)
+       if (wbc->for_reclaim || unlikely(f2fs_cp_error(sbi)))
                f2fs_submit_merged_bio(sbi, META, WRITE);
        return 0;
 
@@ -410,13 +410,13 @@ static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
        spin_unlock(&im->ino_lock);
 }
 
-void add_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
+void add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
 {
        /* add new dirty ino entry into list */
        __add_ino_entry(sbi, ino, type);
 }
 
-void remove_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
+void remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
 {
        /* remove dirty ino entry from list */
        __remove_ino_entry(sbi, ino, type);
@@ -434,7 +434,7 @@ bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
        return e ? true : false;
 }
 
-void release_dirty_inode(struct f2fs_sb_info *sbi)
+void release_ino_entry(struct f2fs_sb_info *sbi)
 {
        struct ino_entry *e, *tmp;
        int i;
@@ -722,47 +722,48 @@ fail_no_cp:
        return -EINVAL;
 }
 
-static int __add_dirty_inode(struct inode *inode, struct inode_entry *new)
+static void __add_dirty_inode(struct inode *inode, enum inode_type type)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
 
-       if (is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR))
-               return -EEXIST;
+       if (is_inode_flag_set(fi, flag))
+               return;
 
-       set_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
-       F2FS_I(inode)->dirty_dir = new;
-       list_add_tail(&new->list, &sbi->dir_inode_list);
-       stat_inc_dirty_dir(sbi);
-       return 0;
+       set_inode_flag(fi, flag);
+       list_add_tail(&fi->dirty_list, &sbi->inode_list[type]);
+       stat_inc_dirty_inode(sbi, type);
+}
+
+static void __remove_dirty_inode(struct inode *inode, enum inode_type type)
+{
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       int flag = (type == DIR_INODE) ? FI_DIRTY_DIR : FI_DIRTY_FILE;
+
+       if (get_dirty_pages(inode) ||
+                       !is_inode_flag_set(F2FS_I(inode), flag))
+               return;
+
+       list_del_init(&fi->dirty_list);
+       clear_inode_flag(fi, flag);
+       stat_dec_dirty_inode(F2FS_I_SB(inode), type);
 }
 
 void update_dirty_page(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct inode_entry *new;
-       int ret = 0;
+       enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
 
        if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
                        !S_ISLNK(inode->i_mode))
                return;
 
-       if (!S_ISDIR(inode->i_mode)) {
-               inode_inc_dirty_pages(inode);
-               goto out;
-       }
-
-       new = f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
-       new->inode = inode;
-       INIT_LIST_HEAD(&new->list);
-
-       spin_lock(&sbi->dir_inode_lock);
-       ret = __add_dirty_inode(inode, new);
+       spin_lock(&sbi->inode_lock[type]);
+       __add_dirty_inode(inode, type);
        inode_inc_dirty_pages(inode);
-       spin_unlock(&sbi->dir_inode_lock);
+       spin_unlock(&sbi->inode_lock[type]);
 
-       if (ret)
-               kmem_cache_free(inode_entry_slab, new);
-out:
        SetPagePrivate(page);
        f2fs_trace_pid(page);
 }
@@ -770,70 +771,60 @@ out:
 void add_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct 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);
-       ret = __add_dirty_inode(inode, new);
-       spin_unlock(&sbi->dir_inode_lock);
-
-       if (ret)
-               kmem_cache_free(inode_entry_slab, new);
+       spin_lock(&sbi->inode_lock[DIR_INODE]);
+       __add_dirty_inode(inode, DIR_INODE);
+       spin_unlock(&sbi->inode_lock[DIR_INODE]);
 }
 
-void remove_dirty_dir_inode(struct inode *inode)
+void remove_dirty_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct inode_entry *entry;
-
-       if (!S_ISDIR(inode->i_mode))
-               return;
+       struct f2fs_inode_info *fi = F2FS_I(inode);
+       enum inode_type type = S_ISDIR(inode->i_mode) ? DIR_INODE : FILE_INODE;
 
-       spin_lock(&sbi->dir_inode_lock);
-       if (get_dirty_pages(inode) ||
-                       !is_inode_flag_set(F2FS_I(inode), FI_DIRTY_DIR)) {
-               spin_unlock(&sbi->dir_inode_lock);
+       if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
+                       !S_ISLNK(inode->i_mode))
                return;
-       }
 
-       entry = F2FS_I(inode)->dirty_dir;
-       list_del(&entry->list);
-       F2FS_I(inode)->dirty_dir = NULL;
-       clear_inode_flag(F2FS_I(inode), FI_DIRTY_DIR);
-       stat_dec_dirty_dir(sbi);
-       spin_unlock(&sbi->dir_inode_lock);
-       kmem_cache_free(inode_entry_slab, entry);
+       spin_lock(&sbi->inode_lock[type]);
+       __remove_dirty_inode(inode, type);
+       spin_unlock(&sbi->inode_lock[type]);
 
        /* 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);
+       if (is_inode_flag_set(fi, FI_DELAY_IPUT)) {
+               clear_inode_flag(fi, FI_DELAY_IPUT);
                iput(inode);
        }
 }
 
-void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
+int sync_dirty_inodes(struct f2fs_sb_info *sbi, enum inode_type type)
 {
        struct list_head *head;
-       struct inode_entry *entry;
        struct inode *inode;
+       struct f2fs_inode_info *fi;
+       bool is_dir = (type == DIR_INODE);
+
+       trace_f2fs_sync_dirty_inodes_enter(sbi->sb, is_dir,
+                               get_pages(sbi, is_dir ?
+                               F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
 retry:
        if (unlikely(f2fs_cp_error(sbi)))
-               return;
+               return -EIO;
 
-       spin_lock(&sbi->dir_inode_lock);
+       spin_lock(&sbi->inode_lock[type]);
 
-       head = &sbi->dir_inode_list;
+       head = &sbi->inode_list[type];
        if (list_empty(head)) {
-               spin_unlock(&sbi->dir_inode_lock);
-               return;
+               spin_unlock(&sbi->inode_lock[type]);
+               trace_f2fs_sync_dirty_inodes_exit(sbi->sb, is_dir,
+                               get_pages(sbi, is_dir ?
+                               F2FS_DIRTY_DENTS : F2FS_DIRTY_DATA));
+               return 0;
        }
-       entry = list_entry(head->next, struct inode_entry, list);
-       inode = igrab(entry->inode);
-       spin_unlock(&sbi->dir_inode_lock);
+       fi = list_entry(head->next, struct f2fs_inode_info, dirty_list);
+       inode = igrab(&fi->vfs_inode);
+       spin_unlock(&sbi->inode_lock[type]);
        if (inode) {
                filemap_fdatawrite(inode->i_mapping);
                iput(inode);
@@ -868,11 +859,9 @@ retry_flush_dents:
        /* write all the dirty dentry pages */
        if (get_pages(sbi, F2FS_DIRTY_DENTS)) {
                f2fs_unlock_all(sbi);
-               sync_dirty_dir_inodes(sbi);
-               if (unlikely(f2fs_cp_error(sbi))) {
-                       err = -EIO;
+               err = sync_dirty_inodes(sbi, DIR_INODE);
+               if (err)
                        goto out;
-               }
                goto retry_flush_dents;
        }
 
@@ -885,10 +874,9 @@ retry_flush_nodes:
 
        if (get_pages(sbi, F2FS_DIRTY_NODES)) {
                up_write(&sbi->node_write);
-               sync_node_pages(sbi, 0, &wbc);
-               if (unlikely(f2fs_cp_error(sbi))) {
+               err = sync_node_pages(sbi, 0, &wbc);
+               if (err) {
                        f2fs_unlock_all(sbi);
-                       err = -EIO;
                        goto out;
                }
                goto retry_flush_nodes;
@@ -919,7 +907,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
        finish_wait(&sbi->cp_wait, &wait);
 }
 
-static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
@@ -945,7 +933,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        while (get_pages(sbi, F2FS_DIRTY_META)) {
                sync_meta_pages(sbi, META, LONG_MAX);
                if (unlikely(f2fs_cp_error(sbi)))
-                       return;
+                       return -EIO;
        }
 
        next_free_nid(sbi, &last_nid);
@@ -1030,7 +1018,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        /* need to wait for end_io results */
        wait_on_all_pages_writeback(sbi);
        if (unlikely(f2fs_cp_error(sbi)))
-               return;
+               return -EIO;
 
        /* write out checkpoint buffer at block 0 */
        update_meta_page(sbi, ckpt, start_blk++);
@@ -1058,7 +1046,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        wait_on_all_pages_writeback(sbi);
 
        if (unlikely(f2fs_cp_error(sbi)))
-               return;
+               return -EIO;
 
        filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX);
        filemap_fdatawait_range(META_MAPPING(sbi), 0, LONG_MAX);
@@ -1081,22 +1069,25 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                invalidate_mapping_pages(META_MAPPING(sbi), discard_blk,
                                                                discard_blk);
 
-       release_dirty_inode(sbi);
+       release_ino_entry(sbi);
 
        if (unlikely(f2fs_cp_error(sbi)))
-               return;
+               return -EIO;
 
        clear_prefree_segments(sbi, cpc);
        clear_sbi_flag(sbi, SBI_IS_DIRTY);
+
+       return 0;
 }
 
 /*
  * We guarantee that this checkpoint procedure will not fail.
  */
-void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+int write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
 {
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
        unsigned long long ckpt_ver;
+       int err = 0;
 
        mutex_lock(&sbi->cp_mutex);
 
@@ -1104,14 +1095,19 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                (cpc->reason == CP_FASTBOOT || cpc->reason == CP_SYNC ||
                (cpc->reason == CP_DISCARD && !sbi->discard_blks)))
                goto out;
-       if (unlikely(f2fs_cp_error(sbi)))
+       if (unlikely(f2fs_cp_error(sbi))) {
+               err = -EIO;
                goto out;
-       if (f2fs_readonly(sbi->sb))
+       }
+       if (f2fs_readonly(sbi->sb)) {
+               err = -EROFS;
                goto out;
+       }
 
        trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops");
 
-       if (block_operations(sbi))
+       err = block_operations(sbi);
+       if (err)
                goto out;
 
        trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops");
@@ -1133,7 +1129,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        flush_sit_entries(sbi, cpc);
 
        /* unlock all the fs_lock[] in do_checkpoint() */
-       do_checkpoint(sbi, cpc);
+       err = do_checkpoint(sbi, cpc);
 
        unblock_operations(sbi);
        stat_inc_cp_count(sbi->stat_info);
@@ -1143,10 +1139,11 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
                        "checkpoint: version = %llx", ckpt_ver);
 
        /* do checkpoint periodically */
-       sbi->cp_expires = round_jiffies_up(jiffies + HZ * sbi->cp_interval);
+       f2fs_update_time(sbi, CP_TIME);
+       trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
 out:
        mutex_unlock(&sbi->cp_mutex);
-       trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
+       return err;
 }
 
 void init_ino_entry_info(struct f2fs_sb_info *sbi)