diff options
Diffstat (limited to 'fs/jbd2/commit.c')
| -rw-r--r-- | fs/jbd2/commit.c | 47 | 
1 files changed, 45 insertions, 2 deletions
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index c067a8cae63b..17f557f01cf0 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -331,6 +331,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)  	struct buffer_head *cbh = NULL; /* For transactional checksums */  	__u32 crc32_sum = ~0;  	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 @@ -340,7 +344,18 @@ void jbd2_journal_commit_transaction(journal_t *journal)  	/* Do we need to erase the effects of a prior jbd2_journal_flush? */  	if (journal->j_flags & JBD2_FLUSHED) {  		jbd_debug(3, "super block updated\n"); -		jbd2_journal_update_superblock(journal, 1); +		mutex_lock(&journal->j_checkpoint_mutex); +		/* +		 * We hold j_checkpoint_mutex so tail cannot change under us. +		 * We don't need any special data guarantees for writing sb +		 * since journal is empty and it is ok for write to be +		 * flushed only with transaction commit. +		 */ +		jbd2_journal_update_sb_log_tail(journal, +						journal->j_tail_sequence, +						journal->j_tail, +						WRITE_SYNC); +		mutex_unlock(&journal->j_checkpoint_mutex);  	} else {  		jbd_debug(3, "superblock not updated\n");  	} @@ -677,10 +692,30 @@ start_journal_io:  		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); +	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);  	commit_transaction->t_state = T_COMMIT_DFLUSH;  	write_unlock(&journal->j_state_lock); +  	/*   	 * If the journal is not located on the file system device,  	 * then we must flush the file system device before we issue @@ -831,6 +866,14 @@ wait_for_iobuf:  	if (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             processing: any buffers committed as a result of this             transaction can be removed from any checkpoint list it was on @@ -1048,7 +1091,7 @@ restart_loop:  	jbd_debug(1, "JBD2: commit %d complete, head %d\n",  		  journal->j_commit_sequence, journal->j_tail_sequence);  	if (to_free) -		kfree(commit_transaction); +		jbd2_journal_free_transaction(commit_transaction);  	wake_up(&journal->j_wait_done_commit);  }  | 
