Skip to content

Commit d9b0193

Browse files
tytsojankara
authored andcommitted
jbd: fix fsync() tid wraparound bug
If an application program does not make any changes to the indirect blocks or extent tree, i_datasync_tid will not get updated. If there are enough commits (i.e., 2**31) such that tid_geq()'s calculations wrap, and there isn't a currently active transaction at the time of the fdatasync() call, this can end up triggering a BUG_ON in fs/jbd/commit.c: J_ASSERT(journal->j_running_transaction != NULL); It's pretty rare that this can happen, since it requires the use of fdatasync() plus *very* frequent and excessive use of fsync(). But with the right workload, it can. We fix this by replacing the use of tid_geq() with an equality test, since there's only one valid transaction id that is valid for us to start: namely, the currently running transaction (if it exists). CC: [email protected] Reported-by: [email protected] Signed-off-by: "Theodore Ts'o" <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent 86c4f6d commit d9b0193

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

fs/jbd/journal.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -437,9 +437,12 @@ int __log_space_left(journal_t *journal)
437437
int __log_start_commit(journal_t *journal, tid_t target)
438438
{
439439
/*
440-
* Are we already doing a recent enough commit?
440+
* The only transaction we can possibly wait upon is the
441+
* currently running transaction (if it exists). Otherwise,
442+
* the target tid must be an old one.
441443
*/
442-
if (!tid_geq(journal->j_commit_request, target)) {
444+
if (journal->j_running_transaction &&
445+
journal->j_running_transaction->t_tid == target) {
443446
/*
444447
* We want a new commit: OK, mark the request and wakeup the
445448
* commit thread. We do _not_ do the commit ourselves.
@@ -451,7 +454,14 @@ int __log_start_commit(journal_t *journal, tid_t target)
451454
journal->j_commit_sequence);
452455
wake_up(&journal->j_wait_commit);
453456
return 1;
454-
}
457+
} else if (!tid_geq(journal->j_commit_request, target))
458+
/* This should never happen, but if it does, preserve
459+
the evidence before kjournald goes into a loop and
460+
increments j_commit_sequence beyond all recognition. */
461+
WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n",
462+
journal->j_commit_request, journal->j_commit_sequence,
463+
target, journal->j_running_transaction ?
464+
journal->j_running_transaction->t_tid : 0);
455465
return 0;
456466
}
457467

0 commit comments

Comments
 (0)