[f2fs-dev] [PATCH] f2fs: report cp block corrupted

2018-02-02 Thread Weichao Guo
There is a potential inconsistent metadata case due to a cp block
crc invalid in the latest checkpoint caused by hardware issues:
1) write nodes into segment x;
2) write checkpoint A;
3) remove nodes in segment x;
4) write checkpoint B;
5) issue discard or write datas into segment x;
6) sudden power-cut;
7) use checkpoint A after reboot as checkpoint B is invalid

This inconsistency may be found after several reboots long time later
and the kernel log about cp block crc invalid has disappeared. This
makes the root cause of the inconsistency is hard to locate. Let us
separate such other part issues from f2fs logical bugs in debug version.

Signed-off-by: Weichao Guo 
---
 fs/f2fs/checkpoint.c | 15 ++-
 1 file changed, 10 insertions(+), 5 deletions(-)

diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index 512dca8..15baba75 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -730,6 +730,7 @@ static int get_checkpoint_version(struct f2fs_sb_info *sbi, 
block_t cp_addr,
unsigned long blk_size = sbi->blocksize;
size_t crc_offset = 0;
__u32 crc = 0;
+   int err = 0;

*cp_page = get_meta_page(sbi, cp_addr);
*cp_block = (struct f2fs_checkpoint *)page_address(*cp_page);
@@ -737,18 +738,22 @@ static int get_checkpoint_version(struct f2fs_sb_info 
*sbi, block_t cp_addr,
crc_offset = le32_to_cpu((*cp_block)->checksum_offset);
if (crc_offset > (blk_size - sizeof(__le32))) {
f2fs_msg(sbi->sb, KERN_WARNING,
-   "invalid crc_offset: %zu", crc_offset);
-   return -EINVAL;
+   "invalid crc_offset: %zu at blk_addr: 0x%x",
+   crc_offset, cp_addr);
+   err = -EINVAL;
+   f2fs_bug_on(sbi, 1);
}

crc = cur_cp_crc(*cp_block);
if (!f2fs_crc_valid(sbi, crc, *cp_block, crc_offset)) {
-   f2fs_msg(sbi->sb, KERN_WARNING, "invalid crc value");
-   return -EINVAL;
+   f2fs_msg(sbi->sb, KERN_WARNING,
+   "invalid crc value at blk_addr: 0x%x", cp_addr);
+   err = -EINVAL;
+   f2fs_bug_on(sbi, 1);
}

*version = cur_cp_version(*cp_block);
-   return 0;
+   return err;
 }

 static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
--
2.10.1


--
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH 2/2] f2fs: add GC_WRITTEN_PAGE to gc atomic file

2018-02-02 Thread Yunlong Song
This patch enables to gc atomic file by adding GC_WRITTEN_PAGE to
identify the gced pages of atomic file, which can avoid
register_inmem_page in set_page_dirty, so the gced pages will not mix
with the inmem pages.

Signed-off-by: Yunlong Song 
---
 fs/f2fs/data.c|  7 ++-
 fs/f2fs/gc.c  | 25 ++---
 fs/f2fs/segment.h |  3 +++
 3 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index edafcb6..5e1fc5d 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -120,6 +120,10 @@ static void f2fs_write_end_io(struct bio *bio)
 
