diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2016-06-03 22:29:38 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2016-06-13 14:55:21 -0400 |
commit | 36abef4e796d382e81a0c2d21ea5327481dd7154 (patch) | |
tree | 64ddad32e0f684ef7a5b5d734bbc7a4684c8bafa | |
parent | aa987273290d206b298e9d09db83e32ead661098 (diff) |
f2fs: introduce mode=lfs mount option
This mount option is to enable original log-structured filesystem forcefully.
So, there should be no random writes for main area.
Especially, this supports host-managed SMR device.
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | Documentation/filesystems/f2fs.txt | 3 | ||||
-rw-r--r-- | fs/f2fs/checkpoint.c | 2 | ||||
-rw-r--r-- | fs/f2fs/data.c | 2 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 2 | ||||
-rw-r--r-- | fs/f2fs/file.c | 8 | ||||
-rw-r--r-- | fs/f2fs/recovery.c | 6 | ||||
-rw-r--r-- | fs/f2fs/segment.c | 20 | ||||
-rw-r--r-- | fs/f2fs/segment.h | 7 | ||||
-rw-r--r-- | fs/f2fs/super.c | 28 |
9 files changed, 74 insertions, 4 deletions
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt index e1c9f0849da6..3a5ce24021d9 100644 --- a/Documentation/filesystems/f2fs.txt +++ b/Documentation/filesystems/f2fs.txt | |||
@@ -151,6 +151,9 @@ noinline_data Disable the inline data feature, inline data feature is | |||
151 | enabled by default. | 151 | enabled by default. |
152 | data_flush Enable data flushing before checkpoint in order to | 152 | data_flush Enable data flushing before checkpoint in order to |
153 | persist data of regular and symlink. | 153 | persist data of regular and symlink. |
154 | mode=%s Control block allocation mode which supports "adaptive" | ||
155 | and "lfs". In "lfs" mode, there should be no random | ||
156 | writes towards main area. | ||
154 | 157 | ||
155 | ================================================================================ | 158 | ================================================================================ |
156 | DEBUGFS ENTRIES | 159 | DEBUGFS ENTRIES |
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 4179c7b971fc..837e6bcad5ce 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c | |||
@@ -981,7 +981,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
981 | * This avoids to conduct wrong roll-forward operations and uses | 981 | * This avoids to conduct wrong roll-forward operations and uses |
982 | * metapages, so should be called prior to sync_meta_pages below. | 982 | * metapages, so should be called prior to sync_meta_pages below. |
983 | */ | 983 | */ |
984 | if (discard_next_dnode(sbi, discard_blk)) | 984 | if (!test_opt(sbi, LFS) && discard_next_dnode(sbi, discard_blk)) |
985 | invalidate = true; | 985 | invalidate = true; |
986 | 986 | ||
987 | /* Flush all the NAT/SIT pages */ | 987 | /* Flush all the NAT/SIT pages */ |
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 5f655d0c5b1f..607ef4397330 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c | |||
@@ -1710,6 +1710,8 @@ static ssize_t f2fs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) | |||
1710 | 1710 | ||
1711 | if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) | 1711 | if (f2fs_encrypted_inode(inode) && S_ISREG(inode->i_mode)) |
1712 | return 0; | 1712 | return 0; |
1713 | if (test_opt(F2FS_I_SB(inode), LFS)) | ||
1714 | return 0; | ||
1713 | 1715 | ||
1714 | trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); | 1716 | trace_f2fs_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); |
1715 | 1717 | ||
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 24c7cde84905..82acdec022ef 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -111,6 +111,8 @@ static inline bool time_to_inject(int type) | |||
111 | #define F2FS_MOUNT_FORCE_FG_GC 0x00004000 | 111 | #define F2FS_MOUNT_FORCE_FG_GC 0x00004000 |
112 | #define F2FS_MOUNT_DATA_FLUSH 0x00008000 | 112 | #define F2FS_MOUNT_DATA_FLUSH 0x00008000 |
113 | #define F2FS_MOUNT_FAULT_INJECTION 0x00010000 | 113 | #define F2FS_MOUNT_FAULT_INJECTION 0x00010000 |
114 | #define F2FS_MOUNT_ADAPTIVE 0x00020000 | ||
115 | #define F2FS_MOUNT_LFS 0x00040000 | ||
114 | 116 | ||
115 | #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) | 117 | #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option) |
116 | #define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) | 118 | #define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option) |
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7a8d262bc488..b9d745ef5b08 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c | |||
@@ -878,9 +878,15 @@ static int __exchange_data_block(struct inode *inode, pgoff_t src, | |||
878 | return full ? truncate_hole(inode, dst, dst + 1) : 0; | 878 | return full ? truncate_hole(inode, dst, dst + 1) : 0; |
879 | 879 | ||
880 | if (do_replace) { | 880 | if (do_replace) { |
881 | struct page *ipage = get_node_page(sbi, inode->i_ino); | 881 | struct page *ipage; |
882 | struct node_info ni; | 882 | struct node_info ni; |
883 | 883 | ||
884 | if (test_opt(sbi, LFS)) { | ||
885 | ret = -ENOTSUPP; | ||
886 | goto err_out; | ||
887 | } | ||
888 | |||
889 | ipage = get_node_page(sbi, inode->i_ino); | ||
884 | if (IS_ERR(ipage)) { | 890 | if (IS_ERR(ipage)) { |
885 | ret = PTR_ERR(ipage); | 891 | ret = PTR_ERR(ipage); |
886 | goto err_out; | 892 | goto err_out; |
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index b568b28c74f2..a39d84ab66b2 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -624,8 +624,12 @@ out: | |||
624 | if (err) { | 624 | if (err) { |
625 | bool invalidate = false; | 625 | bool invalidate = false; |
626 | 626 | ||
627 | if (discard_next_dnode(sbi, blkaddr)) | 627 | if (test_opt(sbi, LFS)) { |
628 | update_meta_page(sbi, NULL, blkaddr); | ||
628 | invalidate = true; | 629 | invalidate = true; |
630 | } else if (discard_next_dnode(sbi, blkaddr)) { | ||
631 | invalidate = true; | ||
632 | } | ||
629 | 633 | ||
630 | /* Flush all the NAT/SIT pages */ | 634 | /* Flush all the NAT/SIT pages */ |
631 | while (get_pages(sbi, F2FS_DIRTY_META)) | 635 | while (get_pages(sbi, F2FS_DIRTY_META)) |
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index eff046a792ad..4792f94089f7 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -707,6 +707,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
707 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 707 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
708 | unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; | 708 | unsigned long *prefree_map = dirty_i->dirty_segmap[PRE]; |
709 | unsigned int start = 0, end = -1; | 709 | unsigned int start = 0, end = -1; |
710 | unsigned int secno, start_segno; | ||
710 | 711 | ||
711 | mutex_lock(&dirty_i->seglist_lock); | 712 | mutex_lock(&dirty_i->seglist_lock); |
712 | 713 | ||
@@ -726,8 +727,22 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
726 | if (!test_opt(sbi, DISCARD)) | 727 | if (!test_opt(sbi, DISCARD)) |
727 | continue; | 728 | continue; |
728 | 729 | ||
729 | f2fs_issue_discard(sbi, START_BLOCK(sbi, start), | 730 | if (!test_opt(sbi, LFS) || sbi->segs_per_sec == 1) { |
731 | f2fs_issue_discard(sbi, START_BLOCK(sbi, start), | ||
730 | (end - start) << sbi->log_blocks_per_seg); | 732 | (end - start) << sbi->log_blocks_per_seg); |
733 | continue; | ||
734 | } | ||
735 | next: | ||
736 | secno = GET_SECNO(sbi, start); | ||
737 | start_segno = secno * sbi->segs_per_sec; | ||
738 | if (!IS_CURSEC(sbi, secno) && | ||
739 | !get_valid_blocks(sbi, start, sbi->segs_per_sec)) | ||
740 | f2fs_issue_discard(sbi, START_BLOCK(sbi, start_segno), | ||
741 | sbi->segs_per_sec << sbi->log_blocks_per_seg); | ||
742 | |||
743 | start = start_segno + sbi->segs_per_sec; | ||
744 | if (start < end) | ||
745 | goto next; | ||
731 | } | 746 | } |
732 | mutex_unlock(&dirty_i->seglist_lock); | 747 | mutex_unlock(&dirty_i->seglist_lock); |
733 | 748 | ||
@@ -1221,6 +1236,9 @@ void allocate_new_segments(struct f2fs_sb_info *sbi) | |||
1221 | { | 1236 | { |
1222 | int i; | 1237 | int i; |
1223 | 1238 | ||
1239 | if (test_opt(sbi, LFS)) | ||
1240 | return; | ||
1241 | |||
1224 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) | 1242 | for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) |
1225 | __allocate_new_segments(sbi, i); | 1243 | __allocate_new_segments(sbi, i); |
1226 | } | 1244 | } |
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 890bb28d2082..d74cc330ae13 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h | |||
@@ -470,6 +470,10 @@ static inline bool need_SSR(struct f2fs_sb_info *sbi) | |||
470 | { | 470 | { |
471 | int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); | 471 | int node_secs = get_blocktype_secs(sbi, F2FS_DIRTY_NODES); |
472 | int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); | 472 | int dent_secs = get_blocktype_secs(sbi, F2FS_DIRTY_DENTS); |
473 | |||
474 | if (test_opt(sbi, LFS)) | ||
475 | return false; | ||
476 | |||
473 | return free_sections(sbi) <= (node_secs + 2 * dent_secs + | 477 | return free_sections(sbi) <= (node_secs + 2 * dent_secs + |
474 | reserved_sections(sbi) + 1); | 478 | reserved_sections(sbi) + 1); |
475 | } | 479 | } |
@@ -533,6 +537,9 @@ static inline bool need_inplace_update(struct inode *inode) | |||
533 | if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode)) | 537 | if (S_ISDIR(inode->i_mode) || f2fs_is_atomic_file(inode)) |
534 | return false; | 538 | return false; |
535 | 539 | ||
540 | if (test_opt(sbi, LFS)) | ||
541 | return false; | ||
542 | |||
536 | if (policy & (0x1 << F2FS_IPU_FORCE)) | 543 | if (policy & (0x1 << F2FS_IPU_FORCE)) |
537 | return true; | 544 | return true; |
538 | if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi)) | 545 | if (policy & (0x1 << F2FS_IPU_SSR) && need_SSR(sbi)) |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index dc66f1623e06..edc736de8ee9 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -94,6 +94,7 @@ enum { | |||
94 | Opt_noextent_cache, | 94 | Opt_noextent_cache, |
95 | Opt_noinline_data, | 95 | Opt_noinline_data, |
96 | Opt_data_flush, | 96 | Opt_data_flush, |
97 | Opt_mode, | ||
97 | Opt_fault_injection, | 98 | Opt_fault_injection, |
98 | Opt_lazytime, | 99 | Opt_lazytime, |
99 | Opt_nolazytime, | 100 | Opt_nolazytime, |
@@ -123,6 +124,7 @@ static match_table_t f2fs_tokens = { | |||
123 | {Opt_noextent_cache, "noextent_cache"}, | 124 | {Opt_noextent_cache, "noextent_cache"}, |
124 | {Opt_noinline_data, "noinline_data"}, | 125 | {Opt_noinline_data, "noinline_data"}, |
125 | {Opt_data_flush, "data_flush"}, | 126 | {Opt_data_flush, "data_flush"}, |
127 | {Opt_mode, "mode=%s"}, | ||
126 | {Opt_fault_injection, "fault_injection=%u"}, | 128 | {Opt_fault_injection, "fault_injection=%u"}, |
127 | {Opt_lazytime, "lazytime"}, | 129 | {Opt_lazytime, "lazytime"}, |
128 | {Opt_nolazytime, "nolazytime"}, | 130 | {Opt_nolazytime, "nolazytime"}, |
@@ -506,6 +508,25 @@ static int parse_options(struct super_block *sb, char *options) | |||
506 | case Opt_data_flush: | 508 | case Opt_data_flush: |
507 | set_opt(sbi, DATA_FLUSH); | 509 | set_opt(sbi, DATA_FLUSH); |
508 | break; | 510 | break; |
511 | case Opt_mode: | ||
512 | name = match_strdup(&args[0]); | ||
513 | |||
514 | if (!name) | ||
515 | return -ENOMEM; | ||
516 | if (strlen(name) == 8 && | ||
517 | !strncmp(name, "adaptive", 8)) { | ||
518 | set_opt(sbi, ADAPTIVE); | ||
519 | clear_opt(sbi, LFS); | ||
520 | } else if (strlen(name) == 3 && | ||
521 | !strncmp(name, "lfs", 3)) { | ||
522 | clear_opt(sbi, ADAPTIVE); | ||
523 | set_opt(sbi, LFS); | ||
524 | } else { | ||
525 | kfree(name); | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | kfree(name); | ||
529 | break; | ||
509 | case Opt_fault_injection: | 530 | case Opt_fault_injection: |
510 | if (args->from && match_int(args, &arg)) | 531 | if (args->from && match_int(args, &arg)) |
511 | return -EINVAL; | 532 | return -EINVAL; |
@@ -870,6 +891,12 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) | |||
870 | seq_puts(seq, ",noextent_cache"); | 891 | seq_puts(seq, ",noextent_cache"); |
871 | if (test_opt(sbi, DATA_FLUSH)) | 892 | if (test_opt(sbi, DATA_FLUSH)) |
872 | seq_puts(seq, ",data_flush"); | 893 | seq_puts(seq, ",data_flush"); |
894 | |||
895 | seq_puts(seq, ",mode="); | ||
896 | if (test_opt(sbi, ADAPTIVE)) | ||
897 | seq_puts(seq, "adaptive"); | ||
898 | else if (test_opt(sbi, LFS)) | ||
899 | seq_puts(seq, "lfs"); | ||
873 | seq_printf(seq, ",active_logs=%u", sbi->active_logs); | 900 | seq_printf(seq, ",active_logs=%u", sbi->active_logs); |
874 | 901 | ||
875 | return 0; | 902 | return 0; |
@@ -953,6 +980,7 @@ static void default_options(struct f2fs_sb_info *sbi) | |||
953 | set_opt(sbi, EXTENT_CACHE); | 980 | set_opt(sbi, EXTENT_CACHE); |
954 | sbi->sb->s_flags |= MS_LAZYTIME; | 981 | sbi->sb->s_flags |= MS_LAZYTIME; |
955 | set_opt(sbi, FLUSH_MERGE); | 982 | set_opt(sbi, FLUSH_MERGE); |
983 | set_opt(sbi, ADAPTIVE); | ||
956 | 984 | ||
957 | #ifdef CONFIG_F2FS_FS_XATTR | 985 | #ifdef CONFIG_F2FS_FS_XATTR |
958 | set_opt(sbi, XATTR_USER); | 986 | set_opt(sbi, XATTR_USER); |