• Zhihao Cheng's avatar
    ubifs: Check @c->dirty_[n|p]n_cnt and @c->nroot state under @c->lp_mutex · c07a4dab
    Zhihao Cheng authored
    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: 944fdef5 ("UBIFS: do not start the commit if there is nothing to commit")
    Link: https://bugzilla.kernel.org/show_bug.cgi?id=218162Signed-off-by: default avatarZhihao Cheng <chengzhihao1@huawei.com>
    Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
    c07a4dab
commit.c 20.3 KB