aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2016-06-03 22:29:38 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2016-06-13 14:55:21 -0400
commit36abef4e796d382e81a0c2d21ea5327481dd7154 (patch)
tree64ddad32e0f684ef7a5b5d734bbc7a4684c8bafa
parentaa987273290d206b298e9d09db83e32ead661098 (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.txt3
-rw-r--r--fs/f2fs/checkpoint.c2
-rw-r--r--fs/f2fs/data.c2
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/file.c8
-rw-r--r--fs/f2fs/recovery.c6
-rw-r--r--fs/f2fs/segment.c20
-rw-r--r--fs/f2fs/segment.h7
-rw-r--r--fs/f2fs/super.c28
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.
152data_flush Enable data flushing before checkpoint in order to 152data_flush Enable data flushing before checkpoint in order to
153 persist data of regular and symlink. 153 persist data of regular and symlink.
154mode=%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================================================================================
156DEBUGFS ENTRIES 159DEBUGFS 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 }
735next:
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);