Commit c34f42e2 authored by Chao Yu's avatar Chao Yu Committed by Jaegeuk Kim

f2fs: report error of do_checkpoint

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: default avatarChao Yu <chao2.yu@samsung.com>
Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 2a340760
...@@ -910,7 +910,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi) ...@@ -910,7 +910,7 @@ static void wait_on_all_pages_writeback(struct f2fs_sb_info *sbi)
finish_wait(&sbi->cp_wait, &wait); 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 f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); 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) ...@@ -936,7 +936,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
while (get_pages(sbi, F2FS_DIRTY_META)) { while (get_pages(sbi, F2FS_DIRTY_META)) {
sync_meta_pages(sbi, META, LONG_MAX); sync_meta_pages(sbi, META, LONG_MAX);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return; return -EIO;
} }
next_free_nid(sbi, &last_nid); next_free_nid(sbi, &last_nid);
...@@ -1021,7 +1021,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1021,7 +1021,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* need to wait for end_io results */ /* need to wait for end_io results */
wait_on_all_pages_writeback(sbi); wait_on_all_pages_writeback(sbi);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return; return -EIO;
/* write out checkpoint buffer at block 0 */ /* write out checkpoint buffer at block 0 */
update_meta_page(sbi, ckpt, start_blk++); update_meta_page(sbi, ckpt, start_blk++);
...@@ -1049,7 +1049,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -1049,7 +1049,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
wait_on_all_pages_writeback(sbi); wait_on_all_pages_writeback(sbi);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return; return -EIO;
filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX); filemap_fdatawait_range(NODE_MAPPING(sbi), 0, LONG_MAX);
filemap_fdatawait_range(META_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) ...@@ -1075,19 +1075,22 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
release_ino_entry(sbi); release_ino_entry(sbi);
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi)))
return; return -EIO;
clear_prefree_segments(sbi, cpc); clear_prefree_segments(sbi, cpc);
clear_sbi_flag(sbi, SBI_IS_DIRTY); clear_sbi_flag(sbi, SBI_IS_DIRTY);
return 0;
} }
/* /*
* We guarantee that this checkpoint procedure will not fail. * 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); struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
unsigned long long ckpt_ver; unsigned long long ckpt_ver;
int err = 0;
mutex_lock(&sbi->cp_mutex); mutex_lock(&sbi->cp_mutex);
...@@ -1095,14 +1098,19 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -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_FASTBOOT || cpc->reason == CP_SYNC ||
(cpc->reason == CP_DISCARD && !sbi->discard_blks))) (cpc->reason == CP_DISCARD && !sbi->discard_blks)))
goto out; goto out;
if (unlikely(f2fs_cp_error(sbi))) if (unlikely(f2fs_cp_error(sbi))) {
err = -EIO;
goto out; goto out;
if (f2fs_readonly(sbi->sb)) }
if (f2fs_readonly(sbi->sb)) {
err = -EROFS;
goto out; goto out;
}
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops"); trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops");
if (block_operations(sbi)) err = block_operations(sbi);
if (err)
goto out; goto out;
trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops"); 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) ...@@ -1124,7 +1132,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
flush_sit_entries(sbi, cpc); flush_sit_entries(sbi, cpc);
/* unlock all the fs_lock[] in do_checkpoint() */ /* unlock all the fs_lock[] in do_checkpoint() */
do_checkpoint(sbi, cpc); err = do_checkpoint(sbi, cpc);
unblock_operations(sbi); unblock_operations(sbi);
stat_inc_cp_count(sbi->stat_info); stat_inc_cp_count(sbi->stat_info);
...@@ -1138,6 +1146,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ...@@ -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"); trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
out: out:
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
return err;
} }
void init_ino_entry_info(struct f2fs_sb_info *sbi) void init_ino_entry_info(struct f2fs_sb_info *sbi)
......
...@@ -1838,7 +1838,7 @@ void update_dirty_page(struct inode *, struct page *); ...@@ -1838,7 +1838,7 @@ void update_dirty_page(struct inode *, struct page *);
void add_dirty_dir_inode(struct inode *); void add_dirty_dir_inode(struct inode *);
void remove_dirty_inode(struct inode *); void remove_dirty_inode(struct inode *);
void sync_dirty_inodes(struct f2fs_sb_info *, enum inode_type); 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 *); void init_ino_entry_info(struct f2fs_sb_info *);
int __init create_checkpoint_caches(void); int __init create_checkpoint_caches(void);
void destroy_checkpoint_caches(void); void destroy_checkpoint_caches(void);
......
...@@ -1618,6 +1618,7 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) ...@@ -1618,6 +1618,7 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
struct inode *inode = file_inode(filp); struct inode *inode = file_inode(filp);
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct cp_control cpc; struct cp_control cpc;
int err;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
...@@ -1628,10 +1629,10 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) ...@@ -1628,10 +1629,10 @@ static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg)
cpc.reason = __get_cp_reason(sbi); cpc.reason = __get_cp_reason(sbi);
mutex_lock(&sbi->gc_mutex); mutex_lock(&sbi->gc_mutex);
write_checkpoint(sbi, &cpc); err = write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
return 0; return err;
} }
static int f2fs_defragment_range(struct f2fs_sb_info *sbi, static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
......
...@@ -623,7 +623,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi) ...@@ -623,7 +623,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
.reason = CP_RECOVERY, .reason = CP_RECOVERY,
}; };
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
write_checkpoint(sbi, &cpc); err = write_checkpoint(sbi, &cpc);
} else { } else {
mutex_unlock(&sbi->cp_mutex); mutex_unlock(&sbi->cp_mutex);
} }
......
...@@ -1118,6 +1118,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) ...@@ -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; __u64 end = start + F2FS_BYTES_TO_BLK(range->len) - 1;
unsigned int start_segno, end_segno; unsigned int start_segno, end_segno;
struct cp_control cpc; struct cp_control cpc;
int err = 0;
if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize) if (start >= MAX_BLKADDR(sbi) || range->len < sbi->blocksize)
return -EINVAL; return -EINVAL;
...@@ -1148,12 +1149,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) ...@@ -1148,12 +1149,12 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
sbi->segs_per_sec) - 1, end_segno); sbi->segs_per_sec) - 1, end_segno);
mutex_lock(&sbi->gc_mutex); mutex_lock(&sbi->gc_mutex);
write_checkpoint(sbi, &cpc); err = write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
} }
out: out:
range->len = F2FS_BLK_TO_BYTES(cpc.trimmed); range->len = F2FS_BLK_TO_BYTES(cpc.trimmed);
return 0; return err;
} }
static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type) static bool __has_curseg_space(struct f2fs_sb_info *sbi, int type)
......
...@@ -579,6 +579,7 @@ static void f2fs_put_super(struct super_block *sb) ...@@ -579,6 +579,7 @@ static void f2fs_put_super(struct super_block *sb)
int f2fs_sync_fs(struct super_block *sb, int sync) int f2fs_sync_fs(struct super_block *sb, int sync)
{ {
struct f2fs_sb_info *sbi = F2FS_SB(sb); struct f2fs_sb_info *sbi = F2FS_SB(sb);
int err = 0;
trace_f2fs_sync_fs(sb, sync); trace_f2fs_sync_fs(sb, sync);
...@@ -588,14 +589,14 @@ int f2fs_sync_fs(struct super_block *sb, int sync) ...@@ -588,14 +589,14 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
cpc.reason = __get_cp_reason(sbi); cpc.reason = __get_cp_reason(sbi);
mutex_lock(&sbi->gc_mutex); mutex_lock(&sbi->gc_mutex);
write_checkpoint(sbi, &cpc); err = write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex); mutex_unlock(&sbi->gc_mutex);
} else { } else {
f2fs_balance_fs(sbi); f2fs_balance_fs(sbi);
} }
f2fs_trace_ios(NULL, 1); f2fs_trace_ios(NULL, 1);
return 0; return err;
} }
static int f2fs_freeze(struct super_block *sb) static int f2fs_freeze(struct super_block *sb)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment