Skip to content

Commit f18d007

Browse files
Sunmin JeongJaegeuk Kim
authored andcommitted
f2fs: use meta inode for GC of COW file
In case of the COW file, new updates and GC writes are already separated to page caches of the atomic file and COW file. As some cases that use the meta inode for GC, there are some race issues between a foreground thread and GC thread. To handle them, we need to take care when to invalidate and wait writeback of GC pages in COW files as the case of using the meta inode. Also, a pointer from the COW inode to the original inode is required to check the state of original pages. For the former, we can solve the problem by using the meta inode for GC of COW files. Then let's get a page from the original inode in move_data_block when GCing the COW file to avoid race condition. Fixes: 3db1de0 ("f2fs: change the current atomic write way") Cc: [email protected] #v5.19+ Reviewed-by: Sungjong Seo <[email protected]> Reviewed-by: Yeongjin Gil <[email protected]> Signed-off-by: Sunmin Jeong <[email protected]> Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent b40a2b0 commit f18d007

File tree

6 files changed

+23
-7
lines changed

6 files changed

+23
-7
lines changed

fs/f2fs/data.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2608,7 +2608,7 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
26082608
return true;
26092609
if (IS_NOQUOTA(inode))
26102610
return true;
2611-
if (f2fs_is_atomic_file(inode))
2611+
if (f2fs_used_in_atomic_write(inode))
26122612
return true;
26132613
/* rewrite low ratio compress data w/ OPU mode to avoid fragmentation */
26142614
if (f2fs_compressed_file(inode) &&

fs/f2fs/f2fs.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -843,7 +843,11 @@ struct f2fs_inode_info {
843843
struct task_struct *atomic_write_task; /* store atomic write task */
844844
struct extent_tree *extent_tree[NR_EXTENT_CACHES];
845845
/* cached extent_tree entry */
846-
struct inode *cow_inode; /* copy-on-write inode for atomic write */
846+
union {
847+
struct inode *cow_inode; /* copy-on-write inode for atomic write */
848+
struct inode *atomic_inode;
849+
/* point to atomic_inode, available only for cow_inode */
850+
};
847851

848852
/* avoid racing between foreground op and gc */
849853
struct f2fs_rwsem i_gc_rwsem[2];
@@ -4263,9 +4267,14 @@ static inline bool f2fs_post_read_required(struct inode *inode)
42634267
f2fs_compressed_file(inode);
42644268
}
42654269

4270+
static inline bool f2fs_used_in_atomic_write(struct inode *inode)
4271+
{
4272+
return f2fs_is_atomic_file(inode) || f2fs_is_cow_file(inode);
4273+
}
4274+
42664275
static inline bool f2fs_meta_inode_gc_required(struct inode *inode)
42674276
{
4268-
return f2fs_post_read_required(inode) || f2fs_is_atomic_file(inode);
4277+
return f2fs_post_read_required(inode) || f2fs_used_in_atomic_write(inode);
42694278
}
42704279

42714280
/*

fs/f2fs/file.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,9 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate)
21832183

21842184
set_inode_flag(fi->cow_inode, FI_COW_FILE);
21852185
clear_inode_flag(fi->cow_inode, FI_INLINE_DATA);
2186+
2187+
/* Set the COW inode's atomic_inode to the atomic inode */
2188+
F2FS_I(fi->cow_inode)->atomic_inode = inode;
21862189
} else {
21872190
/* Reuse the already created COW inode */
21882191
ret = f2fs_do_truncate_blocks(fi->cow_inode, 0, true);

fs/f2fs/gc.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,7 +1171,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
11711171
static int ra_data_block(struct inode *inode, pgoff_t index)
11721172
{
11731173
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1174-
struct address_space *mapping = inode->i_mapping;
1174+
struct address_space *mapping = f2fs_is_cow_file(inode) ?
1175+
F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
11751176
struct dnode_of_data dn;
11761177
struct page *page;
11771178
struct f2fs_io_info fio = {
@@ -1260,6 +1261,8 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
12601261
static int move_data_block(struct inode *inode, block_t bidx,
12611262
int gc_type, unsigned int segno, int off)
12621263
{
1264+
struct address_space *mapping = f2fs_is_cow_file(inode) ?
1265+
F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
12631266
struct f2fs_io_info fio = {
12641267
.sbi = F2FS_I_SB(inode),
12651268
.ino = inode->i_ino,
@@ -1282,7 +1285,7 @@ static int move_data_block(struct inode *inode, block_t bidx,
12821285
CURSEG_ALL_DATA_ATGC : CURSEG_COLD_DATA;
12831286

12841287
/* do not read out */
1285-
page = f2fs_grab_cache_page(inode->i_mapping, bidx, false);
1288+
page = f2fs_grab_cache_page(mapping, bidx, false);
12861289
if (!page)
12871290
return -ENOMEM;
12881291

fs/f2fs/inline.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
static bool support_inline_data(struct inode *inode)
1818
{
19-
if (f2fs_is_atomic_file(inode))
19+
if (f2fs_used_in_atomic_write(inode))
2020
return false;
2121
if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode))
2222
return false;

fs/f2fs/inode.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -804,8 +804,9 @@ void f2fs_evict_inode(struct inode *inode)
804804

805805
f2fs_abort_atomic_write(inode, true);
806806

807-
if (fi->cow_inode) {
807+
if (fi->cow_inode && f2fs_is_cow_file(fi->cow_inode)) {
808808
clear_inode_flag(fi->cow_inode, FI_COW_FILE);
809+
F2FS_I(fi->cow_inode)->atomic_inode = NULL;
809810
iput(fi->cow_inode);
810811
fi->cow_inode = NULL;
811812
}

0 commit comments

Comments
 (0)