diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2019-05-29 13:58:45 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2019-07-02 18:40:41 -0400 |
commit | db6ec53b7e0320c8fad27e9a816e50080154bd51 (patch) | |
tree | 0d8860ebf1d7cf5132e47ce36c510905807563ca | |
parent | c83414aedf369a40b825b0e254d9b36dae17aa66 (diff) |
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: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | fs/f2fs/checkpoint.c | 41 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 1 | ||||
-rw-r--r-- | fs/f2fs/super.c | 38 |
3 files changed, 53 insertions, 27 deletions
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 2d23671d2034..a0eef95b9e0e 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
@@ -1133,17 +1133,24 @@ static void __prepare_cp_block(struct f2fs_sb_info *sbi) | |||
1133 | 1133 | ||
1134 | static bool __need_flush_quota(struct f2fs_sb_info *sbi) | 1134 | static bool __need_flush_quota(struct f2fs_sb_info *sbi) |
1135 | { | 1135 | { |
1136 | bool ret = false; | ||
1137 | |||
1136 | if (!is_journalled_quota(sbi)) | 1138 | if (!is_journalled_quota(sbi)) |
1137 | return false; | 1139 | return false; |
1138 | if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) | 1140 | |
1139 | return false; | 1141 | down_write(&sbi->quota_sem); |
1140 | if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) | 1142 | if (is_sbi_flag_set(sbi, SBI_QUOTA_SKIP_FLUSH)) { |
1141 | return false; | 1143 | ret = false; |
1142 | if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH)) | 1144 | } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_REPAIR)) { |
1143 | return true; | 1145 | ret = false; |
1144 | if (get_pages(sbi, F2FS_DIRTY_QDATA)) | 1146 | } else if (is_sbi_flag_set(sbi, SBI_QUOTA_NEED_FLUSH)) { |
1145 | return true; | 1147 | clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); |
1146 | return false; | 1148 | ret = true; |
1149 | } else if (get_pages(sbi, F2FS_DIRTY_QDATA)) { | ||
1150 | ret = true; | ||
1151 | } | ||
1152 | up_write(&sbi->quota_sem); | ||
1153 | return ret; | ||
1147 | } | 1154 | } |
1148 | 1155 | ||
1149 | /* | 1156 | /* |
@@ -1162,26 +1169,22 @@ static int block_operations(struct f2fs_sb_info *sbi) | |||
1162 | blk_start_plug(&plug); | 1169 | blk_start_plug(&plug); |
1163 | 1170 | ||
1164 | retry_flush_quotas: | 1171 | retry_flush_quotas: |
1172 | f2fs_lock_all(sbi); | ||
1165 | if (__need_flush_quota(sbi)) { | 1173 | if (__need_flush_quota(sbi)) { |
1166 | int locked; | 1174 | int locked; |
1167 | 1175 | ||
1168 | if (++cnt > DEFAULT_RETRY_QUOTA_FLUSH_COUNT) { | 1176 | if (++cnt > DEFAULT_RETRY_QUOTA_FLUSH_COUNT) { |
1169 | set_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH); | 1177 | set_sbi_flag(sbi, SBI_QUOTA_SKIP_FLUSH); |
1170 | f2fs_lock_all(sbi); | 1178 | set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); |
1171 | goto retry_flush_dents; | 1179 | goto retry_flush_dents; |
1172 | } | 1180 | } |
1173 | clear_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); | 1181 | f2fs_unlock_all(sbi); |
1174 | 1182 | ||
1175 | /* only failed during mount/umount/freeze/quotactl */ | 1183 | /* only failed during mount/umount/freeze/quotactl */ |
1176 | locked = down_read_trylock(&sbi->sb->s_umount); | 1184 | locked = down_read_trylock(&sbi->sb->s_umount); |
1177 | f2fs_quota_sync(sbi->sb, -1); | 1185 | f2fs_quota_sync(sbi->sb, -1); |
1178 | if (locked) | 1186 | if (locked) |
1179 | up_read(&sbi->sb->s_umount); | 1187 | up_read(&sbi->sb->s_umount); |
1180 | } | ||
1181 | |||
1182 | f2fs_lock_all(sbi); | ||
1183 | if (__need_flush_quota(sbi)) { | ||
1184 | f2fs_unlock_all(sbi); | ||
1185 | cond_resched(); | 1188 | cond_resched(); |
1186 | goto retry_flush_quotas; | 1189 | goto retry_flush_quotas; |
1187 | } | 1190 | } |
@@ -1203,12 +1206,6 @@ retry_flush_dents: | |||
1203 | */ | 1206 | */ |
1204 | down_write(&sbi->node_change); | 1207 | down_write(&sbi->node_change); |
1205 | 1208 | ||
1206 | if (__need_flush_quota(sbi)) { | ||
1207 | up_write(&sbi->node_change); | ||
1208 | f2fs_unlock_all(sbi); | ||
1209 | goto retry_flush_quotas; | ||
1210 | } | ||
1211 | |||
1212 | if (get_pages(sbi, F2FS_DIRTY_IMETA)) { | 1209 | if (get_pages(sbi, F2FS_DIRTY_IMETA)) { |
1213 | up_write(&sbi->node_change); | 1210 | up_write(&sbi->node_change); |
1214 | f2fs_unlock_all(sbi); | 1211 | f2fs_unlock_all(sbi); |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d643f05cfa34..41a37ffabb8e 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -1256,6 +1256,7 @@ struct f2fs_sb_info { | |||
1256 | block_t unusable_block_count; /* # of blocks saved by last cp */ | 1256 | block_t unusable_block_count; /* # of blocks saved by last cp */ |
1257 | 1257 | ||
1258 | unsigned int nquota_files; /* # of quota sysfile */ | 1258 | unsigned int nquota_files; /* # of quota sysfile */ |
1259 | struct rw_semaphore quota_sem; /* blocking cp for flags */ | ||
1259 | 1260 | ||
1260 | /* # of pages, see count_type */ | 1261 | /* # of pages, see count_type */ |
1261 | atomic_t nr_pages[NR_COUNT_TYPE]; | 1262 | atomic_t nr_pages[NR_COUNT_TYPE]; |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 3ac706506ca2..1d33ca1a8c09 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -1919,6 +1919,18 @@ int f2fs_quota_sync(struct super_block *sb, int type) | |||
1919 | int cnt; | 1919 | int cnt; |
1920 | int ret; | 1920 | int ret; |
1921 | 1921 | ||
1922 | /* | ||
1923 | * do_quotactl | ||
1924 | * f2fs_quota_sync | ||
1925 | * down_read(quota_sem) | ||
1926 | * dquot_writeback_dquots() | ||
1927 | * f2fs_dquot_commit | ||
1928 | * block_operation | ||
1929 | * down_read(quota_sem) | ||
1930 | */ | ||
1931 | f2fs_lock_op(sbi); | ||
1932 | |||
1933 | down_read(&sbi->quota_sem); | ||
1922 | ret = dquot_writeback_dquots(sb, type); | 1934 | ret = dquot_writeback_dquots(sb, type); |
1923 | if (ret) | 1935 | if (ret) |
1924 | goto out; | 1936 | goto out; |
@@ -1956,6 +1968,8 @@ int f2fs_quota_sync(struct super_block *sb, int type) | |||
1956 | out: | 1968 | out: |
1957 | if (ret) | 1969 | if (ret) |
1958 | set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); | 1970 | set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); |
1971 | up_read(&sbi->quota_sem); | ||
1972 | f2fs_unlock_op(sbi); | ||
1959 | return ret; | 1973 | return ret; |
1960 | } | 1974 | } |
1961 | 1975 | ||
@@ -2047,32 +2061,40 @@ static void f2fs_truncate_quota_inode_pages(struct super_block *sb) | |||
2047 | 2061 | ||
2048 | static int f2fs_dquot_commit(struct dquot *dquot) | 2062 | static int f2fs_dquot_commit(struct dquot *dquot) |
2049 | { | 2063 | { |
2064 | struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); | ||
2050 | int ret; | 2065 | int ret; |
2051 | 2066 | ||
2067 | down_read(&sbi->quota_sem); | ||
2052 | ret = dquot_commit(dquot); | 2068 | ret = dquot_commit(dquot); |
2053 | if (ret < 0) | 2069 | if (ret < 0) |
2054 | set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR); | 2070 | set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); |
2071 | up_read(&sbi->quota_sem); | ||
2055 | return ret; | 2072 | return ret; |
2056 | } | 2073 | } |
2057 | 2074 | ||
2058 | static int f2fs_dquot_acquire(struct dquot *dquot) | 2075 | static int f2fs_dquot_acquire(struct dquot *dquot) |
2059 | { | 2076 | { |
2077 | struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); | ||
2060 | int ret; | 2078 | int ret; |
2061 | 2079 | ||
2080 | down_read(&sbi->quota_sem); | ||
2062 | ret = dquot_acquire(dquot); | 2081 | ret = dquot_acquire(dquot); |
2063 | if (ret < 0) | 2082 | if (ret < 0) |
2064 | set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR); | 2083 | set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); |
2065 | 2084 | up_read(&sbi->quota_sem); | |
2066 | return ret; | 2085 | return ret; |
2067 | } | 2086 | } |
2068 | 2087 | ||
2069 | static int f2fs_dquot_release(struct dquot *dquot) | 2088 | static int f2fs_dquot_release(struct dquot *dquot) |
2070 | { | 2089 | { |
2090 | struct f2fs_sb_info *sbi = F2FS_SB(dquot->dq_sb); | ||
2071 | int ret; | 2091 | int ret; |
2072 | 2092 | ||
2093 | down_read(&sbi->quota_sem); | ||
2073 | ret = dquot_release(dquot); | 2094 | ret = dquot_release(dquot); |
2074 | if (ret < 0) | 2095 | if (ret < 0) |
2075 | set_sbi_flag(F2FS_SB(dquot->dq_sb), SBI_QUOTA_NEED_REPAIR); | 2096 | set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); |
2097 | up_read(&sbi->quota_sem); | ||
2076 | return ret; | 2098 | return ret; |
2077 | } | 2099 | } |
2078 | 2100 | ||
@@ -2082,22 +2104,27 @@ static int f2fs_dquot_mark_dquot_dirty(struct dquot *dquot) | |||
2082 | struct f2fs_sb_info *sbi = F2FS_SB(sb); | 2104 | struct f2fs_sb_info *sbi = F2FS_SB(sb); |
2083 | int ret; | 2105 | int ret; |
2084 | 2106 | ||
2107 | down_read(&sbi->quota_sem); | ||
2085 | ret = dquot_mark_dquot_dirty(dquot); | 2108 | ret = dquot_mark_dquot_dirty(dquot); |
2086 | 2109 | ||
2087 | /* if we are using journalled quota */ | 2110 | /* if we are using journalled quota */ |
2088 | if (is_journalled_quota(sbi)) | 2111 | if (is_journalled_quota(sbi)) |
2089 | set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); | 2112 | set_sbi_flag(sbi, SBI_QUOTA_NEED_FLUSH); |
2090 | 2113 | ||
2114 | up_read(&sbi->quota_sem); | ||
2091 | return ret; | 2115 | return ret; |
2092 | } | 2116 | } |
2093 | 2117 | ||
2094 | static int f2fs_dquot_commit_info(struct super_block *sb, int type) | 2118 | static int f2fs_dquot_commit_info(struct super_block *sb, int type) |
2095 | { | 2119 | { |
2120 | struct f2fs_sb_info *sbi = F2FS_SB(sb); | ||
2096 | int ret; | 2121 | int ret; |
2097 | 2122 | ||
2123 | down_read(&sbi->quota_sem); | ||
2098 | ret = dquot_commit_info(sb, type); | 2124 | ret = dquot_commit_info(sb, type); |
2099 | if (ret < 0) | 2125 | if (ret < 0) |
2100 | set_sbi_flag(F2FS_SB(sb), SBI_QUOTA_NEED_REPAIR); | 2126 | set_sbi_flag(sbi, SBI_QUOTA_NEED_REPAIR); |
2127 | up_read(&sbi->quota_sem); | ||
2101 | return ret; | 2128 | return ret; |
2102 | } | 2129 | } |
2103 | 2130 | ||
@@ -3167,6 +3194,7 @@ try_onemore: | |||
3167 | } | 3194 | } |
3168 | 3195 | ||
3169 | init_rwsem(&sbi->cp_rwsem); | 3196 | init_rwsem(&sbi->cp_rwsem); |
3197 | init_rwsem(&sbi->quota_sem); | ||
3170 | init_waitqueue_head(&sbi->cp_wait); | 3198 | init_waitqueue_head(&sbi->cp_wait); |
3171 | init_sb_info(sbi); | 3199 | init_sb_info(sbi); |
3172 | 3200 | ||