Skip to content

Commit a949dc5

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: compress: fix race condition of overwrite vs truncate
pos_fsstress testcase complains a panic as belew: ------------[ cut here ]------------ kernel BUG at fs/f2fs/compress.c:1082! invalid opcode: 0000 [#1] SMP PTI CPU: 4 PID: 2753477 Comm: kworker/u16:2 Tainted: G OE 5.12.0-rc1-custom #1 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014 Workqueue: writeback wb_workfn (flush-252:16) RIP: 0010:prepare_compress_overwrite+0x4c0/0x760 [f2fs] Call Trace: f2fs_prepare_compress_overwrite+0x5f/0x80 [f2fs] f2fs_write_cache_pages+0x468/0x8a0 [f2fs] f2fs_write_data_pages+0x2a4/0x2f0 [f2fs] do_writepages+0x38/0xc0 __writeback_single_inode+0x44/0x2a0 writeback_sb_inodes+0x223/0x4d0 __writeback_inodes_wb+0x56/0xf0 wb_writeback+0x1dd/0x290 wb_workfn+0x309/0x500 process_one_work+0x220/0x3c0 worker_thread+0x53/0x420 kthread+0x12f/0x150 ret_from_fork+0x22/0x30 The root cause is truncate() may race with overwrite as below, so that one reference count left in page can not guarantee the page attaching in mapping tree all the time, after truncation, later find_lock_page() may return NULL pointer. - prepare_compress_overwrite - f2fs_pagecache_get_page - unlock_page - f2fs_setattr - truncate_setsize - truncate_inode_page - delete_from_page_cache - find_lock_page Fix this by avoiding referencing updated page. Fixes: 4c8ff70 ("f2fs: support data compression") Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent a12cc5b commit a949dc5

File tree

1 file changed

+12
-23
lines changed

1 file changed

+12
-23
lines changed

fs/f2fs/compress.c

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,6 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len)
117117
f2fs_drop_rpages(cc, len, true);
118118
}
119119

120-
static void f2fs_put_rpages_mapping(struct address_space *mapping,
121-
pgoff_t start, int len)
122-
{
123-
int i;
124-
125-
for (i = 0; i < len; i++) {
126-
struct page *page = find_get_page(mapping, start + i);
127-
128-
put_page(page);
129-
put_page(page);
130-
}
131-
}
132-
133120
static void f2fs_put_rpages_wbc(struct compress_ctx *cc,
134121
struct writeback_control *wbc, bool redirty, int unlock)
135122
{
@@ -1036,7 +1023,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
10361023
}
10371024

10381025
if (PageUptodate(page))
1039-
unlock_page(page);
1026+
f2fs_put_page(page, 1);
10401027
else
10411028
f2fs_compress_ctx_add_page(cc, page);
10421029
}
@@ -1046,32 +1033,34 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
10461033

10471034
ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
10481035
&last_block_in_bio, false, true);
1036+
f2fs_put_rpages(cc);
10491037
f2fs_destroy_compress_ctx(cc);
10501038
if (ret)
1051-
goto release_pages;
1039+
goto out;
10521040
if (bio)
10531041
f2fs_submit_bio(sbi, bio, DATA);
10541042

10551043
ret = f2fs_init_compress_ctx(cc);
10561044
if (ret)
1057-
goto release_pages;
1045+
goto out;
10581046
}
10591047

10601048
for (i = 0; i < cc->cluster_size; i++) {
10611049
f2fs_bug_on(sbi, cc->rpages[i]);
10621050

10631051
page = find_lock_page(mapping, start_idx + i);
1064-
f2fs_bug_on(sbi, !page);
1052+
if (!page) {
1053+
/* page can be truncated */
1054+
goto release_and_retry;
1055+
}
10651056

10661057
f2fs_wait_on_page_writeback(page, DATA, true, true);
1067-
10681058
f2fs_compress_ctx_add_page(cc, page);
1069-
f2fs_put_page(page, 0);
10701059

10711060
if (!PageUptodate(page)) {
1061+
release_and_retry:
1062+
f2fs_put_rpages(cc);
10721063
f2fs_unlock_rpages(cc, i + 1);
1073-
f2fs_put_rpages_mapping(mapping, start_idx,
1074-
cc->cluster_size);
10751064
f2fs_destroy_compress_ctx(cc);
10761065
goto retry;
10771066
}
@@ -1103,10 +1092,10 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
11031092
}
11041093

11051094
unlock_pages:
1095+
f2fs_put_rpages(cc);
11061096
f2fs_unlock_rpages(cc, i);
1107-
release_pages:
1108-
f2fs_put_rpages_mapping(mapping, start_idx, i);
11091097
f2fs_destroy_compress_ctx(cc);
1098+
out:
11101099
return ret;
11111100
}
11121101

0 commit comments

Comments
 (0)