All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] jbd journal_dirty_data re-check for unmapped buffers
@ 2006-10-16 18:24 Eric Sandeen
  0 siblings, 0 replies; only message in thread
From: Eric Sandeen @ 2006-10-16 18:24 UTC (permalink / raw)
  To: Linux Kernel Mailing List, ext4 development

When running several fsx's and other filesystem stress tests, we found 
cases where an unmapped buffer was still being sent to submit_bh by the 
ext3 dirty data journaling code.

I saw this happen in two ways, both related to another thread doing a 
truncate which would unmap the buffer in question.

Either we would get into journal_dirty_data with a bh which was already 
unmapped (although journal_dirty_data_fn had checked for this earlier, 
the state was not locked at that point), or it would get unmapped in 
the middle of journal_dirty_data when we dropped locks to call 
sync_dirty_buffer.

By re-checking for mapped state after we've acquired the bh state lock, 
we should avoid these races.  If we find a buffer which is no longer 
mapped, we essentially ignore it, because journal_unmap_buffer has 
already decided that this buffer can go away.

I've also added tracepoints in these two cases, and made a couple other 
tracepoint changes that I found useful in debugging this.

Thanks,
-Eric

Signed-off-by: Eric Sandeen <esandeen@redhat.com>


Index: linux-2.6.18/fs/jbd/transaction.c
===================================================================
--- linux-2.6.18.orig/fs/jbd/transaction.c
+++ linux-2.6.18/fs/jbd/transaction.c
@@ -967,6 +967,13 @@ int journal_dirty_data(handle_t *handle,
 	 */
 	jbd_lock_bh_state(bh);
 	spin_lock(&journal->j_list_lock);
+
+	/* Now that we have bh_state locked, are we really still mapped? */
+	if (!buffer_mapped(bh)) {
+		JBUFFER_TRACE(jh, "unmapped buffer, bailing out");
+		goto no_journal;
+	}
+
 	if (jh->b_transaction) {
 		JBUFFER_TRACE(jh, "has transaction");
 		if (jh->b_transaction != handle->h_transaction) {
@@ -1028,6 +1035,11 @@ int journal_dirty_data(handle_t *handle,
 				sync_dirty_buffer(bh);
 				jbd_lock_bh_state(bh);
 				spin_lock(&journal->j_list_lock);
+				/* Since we dropped the lock... */
+				if (!buffer_mapped(bh)) {
+					JBUFFER_TRACE(jh, "buffer got unmapped");
+					goto no_journal;
+				}
 				/* The buffer may become locked again at any
 				   time if it is redirtied */
 			}
@@ -1823,6 +1835,7 @@ static int journal_unmap_buffer(journal_
 			}
 		}
 	} else if (transaction == journal->j_committing_transaction) {
+		JBUFFER_TRACE(jh, "on committing transaction");
 		if (jh->b_jlist == BJ_Locked) {
 			/*
 			 * The buffer is on the committing transaction's locked
@@ -1837,7 +1850,6 @@ static int journal_unmap_buffer(journal_
 		 * can remove it's next_transaction pointer from the
 		 * running transaction if that is set, but nothing
 		 * else. */
-		JBUFFER_TRACE(jh, "on committing transaction");
 		set_buffer_freed(bh);
 		if (jh->b_next_transaction) {
 			J_ASSERT(jh->b_next_transaction ==
@@ -1857,6 +1869,7 @@ static int journal_unmap_buffer(journal_
 		 * i_size already for this truncate so recovery will not
 		 * expose the disk blocks we are discarding here.) */
 		J_ASSERT_JH(jh, transaction == journal->j_running_transaction);
+		JBUFFER_TRACE(jh, "on running transaction");
 		may_free = __dispose_buffer(jh, transaction);
 	}
 

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2006-10-16 18:24 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-10-16 18:24 [PATCH] jbd journal_dirty_data re-check for unmapped buffers Eric Sandeen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.