dec_page_count(sbi, type);
clear_cold_data(page);
+   if (IS_GC_WRITTEN_PAGE(page)) {
+   set_page_private(page, 0);
+   ClearPagePrivate(page);
+   }
end_page_writeback(page);
}
if (!get_pages(sbi, F2FS_WB_CP_DATA) &&
@@ -2418,7 +2422,8 @@ static int f2fs_set_data_page_dirty(struct page *page)
if (!PageUptodate(page))
SetPageUptodate(page);
 
-   if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)) {
+   if (f2fs_is_atomic_file(inode) && !f2fs_is_commit_atomic_write(inode)
+   && !IS_GC_WRITTEN_PAGE(page)) {
if (!IS_ATOMIC_WRITTEN_PAGE(page)) {
register_inmem_page(inode, page);
return 1;
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 84ab3ff..9d54ddb 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -622,10 +622,6 @@ static void move_data_block(struct inode *inode, block_t 
bidx,
if (!check_valid_map(F2FS_I_SB(inode), segno, off))
goto out;
 
-   if (f2fs_is_atomic_file(inode) &&
-   !f2fs_is_commit_atomic_write(inode))
-   goto out;
-
if (f2fs_is_pinned_file(inode)) {
f2fs_pin_file_control(inode, true);
goto out;
@@ -680,6 +676,12 @@ static void move_data_block(struct inode *inode, block_t 
bidx,
goto put_page_out;
}
 
+   if (f2fs_is_atomic_file(inode) &&
+   !f2fs_is_commit_atomic_write(inode) &&
+   !IS_GC_WRITTEN_PAGE(fio.encrypted_page)) {
+   set_page_private(fio.encrypted_page, (unsigned 
long)GC_WRITTEN_PAGE);
+   SetPagePrivate(fio.encrypted_page);
+   }
set_page_dirty(fio.encrypted_page);
f2fs_wait_on_page_writeback(fio.encrypted_page, DATA, true);
if (clear_page_dirty_for_io(fio.encrypted_page))
@@ -730,9 +732,6 @@ static void move_data_page(struct inode *inode, block_t 
bidx, int gc_type,
if (!check_valid_map(F2FS_I_SB(inode), segno, off))
goto out;
 
-   if (f2fs_is_atomic_file(inode) &&
-   !f2fs_is_commit_atomic_write(inode))
-   goto out;
if (f2fs_is_pinned_file(inode)) {
if (gc_type == FG_GC)
f2fs_pin_file_control(inode, true);
@@ -742,6 +741,12 @@ static void move_data_page(struct inode *inode, block_t 
bidx, int gc_type,
if (gc_type == BG_GC) {
if (PageWriteback(page))
goto out;
+   if (f2fs_is_atomic_file(inode) &&
+   !f2fs_is_commit_atomic_write(inode) &&
+   !IS_GC_WRITTEN_PAGE(page)) {
+   set_page_private(page, (unsigned long)GC_WRITTEN_PAGE);
+   SetPagePrivate(page);
+   }
set_page_dirty(page);
set_cold_data(page);
} else {
@@ -762,6 +767,12 @@ static void move_data_page(struct inode *inode, block_t 
bidx, int gc_type,
int err;
 
 retry:
+   if (f2fs_is_atomic_file(inode) &&
+   !f2fs_is_commit_atomic_write(inode) &&
+   !IS_GC_WRITTEN_PAGE(page)) {
+   set_page_private(page, (unsigned long)GC_WRITTEN_PAGE);
+   SetPagePrivate(page);
+   }
set_page_dirty(page);
f2fs_wait_on_page_writeback(page, DATA, true);
if (clear_page_dirty_for_io(page)) {
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index f11c4bc..f0a6432 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -203,11 +203,14 @@ struct segment_allocation {
  */
 #define ATOMIC_WRITTEN_PAGE((unsigned long)-1)
 #define DUMMY_WRITTEN_PAGE ((unsigned long)-2)
+#define GC_WRITTEN_PAGE((unsigned long)-3)
 
 #define IS_ATOMIC_WRITTEN_PAGE(page)   \
(page_private(page) == (unsigned long)ATOMIC_WRITTEN_PAGE)
 #define IS_DUMMY_WRITTEN_PAGE(page)\
(page_private(page) == (unsigned long)DUMMY_WRITTEN_PAGE)
+#define IS_GC_WRITTEN_PAGE(page)   \
+   (page_private(page) == (unsigned 

[f2fs-dev] [PATCH 1/2] f2fs: enable to gc page whose inode already atomic commit

2018-02-02 Thread Yunlong Song
If inode has already started to atomic commit, then set_page_dirty will
not mix the gc pages with the inmem atomic pages, so the page can be
gced safely.

Signed-off-by: Yunlong Song 
---
 fs/f2fs/data.c | 5 ++---
 fs/f2fs/gc.c   | 6 --
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 7435830..edafcb6 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -1580,14 +1580,13 @@ bool should_update_outplace(struct inode *inode, struct 
f2fs_io_info *fio)
return true;
if (S_ISDIR(inode->i_mode))
return true;
-   if (f2fs_is_atomic_file(inode))
-   return true;
if (fio) {
if (is_cold_data(fio->page))
return true;
if (IS_ATOMIC_WRITTEN_PAGE(fio->page))
return true;
-   }
+   } else if (f2fs_is_atomic_file(inode))
+   return true;
return false;
 }
 
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index b9d93fd..84ab3ff 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -622,7 +622,8 @@ static void move_data_block(struct inode *inode, block_t 
bidx,
if (!check_valid_map(F2FS_I_SB(inode), segno, off))
goto out;
 
-   if (f2fs_is_atomic_file(inode))
+   if (f2fs_is_atomic_file(inode) &&
+   !f2fs_is_commit_atomic_write(inode))
goto out;
 
if (f2fs_is_pinned_file(inode)) {
@@ -729,7 +730,8 @@ static void move_data_page(struct inode *inode, block_t 
bidx, int gc_type,
if (!check_valid_map(F2FS_I_SB(inode), segno, off))
goto out;
 
-   if (f2fs_is_atomic_file(inode))
+   if (f2fs_is_atomic_file(inode) &&
+   !f2fs_is_commit_atomic_write(inode))
goto out;
if (f2fs_is_pinned_file(inode)) {
if (gc_type == FG_GC)
-- 
1.8.5.2


--
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] f2fs on top ov LV

2018-02-02 Thread Piergiorgio Sartor
Hi all,

I'm planning to prepare a Linux installation
on an USB flash drive.

The idea is to have /boot (with ext, since grub2
does not support f2fs yet) and / with f2fs.
Both on the USB flash drive while /home will be
somewhere else.

Now, I've a backup tool exploiting lvm snapshots
and I would like to use it.

This means / will be on top of an LV.

Does it make any sense to have f2fs over lvm?
Will still be some benefits from f2fs in this
setup?

How about snapshots? Could they cause problems?
Usually the filesystem mounted from lvm snapshot
has consistency issues, which are they usually
solved by journal.
I guess f2fs should be fine, but I would like to
confirm with experts here.

Of course, one possibility would be to use f2fs
on the raw partition, waiting for snapshot to
be implemented.
What's the plan about this?

Thanks a lot for any answers,

bye,

-- 

piergiorgio

--
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [PATCH v2] f2fs: introduce "strict_fsync" for posix standard fsync

2018-02-02 Thread Junling Zheng
Commit "0a007b97aad6"(f2fs: recover directory operations by fsync)
fixed xfstest generic/342 case, but it also increased the written
data and caused the performance degradation. In most cases, there's
no need to do so heavily fsync actually.

So we introduce a new mount option "strict_fsync" to control the
policy of fsync. It's set by default, and means that fsync follows
POSIX semantics. And "nostrict_fsync" means that the behaviour is
in line with xfs, ext4 and btrfs, where generic/342 will pass.

Signed-off-by: Junling Zheng 
Reviewed-by: Chao Yu 
---
 Documentation/filesystems/f2fs.txt |  4 
 fs/f2fs/dir.c  |  3 ++-
 fs/f2fs/f2fs.h |  1 +
 fs/f2fs/file.c |  3 ++-
 fs/f2fs/namei.c|  9 ++---
 fs/f2fs/super.c| 13 +
 6 files changed, 28 insertions(+), 5 deletions(-)

diff --git a/Documentation/filesystems/f2fs.txt 
b/Documentation/filesystems/f2fs.txt
index 0caf7da0a532..c484ce8d1f4c 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -180,6 +180,10 @@ whint_mode=%s  Control which write hints are 
passed down to block
down hints. In "user-based" mode, f2fs tries to pass
down hints given by users. And in "fs-based" mode, f2fs
passes down hints with its policy.
+{,no}strict_fsync  Control the policy of fsync. Set "strict_fsync" by 
default,
+   which means that fsync will follow POSIX semantics. Use
+   "nostrict_fsync" if you expect fsync to behave in line 
with
+   xfs, ext4 and btrfs, where xfstest generic/342 will 
pass.
 
 

 DEBUGFS ENTRIES
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index f00b5ed8c011..7487b7e77a36 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -713,7 +713,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, 
struct page *page,
 
f2fs_update_time(F2FS_I_SB(dir), REQ_TIME);
 
-   add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
+   if (!test_opt(F2FS_I_SB(dir), STRICT_FSYNC))
+   add_ino_entry(F2FS_I_SB(dir), dir->i_ino, TRANS_DIR_INO);
 
if (f2fs_has_inline_dentry(dir))
return f2fs_delete_inline_entry(dentry, page, dir, inode);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index dbe87c7a266e..8cf914d12f17 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -97,6 +97,7 @@ extern char *fault_name[FAULT_MAX];
 #define F2FS_MOUNT_QUOTA   0x0040
 #define F2FS_MOUNT_INLINE_XATTR_SIZE   0x0080
 #define F2FS_MOUNT_RESERVE_ROOT0x0100
+#define F2FS_MOUNT_STRICT_FSYNC0x0200
 
 #define clear_opt(sbi, option) ((sbi)->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #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 672a542e5464..9b39254f5b48 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -165,7 +165,8 @@ static inline enum cp_reason_type need_do_checkpoint(struct 
inode *inode)
cp_reason = CP_FASTBOOT_MODE;
else if (sbi->active_logs == 2)
cp_reason = CP_SPEC_LOG_NUM;
-   else if (need_dentry_mark(sbi, inode->i_ino) &&
+   else if (!test_opt(sbi, STRICT_FSYNC) &&
+   need_dentry_mark(sbi, inode->i_ino) &&
exist_written_data(sbi, F2FS_I(inode)->i_pino, TRANS_DIR_INO))
cp_reason = CP_RECOVER_DIR;
 
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index c4c94c7e9f4f..ef86ae327f91 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -936,7 +936,8 @@ static int f2fs_rename(struct inode *old_dir, struct dentry 
*old_dentry,
}
f2fs_i_links_write(old_dir, false);
}
-   add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+   if (!test_opt(sbi, STRICT_FSYNC))
+   add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
 
f2fs_unlock_op(sbi);
 
@@ -1091,8 +1092,10 @@ static int f2fs_cross_rename(struct inode *old_dir, 
struct dentry *old_dentry,
}
f2fs_mark_inode_dirty_sync(new_dir, false);
 
-   add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
-   add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+   if (!test_opt(sbi, STRICT_FSYNC)) {
+   add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
+   add_ino_entry(sbi, new_dir->i_ino, TRANS_DIR_INO);
+   }
 
f2fs_unlock_op(sbi);
 
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 7966cf7bfb8e..3066fc9d8985 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -130,6 +130,8 @@ enum {
Opt_jqfmt_vfsv0,
Opt_jqfmt_vfsv1,
Opt_whint,
+   Opt_strict_fsync,
+   Opt_nostrict_fsync,
Opt_err,
 };
 
@@