f2fs: report error of do_checkpoint
authorChao Yu <chao2.yu@samsung.com>
Wed, 23 Dec 2015 09:50:30 +0000 (17:50 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Wed, 30 Dec 2015 18:14:09 +0000 (10:14 -0800)
do_checkpoint and write_checkpoint can fail due to reasons like triggering
in a readonly fs or encountering IO error of storage device.

So it's better to report such error info to user, let user be aware of
failure of doing checkpoint.

Signed-off-by: Chao Yu <chao2.yu@samsung.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fs/f2fs/checkpoint.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/recovery.c
fs/f2fs/segment.c
fs/f2fs/super.c

index fdd43f71d2c6c03b016351f78a060a3ab7e4033b..9cdb161973518fc661d00997732dbe6027c2ff70 100644 (file)
@@ -910,7 +910,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);
@@ -936,7 +936,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);
@@ -1021,7 +1021,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++);
@@ -1049,7 +1049,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);
@@ -1075,19 +1075,22 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        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);
 
@@ -1095,14 +1098,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");
@@ -1124,7 +1132,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);
@@ -1138,6 +1146,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
 out:
        mutex_unlock(&sbi->cp_mutex);
+       return err;
 }
 
 void init_ino_entry_info(struct f2fs_sb_info *sbi)
index 3e4a60da408f5210240ee228f1d47f668fafcb10..79345e7ce6bb8e2878c42f61544cfc4cafbe9d78 100644 (file)
@@ -1838,7 +1838,7 @@ void update_dirty_page(struct inode *, struct page *);
 void add_dirty_dir_inode(struct inode *);
 void remove_dirty_inode(struct inode *);
 void sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type);
-void write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
+int write_checkpoint(struct f2fs_sb_info *, struct cp_control *);
 void init_ino_entry_info(struct f2fs_sb_info *);
 int __init create_checkpoint_caches(void);
 void destroy_checkpoint_caches(void);
index 888ce47657790fd1497fa4b0c6640663276c419b..780db8bd2451e4a2c0c41816d16379bac5b250ed 100644 (file)
@@ -1618,6 +1618,7 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
        struct inode *inode = file_inode(filp);
        struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
        struct cp_control cpc;
+       int err;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -1628,10 +1629,10 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
        cpc.reason = __get_cp_reason(sbi);
 
        mutex_lock(&sbi->gc_mutex);
-       write_checkpoint(sbi, &cpc);
+       err = write_checkpoint(sbi, &cpc);
        mutex_unlock(&sbi->gc_mutex);
 
-       return 0;
+       return err;
 }
 
 static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
index 7fcb6e49defff4683f9f5b61eccdbef583be8413..589b20b8677b8cc1dcf3d16a6f7e0943ce0283eb 100644 (file)
@@ -623,7 +623,7 @@ out:
                        .reason = CP_RECOVERY,
                };
                mutex_unlock(&sbi->cp_mutex);
-               write_checkpoint(sbi, &cpc);
+               err = write_checkpoint(sbi, &cpc);
        } else {
                mutex_unlock(&sbi->cp_mutex);
        }
index c2474509e5de5701284aa60593e51b53bc5e0c2a..a3474bad57702863822be2e2da5d0eae09194b39 100644 (file)
@@ -1118,6 +1118,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
        __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
        unsigned int start_segno, end_segno;
        struct cp_control cpc;
+       int err = 0;
 
        if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
                return -EINVAL;
@@ -1148,12 +1149,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
                                sbi->segs_per_sec) - 1, end_segno);
 
                mutex_lock(&sbi->gc_mutex);
-               write_checkpoint(sbi, &cpc);
+               err = write_checkpoint(sbi, &cpc);
                mutex_unlock(&sbi->gc_mutex);
        }
 out:
        range->len = F2FS_BLK_TO_BYTES(cpc.trimmed);
-       return 0;
+       return err;
 }
 
 static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
index c3070c149c0ecfc70b644bcb54cbccf059a090aa..597b533634e006b8d31c0b1bd9de038c5fa919bf 100644 (file)
@@ -579,6 +579,7 @@ static void f2fs_put_super(struct super_block *sb)
 int f2fs_sync_fs(struct super_block *sb, int sync)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(sb);
+       int err = 0;
 
        trace_f2fs_sync_fs(sb, sync);
 
@@ -588,14 +589,14 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
                cpc.reason = __get_cp_reason(sbi);
 
                mutex_lock(&sbi->gc_mutex);
-               write_checkpoint(sbi, &cpc);
+               err = write_checkpoint(sbi, &cpc);
                mutex_unlock(&sbi->gc_mutex);
        } else {
                f2fs_balance_fs(sbi);
        }
        f2fs_trace_ios(NULL, 1);
 
-       return 0;
+       return err;
 }
 
 static int f2fs_freeze(struct super_block *sb)