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

Commit af2db431 authored by Jaegeuk Kim's avatar Jaegeuk Kim
Browse files

f2fs: add a rw_sem to cover quota flag changes



Two paths to update quota and f2fs_lock_op:

1.
 - lock_op
 |  - quota_update
 `- unlock_op

2.
 - quota_update
 - lock_op
 `- unlock_op

But, we need to make a transaction on quota_update + lock_op in #2 case.
So, this patch introduces:
1. lock_op
2. down_write
3. check __need_flush
4. up_write
5. if there is dirty quota entries, flush them
6. otherwise, good to go

Signed-off-by: default avatarJaegeuk Kim <jaegeuk@kernel.org>
parent 768d8411
Loading
Loading
Loading
Loading
+19 −22
Original line number Diff line number Diff line
@@ -1133,17 +1133,24 @@ static void __prepare_cp_block(struct f2fs_sb_info *sbi)

static bool __need_flush_quota(struct f2fs_sb_info *sbi)
{
	bool ret = false;

	if (!is_journalled_quota(sbi))
		return false;
	if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH))
		return false;
	if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR))
		return false;
	if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH))
		return true;
	if (get_pages(sbi, F2FS_DIRTY_QDATA))
		return true;
	return false;

	down_write(&sbi->quota_sem);
	if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) {
		ret = false;
	} else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) {
		ret = false;
	} else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH)) {
		clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
		ret = true;
	} else if (get_pages(sbi, F2FS_DIRTY_QDATA)) {
		ret = true;
	}
	up_write(&sbi->quota_sem);
	return ret;
}

/*
@@ -1162,26 +1169,22 @@ static int block_operations(struct f2fs_sb_info *sbi)
	blk_start_plug(&plug);

retry_flush_quotas:
	f2fs_lock_all(sbi);
	if (__need_flush_quota(sbi)) {
		int locked;

		if (++cnt > DEFAULT_RETRY_QUOTA_FLUSH_COUNT) {
			set_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH);
			f2fs_lock_all(sbi);
			set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
			goto retry_flush_dents;
		}
		clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
		f2fs_unlock_all(sbi);

		/* only failed during mount/umount/freeze/quotactl */
		locked = down_read_trylock(&sbi->sb->s_umount);
		f2fs_quota_sync(sbi->sb, -1);
		if (locked)
			up_read(&sbi->sb->s_umount);
	}

	f2fs_lock_all(sbi);
	if (__need_flush_quota(sbi)) {
		f2fs_unlock_all(sbi);
		cond_resched();
		goto retry_flush_quotas;
	}
@@ -1203,12 +1206,6 @@ static int block_operations(struct f2fs_sb_info *sbi)
	 */
	down_write(&sbi->node_change);

	if (__need_flush_quota(sbi)) {
		up_write(&sbi->node_change);
		f2fs_unlock_all(sbi);
		goto retry_flush_quotas;
	}

	if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
		up_write(&sbi->node_change);
		f2fs_unlock_all(sbi);
+1 −0
Original line number Diff line number Diff line
@@ -1255,6 +1255,7 @@ struct f2fs_sb_info {
	block_t unusable_block_count;		/* # of blocks saved by last cp */

	unsigned int nquota_files;		/* # of quota sysfile */
	struct rw_semaphore quota_sem;		/* blocking cp for flags */

	/* # of pages, see count_type */
	atomic_t nr_pages[NR_COUNT_TYPE];
+33 −5
Original line number Diff line number Diff line
@@ -1924,6 +1924,18 @@ int f2fs_quota_sync(struct super_block *sb, int type)
	int cnt;
	int ret;

	/*
	 * do_quotactl
	 *  f2fs_quota_sync
	 *  down_read(quota_sem)
	 *  dquot_writeback_dquots()
	 *  f2fs_dquot_commit
	 *                            block_operation
	 *                            down_read(quota_sem)
	 */
	f2fs_lock_op(sbi);

	down_read(&sbi->quota_sem);
	ret = dquot_writeback_dquots(sb, type);
	if (ret)
		goto out;
@@ -1961,6 +1973,8 @@ int f2fs_quota_sync(struct super_block *sb, int type)
out:
	if (ret)
		set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
	up_read(&sbi->quota_sem);
	f2fs_unlock_op(sbi);
	return ret;
}

@@ -2052,32 +2066,40 @@ static void f2fs_truncate_quota_inode_pages(struct super_block *sb)

static int f2fs_dquot_commit(struct dquot *dquot)
{
	struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
	int ret;

	down_read(&sbi->quota_sem);
	ret = dquot_commit(dquot);
	if (ret < 0)
		set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR);
		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
	up_read(&sbi->quota_sem);
	return ret;
}

static int f2fs_dquot_acquire(struct dquot *dquot)
{
	struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
	int ret;

	down_read(&sbi->quota_sem);
	ret = dquot_acquire(dquot);
	if (ret < 0)
		set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR);

		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
	up_read(&sbi->quota_sem);
	return ret;
}

static int f2fs_dquot_release(struct dquot *dquot)
{
	struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb);
	int ret;

	down_read(&sbi->quota_sem);
	ret = dquot_release(dquot);
	if (ret < 0)
		set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR);
		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
	up_read(&sbi->quota_sem);
	return ret;
}

@@ -2087,22 +2109,27 @@ static int f2fs_dquot_mark_dquot_dirty(struct dquot *dquot)
	struct f2fs_sb_info *sbi = F2FS_SB(sb);
	int ret;

	down_read(&sbi->quota_sem);
	ret = dquot_mark_dquot_dirty(dquot);

	/* if we are using journalled quota */
	if (is_journalled_quota(sbi))
		set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);

	up_read(&sbi->quota_sem);
	return ret;
}

static int f2fs_dquot_commit_info(struct super_block *sb, int type)
{
	struct f2fs_sb_info *sbi = F2FS_SB(sb);
	int ret;

	down_read(&sbi->quota_sem);
	ret = dquot_commit_info(sb, type);
	if (ret < 0)
		set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
		set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR);
	up_read(&sbi->quota_sem);
	return ret;
}

@@ -3176,6 +3203,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
	}

	init_rwsem(&sbi->cp_rwsem);
	init_rwsem(&sbi->quota_sem);
	init_waitqueue_head(&sbi->cp_wait);
	init_sb_info(sbi);