diff options
Diffstat (limited to 'fs/f2fs/super.c')
| -rw-r--r-- | fs/f2fs/super.c | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index f71421d70475..f2fe666a6ea9 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "segment.h" | 30 | #include "segment.h" |
| 31 | #include "xattr.h" | 31 | #include "xattr.h" |
| 32 | #include "gc.h" | 32 | #include "gc.h" |
| 33 | #include "trace.h" | ||
| 33 | 34 | ||
| 34 | #define CREATE_TRACE_POINTS | 35 | #define CREATE_TRACE_POINTS |
| 35 | #include <trace/events/f2fs.h> | 36 | #include <trace/events/f2fs.h> |
| @@ -41,6 +42,7 @@ static struct kset *f2fs_kset; | |||
| 41 | enum { | 42 | enum { |
| 42 | Opt_gc_background, | 43 | Opt_gc_background, |
| 43 | Opt_disable_roll_forward, | 44 | Opt_disable_roll_forward, |
| 45 | Opt_norecovery, | ||
| 44 | Opt_discard, | 46 | Opt_discard, |
| 45 | Opt_noheap, | 47 | Opt_noheap, |
| 46 | Opt_user_xattr, | 48 | Opt_user_xattr, |
| @@ -61,6 +63,7 @@ enum { | |||
| 61 | static match_table_t f2fs_tokens = { | 63 | static match_table_t f2fs_tokens = { |
| 62 | {Opt_gc_background, "background_gc=%s"}, | 64 | {Opt_gc_background, "background_gc=%s"}, |
| 63 | {Opt_disable_roll_forward, "disable_roll_forward"}, | 65 | {Opt_disable_roll_forward, "disable_roll_forward"}, |
| 66 | {Opt_norecovery, "norecovery"}, | ||
| 64 | {Opt_discard, "discard"}, | 67 | {Opt_discard, "discard"}, |
| 65 | {Opt_noheap, "no_heap"}, | 68 | {Opt_noheap, "no_heap"}, |
| 66 | {Opt_user_xattr, "user_xattr"}, | 69 | {Opt_user_xattr, "user_xattr"}, |
| @@ -192,6 +195,7 @@ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); | |||
| 192 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); | 195 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); |
| 193 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); | 196 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); |
| 194 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); | 197 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); |
| 198 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); | ||
| 195 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); | 199 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); |
| 196 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); | 200 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); |
| 197 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); | 201 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_fsync_blocks, min_fsync_blocks); |
| @@ -207,6 +211,7 @@ static struct attribute *f2fs_attrs[] = { | |||
| 207 | ATTR_LIST(gc_idle), | 211 | ATTR_LIST(gc_idle), |
| 208 | ATTR_LIST(reclaim_segments), | 212 | ATTR_LIST(reclaim_segments), |
| 209 | ATTR_LIST(max_small_discards), | 213 | ATTR_LIST(max_small_discards), |
| 214 | ATTR_LIST(batched_trim_sections), | ||
| 210 | ATTR_LIST(ipu_policy), | 215 | ATTR_LIST(ipu_policy), |
| 211 | ATTR_LIST(min_ipu_util), | 216 | ATTR_LIST(min_ipu_util), |
| 212 | ATTR_LIST(min_fsync_blocks), | 217 | ATTR_LIST(min_fsync_blocks), |
| @@ -286,6 +291,12 @@ static int parse_options(struct super_block *sb, char *options) | |||
| 286 | case Opt_disable_roll_forward: | 291 | case Opt_disable_roll_forward: |
| 287 | set_opt(sbi, DISABLE_ROLL_FORWARD); | 292 | set_opt(sbi, DISABLE_ROLL_FORWARD); |
| 288 | break; | 293 | break; |
| 294 | case Opt_norecovery: | ||
| 295 | /* this option mounts f2fs with ro */ | ||
| 296 | set_opt(sbi, DISABLE_ROLL_FORWARD); | ||
| 297 | if (!f2fs_readonly(sb)) | ||
| 298 | return -EINVAL; | ||
| 299 | break; | ||
| 289 | case Opt_discard: | 300 | case Opt_discard: |
| 290 | set_opt(sbi, DISCARD); | 301 | set_opt(sbi, DISCARD); |
| 291 | break; | 302 | break; |
| @@ -446,8 +457,13 @@ static void f2fs_put_super(struct super_block *sb) | |||
| 446 | f2fs_destroy_stats(sbi); | 457 | f2fs_destroy_stats(sbi); |
| 447 | stop_gc_thread(sbi); | 458 | stop_gc_thread(sbi); |
| 448 | 459 | ||
| 449 | /* We don't need to do checkpoint when it's clean */ | 460 | /* |
| 450 | if (sbi->s_dirty) { | 461 | * We don't need to do checkpoint when superblock is clean. |
| 462 | * But, the previous checkpoint was not done by umount, it needs to do | ||
| 463 | * clean checkpoint again. | ||
| 464 | */ | ||
| 465 | if (is_sbi_flag_set(sbi, SBI_IS_DIRTY) || | ||
| 466 | !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG)) { | ||
| 451 | struct cp_control cpc = { | 467 | struct cp_control cpc = { |
| 452 | .reason = CP_UMOUNT, | 468 | .reason = CP_UMOUNT, |
| 453 | }; | 469 | }; |
| @@ -486,13 +502,15 @@ int f2fs_sync_fs(struct super_block *sb, int sync) | |||
| 486 | if (sync) { | 502 | if (sync) { |
| 487 | struct cp_control cpc; | 503 | struct cp_control cpc; |
| 488 | 504 | ||
| 489 | cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC; | 505 | cpc.reason = __get_cp_reason(sbi); |
| 506 | |||
| 490 | mutex_lock(&sbi->gc_mutex); | 507 | mutex_lock(&sbi->gc_mutex); |
| 491 | write_checkpoint(sbi, &cpc); | 508 | write_checkpoint(sbi, &cpc); |
| 492 | mutex_unlock(&sbi->gc_mutex); | 509 | mutex_unlock(&sbi->gc_mutex); |
| 493 | } else { | 510 | } else { |
| 494 | f2fs_balance_fs(sbi); | 511 | f2fs_balance_fs(sbi); |
| 495 | } | 512 | } |
| 513 | f2fs_trace_ios(NULL, NULL, 1); | ||
| 496 | 514 | ||
| 497 | return 0; | 515 | return 0; |
| 498 | } | 516 | } |
| @@ -887,7 +905,7 @@ static void init_sb_info(struct f2fs_sb_info *sbi) | |||
| 887 | atomic_set(&sbi->nr_pages[i], 0); | 905 | atomic_set(&sbi->nr_pages[i], 0); |
| 888 | 906 | ||
| 889 | sbi->dir_level = DEF_DIR_LEVEL; | 907 | sbi->dir_level = DEF_DIR_LEVEL; |
| 890 | sbi->need_fsck = false; | 908 | clear_sbi_flag(sbi, SBI_NEED_FSCK); |
| 891 | } | 909 | } |
| 892 | 910 | ||
| 893 | /* | 911 | /* |
| @@ -942,6 +960,7 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 942 | struct inode *root; | 960 | struct inode *root; |
| 943 | long err = -EINVAL; | 961 | long err = -EINVAL; |
| 944 | bool retry = true; | 962 | bool retry = true; |
| 963 | char *options = NULL; | ||
| 945 | int i; | 964 | int i; |
| 946 | 965 | ||
| 947 | try_onemore: | 966 | try_onemore: |
| @@ -973,9 +992,15 @@ try_onemore: | |||
| 973 | set_opt(sbi, POSIX_ACL); | 992 | set_opt(sbi, POSIX_ACL); |
| 974 | #endif | 993 | #endif |
| 975 | /* parse mount options */ | 994 | /* parse mount options */ |
| 976 | err = parse_options(sb, (char *)data); | 995 | options = kstrdup((const char *)data, GFP_KERNEL); |
| 977 | if (err) | 996 | if (data && !options) { |
| 997 | err = -ENOMEM; | ||
| 978 | goto free_sb_buf; | 998 | goto free_sb_buf; |
| 999 | } | ||
| 1000 | |||
| 1001 | err = parse_options(sb, options); | ||
| 1002 | if (err) | ||
| 1003 | goto free_options; | ||
| 979 | 1004 | ||
| 980 | sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); | 1005 | sb->s_maxbytes = max_file_size(le32_to_cpu(raw_super->log_blocksize)); |
| 981 | sb->s_max_links = F2FS_LINK_MAX; | 1006 | sb->s_max_links = F2FS_LINK_MAX; |
| @@ -998,7 +1023,7 @@ try_onemore: | |||
| 998 | mutex_init(&sbi->writepages); | 1023 | mutex_init(&sbi->writepages); |
| 999 | mutex_init(&sbi->cp_mutex); | 1024 | mutex_init(&sbi->cp_mutex); |
| 1000 | init_rwsem(&sbi->node_write); | 1025 | init_rwsem(&sbi->node_write); |
| 1001 | sbi->por_doing = false; | 1026 | clear_sbi_flag(sbi, SBI_POR_DOING); |
| 1002 | spin_lock_init(&sbi->stat_lock); | 1027 | spin_lock_init(&sbi->stat_lock); |
| 1003 | 1028 | ||
| 1004 | init_rwsem(&sbi->read_io.io_rwsem); | 1029 | init_rwsem(&sbi->read_io.io_rwsem); |
| @@ -1019,7 +1044,7 @@ try_onemore: | |||
| 1019 | if (IS_ERR(sbi->meta_inode)) { | 1044 | if (IS_ERR(sbi->meta_inode)) { |
| 1020 | f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode"); | 1045 | f2fs_msg(sb, KERN_ERR, "Failed to read F2FS meta data inode"); |
| 1021 | err = PTR_ERR(sbi->meta_inode); | 1046 | err = PTR_ERR(sbi->meta_inode); |
| 1022 | goto free_sb_buf; | 1047 | goto free_options; |
| 1023 | } | 1048 | } |
| 1024 | 1049 | ||
| 1025 | err = get_valid_checkpoint(sbi); | 1050 | err = get_valid_checkpoint(sbi); |
| @@ -1122,10 +1147,19 @@ try_onemore: | |||
| 1122 | goto free_proc; | 1147 | goto free_proc; |
| 1123 | 1148 | ||
| 1124 | if (!retry) | 1149 | if (!retry) |
| 1125 | sbi->need_fsck = true; | 1150 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
| 1126 | 1151 | ||
| 1127 | /* recover fsynced data */ | 1152 | /* recover fsynced data */ |
| 1128 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { | 1153 | if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) { |
| 1154 | /* | ||
| 1155 | * mount should be failed, when device has readonly mode, and | ||
| 1156 | * previous checkpoint was not done by clean system shutdown. | ||
| 1157 | */ | ||
| 1158 | if (bdev_read_only(sb->s_bdev) && | ||
| 1159 | !is_set_ckpt_flags(sbi->ckpt, CP_UMOUNT_FLAG)) { | ||
| 1160 | err = -EROFS; | ||
| 1161 | goto free_kobj; | ||
| 1162 | } | ||
| 1129 | err = recover_fsync_data(sbi); | 1163 | err = recover_fsync_data(sbi); |
| 1130 | if (err) { | 1164 | if (err) { |
| 1131 | f2fs_msg(sb, KERN_ERR, | 1165 | f2fs_msg(sb, KERN_ERR, |
| @@ -1144,6 +1178,7 @@ try_onemore: | |||
| 1144 | if (err) | 1178 | if (err) |
| 1145 | goto free_kobj; | 1179 | goto free_kobj; |
| 1146 | } | 1180 | } |
| 1181 | kfree(options); | ||
| 1147 | return 0; | 1182 | return 0; |
| 1148 | 1183 | ||
| 1149 | free_kobj: | 1184 | free_kobj: |
| @@ -1168,6 +1203,8 @@ free_cp: | |||
| 1168 | free_meta_inode: | 1203 | free_meta_inode: |
| 1169 | make_bad_inode(sbi->meta_inode); | 1204 | make_bad_inode(sbi->meta_inode); |
| 1170 | iput(sbi->meta_inode); | 1205 | iput(sbi->meta_inode); |
| 1206 | free_options: | ||
| 1207 | kfree(options); | ||
| 1171 | free_sb_buf: | 1208 | free_sb_buf: |
| 1172 | brelse(raw_super_buf); | 1209 | brelse(raw_super_buf); |
| 1173 | free_sbi: | 1210 | free_sbi: |
| @@ -1188,11 +1225,18 @@ static struct dentry *f2fs_mount(struct file_system_type *fs_type, int flags, | |||
| 1188 | return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); | 1225 | return mount_bdev(fs_type, flags, dev_name, data, f2fs_fill_super); |
| 1189 | } | 1226 | } |
| 1190 | 1227 | ||
| 1228 | static void kill_f2fs_super(struct super_block *sb) | ||
| 1229 | { | ||
| 1230 | if (sb->s_root) | ||
| 1231 | set_sbi_flag(F2FS_SB(sb), SBI_IS_CLOSE); | ||
| 1232 | kill_block_super(sb); | ||
| 1233 | } | ||
| 1234 | |||
| 1191 | static struct file_system_type f2fs_fs_type = { | 1235 | static struct file_system_type f2fs_fs_type = { |
| 1192 | .owner = THIS_MODULE, | 1236 | .owner = THIS_MODULE, |
| 1193 | .name = "f2fs", | 1237 | .name = "f2fs", |
| 1194 | .mount = f2fs_mount, | 1238 | .mount = f2fs_mount, |
| 1195 | .kill_sb = kill_block_super, | 1239 | .kill_sb = kill_f2fs_super, |
| 1196 | .fs_flags = FS_REQUIRES_DEV, | 1240 | .fs_flags = FS_REQUIRES_DEV, |
| 1197 | }; | 1241 | }; |
| 1198 | MODULE_ALIAS_FS("f2fs"); | 1242 | MODULE_ALIAS_FS("f2fs"); |
| @@ -1220,6 +1264,8 @@ static int __init init_f2fs_fs(void) | |||
| 1220 | { | 1264 | { |
| 1221 | int err; | 1265 | int err; |
| 1222 | 1266 | ||
| 1267 | f2fs_build_trace_ios(); | ||
| 1268 | |||
| 1223 | err = init_inodecache(); | 1269 | err = init_inodecache(); |
| 1224 | if (err) | 1270 | if (err) |
| 1225 | goto fail; | 1271 | goto fail; |
| @@ -1229,12 +1275,9 @@ static int __init init_f2fs_fs(void) | |||
| 1229 | err = create_segment_manager_caches(); | 1275 | err = create_segment_manager_caches(); |
| 1230 | if (err) | 1276 | if (err) |
| 1231 | goto free_node_manager_caches; | 1277 | goto free_node_manager_caches; |
| 1232 | err = create_gc_caches(); | ||
| 1233 | if (err) | ||
| 1234 | goto free_segment_manager_caches; | ||
| 1235 | err = create_checkpoint_caches(); | 1278 | err = create_checkpoint_caches(); |
| 1236 | if (err) | 1279 | if (err) |
| 1237 | goto free_gc_caches; | 1280 | goto free_segment_manager_caches; |
| 1238 | f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj); | 1281 | f2fs_kset = kset_create_and_add("f2fs", NULL, fs_kobj); |
| 1239 | if (!f2fs_kset) { | 1282 | if (!f2fs_kset) { |
| 1240 | err = -ENOMEM; | 1283 | err = -ENOMEM; |
| @@ -1251,8 +1294,6 @@ free_kset: | |||
| 1251 | kset_unregister(f2fs_kset); | 1294 | kset_unregister(f2fs_kset); |
| 1252 | free_checkpoint_caches: | 1295 | free_checkpoint_caches: |
| 1253 | destroy_checkpoint_caches(); | 1296 | destroy_checkpoint_caches(); |
| 1254 | free_gc_caches: | ||
| 1255 | destroy_gc_caches(); | ||
| 1256 | free_segment_manager_caches: | 1297 | free_segment_manager_caches: |
| 1257 | destroy_segment_manager_caches(); | 1298 | destroy_segment_manager_caches(); |
| 1258 | free_node_manager_caches: | 1299 | free_node_manager_caches: |
| @@ -1269,11 +1310,11 @@ static void __exit exit_f2fs_fs(void) | |||
| 1269 | f2fs_destroy_root_stats(); | 1310 | f2fs_destroy_root_stats(); |
| 1270 | unregister_filesystem(&f2fs_fs_type); | 1311 | unregister_filesystem(&f2fs_fs_type); |
| 1271 | destroy_checkpoint_caches(); | 1312 | destroy_checkpoint_caches(); |
| 1272 | destroy_gc_caches(); | ||
| 1273 | destroy_segment_manager_caches(); | 1313 | destroy_segment_manager_caches(); |
| 1274 | destroy_node_manager_caches(); | 1314 | destroy_node_manager_caches(); |
| 1275 | destroy_inodecache(); | 1315 | destroy_inodecache(); |
| 1276 | kset_unregister(f2fs_kset); | 1316 | kset_unregister(f2fs_kset); |
| 1317 | f2fs_destroy_trace_ios(); | ||
| 1277 | } | 1318 | } |
| 1278 | 1319 | ||
| 1279 | module_init(init_f2fs_fs) | 1320 | module_init(init_f2fs_fs) |
