[Ocfs2-commits] rev 769 - in trunk: . src

svn-commits at oss.oracle.com svn-commits at oss.oracle.com
Wed Mar 10 12:26:10 CST 2004


Author: mfasheh
Date: 2004-03-10 12:26:08 -0600 (Wed, 10 Mar 2004)
New Revision: 769

Modified:
   trunk/TODO
   trunk/src/journal.c
Log:
* Knock a long standing item off the TODO list. This fixes a potential
  corruption due to improper cleanup of buffers before an
  abort_trans. Below is the comment from ocfs_abort_trans which explains
  the fixed bug.

/* There is a potential bug here which we may have to
 * resolve. What if you do a get_write_access on a buffer,
 * modify it, but error out before you've passed it to
 * dirty_metadata? We currently have to way to get to these
 * (unless we start tracking them much like dirty buffers). In
 * the worst case, the buffer could potentially hang around
 * the system and be picked up by another call and used as
 * though it were clean, even though it contains aborted
 * data!*/



Modified: trunk/TODO
===================================================================
--- trunk/TODO	2004-03-09 22:50:13 UTC (rev 768)
+++ trunk/TODO	2004-03-10 18:26:08 UTC (rev 769)
@@ -9,10 +9,6 @@
 * Move the journal file entry over to the next system slot which is unused.
   This should make downgrading back to ocfs version 1 easier.
 
-* Provide a solution for the potential problem with journal_access buffers
-  who haven't been journal_dirtied in abort_trans. Check out the comment in
-  abort_trans for more info on this.
-
 * fsck must be able to replay the journal
 
 * provide an ocfsmigrate utility to migrate v1 -> v2 and back.

Modified: trunk/src/journal.c
===================================================================
--- trunk/src/journal.c	2004-03-09 22:50:13 UTC (rev 768)
+++ trunk/src/journal.c	2004-03-10 18:26:08 UTC (rev 769)
@@ -451,41 +451,52 @@
 	int j;
 	ocfs_journal_copyout *co = NULL;
 	char *data;
+	bool dirtied;
 
 	LOG_ENTRY();
 
 	osb = handle->osb;
 	journal = &osb->journal;
 
-	/* There is a potential bug here which we may have to
-	 * resolve. What if you do a get_write_access on a buffer,
-	 * modify it, but error out before you've passed it to
-	 * dirty_metadata? We currently have to way to get to these
-	 * (unless we start tracking them much like dirty buffers). In
-	 * the worst case, the buffer could potentially hang around
-	 * the system and be picked up by another call and used as
-	 * though it were clean, even though it contains aborted
-	 * data!*/
+	if (handle->num_co < handle->num_buffs)
+		BUG();
 
-	/* Ok, we're aborting. For all dirtied buffers, copy our old
-	 * data back in. This should reverse what happened during the
-	 * transaction and revert us back.*/
-	for(i = 0; i < handle->num_buffs; i++) {
-		bh = handle->buffs[i];
-		
-		/* find the copyout. */
-		co = NULL;
-		for(j = 0; j < handle->num_co; j++)
-			if (handle->co_buffs[j].blocknr == bh->b_blocknr) {
-				co = &(handle->co_buffs[j]);
+	/* Ok, we're aborting. For all buffers I've seen, we want to
+	 * either forget it, or copy our old data back in. This should
+	 * revert what happened during the transaction.*/
+	for(i = 0; i < handle->num_co; i++) {
+		co = &(handle->co_buffs[i]);
+
+		/* Ok, search the dirtied buffers list for this
+		 * block. */
+		bh = NULL;
+		dirtied = true;
+		for(j = 0; j < handle->num_buffs; j++)
+			if (handle->buffs[j]->b_blocknr == co->blocknr) {
+				bh = handle->buffs[j];
 				break;
 			}
 
-		if (co == NULL)
-			BUG();
+		/* If we didn't have it then it was passed to
+		 * journal_access but never dirtied. We still have to
+		 * process it though as our abort paths may have left
+		 * the buffer with data that needs to be aborted */
+		if (!bh) {
+			/* log_trace_args for tracing, can safely be
+			 * turned off later. */
+			LOG_ERROR_ARGS("block %lu was modified but never "
+				       "dirtied!\n", co->blocknr);
+			bh = getblk(OCFS_GET_BLOCKDEV(osb->sb), co->blocknr,
+				    osb->sect_size);
+			if (bh == NULL)
+				BUG();
 
+			dirtied = false;
+		}
+
 		LOG_TRACE_ARGS("Aborting block %lu, forget=%u\n", co->blocknr,
 			       co->forget);
+
 		data = OCFS_BH_GET_DATA_WRITE(bh);
 		if (co->forget) {
 			/* journal_forget will perform a brelse for us */
@@ -497,6 +508,11 @@
 	                 * old. */
 			CLEAR_BH_SEQNUM(bh);
 
+			if (buffer_jbd(bh))
+				LOG_ERROR_ARGS("Buffer %lu has JBD bit set "
+					       "after a journal_forget!\n",
+					       bh->b_blocknr);
+
 			lock_buffer(bh);
 			clear_buffer_uptodate(bh);
 			clear_buffer_dirty(bh);
@@ -505,6 +521,12 @@
 			memcpy(data, co->data, bh->b_size);
 		}
 		OCFS_BH_PUT_DATA(bh);
+
+		/* we no longer need the buffer in this case. */
+		if (!dirtied) {
+			ocfs_clear_buffer_modified(bh);
+			brelse(bh);
+		}
 	}
 
 	/* done copying them, free it now. */
@@ -611,7 +633,7 @@
 	 * handle. 
 	 *
 	 * Note that we want to make a copy of the buffer on the 1st access
-	 * call as that when we know for sure it's clean. */
+	 * call as that's when we know for sure it's clean. */
 	for(i = 0; i < handle->num_co; i++)
 		if (handle->co_buffs[i].blocknr == bh->b_blocknr) {
 			found = true;



More information about the Ocfs2-commits mailing list