Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

jbd: protect all log tail updates with j_checkpoint_mutex

There are some log tail updates that are not protected by j_checkpoint_mutex.
Some of these are harmless because they happen during startup or shutdown but
updates in journal_commit_transaction() and journal_flush() can really race
with other log tail updates (e.g. someone doing journal_flush() with someone
running cleanup_journal_tail()). So protect all log tail updates with
j_checkpoint_mutex.

Signed-off-by: Jan Kara <jack@suse.cz>

Jan Kara 1ce8486d 9754e39c

+17 -1
+2
fs/jbd/commit.c
··· 308 308 /* Do we need to erase the effects of a prior journal_flush? */ 309 309 if (journal->j_flags & JFS_FLUSHED) { 310 310 jbd_debug(3, "super block updated\n"); 311 + mutex_lock(&journal->j_checkpoint_mutex); 311 312 journal_update_sb_log_tail(journal); 313 + mutex_unlock(&journal->j_checkpoint_mutex); 312 314 } else { 313 315 jbd_debug(3, "superblock not updated\n"); 314 316 }
+15 -1
fs/jbd/journal.c
··· 936 936 journal->j_errno); 937 937 journal->j_flags |= JFS_FLUSHED; 938 938 } else { 939 + /* Lock here to make assertions happy... */ 940 + mutex_lock(&journal->j_checkpoint_mutex); 939 941 /* Add the dynamic fields and write it to disk. */ 940 942 journal_update_sb_log_tail(journal); 943 + mutex_unlock(&journal->j_checkpoint_mutex); 941 944 } 942 945 return journal_start_thread(journal); 943 946 } ··· 1064 1061 { 1065 1062 journal_superblock_t *sb = journal->j_superblock; 1066 1063 1064 + BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); 1067 1065 spin_lock(&journal->j_state_lock); 1068 1066 jbd_debug(1,"JBD: updating superblock (start %u, seq %d, errno %d)\n", 1069 1067 journal->j_tail, journal->j_tail_sequence, journal->j_errno); ··· 1093 1089 { 1094 1090 journal_superblock_t *sb = journal->j_superblock; 1095 1091 1092 + BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); 1096 1093 spin_lock(&journal->j_state_lock); 1097 1094 jbd_debug(1, "JBD: Marking journal as empty (seq %d)\n", 1098 1095 journal->j_tail_sequence); ··· 1298 1293 1299 1294 /* Force any old transactions to disk */ 1300 1295 1296 + /* We cannot race with anybody but must keep assertions happy */ 1297 + mutex_lock(&journal->j_checkpoint_mutex); 1301 1298 /* Totally anal locking here... */ 1302 1299 spin_lock(&journal->j_list_lock); 1303 1300 while (journal->j_checkpoint_transactions != NULL) { ··· 1322 1315 err = -EIO; 1323 1316 brelse(journal->j_sb_buffer); 1324 1317 } 1318 + mutex_unlock(&journal->j_checkpoint_mutex); 1325 1319 1326 1320 if (journal->j_inode) 1327 1321 iput(journal->j_inode); ··· 1536 1528 if (is_journal_aborted(journal)) 1537 1529 return -EIO; 1538 1530 1531 + mutex_lock(&journal->j_checkpoint_mutex); 1539 1532 cleanup_journal_tail(journal); 1540 1533 1541 1534 /* Finally, mark the journal as really needing no recovery. ··· 1545 1536 * commits of data to the journal will restore the current 1546 1537 * s_start value. */ 1547 1538 mark_journal_empty(journal); 1539 + mutex_unlock(&journal->j_checkpoint_mutex); 1548 1540 spin_lock(&journal->j_state_lock); 1549 1541 J_ASSERT(!journal->j_running_transaction); 1550 1542 J_ASSERT(!journal->j_committing_transaction); ··· 1586 1576 write ? "Clearing" : "Ignoring"); 1587 1577 1588 1578 err = journal_skip_recovery(journal); 1589 - if (write) 1579 + if (write) { 1580 + /* Lock to make assertions happy... */ 1581 + mutex_lock(&journal->j_checkpoint_mutex); 1590 1582 mark_journal_empty(journal); 1583 + mutex_unlock(&journal->j_checkpoint_mutex); 1584 + } 1591 1585 1592 1586 no_recovery: 1593 1587 return err;