mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-28 22:54:05 +08:00
jbd2: cleanup journal tail after transaction commit
Normally, we have to issue a cache flush before we can update journal tail in journal superblock, effectively wiping out old transactions from the journal. So use the fact that during transaction commit we issue cache flush anyway and opportunistically push journal tail as far as we can. Since update of journal superblock is still costly (we have to use WRITE_FUA), we update log tail only if we can free significant amount of space. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
932bb305ba
commit
3339578f05
@ -331,6 +331,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)
|
|||||||
struct buffer_head *cbh = NULL; /* For transactional checksums */
|
struct buffer_head *cbh = NULL; /* For transactional checksums */
|
||||||
__u32 crc32_sum = ~0;
|
__u32 crc32_sum = ~0;
|
||||||
struct blk_plug plug;
|
struct blk_plug plug;
|
||||||
|
/* Tail of the journal */
|
||||||
|
unsigned long first_block;
|
||||||
|
tid_t first_tid;
|
||||||
|
int update_tail;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First job: lock down the current transaction and wait for
|
* First job: lock down the current transaction and wait for
|
||||||
@ -688,10 +692,30 @@ start_journal_io:
|
|||||||
err = 0;
|
err = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get current oldest transaction in the log before we issue flush
|
||||||
|
* to the filesystem device. After the flush we can be sure that
|
||||||
|
* blocks of all older transactions are checkpointed to persistent
|
||||||
|
* storage and we will be safe to update journal start in the
|
||||||
|
* superblock with the numbers we get here.
|
||||||
|
*/
|
||||||
|
update_tail =
|
||||||
|
jbd2_journal_get_log_tail(journal, &first_tid, &first_block);
|
||||||
|
|
||||||
write_lock(&journal->j_state_lock);
|
write_lock(&journal->j_state_lock);
|
||||||
|
if (update_tail) {
|
||||||
|
long freed = first_block - journal->j_tail;
|
||||||
|
|
||||||
|
if (first_block < journal->j_tail)
|
||||||
|
freed += journal->j_last - journal->j_first;
|
||||||
|
/* Update tail only if we free significant amount of space */
|
||||||
|
if (freed < journal->j_maxlen / 4)
|
||||||
|
update_tail = 0;
|
||||||
|
}
|
||||||
J_ASSERT(commit_transaction->t_state == T_COMMIT);
|
J_ASSERT(commit_transaction->t_state == T_COMMIT);
|
||||||
commit_transaction->t_state = T_COMMIT_DFLUSH;
|
commit_transaction->t_state = T_COMMIT_DFLUSH;
|
||||||
write_unlock(&journal->j_state_lock);
|
write_unlock(&journal->j_state_lock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the journal is not located on the file system device,
|
* If the journal is not located on the file system device,
|
||||||
* then we must flush the file system device before we issue
|
* then we must flush the file system device before we issue
|
||||||
@ -842,6 +866,14 @@ wait_for_iobuf:
|
|||||||
if (err)
|
if (err)
|
||||||
jbd2_journal_abort(journal, err);
|
jbd2_journal_abort(journal, err);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now disk caches for filesystem device are flushed so we are safe to
|
||||||
|
* erase checkpointed transactions from the log by updating journal
|
||||||
|
* superblock.
|
||||||
|
*/
|
||||||
|
if (update_tail)
|
||||||
|
jbd2_update_log_tail(journal, first_tid, first_block);
|
||||||
|
|
||||||
/* End of a transaction! Finally, we can do checkpoint
|
/* End of a transaction! Finally, we can do checkpoint
|
||||||
processing: any buffers committed as a result of this
|
processing: any buffers committed as a result of this
|
||||||
transaction can be removed from any checkpoint list it was on
|
transaction can be removed from any checkpoint list it was on
|
||||||
|
@ -821,6 +821,19 @@ void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
|
|||||||
write_unlock(&journal->j_state_lock);
|
write_unlock(&journal->j_state_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is a variaon of __jbd2_update_log_tail which checks for validity of
|
||||||
|
* provided log tail and locks j_checkpoint_mutex. So it is safe against races
|
||||||
|
* with other threads updating log tail.
|
||||||
|
*/
|
||||||
|
void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block)
|
||||||
|
{
|
||||||
|
mutex_lock(&journal->j_checkpoint_mutex);
|
||||||
|
if (tid_gt(tid, journal->j_tail_sequence))
|
||||||
|
__jbd2_update_log_tail(journal, tid, block);
|
||||||
|
mutex_unlock(&journal->j_checkpoint_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
struct jbd2_stats_proc_session {
|
struct jbd2_stats_proc_session {
|
||||||
journal_t *journal;
|
journal_t *journal;
|
||||||
struct transaction_stats_s *stats;
|
struct transaction_stats_s *stats;
|
||||||
|
@ -974,6 +974,7 @@ int jbd2_journal_next_log_block(journal_t *, unsigned long long *);
|
|||||||
int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid,
|
int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid,
|
||||||
unsigned long *block);
|
unsigned long *block);
|
||||||
void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
|
void __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
|
||||||
|
void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block);
|
||||||
|
|
||||||
/* Commit management */
|
/* Commit management */
|
||||||
extern void jbd2_journal_commit_transaction(journal_t *);
|
extern void jbd2_journal_commit_transaction(journal_t *);
|
||||||
|
Loading…
Reference in New Issue
Block a user