Commit c07a4da
The checking of @c->nroot->flags and @c->dirty_[n|p]n_cnt in function
nothing_to_commit() is not atomic, which could be raced with modifying
of lpt, for example:
P1 P2 P3
run_gc
ubifs_garbage_collect
do_commit
ubifs_return_leb
ubifs_lpt_lookup_dirty
dirty_cow_nnode
do_commit
nothing_to_commit
if (test_bit(DIRTY_CNODE, &c->nroot->flags)
// false
test_and_set_bit(DIRTY_CNODE, &nnode->flags)
c->dirty_nn_cnt += 1
ubifs_assert(c, c->dirty_nn_cnt == 0)
// false !
Fetch a reproducer in Link:
UBIFS error (ubi0:0 pid 2747): ubifs_assert_failed
UBIFS assert failed: c->dirty_pn_cnt == 0, in fs/ubifs/commit.c
Call Trace:
ubifs_ro_mode+0x58/0x70 [ubifs]
ubifs_assert_failed+0x6a/0x90 [ubifs]
do_commit+0x5b7/0x930 [ubifs]
ubifs_run_commit+0xc6/0x1a0 [ubifs]
ubifs_sync_fs+0xd8/0x110 [ubifs]
sync_filesystem+0xb4/0x120
do_syscall_64+0x6f/0x140
Fix it by checking @c->dirty_[n|p]n_cnt and @c->nroot state with
@c->lp_mutex locked.
Fixes: 944fdef ("UBIFS: do not start the commit if there is nothing to commit")
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218162
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
1 parent 2ba5b48 commit c07a4da
1 file changed
Lines changed: 12 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
72 | 80 | | |
73 | 81 | | |
74 | 82 | | |
75 | 83 | | |
76 | 84 | | |
77 | 85 | | |
78 | 86 | | |
79 | | - | |
| 87 | + | |
| 88 | + | |
80 | 89 | | |
| 90 | + | |
81 | 91 | | |
82 | 92 | | |
83 | 93 | | |
84 | 94 | | |
| 95 | + | |
85 | 96 | | |
86 | 97 | | |
87 | 98 | | |
| |||
0 commit comments