Commit db6ec53b authored by Jaegeuk Kim's avatar Jaegeuk Kim

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
...@@ -1133,17 +1133,24 @@ static void __prepare_cp_block(struct f2fs_sb_info *sbi) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -1256,6 +1256,7 @@ struct f2fs_sb_info { ...@@ -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];
......
...@@ -1919,6 +1919,18 @@ int f2fs_quota_sync(struct super_block *sb, int type) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment