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: Chao Yu <chao2.yu@samsung.com> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
2a34076070
commit
c34f42e2cb
|
@ -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)
|
||||||
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)
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
(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)
|
||||||
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)
|
||||||
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 *);
|
||||||
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)
|
||||||
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)
|
||||||
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 @@ out:
|
||||||
.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)
|
||||||
__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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
Loading…
Reference in New Issue