mirror of
https://github.com/torvalds/linux.git
synced 2026-09-22 04:34:03 +02:00
f2fs: dirty directory inodes on mtime/ctime update
Xfstests generic/547 sometimes fail with mismatched directory metadata
before and after a power failure. This happens because when a directory
entry is added, renamed, or deleted, its mtime and ctime are updated and
the inode is marked dirty via
f2fs_mark_inode_dirty_sync(dir, sync=false). The sync=false flag means
the dirty inode is not added to the global DIRTY_META list. Therefore,
subsequent checkpoints skip flushing these updated directory blocks,
causing directory timestamps to revert to stale values after a sudden
power failure.
Address this by changing the dirtying parameter to sync=true during
directory entry mutations and renames. This forces F2FS to immediately
queue the updated directory blocks on the global DIRTY_META list,
ensuring timestamps are committed to checkpoints.
Fixes: 7c45729a4d ("f2fs: keep dirty inodes selectively for checkpoint")
Cc: stable@vger.kernel.org
Signed-off-by: Joanne Chang <joannechien@google.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
parent
575f6f8ef2
commit
9ec09d5f4b
|
|
@ -461,7 +461,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
|
|||
folio_mark_dirty(folio);
|
||||
|
||||
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||
f2fs_mark_inode_dirty_sync(dir, false);
|
||||
f2fs_mark_inode_dirty_sync(dir, true);
|
||||
f2fs_folio_put(folio, true);
|
||||
}
|
||||
|
||||
|
|
@ -616,7 +616,7 @@ void f2fs_update_parent_metadata(struct inode *dir, struct inode *inode,
|
|||
clear_inode_flag(inode, FI_NEW_INODE);
|
||||
}
|
||||
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||
f2fs_mark_inode_dirty_sync(dir, false);
|
||||
f2fs_mark_inode_dirty_sync(dir, true);
|
||||
|
||||
if (F2FS_I(dir)->i_current_depth != current_depth)
|
||||
f2fs_i_depth_write(dir, current_depth);
|
||||
|
|
@ -928,7 +928,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct folio *folio,
|
|||
f2fs_folio_put(folio, true);
|
||||
|
||||
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||
f2fs_mark_inode_dirty_sync(dir, false);
|
||||
f2fs_mark_inode_dirty_sync(dir, true);
|
||||
|
||||
if (inode)
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
|
|
|
|||
|
|
@ -732,7 +732,7 @@ void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry,
|
|||
f2fs_folio_put(folio, true);
|
||||
|
||||
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||
f2fs_mark_inode_dirty_sync(dir, false);
|
||||
f2fs_mark_inode_dirty_sync(dir, true);
|
||||
|
||||
if (inode)
|
||||
f2fs_drop_nlink(dir, inode);
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ static int f2fs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
|||
f2fs_up_write(&F2FS_I(old_inode)->i_sem);
|
||||
|
||||
inode_set_ctime_current(old_inode);
|
||||
f2fs_mark_inode_dirty_sync(old_inode, false);
|
||||
f2fs_mark_inode_dirty_sync(old_inode, true);
|
||||
|
||||
f2fs_delete_entry(old_entry, old_folio, old_dir, NULL);
|
||||
old_folio = NULL;
|
||||
|
|
@ -1246,7 +1246,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
f2fs_i_links_write(old_dir, old_nlink > 0);
|
||||
f2fs_up_write(&F2FS_I(old_dir)->i_sem);
|
||||
}
|
||||
f2fs_mark_inode_dirty_sync(old_dir, false);
|
||||
f2fs_mark_inode_dirty_sync(old_dir, true);
|
||||
|
||||
/* update directory entry info of new dir inode */
|
||||
f2fs_set_link(new_dir, new_entry, new_folio, old_inode);
|
||||
|
|
@ -1265,7 +1265,7 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
|
|||
f2fs_i_links_write(new_dir, new_nlink > 0);
|
||||
f2fs_up_write(&F2FS_I(new_dir)->i_sem);
|
||||
}
|
||||
f2fs_mark_inode_dirty_sync(new_dir, false);
|
||||
f2fs_mark_inode_dirty_sync(new_dir, true);
|
||||
|
||||
if (F2FS_OPTION(sbi).fsync_mode == FSYNC_MODE_STRICT) {
|
||||
f2fs_add_ino_entry(sbi, old_dir->i_ino, TRANS_DIR_INO);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user