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

Commit db6ec53b 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 c83414ae
Loading
Loading
Loading
Loading
+19 −22
Original line number Original line 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)
static bool __need_flush_quota(struct f2fs_sb_info *sbi)
{
{
	bool ret = false;

	if (!is_journalled_quota(sbi))
	if (!is_journalled_quota(sbi))
		return false;
		return false;
	if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH))

		return false;
	down_write(&sbi->quota_sem);
	if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR))
	if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) {
		return false;
		ret = false;
	if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH))
	} else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) {
		return true;
		ret = false;
	if (get_pages(sbi, F2FS_DIRTY_QDATA))
	} else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH)) {
		return true;
		clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH);
	return false;
		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);
	blk_start_plug(&plug);


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


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


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

	f2fs_lock_all(sbi);
	if (__need_flush_quota(sbi)) {
		f2fs_unlock_all(sbi);
		cond_resched();
		cond_resched();
		goto retry_flush_quotas;
		goto retry_flush_quotas;
	}
	}
@@ -1203,12 +1206,6 @@ static int block_operations(struct f2fs_sb_info *sbi)
	 */
	 */
	down_write(&sbi->node_change);
	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)) {
	if (get_pages(sbi, F2FS_DIRTY_IMETA)) {
		up_write(&sbi->node_change);
		up_write(&sbi->node_change);
		f2fs_unlock_all(sbi);
		f2fs_unlock_all(sbi);
+1 −0
Original line number Original line Diff line number Diff line
@@ -1256,6 +1256,7 @@ struct f2fs_sb_info {
	block_t unusable_block_count;		/* # of blocks saved by last cp */
	block_t unusable_block_count;		/* # of blocks saved by last cp */


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


	/* # of pages, see count_type */
	/* # of pages, see count_type */
	atomic_t nr_pages[NR_COUNT_TYPE];
	atomic_t nr_pages[NR_COUNT_TYPE];
+33 −5
Original line number Original line Diff line number Diff line
@@ -1919,6 +1919,18 @@ int f2fs_quota_sync(struct super_block *sb, int type)
	int cnt;
	int cnt;
	int ret;
	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);
	ret = dquot_writeback_dquots(sb, type);
	if (ret)
	if (ret)
		goto out;
		goto out;
@@ -1956,6 +1968,8 @@ int f2fs_quota_sync(struct super_block *sb, int type)
out:
out:
	if (ret)
	if (ret)
		set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
		set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR);
	up_read(&sbi->quota_sem);
	f2fs_unlock_op(sbi);
	return ret;
	return ret;
}
}


@@ -2047,32 +2061,40 @@ static void f2fs_truncate_quota_inode_pages(struct super_block *sb)


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


	down_read(&sbi->quota_sem);
	ret = dquot_commit(dquot);
	ret = dquot_commit(dquot);
	if (ret < 0)
	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;
	return ret;
}
}


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


	down_read(&sbi->quota_sem);
	ret = dquot_acquire(dquot);
	ret = dquot_acquire(dquot);
	if (ret < 0)
	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;
	return ret;
}
}


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


	down_read(&sbi->quota_sem);
	ret = dquot_release(dquot);
	ret = dquot_release(dquot);
	if (ret < 0)
	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;
	return ret;
}
}


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


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


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


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


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


	down_read(&sbi->quota_sem);
	ret = dquot_commit_info(sb, type);
	ret = dquot_commit_info(sb, type);
	if (ret < 0)
	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;
	return ret;
}
}


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


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