* [PATCH v2] f2fs: fix to keep isolation of atomic write @ 2020-12-30 7:55 Chao Yu 2021-01-06 22:28 ` Jaegeuk Kim 2021-01-14 21:53 ` Jaegeuk Kim 0 siblings, 2 replies; 13+ messages in thread From: Chao Yu @ 2020-12-30 7:55 UTC (permalink / raw) To: jaegeuk; +Cc: linux-f2fs-devel, linux-kernel, chao, Chao Yu ThreadA ThreadB - f2fs_ioc_start_atomic_write - write - f2fs_ioc_commit_atomic_write - f2fs_commit_inmem_pages - f2fs_drop_inmem_pages - f2fs_drop_inmem_pages - __revoke_inmem_pages - f2fs_vm_page_mkwrite - set_page_dirty - tag ATOMIC_WRITTEN_PAGE and add page to inmem_pages list - clear_inode_flag(FI_ATOMIC_FILE) - f2fs_vm_page_mkwrite - set_page_dirty - f2fs_update_dirty_page - f2fs_trace_pid - tag inmem page private to pid - truncate - f2fs_invalidate_page - set page->mapping to NULL then it will cause panic once we access page->mapping The root cause is we missed to keep isolation of atomic write in the case of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem lock to avoid this issue. Signed-off-by: Chao Yu <yuchao0@huawei.com> --- v2: - use i_mmap_sem to avoid mkwrite racing with below flows: * f2fs_ioc_start_atomic_write * f2fs_drop_inmem_pages * f2fs_commit_inmem_pages fs/f2fs/file.c | 3 +++ fs/f2fs/segment.c | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 4e6d4b9120a8..a48ec650d691 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) goto out; down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); + down_write(&F2FS_I(inode)->i_mmap_sem); /* * Should wait end_io to count F2FS_WB_CP_DATA correctly by @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) inode->i_ino, get_dirty_pages(inode)); ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); if (ret) { + up_write(&F2FS_I(inode)->i_mmap_sem); up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); goto out; } @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) /* add inode in inmem_list first and set atomic_file */ set_inode_flag(inode, FI_ATOMIC_FILE); clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); + up_write(&F2FS_I(inode)->i_mmap_sem); up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index d8570b0359f5..dab870d9faf6 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_inode_info *fi = F2FS_I(inode); + down_write(&F2FS_I(inode)->i_mmap_sem); + while (!list_empty(&fi->inmem_pages)) { mutex_lock(&fi->inmem_lock); __revoke_inmem_pages(inode, &fi->inmem_pages, @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) sbi->atomic_files--; } spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); + + up_write(&F2FS_I(inode)->i_mmap_sem); } void f2fs_drop_inmem_page(struct inode *inode, struct page *page) @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) f2fs_balance_fs(sbi, true); down_write(&fi->i_gc_rwsem[WRITE]); + down_write(&F2FS_I(inode)->i_mmap_sem); f2fs_lock_op(sbi); set_inode_flag(inode, FI_ATOMIC_COMMIT); @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) clear_inode_flag(inode, FI_ATOMIC_COMMIT); f2fs_unlock_op(sbi); + + up_write(&F2FS_I(inode)->i_mmap_sem); up_write(&fi->i_gc_rwsem[WRITE]); return err; -- 2.29.2 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2020-12-30 7:55 [PATCH v2] f2fs: fix to keep isolation of atomic write Chao Yu @ 2021-01-06 22:28 ` Jaegeuk Kim 2021-01-06 22:57 ` [f2fs-dev] " Jaegeuk Kim 2021-01-14 21:53 ` Jaegeuk Kim 1 sibling, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-06 22:28 UTC (permalink / raw) To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao Hi Chao, With a quick test, this patch causes down_write failure resulting in blocking process. I didn't dig in the bug so, please check the code again. :P On 12/30, Chao Yu wrote: > ThreadA ThreadB > - f2fs_ioc_start_atomic_write > - write > - f2fs_ioc_commit_atomic_write > - f2fs_commit_inmem_pages > - f2fs_drop_inmem_pages > - f2fs_drop_inmem_pages > - __revoke_inmem_pages > - f2fs_vm_page_mkwrite > - set_page_dirty > - tag ATOMIC_WRITTEN_PAGE and add page > to inmem_pages list > - clear_inode_flag(FI_ATOMIC_FILE) > - f2fs_vm_page_mkwrite > - set_page_dirty > - f2fs_update_dirty_page > - f2fs_trace_pid > - tag inmem page private to pid > - truncate > - f2fs_invalidate_page > - set page->mapping to NULL > then it will cause panic once we > access page->mapping > > The root cause is we missed to keep isolation of atomic write in the case > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > lock to avoid this issue. > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > --- > v2: > - use i_mmap_sem to avoid mkwrite racing with below flows: > * f2fs_ioc_start_atomic_write > * f2fs_drop_inmem_pages > * f2fs_commit_inmem_pages > > fs/f2fs/file.c | 3 +++ > fs/f2fs/segment.c | 7 +++++++ > 2 files changed, 10 insertions(+) > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > index 4e6d4b9120a8..a48ec650d691 100644 > --- a/fs/f2fs/file.c > +++ b/fs/f2fs/file.c > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > goto out; > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > + down_write(&F2FS_I(inode)->i_mmap_sem); > > /* > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > inode->i_ino, get_dirty_pages(inode)); > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > if (ret) { > + up_write(&F2FS_I(inode)->i_mmap_sem); > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > goto out; > } > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > /* add inode in inmem_list first and set atomic_file */ > set_inode_flag(inode, FI_ATOMIC_FILE); > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > + up_write(&F2FS_I(inode)->i_mmap_sem); > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index d8570b0359f5..dab870d9faf6 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > struct f2fs_inode_info *fi = F2FS_I(inode); > > + down_write(&F2FS_I(inode)->i_mmap_sem); > + > while (!list_empty(&fi->inmem_pages)) { > mutex_lock(&fi->inmem_lock); > __revoke_inmem_pages(inode, &fi->inmem_pages, > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > sbi->atomic_files--; > } > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > + > + up_write(&F2FS_I(inode)->i_mmap_sem); > } > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > f2fs_balance_fs(sbi, true); > > down_write(&fi->i_gc_rwsem[WRITE]); > + down_write(&F2FS_I(inode)->i_mmap_sem); > > f2fs_lock_op(sbi); > set_inode_flag(inode, FI_ATOMIC_COMMIT); > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > f2fs_unlock_op(sbi); > + > + up_write(&F2FS_I(inode)->i_mmap_sem); > up_write(&fi->i_gc_rwsem[WRITE]); > > return err; > -- > 2.29.2 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [f2fs-dev] [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-06 22:28 ` Jaegeuk Kim @ 2021-01-06 22:57 ` Jaegeuk Kim 2021-01-11 16:32 ` Jaegeuk Kim 0 siblings, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-06 22:57 UTC (permalink / raw) To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel On 01/06, Jaegeuk Kim wrote: > Hi Chao, > > With a quick test, this patch causes down_write failure resulting in blocking > process. I didn't dig in the bug so, please check the code again. :P nvm. I can see it works now. > > On 12/30, Chao Yu wrote: > > ThreadA ThreadB > > - f2fs_ioc_start_atomic_write > > - write > > - f2fs_ioc_commit_atomic_write > > - f2fs_commit_inmem_pages > > - f2fs_drop_inmem_pages > > - f2fs_drop_inmem_pages > > - __revoke_inmem_pages > > - f2fs_vm_page_mkwrite > > - set_page_dirty > > - tag ATOMIC_WRITTEN_PAGE and add page > > to inmem_pages list > > - clear_inode_flag(FI_ATOMIC_FILE) > > - f2fs_vm_page_mkwrite > > - set_page_dirty > > - f2fs_update_dirty_page > > - f2fs_trace_pid > > - tag inmem page private to pid > > - truncate > > - f2fs_invalidate_page > > - set page->mapping to NULL > > then it will cause panic once we > > access page->mapping > > > > The root cause is we missed to keep isolation of atomic write in the case > > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > > lock to avoid this issue. > > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > --- > > v2: > > - use i_mmap_sem to avoid mkwrite racing with below flows: > > * f2fs_ioc_start_atomic_write > > * f2fs_drop_inmem_pages > > * f2fs_commit_inmem_pages > > > > fs/f2fs/file.c | 3 +++ > > fs/f2fs/segment.c | 7 +++++++ > > 2 files changed, 10 insertions(+) > > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > > index 4e6d4b9120a8..a48ec650d691 100644 > > --- a/fs/f2fs/file.c > > +++ b/fs/f2fs/file.c > > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > goto out; > > > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > /* > > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > inode->i_ino, get_dirty_pages(inode)); > > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > > if (ret) { > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > goto out; > > } > > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > /* add inode in inmem_list first and set atomic_file */ > > set_inode_flag(inode, FI_ATOMIC_FILE); > > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > index d8570b0359f5..dab870d9faf6 100644 > > --- a/fs/f2fs/segment.c > > +++ b/fs/f2fs/segment.c > > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > > struct f2fs_inode_info *fi = F2FS_I(inode); > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > + > > while (!list_empty(&fi->inmem_pages)) { > > mutex_lock(&fi->inmem_lock); > > __revoke_inmem_pages(inode, &fi->inmem_pages, > > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > sbi->atomic_files--; > > } > > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > > + > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > } > > > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > f2fs_balance_fs(sbi, true); > > > > down_write(&fi->i_gc_rwsem[WRITE]); > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > f2fs_lock_op(sbi); > > set_inode_flag(inode, FI_ATOMIC_COMMIT); > > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > > > f2fs_unlock_op(sbi); > > + > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > up_write(&fi->i_gc_rwsem[WRITE]); > > > > return err; > > -- > > 2.29.2 > > > _______________________________________________ > Linux-f2fs-devel mailing list > Linux-f2fs-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [f2fs-dev] [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-06 22:57 ` [f2fs-dev] " Jaegeuk Kim @ 2021-01-11 16:32 ` Jaegeuk Kim 2021-01-12 2:59 ` Chao Yu 0 siblings, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-11 16:32 UTC (permalink / raw) To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel On 01/06, Jaegeuk Kim wrote: > On 01/06, Jaegeuk Kim wrote: > > Hi Chao, > > > > With a quick test, this patch causes down_write failure resulting in blocking > > process. I didn't dig in the bug so, please check the code again. :P > > nvm. I can see it works now. Hmm, this gives a huge perf regression when running sqlite. :( We may need to check the lock coverage. Thoughts? > > > > > On 12/30, Chao Yu wrote: > > > ThreadA ThreadB > > > - f2fs_ioc_start_atomic_write > > > - write > > > - f2fs_ioc_commit_atomic_write > > > - f2fs_commit_inmem_pages > > > - f2fs_drop_inmem_pages > > > - f2fs_drop_inmem_pages > > > - __revoke_inmem_pages > > > - f2fs_vm_page_mkwrite > > > - set_page_dirty > > > - tag ATOMIC_WRITTEN_PAGE and add page > > > to inmem_pages list > > > - clear_inode_flag(FI_ATOMIC_FILE) > > > - f2fs_vm_page_mkwrite > > > - set_page_dirty > > > - f2fs_update_dirty_page > > > - f2fs_trace_pid > > > - tag inmem page private to pid > > > - truncate > > > - f2fs_invalidate_page > > > - set page->mapping to NULL > > > then it will cause panic once we > > > access page->mapping > > > > > > The root cause is we missed to keep isolation of atomic write in the case > > > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > > > lock to avoid this issue. > > > > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > > --- > > > v2: > > > - use i_mmap_sem to avoid mkwrite racing with below flows: > > > * f2fs_ioc_start_atomic_write > > > * f2fs_drop_inmem_pages > > > * f2fs_commit_inmem_pages > > > > > > fs/f2fs/file.c | 3 +++ > > > fs/f2fs/segment.c | 7 +++++++ > > > 2 files changed, 10 insertions(+) > > > > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > > > index 4e6d4b9120a8..a48ec650d691 100644 > > > --- a/fs/f2fs/file.c > > > +++ b/fs/f2fs/file.c > > > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > goto out; > > > > > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > > /* > > > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > > > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > inode->i_ino, get_dirty_pages(inode)); > > > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > > > if (ret) { > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > goto out; > > > } > > > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > /* add inode in inmem_list first and set atomic_file */ > > > set_inode_flag(inode, FI_ATOMIC_FILE); > > > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > > index d8570b0359f5..dab870d9faf6 100644 > > > --- a/fs/f2fs/segment.c > > > +++ b/fs/f2fs/segment.c > > > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > > > struct f2fs_inode_info *fi = F2FS_I(inode); > > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > + > > > while (!list_empty(&fi->inmem_pages)) { > > > mutex_lock(&fi->inmem_lock); > > > __revoke_inmem_pages(inode, &fi->inmem_pages, > > > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > sbi->atomic_files--; > > > } > > > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > > > + > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > } > > > > > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > > > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > f2fs_balance_fs(sbi, true); > > > > > > down_write(&fi->i_gc_rwsem[WRITE]); > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > > f2fs_lock_op(sbi); > > > set_inode_flag(inode, FI_ATOMIC_COMMIT); > > > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > > > > > f2fs_unlock_op(sbi); > > > + > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > up_write(&fi->i_gc_rwsem[WRITE]); > > > > > > return err; > > > -- > > > 2.29.2 > > > > > > _______________________________________________ > > Linux-f2fs-devel mailing list > > Linux-f2fs-devel@lists.sourceforge.net > > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel > > > _______________________________________________ > Linux-f2fs-devel mailing list > Linux-f2fs-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [f2fs-dev] [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-11 16:32 ` Jaegeuk Kim @ 2021-01-12 2:59 ` Chao Yu 2021-01-12 22:32 ` Jaegeuk Kim 0 siblings, 1 reply; 13+ messages in thread From: Chao Yu @ 2021-01-12 2:59 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-kernel, linux-f2fs-devel On 2021/1/12 0:32, Jaegeuk Kim wrote: > On 01/06, Jaegeuk Kim wrote: >> On 01/06, Jaegeuk Kim wrote: >>> Hi Chao, >>> >>> With a quick test, this patch causes down_write failure resulting in blocking >>> process. I didn't dig in the bug so, please check the code again. :P >> >> nvm. I can see it works now. > > Hmm, this gives a huge perf regression when running sqlite. :( > We may need to check the lock coverage. Thoughts? I added i_mmap_sem lock only, so it can cause atomic_{start,commit,finish} race with mmap and truncation operations in additionally. I'd like to know what's your sqlite testcase? Thanks, > >> >>> >>> On 12/30, Chao Yu wrote: >>>> ThreadA ThreadB >>>> - f2fs_ioc_start_atomic_write >>>> - write >>>> - f2fs_ioc_commit_atomic_write >>>> - f2fs_commit_inmem_pages >>>> - f2fs_drop_inmem_pages >>>> - f2fs_drop_inmem_pages >>>> - __revoke_inmem_pages >>>> - f2fs_vm_page_mkwrite >>>> - set_page_dirty >>>> - tag ATOMIC_WRITTEN_PAGE and add page >>>> to inmem_pages list >>>> - clear_inode_flag(FI_ATOMIC_FILE) >>>> - f2fs_vm_page_mkwrite >>>> - set_page_dirty >>>> - f2fs_update_dirty_page >>>> - f2fs_trace_pid >>>> - tag inmem page private to pid >>>> - truncate >>>> - f2fs_invalidate_page >>>> - set page->mapping to NULL >>>> then it will cause panic once we >>>> access page->mapping >>>> >>>> The root cause is we missed to keep isolation of atomic write in the case >>>> of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem >>>> lock to avoid this issue. >>>> >>>> Signed-off-by: Chao Yu <yuchao0@huawei.com> >>>> --- >>>> v2: >>>> - use i_mmap_sem to avoid mkwrite racing with below flows: >>>> * f2fs_ioc_start_atomic_write >>>> * f2fs_drop_inmem_pages >>>> * f2fs_commit_inmem_pages >>>> >>>> fs/f2fs/file.c | 3 +++ >>>> fs/f2fs/segment.c | 7 +++++++ >>>> 2 files changed, 10 insertions(+) >>>> >>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c >>>> index 4e6d4b9120a8..a48ec650d691 100644 >>>> --- a/fs/f2fs/file.c >>>> +++ b/fs/f2fs/file.c >>>> @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>> goto out; >>>> >>>> down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>> >>>> /* >>>> * Should wait end_io to count F2FS_WB_CP_DATA correctly by >>>> @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>> inode->i_ino, get_dirty_pages(inode)); >>>> ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); >>>> if (ret) { >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>> goto out; >>>> } >>>> @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>> /* add inode in inmem_list first and set atomic_file */ >>>> set_inode_flag(inode, FI_ATOMIC_FILE); >>>> clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>> >>>> f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); >>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >>>> index d8570b0359f5..dab870d9faf6 100644 >>>> --- a/fs/f2fs/segment.c >>>> +++ b/fs/f2fs/segment.c >>>> @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>> struct f2fs_sb_info *sbi = F2FS_I_SB(inode); >>>> struct f2fs_inode_info *fi = F2FS_I(inode); >>>> >>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>> + >>>> while (!list_empty(&fi->inmem_pages)) { >>>> mutex_lock(&fi->inmem_lock); >>>> __revoke_inmem_pages(inode, &fi->inmem_pages, >>>> @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>> sbi->atomic_files--; >>>> } >>>> spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); >>>> + >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> } >>>> >>>> void f2fs_drop_inmem_page(struct inode *inode, struct page *page) >>>> @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>> f2fs_balance_fs(sbi, true); >>>> >>>> down_write(&fi->i_gc_rwsem[WRITE]); >>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>> >>>> f2fs_lock_op(sbi); >>>> set_inode_flag(inode, FI_ATOMIC_COMMIT); >>>> @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>> clear_inode_flag(inode, FI_ATOMIC_COMMIT); >>>> >>>> f2fs_unlock_op(sbi); >>>> + >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> up_write(&fi->i_gc_rwsem[WRITE]); >>>> >>>> return err; >>>> -- >>>> 2.29.2 >>> >>> >>> _______________________________________________ >>> Linux-f2fs-devel mailing list >>> Linux-f2fs-devel@lists.sourceforge.net >>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel >> >> >> _______________________________________________ >> Linux-f2fs-devel mailing list >> Linux-f2fs-devel@lists.sourceforge.net >> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel > . > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [f2fs-dev] [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-12 2:59 ` Chao Yu @ 2021-01-12 22:32 ` Jaegeuk Kim 2021-01-13 1:30 ` Chao Yu 0 siblings, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-12 22:32 UTC (permalink / raw) To: Chao Yu; +Cc: linux-kernel, linux-f2fs-devel On 01/12, Chao Yu wrote: > On 2021/1/12 0:32, Jaegeuk Kim wrote: > > On 01/06, Jaegeuk Kim wrote: > > > On 01/06, Jaegeuk Kim wrote: > > > > Hi Chao, > > > > > > > > With a quick test, this patch causes down_write failure resulting in blocking > > > > process. I didn't dig in the bug so, please check the code again. :P > > > > > > nvm. I can see it works now. > > > > Hmm, this gives a huge perf regression when running sqlite. :( > > We may need to check the lock coverage. Thoughts? > > I added i_mmap_sem lock only, so it can cause atomic_{start,commit,finish} > race with mmap and truncation operations in additionally. > > I'd like to know what's your sqlite testcase? Nothing special. Just generating multiple sqlite transactions to the same db. > > Thanks, > > > > > > > > > > > > > > On 12/30, Chao Yu wrote: > > > > > ThreadA ThreadB > > > > > - f2fs_ioc_start_atomic_write > > > > > - write > > > > > - f2fs_ioc_commit_atomic_write > > > > > - f2fs_commit_inmem_pages > > > > > - f2fs_drop_inmem_pages > > > > > - f2fs_drop_inmem_pages > > > > > - __revoke_inmem_pages > > > > > - f2fs_vm_page_mkwrite > > > > > - set_page_dirty > > > > > - tag ATOMIC_WRITTEN_PAGE and add page > > > > > to inmem_pages list > > > > > - clear_inode_flag(FI_ATOMIC_FILE) > > > > > - f2fs_vm_page_mkwrite > > > > > - set_page_dirty > > > > > - f2fs_update_dirty_page > > > > > - f2fs_trace_pid > > > > > - tag inmem page private to pid > > > > > - truncate > > > > > - f2fs_invalidate_page > > > > > - set page->mapping to NULL > > > > > then it will cause panic once we > > > > > access page->mapping > > > > > > > > > > The root cause is we missed to keep isolation of atomic write in the case > > > > > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > > > > > lock to avoid this issue. > > > > > > > > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > > > > --- > > > > > v2: > > > > > - use i_mmap_sem to avoid mkwrite racing with below flows: > > > > > * f2fs_ioc_start_atomic_write > > > > > * f2fs_drop_inmem_pages > > > > > * f2fs_commit_inmem_pages > > > > > > > > > > fs/f2fs/file.c | 3 +++ > > > > > fs/f2fs/segment.c | 7 +++++++ > > > > > 2 files changed, 10 insertions(+) > > > > > > > > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > > > > > index 4e6d4b9120a8..a48ec650d691 100644 > > > > > --- a/fs/f2fs/file.c > > > > > +++ b/fs/f2fs/file.c > > > > > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > > > goto out; > > > > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > /* > > > > > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > > > > > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > > > inode->i_ino, get_dirty_pages(inode)); > > > > > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > > > > > if (ret) { > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > goto out; > > > > > } > > > > > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > > > /* add inode in inmem_list first and set atomic_file */ > > > > > set_inode_flag(inode, FI_ATOMIC_FILE); > > > > > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > > > > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > > > > index d8570b0359f5..dab870d9faf6 100644 > > > > > --- a/fs/f2fs/segment.c > > > > > +++ b/fs/f2fs/segment.c > > > > > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > > > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > > > > > struct f2fs_inode_info *fi = F2FS_I(inode); > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > + > > > > > while (!list_empty(&fi->inmem_pages)) { > > > > > mutex_lock(&fi->inmem_lock); > > > > > __revoke_inmem_pages(inode, &fi->inmem_pages, > > > > > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > > > sbi->atomic_files--; > > > > > } > > > > > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > > > > > + > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > } > > > > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > > > > > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > > > f2fs_balance_fs(sbi, true); > > > > > down_write(&fi->i_gc_rwsem[WRITE]); > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > f2fs_lock_op(sbi); > > > > > set_inode_flag(inode, FI_ATOMIC_COMMIT); > > > > > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > > > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > > > > f2fs_unlock_op(sbi); > > > > > + > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > up_write(&fi->i_gc_rwsem[WRITE]); > > > > > return err; > > > > > -- > > > > > 2.29.2 > > > > > > > > > > > > _______________________________________________ > > > > Linux-f2fs-devel mailing list > > > > Linux-f2fs-devel@lists.sourceforge.net > > > > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel > > > > > > > > > _______________________________________________ > > > Linux-f2fs-devel mailing list > > > Linux-f2fs-devel@lists.sourceforge.net > > > https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel > > . > > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [f2fs-dev] [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-12 22:32 ` Jaegeuk Kim @ 2021-01-13 1:30 ` Chao Yu 0 siblings, 0 replies; 13+ messages in thread From: Chao Yu @ 2021-01-13 1:30 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-kernel, linux-f2fs-devel On 2021/1/13 6:32, Jaegeuk Kim wrote: > On 01/12, Chao Yu wrote: >> On 2021/1/12 0:32, Jaegeuk Kim wrote: >>> On 01/06, Jaegeuk Kim wrote: >>>> On 01/06, Jaegeuk Kim wrote: >>>>> Hi Chao, >>>>> >>>>> With a quick test, this patch causes down_write failure resulting in blocking >>>>> process. I didn't dig in the bug so, please check the code again. :P >>>> >>>> nvm. I can see it works now. >>> >>> Hmm, this gives a huge perf regression when running sqlite. :( >>> We may need to check the lock coverage. Thoughts? >> >> I added i_mmap_sem lock only, so it can cause atomic_{start,commit,finish} >> race with mmap and truncation operations in additionally. >> >> I'd like to know what's your sqlite testcase? > > Nothing special. Just generating multiple sqlite transactions to the same db. I doubt that start/commit flow race with ->release/->flush interface can cause lower concurrency? f2fs_ioc_start_atomic_write or ->release or ->flush f2fs_ioc_commit_atomic_write - f2fs_drop_inmem_pages down_write(&F2FS_I(inode)->i_mmap_sem); down_write(&F2FS_I(inode)->i_mmap_sem); How about trying this testcase again after removing i_mmap_sem lock in f2fs_drop_inmem_pages()? Thanks, > >> >> Thanks, >> >>> >>>> >>>>> >>>>> On 12/30, Chao Yu wrote: >>>>>> ThreadA ThreadB >>>>>> - f2fs_ioc_start_atomic_write >>>>>> - write >>>>>> - f2fs_ioc_commit_atomic_write >>>>>> - f2fs_commit_inmem_pages >>>>>> - f2fs_drop_inmem_pages >>>>>> - f2fs_drop_inmem_pages >>>>>> - __revoke_inmem_pages >>>>>> - f2fs_vm_page_mkwrite >>>>>> - set_page_dirty >>>>>> - tag ATOMIC_WRITTEN_PAGE and add page >>>>>> to inmem_pages list >>>>>> - clear_inode_flag(FI_ATOMIC_FILE) >>>>>> - f2fs_vm_page_mkwrite >>>>>> - set_page_dirty >>>>>> - f2fs_update_dirty_page >>>>>> - f2fs_trace_pid >>>>>> - tag inmem page private to pid >>>>>> - truncate >>>>>> - f2fs_invalidate_page >>>>>> - set page->mapping to NULL >>>>>> then it will cause panic once we >>>>>> access page->mapping >>>>>> >>>>>> The root cause is we missed to keep isolation of atomic write in the case >>>>>> of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem >>>>>> lock to avoid this issue. >>>>>> >>>>>> Signed-off-by: Chao Yu <yuchao0@huawei.com> >>>>>> --- >>>>>> v2: >>>>>> - use i_mmap_sem to avoid mkwrite racing with below flows: >>>>>> * f2fs_ioc_start_atomic_write >>>>>> * f2fs_drop_inmem_pages >>>>>> * f2fs_commit_inmem_pages >>>>>> >>>>>> fs/f2fs/file.c | 3 +++ >>>>>> fs/f2fs/segment.c | 7 +++++++ >>>>>> 2 files changed, 10 insertions(+) >>>>>> >>>>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c >>>>>> index 4e6d4b9120a8..a48ec650d691 100644 >>>>>> --- a/fs/f2fs/file.c >>>>>> +++ b/fs/f2fs/file.c >>>>>> @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>>>> goto out; >>>>>> down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> /* >>>>>> * Should wait end_io to count F2FS_WB_CP_DATA correctly by >>>>>> @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>>>> inode->i_ino, get_dirty_pages(inode)); >>>>>> ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); >>>>>> if (ret) { >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>>>> goto out; >>>>>> } >>>>>> @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>>>> /* add inode in inmem_list first and set atomic_file */ >>>>>> set_inode_flag(inode, FI_ATOMIC_FILE); >>>>>> clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>>>> f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); >>>>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >>>>>> index d8570b0359f5..dab870d9faf6 100644 >>>>>> --- a/fs/f2fs/segment.c >>>>>> +++ b/fs/f2fs/segment.c >>>>>> @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>>>> struct f2fs_sb_info *sbi = F2FS_I_SB(inode); >>>>>> struct f2fs_inode_info *fi = F2FS_I(inode); >>>>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> + >>>>>> while (!list_empty(&fi->inmem_pages)) { >>>>>> mutex_lock(&fi->inmem_lock); >>>>>> __revoke_inmem_pages(inode, &fi->inmem_pages, >>>>>> @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>>>> sbi->atomic_files--; >>>>>> } >>>>>> spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); >>>>>> + >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> } >>>>>> void f2fs_drop_inmem_page(struct inode *inode, struct page *page) >>>>>> @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>>>> f2fs_balance_fs(sbi, true); >>>>>> down_write(&fi->i_gc_rwsem[WRITE]); >>>>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> f2fs_lock_op(sbi); >>>>>> set_inode_flag(inode, FI_ATOMIC_COMMIT); >>>>>> @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>>>> clear_inode_flag(inode, FI_ATOMIC_COMMIT); >>>>>> f2fs_unlock_op(sbi); >>>>>> + >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> up_write(&fi->i_gc_rwsem[WRITE]); >>>>>> return err; >>>>>> -- >>>>>> 2.29.2 >>>>> >>>>> >>>>> _______________________________________________ >>>>> Linux-f2fs-devel mailing list >>>>> Linux-f2fs-devel@lists.sourceforge.net >>>>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel >>>> >>>> >>>> _______________________________________________ >>>> Linux-f2fs-devel mailing list >>>> Linux-f2fs-devel@lists.sourceforge.net >>>> https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel >>> . >>> > . > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2020-12-30 7:55 [PATCH v2] f2fs: fix to keep isolation of atomic write Chao Yu 2021-01-06 22:28 ` Jaegeuk Kim @ 2021-01-14 21:53 ` Jaegeuk Kim 2021-01-15 7:59 ` Chao Yu 1 sibling, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-14 21:53 UTC (permalink / raw) To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao On 12/30, Chao Yu wrote: > ThreadA ThreadB > - f2fs_ioc_start_atomic_write > - write > - f2fs_ioc_commit_atomic_write > - f2fs_commit_inmem_pages > - f2fs_drop_inmem_pages > - f2fs_drop_inmem_pages > - __revoke_inmem_pages > - f2fs_vm_page_mkwrite > - set_page_dirty > - tag ATOMIC_WRITTEN_PAGE and add page > to inmem_pages list > - clear_inode_flag(FI_ATOMIC_FILE) > - f2fs_vm_page_mkwrite > - set_page_dirty > - f2fs_update_dirty_page > - f2fs_trace_pid > - tag inmem page private to pid Hmm, how about removing fs/f2fs/trace.c to make private more complicated like this? I think we can get IO traces from tracepoints. > - truncate > - f2fs_invalidate_page > - set page->mapping to NULL > then it will cause panic once we > access page->mapping > > The root cause is we missed to keep isolation of atomic write in the case > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > lock to avoid this issue. > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > --- > v2: > - use i_mmap_sem to avoid mkwrite racing with below flows: > * f2fs_ioc_start_atomic_write > * f2fs_drop_inmem_pages > * f2fs_commit_inmem_pages > > fs/f2fs/file.c | 3 +++ > fs/f2fs/segment.c | 7 +++++++ > 2 files changed, 10 insertions(+) > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > index 4e6d4b9120a8..a48ec650d691 100644 > --- a/fs/f2fs/file.c > +++ b/fs/f2fs/file.c > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > goto out; > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > + down_write(&F2FS_I(inode)->i_mmap_sem); > > /* > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > inode->i_ino, get_dirty_pages(inode)); > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > if (ret) { > + up_write(&F2FS_I(inode)->i_mmap_sem); > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > goto out; > } > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > /* add inode in inmem_list first and set atomic_file */ > set_inode_flag(inode, FI_ATOMIC_FILE); > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > + up_write(&F2FS_I(inode)->i_mmap_sem); > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index d8570b0359f5..dab870d9faf6 100644 > --- a/fs/f2fs/segment.c > +++ b/fs/f2fs/segment.c > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > struct f2fs_inode_info *fi = F2FS_I(inode); > > + down_write(&F2FS_I(inode)->i_mmap_sem); > + > while (!list_empty(&fi->inmem_pages)) { > mutex_lock(&fi->inmem_lock); > __revoke_inmem_pages(inode, &fi->inmem_pages, > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > sbi->atomic_files--; > } > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > + > + up_write(&F2FS_I(inode)->i_mmap_sem); > } > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > f2fs_balance_fs(sbi, true); > > down_write(&fi->i_gc_rwsem[WRITE]); > + down_write(&F2FS_I(inode)->i_mmap_sem); > > f2fs_lock_op(sbi); > set_inode_flag(inode, FI_ATOMIC_COMMIT); > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > f2fs_unlock_op(sbi); > + > + up_write(&F2FS_I(inode)->i_mmap_sem); > up_write(&fi->i_gc_rwsem[WRITE]); > > return err; > -- > 2.29.2 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-14 21:53 ` Jaegeuk Kim @ 2021-01-15 7:59 ` Chao Yu 2021-01-19 19:06 ` Jaegeuk Kim 0 siblings, 1 reply; 13+ messages in thread From: Chao Yu @ 2021-01-15 7:59 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao On 2021/1/15 5:53, Jaegeuk Kim wrote: > On 12/30, Chao Yu wrote: >> ThreadA ThreadB >> - f2fs_ioc_start_atomic_write >> - write >> - f2fs_ioc_commit_atomic_write >> - f2fs_commit_inmem_pages >> - f2fs_drop_inmem_pages >> - f2fs_drop_inmem_pages >> - __revoke_inmem_pages >> - f2fs_vm_page_mkwrite >> - set_page_dirty >> - tag ATOMIC_WRITTEN_PAGE and add page >> to inmem_pages list >> - clear_inode_flag(FI_ATOMIC_FILE) >> - f2fs_vm_page_mkwrite >> - set_page_dirty >> - f2fs_update_dirty_page >> - f2fs_trace_pid >> - tag inmem page private to pid > > Hmm, how about removing fs/f2fs/trace.c to make private more complicated > like this? I think we can get IO traces from tracepoints. Hmm, actually, there is are issues, one is the trace IO, the other is the race issue (atomic_start,commit,drop vs mkwrite) which can make isolation semantics of transaction be broken. Or can we avoid atomic file racing with file mmap? - atomic_start - file_mmap - inode_lock - if (FI_ATOMIC_FILE) return - inode_lock - if (FI_MMAP_FILE) return Thanks, > >> - truncate >> - f2fs_invalidate_page >> - set page->mapping to NULL >> then it will cause panic once we >> access page->mapping >> >> The root cause is we missed to keep isolation of atomic write in the case >> of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem >> lock to avoid this issue. >> >> Signed-off-by: Chao Yu <yuchao0@huawei.com> >> --- >> v2: >> - use i_mmap_sem to avoid mkwrite racing with below flows: >> * f2fs_ioc_start_atomic_write >> * f2fs_drop_inmem_pages >> * f2fs_commit_inmem_pages >> >> fs/f2fs/file.c | 3 +++ >> fs/f2fs/segment.c | 7 +++++++ >> 2 files changed, 10 insertions(+) >> >> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c >> index 4e6d4b9120a8..a48ec650d691 100644 >> --- a/fs/f2fs/file.c >> +++ b/fs/f2fs/file.c >> @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >> goto out; >> >> down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >> + down_write(&F2FS_I(inode)->i_mmap_sem); >> >> /* >> * Should wait end_io to count F2FS_WB_CP_DATA correctly by >> @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >> inode->i_ino, get_dirty_pages(inode)); >> ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); >> if (ret) { >> + up_write(&F2FS_I(inode)->i_mmap_sem); >> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >> goto out; >> } >> @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >> /* add inode in inmem_list first and set atomic_file */ >> set_inode_flag(inode, FI_ATOMIC_FILE); >> clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); >> + up_write(&F2FS_I(inode)->i_mmap_sem); >> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >> >> f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); >> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >> index d8570b0359f5..dab870d9faf6 100644 >> --- a/fs/f2fs/segment.c >> +++ b/fs/f2fs/segment.c >> @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >> struct f2fs_sb_info *sbi = F2FS_I_SB(inode); >> struct f2fs_inode_info *fi = F2FS_I(inode); >> >> + down_write(&F2FS_I(inode)->i_mmap_sem); >> + >> while (!list_empty(&fi->inmem_pages)) { >> mutex_lock(&fi->inmem_lock); >> __revoke_inmem_pages(inode, &fi->inmem_pages, >> @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >> sbi->atomic_files--; >> } >> spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); >> + >> + up_write(&F2FS_I(inode)->i_mmap_sem); >> } >> >> void f2fs_drop_inmem_page(struct inode *inode, struct page *page) >> @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) >> f2fs_balance_fs(sbi, true); >> >> down_write(&fi->i_gc_rwsem[WRITE]); >> + down_write(&F2FS_I(inode)->i_mmap_sem); >> >> f2fs_lock_op(sbi); >> set_inode_flag(inode, FI_ATOMIC_COMMIT); >> @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) >> clear_inode_flag(inode, FI_ATOMIC_COMMIT); >> >> f2fs_unlock_op(sbi); >> + >> + up_write(&F2FS_I(inode)->i_mmap_sem); >> up_write(&fi->i_gc_rwsem[WRITE]); >> >> return err; >> -- >> 2.29.2 > . > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-15 7:59 ` Chao Yu @ 2021-01-19 19:06 ` Jaegeuk Kim 2021-01-20 1:18 ` Chao Yu 0 siblings, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-19 19:06 UTC (permalink / raw) To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao On 01/15, Chao Yu wrote: > On 2021/1/15 5:53, Jaegeuk Kim wrote: > > On 12/30, Chao Yu wrote: > > > ThreadA ThreadB > > > - f2fs_ioc_start_atomic_write > > > - write > > > - f2fs_ioc_commit_atomic_write > > > - f2fs_commit_inmem_pages > > > - f2fs_drop_inmem_pages > > > - f2fs_drop_inmem_pages > > > - __revoke_inmem_pages > > > - f2fs_vm_page_mkwrite > > > - set_page_dirty > > > - tag ATOMIC_WRITTEN_PAGE and add page > > > to inmem_pages list > > > - clear_inode_flag(FI_ATOMIC_FILE) > > > - f2fs_vm_page_mkwrite > > > - set_page_dirty > > > - f2fs_update_dirty_page > > > - f2fs_trace_pid > > > - tag inmem page private to pid > > > > Hmm, how about removing fs/f2fs/trace.c to make private more complicated > > like this? I think we can get IO traces from tracepoints. > > Hmm, actually, there is are issues, one is the trace IO, the other is the > race issue (atomic_start,commit,drop vs mkwrite) which can make isolation > semantics of transaction be broken. > > Or can we avoid atomic file racing with file mmap? No, we can't. We may need to find other way to check the race. :) > > - atomic_start - file_mmap > - inode_lock > - if (FI_ATOMIC_FILE) return > - inode_lock > - if (FI_MMAP_FILE) return > > Thanks, > > > > > > - truncate > > > - f2fs_invalidate_page > > > - set page->mapping to NULL > > > then it will cause panic once we > > > access page->mapping > > > > > > The root cause is we missed to keep isolation of atomic write in the case > > > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > > > lock to avoid this issue. > > > > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > > --- > > > v2: > > > - use i_mmap_sem to avoid mkwrite racing with below flows: > > > * f2fs_ioc_start_atomic_write > > > * f2fs_drop_inmem_pages > > > * f2fs_commit_inmem_pages > > > > > > fs/f2fs/file.c | 3 +++ > > > fs/f2fs/segment.c | 7 +++++++ > > > 2 files changed, 10 insertions(+) > > > > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > > > index 4e6d4b9120a8..a48ec650d691 100644 > > > --- a/fs/f2fs/file.c > > > +++ b/fs/f2fs/file.c > > > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > goto out; > > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > /* > > > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > > > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > inode->i_ino, get_dirty_pages(inode)); > > > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > > > if (ret) { > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > goto out; > > > } > > > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > /* add inode in inmem_list first and set atomic_file */ > > > set_inode_flag(inode, FI_ATOMIC_FILE); > > > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > > index d8570b0359f5..dab870d9faf6 100644 > > > --- a/fs/f2fs/segment.c > > > +++ b/fs/f2fs/segment.c > > > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > > > struct f2fs_inode_info *fi = F2FS_I(inode); > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > + > > > while (!list_empty(&fi->inmem_pages)) { > > > mutex_lock(&fi->inmem_lock); > > > __revoke_inmem_pages(inode, &fi->inmem_pages, > > > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > sbi->atomic_files--; > > > } > > > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > > > + > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > } > > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > > > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > f2fs_balance_fs(sbi, true); > > > down_write(&fi->i_gc_rwsem[WRITE]); > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > f2fs_lock_op(sbi); > > > set_inode_flag(inode, FI_ATOMIC_COMMIT); > > > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > > f2fs_unlock_op(sbi); > > > + > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > up_write(&fi->i_gc_rwsem[WRITE]); > > > return err; > > > -- > > > 2.29.2 > > . > > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-19 19:06 ` Jaegeuk Kim @ 2021-01-20 1:18 ` Chao Yu 2021-01-28 16:21 ` Jaegeuk Kim 0 siblings, 1 reply; 13+ messages in thread From: Chao Yu @ 2021-01-20 1:18 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao On 2021/1/20 3:06, Jaegeuk Kim wrote: > On 01/15, Chao Yu wrote: >> On 2021/1/15 5:53, Jaegeuk Kim wrote: >>> On 12/30, Chao Yu wrote: >>>> ThreadA ThreadB >>>> - f2fs_ioc_start_atomic_write >>>> - write >>>> - f2fs_ioc_commit_atomic_write >>>> - f2fs_commit_inmem_pages >>>> - f2fs_drop_inmem_pages >>>> - f2fs_drop_inmem_pages >>>> - __revoke_inmem_pages >>>> - f2fs_vm_page_mkwrite >>>> - set_page_dirty >>>> - tag ATOMIC_WRITTEN_PAGE and add page >>>> to inmem_pages list >>>> - clear_inode_flag(FI_ATOMIC_FILE) >>>> - f2fs_vm_page_mkwrite >>>> - set_page_dirty >>>> - f2fs_update_dirty_page >>>> - f2fs_trace_pid >>>> - tag inmem page private to pid >>> >>> Hmm, how about removing fs/f2fs/trace.c to make private more complicated >>> like this? I think we can get IO traces from tracepoints. >> >> Hmm, actually, there is are issues, one is the trace IO, the other is the >> race issue (atomic_start,commit,drop vs mkwrite) which can make isolation >> semantics of transaction be broken. >> >> Or can we avoid atomic file racing with file mmap? Otherwise I think we should add i_mmap_sem to avoid the race. > > No, we can't. We may need to find other way to check the race. :) Well, any thoughts about this issue? Thanks, > >> >> - atomic_start - file_mmap >> - inode_lock >> - if (FI_ATOMIC_FILE) return >> - inode_lock >> - if (FI_MMAP_FILE) return >> >> Thanks, >> >>> >>>> - truncate >>>> - f2fs_invalidate_page >>>> - set page->mapping to NULL >>>> then it will cause panic once we >>>> access page->mapping >>>> >>>> The root cause is we missed to keep isolation of atomic write in the case >>>> of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem >>>> lock to avoid this issue. >>>> >>>> Signed-off-by: Chao Yu <yuchao0@huawei.com> >>>> --- >>>> v2: >>>> - use i_mmap_sem to avoid mkwrite racing with below flows: >>>> * f2fs_ioc_start_atomic_write >>>> * f2fs_drop_inmem_pages >>>> * f2fs_commit_inmem_pages >>>> >>>> fs/f2fs/file.c | 3 +++ >>>> fs/f2fs/segment.c | 7 +++++++ >>>> 2 files changed, 10 insertions(+) >>>> >>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c >>>> index 4e6d4b9120a8..a48ec650d691 100644 >>>> --- a/fs/f2fs/file.c >>>> +++ b/fs/f2fs/file.c >>>> @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>> goto out; >>>> down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>> /* >>>> * Should wait end_io to count F2FS_WB_CP_DATA correctly by >>>> @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>> inode->i_ino, get_dirty_pages(inode)); >>>> ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); >>>> if (ret) { >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>> goto out; >>>> } >>>> @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>> /* add inode in inmem_list first and set atomic_file */ >>>> set_inode_flag(inode, FI_ATOMIC_FILE); >>>> clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>> f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); >>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >>>> index d8570b0359f5..dab870d9faf6 100644 >>>> --- a/fs/f2fs/segment.c >>>> +++ b/fs/f2fs/segment.c >>>> @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>> struct f2fs_sb_info *sbi = F2FS_I_SB(inode); >>>> struct f2fs_inode_info *fi = F2FS_I(inode); >>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>> + >>>> while (!list_empty(&fi->inmem_pages)) { >>>> mutex_lock(&fi->inmem_lock); >>>> __revoke_inmem_pages(inode, &fi->inmem_pages, >>>> @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>> sbi->atomic_files--; >>>> } >>>> spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); >>>> + >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> } >>>> void f2fs_drop_inmem_page(struct inode *inode, struct page *page) >>>> @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>> f2fs_balance_fs(sbi, true); >>>> down_write(&fi->i_gc_rwsem[WRITE]); >>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>> f2fs_lock_op(sbi); >>>> set_inode_flag(inode, FI_ATOMIC_COMMIT); >>>> @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>> clear_inode_flag(inode, FI_ATOMIC_COMMIT); >>>> f2fs_unlock_op(sbi); >>>> + >>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>> up_write(&fi->i_gc_rwsem[WRITE]); >>>> return err; >>>> -- >>>> 2.29.2 >>> . >>> > . > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-20 1:18 ` Chao Yu @ 2021-01-28 16:21 ` Jaegeuk Kim 2021-01-29 1:38 ` Chao Yu 0 siblings, 1 reply; 13+ messages in thread From: Jaegeuk Kim @ 2021-01-28 16:21 UTC (permalink / raw) To: Chao Yu; +Cc: linux-f2fs-devel, linux-kernel, chao On 01/20, Chao Yu wrote: > On 2021/1/20 3:06, Jaegeuk Kim wrote: > > On 01/15, Chao Yu wrote: > > > On 2021/1/15 5:53, Jaegeuk Kim wrote: > > > > On 12/30, Chao Yu wrote: > > > > > ThreadA ThreadB > > > > > - f2fs_ioc_start_atomic_write > > > > > - write > > > > > - f2fs_ioc_commit_atomic_write > > > > > - f2fs_commit_inmem_pages > > > > > - f2fs_drop_inmem_pages > > > > > - f2fs_drop_inmem_pages > > > > > - __revoke_inmem_pages > > > > > - f2fs_vm_page_mkwrite > > > > > - set_page_dirty > > > > > - tag ATOMIC_WRITTEN_PAGE and add page > > > > > to inmem_pages list > > > > > - clear_inode_flag(FI_ATOMIC_FILE) > > > > > - f2fs_vm_page_mkwrite > > > > > - set_page_dirty > > > > > - f2fs_update_dirty_page > > > > > - f2fs_trace_pid > > > > > - tag inmem page private to pid > > > > > > > > Hmm, how about removing fs/f2fs/trace.c to make private more complicated > > > > like this? I think we can get IO traces from tracepoints. > > > > > > Hmm, actually, there is are issues, one is the trace IO, the other is the > > > race issue (atomic_start,commit,drop vs mkwrite) which can make isolation > > > semantics of transaction be broken. > > > > > > Or can we avoid atomic file racing with file mmap? > > Otherwise I think we should add i_mmap_sem to avoid the race. > > > > > No, we can't. We may need to find other way to check the race. :) > > Well, any thoughts about this issue? > > Thanks, > > > > > > > > > - atomic_start - file_mmap > > > - inode_lock > > > - if (FI_ATOMIC_FILE) return > > > - inode_lock > > > - if (FI_MMAP_FILE) return > > > > > > Thanks, > > > > > > > > > > > > - truncate > > > > > - f2fs_invalidate_page > > > > > - set page->mapping to NULL > > > > > then it will cause panic once we > > > > > access page->mapping Are we hitting this, since page was referenced by in-mem list? > > > > > > > > > > The root cause is we missed to keep isolation of atomic write in the case > > > > > of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem > > > > > lock to avoid this issue. > > > > > > > > > > Signed-off-by: Chao Yu <yuchao0@huawei.com> > > > > > --- > > > > > v2: > > > > > - use i_mmap_sem to avoid mkwrite racing with below flows: > > > > > * f2fs_ioc_start_atomic_write > > > > > * f2fs_drop_inmem_pages > > > > > * f2fs_commit_inmem_pages > > > > > > > > > > fs/f2fs/file.c | 3 +++ > > > > > fs/f2fs/segment.c | 7 +++++++ > > > > > 2 files changed, 10 insertions(+) > > > > > > > > > > diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c > > > > > index 4e6d4b9120a8..a48ec650d691 100644 > > > > > --- a/fs/f2fs/file.c > > > > > +++ b/fs/f2fs/file.c > > > > > @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > > > goto out; > > > > > down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > /* > > > > > * Should wait end_io to count F2FS_WB_CP_DATA correctly by > > > > > @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > > > inode->i_ino, get_dirty_pages(inode)); > > > > > ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); > > > > > if (ret) { > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > goto out; > > > > > } > > > > > @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) > > > > > /* add inode in inmem_list first and set atomic_file */ > > > > > set_inode_flag(inode, FI_ATOMIC_FILE); > > > > > clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); > > > > > f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); > > > > > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > > > > > index d8570b0359f5..dab870d9faf6 100644 > > > > > --- a/fs/f2fs/segment.c > > > > > +++ b/fs/f2fs/segment.c > > > > > @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > > > struct f2fs_sb_info *sbi = F2FS_I_SB(inode); > > > > > struct f2fs_inode_info *fi = F2FS_I(inode); > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > + > > > > > while (!list_empty(&fi->inmem_pages)) { > > > > > mutex_lock(&fi->inmem_lock); > > > > > __revoke_inmem_pages(inode, &fi->inmem_pages, > > > > > @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) > > > > > sbi->atomic_files--; > > > > > } > > > > > spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); > > > > > + > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > } > > > > > void f2fs_drop_inmem_page(struct inode *inode, struct page *page) > > > > > @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > > > f2fs_balance_fs(sbi, true); > > > > > down_write(&fi->i_gc_rwsem[WRITE]); > > > > > + down_write(&F2FS_I(inode)->i_mmap_sem); > > > > > f2fs_lock_op(sbi); > > > > > set_inode_flag(inode, FI_ATOMIC_COMMIT); > > > > > @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) > > > > > clear_inode_flag(inode, FI_ATOMIC_COMMIT); > > > > > f2fs_unlock_op(sbi); > > > > > + > > > > > + up_write(&F2FS_I(inode)->i_mmap_sem); > > > > > up_write(&fi->i_gc_rwsem[WRITE]); > > > > > return err; > > > > > -- > > > > > 2.29.2 > > > > . > > > > > > . > > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH v2] f2fs: fix to keep isolation of atomic write 2021-01-28 16:21 ` Jaegeuk Kim @ 2021-01-29 1:38 ` Chao Yu 0 siblings, 0 replies; 13+ messages in thread From: Chao Yu @ 2021-01-29 1:38 UTC (permalink / raw) To: Jaegeuk Kim; +Cc: linux-f2fs-devel, linux-kernel, chao On 2021/1/29 0:21, Jaegeuk Kim wrote: > On 01/20, Chao Yu wrote: >> On 2021/1/20 3:06, Jaegeuk Kim wrote: >>> On 01/15, Chao Yu wrote: >>>> On 2021/1/15 5:53, Jaegeuk Kim wrote: >>>>> On 12/30, Chao Yu wrote: >>>>>> ThreadA ThreadB >>>>>> - f2fs_ioc_start_atomic_write >>>>>> - write >>>>>> - f2fs_ioc_commit_atomic_write >>>>>> - f2fs_commit_inmem_pages >>>>>> - f2fs_drop_inmem_pages >>>>>> - f2fs_drop_inmem_pages >>>>>> - __revoke_inmem_pages >>>>>> - f2fs_vm_page_mkwrite >>>>>> - set_page_dirty >>>>>> - tag ATOMIC_WRITTEN_PAGE and add page >>>>>> to inmem_pages list >>>>>> - clear_inode_flag(FI_ATOMIC_FILE) >>>>>> - f2fs_vm_page_mkwrite >>>>>> - set_page_dirty >>>>>> - f2fs_update_dirty_page >>>>>> - f2fs_trace_pid >>>>>> - tag inmem page private to pid >>>>> >>>>> Hmm, how about removing fs/f2fs/trace.c to make private more complicated >>>>> like this? I think we can get IO traces from tracepoints. >>>> >>>> Hmm, actually, there is are issues, one is the trace IO, the other is the >>>> race issue (atomic_start,commit,drop vs mkwrite) which can make isolation >>>> semantics of transaction be broken. >>>> >>>> Or can we avoid atomic file racing with file mmap? >> >> Otherwise I think we should add i_mmap_sem to avoid the race. >> >>> >>> No, we can't. We may need to find other way to check the race. :) >> >> Well, any thoughts about this issue? >> >> Thanks, >> >>> >>>> >>>> - atomic_start - file_mmap >>>> - inode_lock >>>> - if (FI_ATOMIC_FILE) return >>>> - inode_lock >>>> - if (FI_MMAP_FILE) return >>>> >>>> Thanks, >>>> >>>>> >>>>>> - truncate >>>>>> - f2fs_invalidate_page >>>>>> - set page->mapping to NULL >>>>>> then it will cause panic once we >>>>>> access page->mapping > > Are we hitting this, since page was referenced by in-mem list? Yes, we hit this NULL point dereferencing issue when running fuzz tool, but the condition is not the same, because in our product, CONFIG_F2FS_IO_TRACE was not set. Thanks, > >>>>>> >>>>>> The root cause is we missed to keep isolation of atomic write in the case >>>>>> of commit_atomic_write vs mkwrite, let commit_atomic_write helds i_mmap_sem >>>>>> lock to avoid this issue. >>>>>> >>>>>> Signed-off-by: Chao Yu <yuchao0@huawei.com> >>>>>> --- >>>>>> v2: >>>>>> - use i_mmap_sem to avoid mkwrite racing with below flows: >>>>>> * f2fs_ioc_start_atomic_write >>>>>> * f2fs_drop_inmem_pages >>>>>> * f2fs_commit_inmem_pages >>>>>> >>>>>> fs/f2fs/file.c | 3 +++ >>>>>> fs/f2fs/segment.c | 7 +++++++ >>>>>> 2 files changed, 10 insertions(+) >>>>>> >>>>>> diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c >>>>>> index 4e6d4b9120a8..a48ec650d691 100644 >>>>>> --- a/fs/f2fs/file.c >>>>>> +++ b/fs/f2fs/file.c >>>>>> @@ -2050,6 +2050,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>>>> goto out; >>>>>> down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> /* >>>>>> * Should wait end_io to count F2FS_WB_CP_DATA correctly by >>>>>> @@ -2060,6 +2061,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>>>> inode->i_ino, get_dirty_pages(inode)); >>>>>> ret = filemap_write_and_wait_range(inode->i_mapping, 0, LLONG_MAX); >>>>>> if (ret) { >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>>>> goto out; >>>>>> } >>>>>> @@ -2073,6 +2075,7 @@ static int f2fs_ioc_start_atomic_write(struct file *filp) >>>>>> /* add inode in inmem_list first and set atomic_file */ >>>>>> set_inode_flag(inode, FI_ATOMIC_FILE); >>>>>> clear_inode_flag(inode, FI_ATOMIC_REVOKE_REQUEST); >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> up_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]); >>>>>> f2fs_update_time(F2FS_I_SB(inode), REQ_TIME); >>>>>> diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c >>>>>> index d8570b0359f5..dab870d9faf6 100644 >>>>>> --- a/fs/f2fs/segment.c >>>>>> +++ b/fs/f2fs/segment.c >>>>>> @@ -327,6 +327,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>>>> struct f2fs_sb_info *sbi = F2FS_I_SB(inode); >>>>>> struct f2fs_inode_info *fi = F2FS_I(inode); >>>>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> + >>>>>> while (!list_empty(&fi->inmem_pages)) { >>>>>> mutex_lock(&fi->inmem_lock); >>>>>> __revoke_inmem_pages(inode, &fi->inmem_pages, >>>>>> @@ -344,6 +346,8 @@ void f2fs_drop_inmem_pages(struct inode *inode) >>>>>> sbi->atomic_files--; >>>>>> } >>>>>> spin_unlock(&sbi->inode_lock[ATOMIC_FILE]); >>>>>> + >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> } >>>>>> void f2fs_drop_inmem_page(struct inode *inode, struct page *page) >>>>>> @@ -467,6 +471,7 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>>>> f2fs_balance_fs(sbi, true); >>>>>> down_write(&fi->i_gc_rwsem[WRITE]); >>>>>> + down_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> f2fs_lock_op(sbi); >>>>>> set_inode_flag(inode, FI_ATOMIC_COMMIT); >>>>>> @@ -478,6 +483,8 @@ int f2fs_commit_inmem_pages(struct inode *inode) >>>>>> clear_inode_flag(inode, FI_ATOMIC_COMMIT); >>>>>> f2fs_unlock_op(sbi); >>>>>> + >>>>>> + up_write(&F2FS_I(inode)->i_mmap_sem); >>>>>> up_write(&fi->i_gc_rwsem[WRITE]); >>>>>> return err; >>>>>> -- >>>>>> 2.29.2 >>>>> . >>>>> >>> . >>> > . > ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2021-01-29 1:39 UTC | newest] Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2020-12-30 7:55 [PATCH v2] f2fs: fix to keep isolation of atomic write Chao Yu 2021-01-06 22:28 ` Jaegeuk Kim 2021-01-06 22:57 ` [f2fs-dev] " Jaegeuk Kim 2021-01-11 16:32 ` Jaegeuk Kim 2021-01-12 2:59 ` Chao Yu 2021-01-12 22:32 ` Jaegeuk Kim 2021-01-13 1:30 ` Chao Yu 2021-01-14 21:53 ` Jaegeuk Kim 2021-01-15 7:59 ` Chao Yu 2021-01-19 19:06 ` Jaegeuk Kim 2021-01-20 1:18 ` Chao Yu 2021-01-28 16:21 ` Jaegeuk Kim 2021-01-29 1:38 ` Chao Yu
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).