Skip to content

Commit

Permalink
f2fs: add a rw_sem to cover quota flag changes
Browse files Browse the repository at this point in the history
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 OnePlusOSS#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: Jaegeuk Kim <jaegeuk@kernel.org>
(cherry picked from commit 495fcc4)
  • Loading branch information
Jaegeuk Kim authored and pappschlumpf committed Aug 1, 2019
1 parent 70841b1 commit 111462c
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 27 deletions.
41 changes: 19 additions & 22 deletions fs/f2fs/checkpoint.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/*
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down
1 change: 1 addition & 0 deletions fs/f2fs/f2fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,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];
Expand Down
38 changes: 33 additions & 5 deletions fs/f2fs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -1942,6 +1942,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;
Expand Down Expand Up @@ -1979,6 +1991,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;
}

Expand Down Expand Up @@ -2070,32 +2084,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;
}

Expand All @@ -2105,22 +2127,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;
}

Expand Down Expand Up @@ -3191,6 +3218,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);

Expand Down

0 comments on commit 111462c

Please sign in to comment.