ubifs: ubifs_writepage: Mark page dirty after writing inode failed
[ Upstream commit fb8bc4c74ae4526d9489362ab2793a936d072b84 ] There are two states for ubifs writing pages: 1. Dirty, Private 2. Not Dirty, Not Private There is a third possibility which maybe related to [1] that page is private but not dirty caused by following process: PA lock(page) ubifs_write_end attach_page_private // set Private __set_page_dirty_nobuffers // set Dirty unlock(page) write_cache_pages lock(page) clear_page_dirty_for_io(page) // clear Dirty ubifs_writepage write_inode // fail, goto out, following codes are not executed // do_writepage // set_page_writeback // set Writeback // detach_page_private // clear Private // end_page_writeback // clear Writeback out: unlock(page) // Private, Not Dirty PB ksys_fadvise64_64 generic_fadvise invalidate_inode_page // page is neither Dirty nor Writeback invalidate_complete_page // page_has_private is true try_to_release_page ubifs_releasepage ubifs_assert(c, 0) !!! Then we may get following assertion failed: UBIFS error (ubi0:0 pid 1492): ubifs_assert_failed [ubifs]: UBIFS assert failed: 0, in fs/ubifs/file.c:1499 UBIFS warning (ubi0:0 pid 1492): ubifs_ro_mode [ubifs]: switched to read-only mode, error -22 CPU: 2 PID: 1492 Comm: aa Not tainted 5.16.0-rc2-00012-g7bb767dee0ba-dirty Call Trace: dump_stack+0x13/0x1b ubifs_ro_mode+0x54/0x60 [ubifs] ubifs_assert_failed+0x4b/0x80 [ubifs] ubifs_releasepage+0x7e/0x1e0 [ubifs] try_to_release_page+0x57/0xe0 invalidate_inode_page+0xfb/0x130 invalidate_mapping_pagevec+0x12/0x20 generic_fadvise+0x303/0x3c0 vfs_fadvise+0x35/0x40 ksys_fadvise64_64+0x4c/0xb0 Jump [2] to find a reproducer. [1] https://linux-mtd.infradead.narkive.com/NQoBeT1u/patch-rfc-ubifs-fix-assert-failed-in-ubifs-set-page-dirty [2] https://bugzilla.kernel.org/show_bug.cgi?id=215357 Fixes: 1e51764a3c2ac0 ("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
10b6c359e3
commit
79db0e8323
@ -1031,7 +1031,7 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
if (page->index >= synced_i_size >> PAGE_SHIFT) {
|
||||
err = inode->i_sb->s_op->write_inode(inode, NULL);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
goto out_redirty;
|
||||
/*
|
||||
* The inode has been written, but the write-buffer has
|
||||
* not been synchronized, so in case of an unclean
|
||||
@ -1059,11 +1059,17 @@ static int ubifs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
if (i_size > synced_i_size) {
|
||||
err = inode->i_sb->s_op->write_inode(inode, NULL);
|
||||
if (err)
|
||||
goto out_unlock;
|
||||
goto out_redirty;
|
||||
}
|
||||
|
||||
return do_writepage(page, len);
|
||||
|
||||
out_redirty:
|
||||
/*
|
||||
* redirty_page_for_writepage() won't call ubifs_dirty_inode() because
|
||||
* it passes I_DIRTY_PAGES flag while calling __mark_inode_dirty(), so
|
||||
* there is no need to do space budget for dirty inode.
|
||||
*/
|
||||
redirty_page_for_writepage(wbc, page);
|
||||
out_unlock:
|
||||
unlock_page(page);
|
||||
return err;
|
||||
|
Loading…
x
Reference in New Issue
Block a user