• J
    jbd2: fix assertion failure in jbd2_journal_flush() · d7961c7f
    Jan Kara 提交于
    The following race is possible between start_this_handle() and someone
    calling jbd2_journal_flush().
    
    Process A                              Process B
    start_this_handle().
      if (journal->j_barrier_count) # false
      if (!journal->j_running_transaction) { #true
        read_unlock(&journal->j_state_lock);
                                           jbd2_journal_lock_updates()
                                           jbd2_journal_flush()
                                             write_lock(&journal->j_state_lock);
                                             if (journal->j_running_transaction) {
                                               # false
                                             ... wait for committing trans ...
                                             write_unlock(&journal->j_state_lock);
        ...
        write_lock(&journal->j_state_lock);
        if (!journal->j_running_transaction) { # true
          jbd2_get_transaction(journal, new_transaction);
        write_unlock(&journal->j_state_lock);
        goto repeat; # eventually blocks on j_barrier_count > 0
                                             ...
                                             J_ASSERT(!journal->j_running_transaction);
                                               # fails
    
    We fix the race by rechecking j_barrier_count after reacquiring j_state_lock
    in exclusive mode.
    
    Reported-by: yjwsignal@empal.com
    Signed-off-by: NJan Kara <jack@suse.cz>
    Signed-off-by: N"Theodore Ts'o" <tytso@mit.edu>
    Cc: stable@vger.kernel.org
    d7961c7f
transaction.c 69.6 KB