mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-27 12:57:53 +00:00
ubifs: ubifs_releasepage: Remove ubifs_assert(0) to valid this process
[ Upstream commit66f4742e93
] There are two states for ubifs writing pages: 1. Dirty, Private 2. Not Dirty, Not Private The normal process cannot go to ubifs_releasepage() which means there exists pages being private but not dirty. Reproducer[1] shows that it could occur (which maybe related to [2]) with following process: PA PB PC lock(page)[PA] ubifs_write_end attach_page_private // set Private __set_page_dirty_nobuffers // set Dirty unlock(page) write_cache_pages[PA] lock(page) clear_page_dirty_for_io(page) // clear Dirty ubifs_writepage do_truncation[PB] truncate_setsize i_size_write(inode, newsize) // newsize = 0 i_size = i_size_read(inode) // i_size = 0 end_index = i_size >> PAGE_SHIFT if (page->index > end_index) goto out // jump out: unlock(page) // Private, Not Dirty generic_fadvise[PC] lock(page) invalidate_inode_page try_to_release_page ubifs_releasepage ubifs_assert(c, 0) // bad assertion! unlock(page) truncate_pagecache[PB] Then we may get following assertion failed: UBIFS error (ubi0:0 pid 1683): ubifs_assert_failed [ubifs]: UBIFS assert failed: 0, in fs/ubifs/file.c:1513 UBIFS warning (ubi0:0 pid 1683): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 CPU: 2 PID: 1683 Comm: aa Not tainted 5.16.0-rc5-00184-g0bca5994cacc-dirty #308 Call Trace: dump_stack+0x13/0x1b ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_releasepage+0x67/0x1d0 [ubifs] try_to_release_page+0x57/0xe0 invalidate_inode_page+0xfb/0x130 __invalidate_mapping_pages+0xb9/0x280 invalidate_mapping_pagevec+0x12/0x20 generic_fadvise+0x303/0x3c0 ksys_fadvise64_64+0x4c/0xb0 [1] https://bugzilla.kernel.org/show_bug.cgi?id=215373 [2] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty Fixes:1e51764a3c
("UBIFS: add new flash file system") Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> Signed-off-by: Richard Weinberger <richard@nod.at> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
1d7d02e9cb
commit
bd188ff1c8
1 changed files with 14 additions and 5 deletions
|
@ -1472,14 +1472,23 @@ static bool ubifs_release_folio(struct folio *folio, gfp_t unused_gfp_flags)
|
|||
struct inode *inode = folio->mapping->host;
|
||||
struct ubifs_info *c = inode->i_sb->s_fs_info;
|
||||
|
||||
/*
|
||||
* An attempt to release a dirty page without budgeting for it - should
|
||||
* not happen.
|
||||
*/
|
||||
if (folio_test_writeback(folio))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Page is private but not dirty, weird? There is one condition
|
||||
* making it happened. ubifs_writepage skipped the page because
|
||||
* page index beyonds isize (for example. truncated by other
|
||||
* process named A), then the page is invalidated by fadvise64
|
||||
* syscall before being truncated by process A.
|
||||
*/
|
||||
ubifs_assert(c, folio_test_private(folio));
|
||||
ubifs_assert(c, 0);
|
||||
if (folio_test_checked(folio))
|
||||
release_new_page_budget(c);
|
||||
else
|
||||
release_existing_page_budget(c);
|
||||
|
||||
atomic_long_dec(&c->dirty_pg_cnt);
|
||||
folio_detach_private(folio);
|
||||
folio_clear_checked(folio);
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue