diff options
Diffstat (limited to 'fs/jbd2/commit.c')
| -rw-r--r-- | fs/jbd2/commit.c | 38 | 
1 files changed, 22 insertions, 16 deletions
| diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c index d4cfd6d2779..671da7fb7ff 100644 --- a/fs/jbd2/commit.c +++ b/fs/jbd2/commit.c @@ -259,6 +259,7 @@ static int journal_submit_data_buffers(journal_t *journal,  			ret = err;  		spin_lock(&journal->j_list_lock);  		J_ASSERT(jinode->i_transaction == commit_transaction); +		commit_transaction->t_flushed_data_blocks = 1;  		jinode->i_flags &= ~JI_COMMIT_RUNNING;  		wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING);  	} @@ -286,7 +287,7 @@ static int journal_finish_inode_data_buffers(journal_t *journal,  		if (err) {  			/*  			 * Because AS_EIO is cleared by -			 * wait_on_page_writeback_range(), set it again so +			 * filemap_fdatawait_range(), set it again so  			 * that user process can get -EIO from fsync().  			 */  			set_bit(AS_EIO, @@ -636,6 +637,10 @@ void jbd2_journal_commit_transaction(journal_t *journal)  		JBUFFER_TRACE(jh, "ph3: write metadata");  		flags = jbd2_journal_write_metadata_buffer(commit_transaction,  						      jh, &new_jh, blocknr); +		if (flags < 0) { +			jbd2_journal_abort(journal, flags); +			continue; +		}  		set_bit(BH_JWrite, &jh2bh(new_jh)->b_state);  		wbuf[bufs++] = jh2bh(new_jh); @@ -704,8 +709,17 @@ start_journal_io:  		}  	} -	/* Done it all: now write the commit record asynchronously. */ +	/*  +	 * If the journal is not located on the file system device, +	 * then we must flush the file system device before we issue +	 * the commit record +	 */ +	if (commit_transaction->t_flushed_data_blocks && +	    (journal->j_fs_dev != journal->j_dev) && +	    (journal->j_flags & JBD2_BARRIER)) +		blkdev_issue_flush(journal->j_fs_dev, NULL); +	/* Done it all: now write the commit record asynchronously. */  	if (JBD2_HAS_INCOMPAT_FEATURE(journal,  				      JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)) {  		err = journal_submit_commit_record(journal, commit_transaction, @@ -716,13 +730,6 @@ start_journal_io:  			blkdev_issue_flush(journal->j_dev, NULL);  	} -	/* -	 * This is the right place to wait for data buffers both for ASYNC -	 * and !ASYNC commit. If commit is ASYNC, we need to wait only after -	 * the commit block went to disk (which happens above). If commit is -	 * SYNC, we need to wait for data buffers before we start writing -	 * commit block, which happens below in such setting. -	 */  	err = journal_finish_inode_data_buffers(journal, commit_transaction);  	if (err) {  		printk(KERN_WARNING @@ -876,8 +883,7 @@ restart_loop:  		spin_unlock(&journal->j_list_lock);  		bh = jh2bh(jh);  		jbd_lock_bh_state(bh); -		J_ASSERT_JH(jh,	jh->b_transaction == commit_transaction || -			jh->b_transaction == journal->j_running_transaction); +		J_ASSERT_JH(jh,	jh->b_transaction == commit_transaction);  		/*  		 * If there is undo-protected committed data against @@ -923,12 +929,12 @@ restart_loop:  		/* A buffer which has been freed while still being  		 * journaled by a previous transaction may end up still  		 * being dirty here, but we want to avoid writing back -		 * that buffer in the future now that the last use has -		 * been committed.  That's not only a performance gain, -		 * it also stops aliasing problems if the buffer is left -		 * behind for writeback and gets reallocated for another +		 * that buffer in the future after the "add to orphan" +		 * operation been committed,  That's not only a performance +		 * gain, it also stops aliasing problems if the buffer is +		 * left behind for writeback and gets reallocated for another  		 * use in a different page. */ -		if (buffer_freed(bh)) { +		if (buffer_freed(bh) && !jh->b_next_transaction) {  			clear_buffer_freed(bh);  			clear_buffer_jbddirty(bh);  		} | 
