f2fs crypto: fix racing of accessing encrypted page among different competitors
PATCH 1/1 f2fs crypto: fix racing of accessing encrypted page among different competitors
Quoted 1 line
From
0211c6ed82440891b3369851d079f6c69b432b6cMon Sep 17 00:00:00 2001
From: Chao Yu <[email protected]>
Date: Thu, 8 Oct 2015 13:27:34 +0800
Subject: [PATCH] f2fs crypto: fix racing of accessing encrypted page among
different competitors
Since we use different page cache (normally inode's page cache for R/W and meta inode's page cache for GC) to cache the same physical block which is belong to an encrypted inode. Writeback of these two page cache should be exclusive, but now we didn't handle writeback state well, so there may be potential racing problem:
a)
kworker: f2fs_gc:
- f2fs_write_data_pages
- f2fs_write_data_page
- do_write_data_page
- write_data_page
- f2fs_submit_page_mbio
(page#1 in inode's page cache was queued
in f2fs bio cache, and be ready to write
to new blkaddr)
- gc_data_segment
- move_encrypted_block
- pagecache_get_page
(page#2 in meta inode's page cache was cached with the invalid datas of physical block located in new blkaddr)
- f2fs_submit_page_mbio
(page#1 was submitted, later, page#2 with invalid data will be submitted)
b)f2fs_gc:
- gc_data_segment
- move_encrypted_block
- f2fs_submit_page_mbio
(page#1 in meta inode's page cache was
queued in f2fs bio cache, and be ready
to write to new blkaddr)
user thread:
- f2fs_write_begin
- f2fs_submit_page_bio
(we submit the request to block layer to update page#2 in inode's page cache with physical block located in new blkaddr, so here we may read gabbage data from new blkaddr since GC hasn't writebacked the page#1 yet)
This patch fixes above potential racing problem for encrypted inode.
--- fs/f2fs/data.c | 20 +++++++++++--------- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 5 +++++ fs/f2fs/gc.c | 13 ++++++++++--- fs/f2fs/segment.c | 17 +++++++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-)
fs/f2fs/data.c +11 -9
@@ -954,21 +954,14 @@ submit_and_realloc:if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { -struct page *cpage; ctx =f2fs_get_crypto_ctx (inode);if (IS_ERR (ctx)) goto set_error_page;/* wait the page to be moved by cleaning */ - cpage =find_lock_page ( -META_MAPPING (F2FS_I_SB (inode)), - block_nr); -if (cpage) { -f2fs_wait_on_page_writeback (cpage, -DATA ); -f2fs_put_page (cpage,1 ); - } +f2fs_wait_on_encrypted_page_writeback ( +F2FS_I_SB (inode), block_nr); } bio = bio_alloc(GFP_KERNEL,
@@ -1059,6 +1052,11 @@ int do_write_data_page(struct f2fs_io_info *fio) }if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { + +/* wait for GCed encrypted page writeback */ +f2fs_wait_on_encrypted_page_writeback (F2FS_I_SB (inode), + fio->blk_addr); + fio->encrypted_page =f2fs_encrypt (inode, fio->page);if (IS_ERR (fio->encrypted_page)) { err =PTR_ERR (fio->encrypted_page);
@@ -1446,6 +1444,10 @@ put_next:f2fs_wait_on_page_writeback (page,DATA ); +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +if (len ==PAGE_CACHE_SIZE ) goto out_update;if (PageUptodate (page))
fs/f2fs/f2fs.h +1 -0
@@ -1778,6 +1778,7 @@ void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *,void allocate_data_block (struct f2fs_sb_info *,struct page *,block_t ,block_t *,struct f2fs_summary *,int );void f2fs_wait_on_page_writeback (struct page *,enum page_type ); +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *,block_t );void write_data_summaries (struct f2fs_sb_info *,block_t );void write_node_summaries (struct f2fs_sb_info *,block_t ); int lookup_journal_in_cursum(struct f2fs_summary_block *,
fs/f2fs/file.c +5 -0
@@ -87,6 +87,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, mapped:/* fill the page */ f2fs_wait_on_page_writeback (page,DATA ); + +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +/* if gced page is attached, don't write to cold segment */ clear_cold_data (page); out:
fs/f2fs/gc.c +10 -3
@@ -559,14 +559,21 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)if (err) goto out; -if (unlikely (dn.data_blkaddr ==NULL_ADDR )) +if (unlikely (dn.data_blkaddr ==NULL_ADDR )) { +ClearPageUptodate (page); goto put_out; + } + +/* +* don't cache encrypted data into meta inode until previous dirty +* data were writebacked to avoid racing between GC and flush. +*/ +f2fs_wait_on_page_writeback (page,DATA );get_node_info (fio.sbi, dn.nid, &ni);set_summary (&sum, dn.nid, dn.ofs_in_node, ni.version);/* read page */ - fio.page = page; fio.blk_addr = dn.data_blkaddr; fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi),
@@ -589,7 +596,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) goto put_page_out;set_page_dirty (fio.encrypted_page); -f2fs_wait_on_page_writeback (fio.encrypted_page,META ); +f2fs_wait_on_page_writeback (fio.encrypted_page,DATA );if (clear_page_dirty_for_io (fio.encrypted_page))dec_page_count (fio.sbi,F2FS_DIRTY_META );
fs/f2fs/segment.c +17 -0
@@ -1462,6 +1462,23 @@ void f2fs_wait_on_page_writeback(struct page *page, } } +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *sbi, +block_t blkaddr) +{ +struct page *cpage; + +if (blkaddr ==NEW_ADDR ) +return ; + +f2fs_bug_on (sbi, blkaddr ==NULL_ADDR ); + + cpage =find_lock_page (META_MAPPING (sbi), blkaddr); +if (cpage) { +f2fs_wait_on_page_writeback (cpage,DATA ); +f2fs_put_page (cpage,1 ); + } +} +static int read_compacted_summaries (struct f2fs_sb_info *sbi) {struct f2fs_checkpoint *ckpt =F2FS_CKPT (sbi);
Signature · 1 line
2.5.2
Jaegeuk Kim
maintainerQuoted 156 lines · Chao Yu
Quoted 1 line
From
0211c6ed82440891b3369851d079f6c69b432b6cMon Sep 17 00:00:00 2001From: Chao Yu <[email protected]>
Date: Thu, 8 Oct 2015 13:27:34 +0800
Subject: [PATCH] f2fs crypto: fix racing of accessing encrypted page among
different competitorsSince we use different page cache (normally inode's page cache for R/W and meta inode's page cache for GC) to cache the same physical block which is belong to an encrypted inode. Writeback of these two page cache should be exclusive, but now we didn't handle writeback state well, so there may be potential racing problem:
a)
kworker:f2fs_gc:
-f2fs_write_data_pages
-f2fs_write_data_page
-do_write_data_page
-write_data_page
-f2fs_submit_page_mbio
(page#1 in inode's page cache was queued
in f2fs bio cache, and be ready to write
to new blkaddr)
-gc_data_segment
-move_encrypted_block
-pagecache_get_page
(page#2 in meta inode's page cache was cached with the invalid datas of physical block located in new blkaddr)
-f2fs_submit_page_mbio
(page#1 was submitted, later, page#2 with invalid data will be submitted)b)
f2fs_gc:
-gc_data_segment
-move_encrypted_block
-f2fs_submit_page_mbio
(page#1 in meta inode's page cache was
queued in f2fs bio cache, and be ready
to write to new blkaddr)
user thread:
-f2fs_write_begin
-f2fs_submit_page_bio
(we submit the request to block layer to update page#2 in inode's page cache with physical block located in new blkaddr, so here we may read gabbage data from new blkaddr since GC hasn't writebacked the page#1 yet)This patch fixes above potential racing problem for encrypted inode.
Signed-off-by Chao Yu <[email protected]>--- fs/f2fs/data.c | 20 +++++++++++--------- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 5 +++++ fs/f2fs/gc.c | 13 ++++++++++--- fs/f2fs/segment.c | 17 +++++++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-)fs/f2fs/data.c +11
-9@@ -954,21 +954,14 @@ submit_and_realloc:if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { -struct page *cpage; ctx =f2fs_get_crypto_ctx (inode);if (IS_ERR (ctx)) goto set_error_page;/* wait the page to be moved by cleaning */ - cpage =find_lock_page ( -META_MAPPING (F2FS_I_SB (inode)), - block_nr); -if (cpage) { -f2fs_wait_on_page_writeback (cpage, -DATA ); -f2fs_put_page (cpage,1 ); - } +f2fs_wait_on_encrypted_page_writeback ( +F2FS_I_SB (inode), block_nr); } bio = bio_alloc(GFP_KERNEL,@@ -1059,6 +1052,11 @@ int do_write_data_page(struct f2fs_io_info *fio) }if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { + +/* wait for GCed encrypted page writeback */ +f2fs_wait_on_encrypted_page_writeback (F2FS_I_SB (inode), + fio->blk_addr); + fio->encrypted_page =f2fs_encrypt (inode, fio->page);if (IS_ERR (fio->encrypted_page)) { err =PTR_ERR (fio->encrypted_page);@@ -1446,6 +1444,10 @@ put_next:f2fs_wait_on_page_writeback (page,DATA ); +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +if (len ==PAGE_CACHE_SIZE ) goto out_update;if (PageUptodate (page))fs/f2fs/f2fs.h +1
-0@@ -1778,6 +1778,7 @@ void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data *,void allocate_data_block (struct f2fs_sb_info *,struct page *,block_t ,block_t *,struct f2fs_summary *,int );void f2fs_wait_on_page_writeback (struct page *,enum page_type ); +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *,block_t );void write_data_summaries (struct f2fs_sb_info *,block_t );void write_node_summaries (struct f2fs_sb_info *,block_t ); int lookup_journal_in_cursum(struct f2fs_summary_block *,fs/f2fs/file.c +5
-0@@ -87,6 +87,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, mapped:/* fill the page */ f2fs_wait_on_page_writeback (page,DATA ); + +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +/* if gced page is attached, don't write to cold segment */ clear_cold_data (page); out:fs/f2fs/gc.c +5
-1@@ -559,14 +559,21 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)if (err) goto out; -if (unlikely (dn.data_blkaddr ==NULL_ADDR )) +if (unlikely (dn.data_blkaddr ==NULL_ADDR )) { +ClearPageUptodate (page); goto put_out; + } + +/*
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 569
Quoted 10 lines
fs/f2fs/gc.c +4
-1+* don't cache encrypted data into meta inode until previous dirty +* data were writebacked to avoid racing between GC and flush. +*/ +f2fs_wait_on_page_writeback (page,DATA );get_node_info (fio.sbi, dn.nid, &ni);set_summary (&sum, dn.nid, dn.ofs_in_node, ni.version);/* read page */ - fio.page = page;
Let's remain just to make sure.
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 599
Quoted 9 lines
fs/f2fs/gc.c +1
-1fio.blk_addr = dn.data_blkaddr; fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi),@@ -589,7 +596,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) goto put_page_out;set_page_dirty (fio.encrypted_page); -f2fs_wait_on_page_writeback (fio.encrypted_page,META ); +f2fs_wait_on_page_writeback (fio.encrypted_page,DATA );
Why DATA?
Quoted 33 lines
fs/f2fs/gc.c +0
-0if (clear_page_dirty_for_io (fio.encrypted_page))dec_page_count (fio.sbi,F2FS_DIRTY_META );fs/f2fs/segment.c +17
-0@@ -1462,6 +1462,23 @@ void f2fs_wait_on_page_writeback(struct page *page, } } +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *sbi, +block_t blkaddr) +{ +struct page *cpage; + +if (blkaddr ==NEW_ADDR ) +return ; + +f2fs_bug_on (sbi, blkaddr ==NULL_ADDR ); + + cpage =find_lock_page (META_MAPPING (sbi), blkaddr); +if (cpage) { +f2fs_wait_on_page_writeback (cpage,DATA ); +f2fs_put_page (cpage,1 ); + } +} +static int read_compacted_summaries (struct f2fs_sb_info *sbi) {struct f2fs_checkpoint *ckpt =F2FS_CKPT (sbi);Signature · 1 line
2.5.2
Quoted 171 lines
-----Original Message-----
From: Jaegeuk Kim [mailto:[email protected]]
Sent: Tuesday, October 13, 2015 5:00 AM
To: Chao Yu
Cc: [email protected]; [email protected]
Subject: Re: [PATCH] f2fs crypto: fix racing of accessing encrypted page among different competitorsfs/f2fs/f2fs.h void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data
Quoted 118 lines · Chao Yu
Quoted 1 line
From
0211c6ed82440891b3369851d079f6c69b432b6cMon Sep 17 00:00:00 2001From: Chao Yu <[email protected]>
Date: Thu, 8 Oct 2015 13:27:34 +0800
Subject: [PATCH] f2fs crypto: fix racing of accessing encrypted page among
different competitorsSince we use different page cache (normally inode's page cache for R/W and meta inode's page cache for GC) to cache the same physical block which is belong to an encrypted inode. Writeback of these two page cache should be exclusive, but now we didn't handle writeback state well, so there may be potential racing problem:
a)
kworker:f2fs_gc:
-f2fs_write_data_pages
-f2fs_write_data_page
-do_write_data_page
-write_data_page
-f2fs_submit_page_mbio
(page#1 in inode's page cache was queued
in f2fs bio cache, and be ready to write
to new blkaddr)
-gc_data_segment
-move_encrypted_block
-pagecache_get_page
(page#2 in meta inode's page cache was cached with the invalid datas of physical block located in new blkaddr)
-f2fs_submit_page_mbio
(page#1 was submitted, later, page#2 with invalid data will be submitted)b)
f2fs_gc:
-gc_data_segment
-move_encrypted_block
-f2fs_submit_page_mbio
(page#1 in meta inode's page cache was
queued in f2fs bio cache, and be ready
to write to new blkaddr)
user thread:
-f2fs_write_begin
-f2fs_submit_page_bio
(we submit the request to block layer to update page#2 in inode's page cache with physical block located in new blkaddr, so here we may read gabbage data from new blkaddr since GC hasn't writebacked the page#1 yet)This patch fixes above potential racing problem for encrypted inode.
Signed-off-by Chao Yu <[email protected]>--- fs/f2fs/data.c | 20 +++++++++++--------- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 5 +++++ fs/f2fs/gc.c | 13 ++++++++++--- fs/f2fs/segment.c | 17 +++++++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-)fs/f2fs/data.c +11
-9@@ -954,21 +954,14 @@ submit_and_realloc:if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { -struct page *cpage; ctx =f2fs_get_crypto_ctx (inode);if (IS_ERR (ctx)) goto set_error_page;/* wait the page to be moved by cleaning */ - cpage =find_lock_page ( -META_MAPPING (F2FS_I_SB (inode)), - block_nr); -if (cpage) { -f2fs_wait_on_page_writeback (cpage, -DATA ); -f2fs_put_page (cpage,1 ); - } +f2fs_wait_on_encrypted_page_writeback ( +F2FS_I_SB (inode), block_nr); } bio = bio_alloc(GFP_KERNEL,@@ -1059,6 +1052,11 @@ int do_write_data_page(struct f2fs_io_info *fio) }if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { + +/* wait for GCed encrypted page writeback */ +f2fs_wait_on_encrypted_page_writeback (F2FS_I_SB (inode), + fio->blk_addr); + fio->encrypted_page =f2fs_encrypt (inode, fio->page);if (IS_ERR (fio->encrypted_page)) { err =PTR_ERR (fio->encrypted_page);@@ -1446,6 +1444,10 @@ put_next:f2fs_wait_on_page_writeback (page,DATA ); +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +if (len ==PAGE_CACHE_SIZE ) goto out_update;if (PageUptodate (page))fs/f2fs/f2fs.h +0
-0@@ -1778,6 +1778,7 @@ void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data*,
Quoted 43 lines
fs/f2fs/f2fs.h +1
-0void allocate_data_block (struct f2fs_sb_info *,struct page *,block_t ,block_t *,struct f2fs_summary *,int );void f2fs_wait_on_page_writeback (struct page *,enum page_type ); +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *,block_t );void write_data_summaries (struct f2fs_sb_info *,block_t );void write_node_summaries (struct f2fs_sb_info *,block_t ); int lookup_journal_in_cursum(struct f2fs_summary_block *,fs/f2fs/file.c +5
-0@@ -87,6 +87,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, mapped:/* fill the page */ f2fs_wait_on_page_writeback (page,DATA ); + +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +/* if gced page is attached, don't write to cold segment */ clear_cold_data (page); out:fs/f2fs/gc.c +9
-1@@ -559,14 +559,21 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)if (err) goto out; -if (unlikely (dn.data_blkaddr ==NULL_ADDR )) +if (unlikely (dn.data_blkaddr ==NULL_ADDR )) { +ClearPageUptodate (page); goto put_out; + } + +/* +* don't cache encrypted data into meta inode until previous dirty +* data were writebacked to avoid racing between GC and flush. +*/ +f2fs_wait_on_page_writeback (page,DATA );
Quoted 7 lines
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 569
Quoted 5 lines
fs/f2fs/gc.c +0
-1get_node_info (fio.sbi, dn.nid, &ni);set_summary (&sum, dn.nid, dn.ofs_in_node, ni.version);/* read page */ - fio.page = page;Let's remain just to make sure.
OK.
Quoted 7 lines
Quoted 7 lines
fs/f2fs/gc.c +0
-0fio.blk_addr = dn.data_blkaddr; fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi),@@ -589,7 +596,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) goto put_page_out;
Quoted 5 lines
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 599
Quoted 3 lines
fs/f2fs/gc.c +1
-1set_page_dirty (fio.encrypted_page); -f2fs_wait_on_page_writeback (fio.encrypted_page,META ); +f2fs_wait_on_page_writeback (fio.encrypted_page,DATA );Why DATA?
This is because we only submit the encrypted page in to DATA type bio cache, so we should check whether the page is cached or not in DATA type bio, rather than META type cache. Right?
Thanks,
Quoted 34 lines
Quoted 34 lines
fs/f2fs/gc.c +0
-0if (clear_page_dirty_for_io (fio.encrypted_page))dec_page_count (fio.sbi,F2FS_DIRTY_META );fs/f2fs/segment.c +17
-1@@ -1462,6 +1462,23 @@ void f2fs_wait_on_page_writeback(struct page *page, } } +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *sbi, +block_t blkaddr) +{ +struct page *cpage; + +if (blkaddr ==NEW_ADDR ) +return ; + +f2fs_bug_on (sbi, blkaddr ==NULL_ADDR ); + + cpage =find_lock_page (META_MAPPING (sbi), blkaddr); +if (cpage) { +f2fs_wait_on_page_writeback (cpage,DATA ); +f2fs_put_page (cpage,1 ); + } +} +static int read_compacted_summaries (struct f2fs_sb_info *sbi) {struct f2fs_checkpoint *ckpt =F2FS_CKPT (sbi); --2.5.2
Jaegeuk Kim
maintainerQuoted 194 lines · Chao Yu
Quoted 171 lines
-----Original Message-----
From: Jaegeuk Kim [mailto:[email protected]]
Sent: Tuesday, October 13, 2015 5:00 AM
To: Chao Yu
Cc: [email protected]; [email protected]
Subject: Re: [PATCH] f2fs crypto: fix racing of accessing encrypted page among different competitorsfs/f2fs/f2fs.h void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data
Quoted 118 lines · Chao Yu
Quoted 1 line
From
0211c6ed82440891b3369851d079f6c69b432b6cMon Sep 17 00:00:00 2001From: Chao Yu <[email protected]>
Date: Thu, 8 Oct 2015 13:27:34 +0800
Subject: [PATCH] f2fs crypto: fix racing of accessing encrypted page among
different competitorsSince we use different page cache (normally inode's page cache for R/W and meta inode's page cache for GC) to cache the same physical block which is belong to an encrypted inode. Writeback of these two page cache should be exclusive, but now we didn't handle writeback state well, so there may be potential racing problem:
a)
kworker:f2fs_gc:
-f2fs_write_data_pages
-f2fs_write_data_page
-do_write_data_page
-write_data_page
-f2fs_submit_page_mbio
(page#1 in inode's page cache was queued
in f2fs bio cache, and be ready to write
to new blkaddr)
-gc_data_segment
-move_encrypted_block
-pagecache_get_page
(page#2 in meta inode's page cache was cached with the invalid datas of physical block located in new blkaddr)
-f2fs_submit_page_mbio
(page#1 was submitted, later, page#2 with invalid data will be submitted)b)
f2fs_gc:
-gc_data_segment
-move_encrypted_block
-f2fs_submit_page_mbio
(page#1 in meta inode's page cache was
queued in f2fs bio cache, and be ready
to write to new blkaddr)
user thread:
-f2fs_write_begin
-f2fs_submit_page_bio
(we submit the request to block layer to update page#2 in inode's page cache with physical block located in new blkaddr, so here we may read gabbage data from new blkaddr since GC hasn't writebacked the page#1 yet)This patch fixes above potential racing problem for encrypted inode.
Signed-off-by Chao Yu <[email protected]>--- fs/f2fs/data.c | 20 +++++++++++--------- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 5 +++++ fs/f2fs/gc.c | 13 ++++++++++--- fs/f2fs/segment.c | 17 +++++++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-)fs/f2fs/data.c +11
-9@@ -954,21 +954,14 @@ submit_and_realloc:if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { -struct page *cpage; ctx =f2fs_get_crypto_ctx (inode);if (IS_ERR (ctx)) goto set_error_page;/* wait the page to be moved by cleaning */ - cpage =find_lock_page ( -META_MAPPING (F2FS_I_SB (inode)), - block_nr); -if (cpage) { -f2fs_wait_on_page_writeback (cpage, -DATA ); -f2fs_put_page (cpage,1 ); - } +f2fs_wait_on_encrypted_page_writeback ( +F2FS_I_SB (inode), block_nr); } bio = bio_alloc(GFP_KERNEL,@@ -1059,6 +1052,11 @@ int do_write_data_page(struct f2fs_io_info *fio) }if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { + +/* wait for GCed encrypted page writeback */ +f2fs_wait_on_encrypted_page_writeback (F2FS_I_SB (inode), + fio->blk_addr); + fio->encrypted_page =f2fs_encrypt (inode, fio->page);if (IS_ERR (fio->encrypted_page)) { err =PTR_ERR (fio->encrypted_page);@@ -1446,6 +1444,10 @@ put_next:f2fs_wait_on_page_writeback (page,DATA ); +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +if (len ==PAGE_CACHE_SIZE ) goto out_update;if (PageUptodate (page))fs/f2fs/f2fs.h +0
-0@@ -1778,6 +1778,7 @@ void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data*,
Quoted 43 lines
fs/f2fs/f2fs.h +1
-0void allocate_data_block (struct f2fs_sb_info *,struct page *,block_t ,block_t *,struct f2fs_summary *,int );void f2fs_wait_on_page_writeback (struct page *,enum page_type ); +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *,block_t );void write_data_summaries (struct f2fs_sb_info *,block_t );void write_node_summaries (struct f2fs_sb_info *,block_t ); int lookup_journal_in_cursum(struct f2fs_summary_block *,fs/f2fs/file.c +5
-0@@ -87,6 +87,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, mapped:/* fill the page */ f2fs_wait_on_page_writeback (page,DATA ); + +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +/* if gced page is attached, don't write to cold segment */ clear_cold_data (page); out:fs/f2fs/gc.c +9
-1@@ -559,14 +559,21 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)if (err) goto out; -if (unlikely (dn.data_blkaddr ==NULL_ADDR )) +if (unlikely (dn.data_blkaddr ==NULL_ADDR )) { +ClearPageUptodate (page); goto put_out; + } + +/* +* don't cache encrypted data into meta inode until previous dirty +* data were writebacked to avoid racing between GC and flush. +*/ +f2fs_wait_on_page_writeback (page,DATA );Quoted 7 lines
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 569
Quoted 5 lines
fs/f2fs/gc.c +0
-1get_node_info (fio.sbi, dn.nid, &ni);set_summary (&sum, dn.nid, dn.ofs_in_node, ni.version);/* read page */ - fio.page = page;Let's remain just to make sure.
OK.
Quoted 7 lines
Quoted 7 lines
fs/f2fs/gc.c +0
-0fio.blk_addr = dn.data_blkaddr; fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi),@@ -589,7 +596,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) goto put_page_out;Quoted 5 lines
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 599
Quoted 3 lines
fs/f2fs/gc.c +1
-1set_page_dirty (fio.encrypted_page); -f2fs_wait_on_page_writeback (fio.encrypted_page,META ); +f2fs_wait_on_page_writeback (fio.encrypted_page,DATA );Why DATA?
Quoted 3 lines
This is because we only submit the encrypted page in to DATA type bio cache, so we should check whether the page is cached or not in DATA type bio, rather than META type cache. Right?
Oh, right, type was DATA. :)
I'll test this patch with adding the above initialization.
Thanks,
Quoted 37 lines
Thanks,
Quoted 34 lines
Quoted 34 lines
fs/f2fs/gc.c +0
-0if (clear_page_dirty_for_io (fio.encrypted_page))dec_page_count (fio.sbi,F2FS_DIRTY_META );fs/f2fs/segment.c +17
-1@@ -1462,6 +1462,23 @@ void f2fs_wait_on_page_writeback(struct page *page, } } +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *sbi, +block_t blkaddr) +{ +struct page *cpage; + +if (blkaddr ==NEW_ADDR ) +return ; + +f2fs_bug_on (sbi, blkaddr ==NULL_ADDR ); + + cpage =find_lock_page (META_MAPPING (sbi), blkaddr); +if (cpage) { +f2fs_wait_on_page_writeback (cpage,DATA ); +f2fs_put_page (cpage,1 ); + } +} +static int read_compacted_summaries (struct f2fs_sb_info *sbi) {struct f2fs_checkpoint *ckpt =F2FS_CKPT (sbi); --2.5.2
Quoted 203 lines
-----Original Message-----
From: Jaegeuk Kim [mailto:[email protected]]
Sent: Wednesday, October 14, 2015 12:52 AM
To: Chao Yu
Cc: [email protected]; [email protected]
Subject: Re: [PATCH] f2fs crypto: fix racing of accessing encrypted page among different competitorsQuoted 194 lines · Chao Yu
Quoted 171 lines
-----Original Message-----
From: Jaegeuk Kim [mailto:[email protected]]
Sent: Tuesday, October 13, 2015 5:00 AM
To: Chao Yu
Cc: [email protected]; [email protected]
Subject: Re: [PATCH] f2fs crypto: fix racing of accessing encrypted page among different competitorsfs/f2fs/f2fs.h void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data
Quoted 118 lines · Chao Yu
Quoted 1 line
From
0211c6ed82440891b3369851d079f6c69b432b6cMon Sep 17 00:00:00 2001From: Chao Yu <[email protected]>
Date: Thu, 8 Oct 2015 13:27:34 +0800
Subject: [PATCH] f2fs crypto: fix racing of accessing encrypted page among
different competitorsSince we use different page cache (normally inode's page cache for R/W and meta inode's page cache for GC) to cache the same physical block which is belong to an encrypted inode. Writeback of these two page cache should be exclusive, but now we didn't handle writeback state well, so there may be potential racing problem:
a)
kworker:f2fs_gc:
-f2fs_write_data_pages
-f2fs_write_data_page
-do_write_data_page
-write_data_page
-f2fs_submit_page_mbio
(page#1 in inode's page cache was queued
in f2fs bio cache, and be ready to write
to new blkaddr)
-gc_data_segment
-move_encrypted_block
-pagecache_get_page
(page#2 in meta inode's page cache was cached with the invalid datas of physical block located in new blkaddr)
-f2fs_submit_page_mbio
(page#1 was submitted, later, page#2 with invalid data will be submitted)b)
f2fs_gc:
-gc_data_segment
-move_encrypted_block
-f2fs_submit_page_mbio
(page#1 in meta inode's page cache was
queued in f2fs bio cache, and be ready
to write to new blkaddr)
user thread:
-f2fs_write_begin
-f2fs_submit_page_bio
(we submit the request to block layer to update page#2 in inode's page cache with physical block located in new blkaddr, so here we may read gabbage data from new blkaddr since GC hasn't writebacked the page#1 yet)This patch fixes above potential racing problem for encrypted inode.
Signed-off-by Chao Yu <[email protected]>--- fs/f2fs/data.c | 20 +++++++++++--------- fs/f2fs/f2fs.h | 1 + fs/f2fs/file.c | 5 +++++ fs/f2fs/gc.c | 13 ++++++++++--- fs/f2fs/segment.c | 17 +++++++++++++++++ 5 files changed, 44 insertions(+), 12 deletions(-)fs/f2fs/data.c +11
-9@@ -954,21 +954,14 @@ submit_and_realloc:if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { -struct page *cpage; ctx =f2fs_get_crypto_ctx (inode);if (IS_ERR (ctx)) goto set_error_page;/* wait the page to be moved by cleaning */ - cpage =find_lock_page ( -META_MAPPING (F2FS_I_SB (inode)), - block_nr); -if (cpage) { -f2fs_wait_on_page_writeback (cpage, -DATA ); -f2fs_put_page (cpage,1 ); - } +f2fs_wait_on_encrypted_page_writeback ( +F2FS_I_SB (inode), block_nr); } bio = bio_alloc(GFP_KERNEL,@@ -1059,6 +1052,11 @@ int do_write_data_page(struct f2fs_io_info *fio) }if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) { + +/* wait for GCed encrypted page writeback */ +f2fs_wait_on_encrypted_page_writeback (F2FS_I_SB (inode), + fio->blk_addr); + fio->encrypted_page =f2fs_encrypt (inode, fio->page);if (IS_ERR (fio->encrypted_page)) { err =PTR_ERR (fio->encrypted_page);@@ -1446,6 +1444,10 @@ put_next:f2fs_wait_on_page_writeback (page,DATA ); +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +if (len ==PAGE_CACHE_SIZE ) goto out_update;if (PageUptodate (page))fs/f2fs/f2fs.h +0
-0@@ -1778,6 +1778,7 @@ void f2fs_replace_block(struct f2fs_sb_info *, struct dnode_of_data*,
Quoted 43 lines
fs/f2fs/f2fs.h +1
-0void allocate_data_block (struct f2fs_sb_info *,struct page *,block_t ,block_t *,struct f2fs_summary *,int );void f2fs_wait_on_page_writeback (struct page *,enum page_type ); +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *,block_t );void write_data_summaries (struct f2fs_sb_info *,block_t );void write_node_summaries (struct f2fs_sb_info *,block_t ); int lookup_journal_in_cursum(struct f2fs_summary_block *,fs/f2fs/file.c +5
-0@@ -87,6 +87,11 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma, mapped:/* fill the page */ f2fs_wait_on_page_writeback (page,DATA ); + +/* wait for GCed encrypted page writeback */ +if (f2fs_encrypted_inode (inode) &&S_ISREG (inode->i_mode)) +f2fs_wait_on_encrypted_page_writeback (sbi, dn.data_blkaddr); +/* if gced page is attached, don't write to cold segment */ clear_cold_data (page); out:fs/f2fs/gc.c +9
-1@@ -559,14 +559,21 @@ static void move_encrypted_block(struct inode *inode, block_t bidx)if (err) goto out; -if (unlikely (dn.data_blkaddr ==NULL_ADDR )) +if (unlikely (dn.data_blkaddr ==NULL_ADDR )) { +ClearPageUptodate (page); goto put_out; + } + +/* +* don't cache encrypted data into meta inode until previous dirty +* data were writebacked to avoid racing between GC and flush. +*/ +f2fs_wait_on_page_writeback (page,DATA );Quoted 7 lines
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 569
Quoted 5 lines
fs/f2fs/gc.c +0
-1get_node_info (fio.sbi, dn.nid, &ni);set_summary (&sum, dn.nid, dn.ofs_in_node, ni.version);/* read page */ - fio.page = page;Let's remain just to make sure.
OK.
Quoted 12 lines
fs/f2fs/gc.c static void move_encrypted_block(struct inode *inode, block_t bidx) · line 599
Quoted 10 lines
fs/f2fs/gc.c +1
-1fio.blk_addr = dn.data_blkaddr; fio.encrypted_page = pagecache_get_page(META_MAPPING(fio.sbi),@@ -589,7 +596,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx) goto put_page_out;set_page_dirty (fio.encrypted_page); -f2fs_wait_on_page_writeback (fio.encrypted_page,META ); +f2fs_wait_on_page_writeback (fio.encrypted_page,DATA );Why DATA?
Quoted 6 lines
Quoted 3 lines
This is because we only submit the encrypted page in to DATA type bio cache, so we should check whether the page is cached or not in DATA type bio, rather than META type cache. Right?
Oh, right, type was DATA. :)
I'll test this patch with adding the above initialization.
OK, thanks :)
Thanks,
Quoted 40 lines
Thanks,
Quoted 37 lines
Thanks,
Quoted 34 lines
Quoted 34 lines
fs/f2fs/gc.c +0
-0if (clear_page_dirty_for_io (fio.encrypted_page))dec_page_count (fio.sbi,F2FS_DIRTY_META );fs/f2fs/segment.c +17
-1@@ -1462,6 +1462,23 @@ void f2fs_wait_on_page_writeback(struct page *page, } } +void f2fs_wait_on_encrypted_page_writeback (struct f2fs_sb_info *sbi, +block_t blkaddr) +{ +struct page *cpage; + +if (blkaddr ==NEW_ADDR ) +return ; + +f2fs_bug_on (sbi, blkaddr ==NULL_ADDR ); + + cpage =find_lock_page (META_MAPPING (sbi), blkaddr); +if (cpage) { +f2fs_wait_on_page_writeback (cpage,DATA ); +f2fs_put_page (cpage,1 ); + } +} +static int read_compacted_summaries (struct f2fs_sb_info *sbi) {struct f2fs_checkpoint *ckpt =F2FS_CKPT (sbi); --2.5.2