Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+19 −10
Original line number Diff line number Diff line
@@ -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)
+1 −1
Original line number Diff line number Diff line
@@ -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);
+3 −2
Original line number Diff line number Diff line
@@ -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,
+1 −1
Original line number Diff line number Diff line
@@ -623,7 +623,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
			.reason = CP_RECOVERY,
		};
		mutex_unlock(&sbi->cp_mutex);
		write_checkpoint(sbi, &cpc);
		err = write_checkpoint(sbi, &cpc);
	} else {
		mutex_unlock(&sbi->cp_mutex);
	}
+3 −2
Original line number Diff line number Diff line
@@ -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)
Loading