ubifs: ubifs_writepage: Mark page dirty after writing inode failed
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: 1e51764a3c
("UBIFS: add new flash file system")
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
This commit is contained in:
parent
122deabfe1
commit
fb8bc4c74a
|
@ -1032,7 +1032,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
|
||||
|
@ -1060,11 +1060,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…
Reference in New Issue