ubifs: Re-statistic cleaned znode count if commit failed
Dirty znodes will be written on flash in committing process with following states: process A | znode state ------------------------------------------------------ do_commit | DIRTY_ZNODE ubifs_tnc_start_commit | DIRTY_ZNODE get_znodes_to_commit | DIRTY_ZNODE | COW_ZNODE layout_commit | DIRTY_ZNODE | COW_ZNODE fill_gap | 0 write master | 0 or OBSOLETE_ZNODE process B | znode state ------------------------------------------------------ do_commit | DIRTY_ZNODE[1] ubifs_tnc_start_commit | DIRTY_ZNODE get_znodes_to_commit | DIRTY_ZNODE | COW_ZNODE ubifs_tnc_end_commit | DIRTY_ZNODE | COW_ZNODE write_index | 0 write master | 0 or OBSOLETE_ZNODE[2] or | DIRTY_ZNODE[3] [1] znode is dirtied without concurrent committing process [2] znode is copied up (re-dirtied by other process) before cleaned up in committing process [3] znode is re-dirtied after cleaned up in committing process Currently, the clean znode count is updated in free_obsolete_znodes(), which is called only in normal path. If do_commit failed, clean znode count won't be updated, which triggers a failure ubifs assertion[4] in ubifs_tnc_close(): ubifs_assert_failed [ubifs]: UBIFS assert failed: freed == n [4] Commit380347e9ca
("UBIFS: Add an assertion for clean_zn_cnt"). Fix it by re-statisticing cleaned znode count in tnc_destroy_cnext(). Fetch a reproducer in [Link]. Link: https://bugzilla.kernel.org/show_bug.cgi?id=216704 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:
Родитель
2de203d8ab
Коммит
944e096aa2
|
@ -3053,6 +3053,21 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
|
|||
cnext = cnext->cnext;
|
||||
if (ubifs_zn_obsolete(znode))
|
||||
kfree(znode);
|
||||
else if (!ubifs_zn_cow(znode)) {
|
||||
/*
|
||||
* Don't forget to update clean znode count after
|
||||
* committing failed, because ubifs will check this
|
||||
* count while closing tnc. Non-obsolete znode could
|
||||
* be re-dirtied during committing process, so dirty
|
||||
* flag is untrustable. The flag 'COW_ZNODE' is set
|
||||
* for each dirty znode before committing, and it is
|
||||
* cleared as long as the znode become clean, so we
|
||||
* can statistic clean znode count according to this
|
||||
* flag.
|
||||
*/
|
||||
atomic_long_inc(&c->clean_zn_cnt);
|
||||
atomic_long_inc(&ubifs_clean_zn_cnt);
|
||||
}
|
||||
} while (cnext && cnext != c->cnext);
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче