shithub: lwext4

Download patch

ref: 398c113aca07017680740caa93a236edcba91f3e
parent: 2ad6d9ab9645eb672607e2ddf655d885d1be914b
author: ngkaho1234 <ngkaho1234@gmail.com>
date: Sat Dec 19 13:40:37 EST 2015

ext4_journal: code logic changes on jbd_trans_add_block.

Now jbd_trans_add_block should be called before making any
modications on the buffer.

--- a/lwext4/ext4.c
+++ b/lwext4/ext4.c
@@ -2551,8 +2551,6 @@
 			if (r != EOK)
 				goto out;
 
-			ext4_bcache_set_dirty(block.buf);
-
 			struct jbd_trans *t = jbd_journal_new_trans(journal);
 			if (!t) {
 				ext4_block_set(mp->fs.bdev, &block);
@@ -2570,6 +2568,7 @@
 					r = ENOMEM;
 					goto out;
 				}
+				ext4_bcache_set_dirty(block.buf);
 				break;
 			case 1:
 				r = jbd_trans_revoke_block(t, rand_block);
--- a/lwext4/ext4_journal.c
+++ b/lwext4/ext4_journal.c
@@ -1049,7 +1049,8 @@
 			  int res,
 			  void *arg);
 
-/**@brief  Add block to a transaction
+/**@brief  Add block to a transaction and gain
+ *         access to it before making any modications.
  * @param  trans transaction
  * @param  block block descriptor
  * @return standard error code*/
@@ -1057,11 +1058,17 @@
 			struct ext4_block *block)
 {
 	struct jbd_buf *buf;
-	/* We do not need to add those unmodified buffer to
-	 * a transaction. */
-	if (!ext4_bcache_test_flag(block->buf, BC_DIRTY))
-		return EOK;
+	struct ext4_fs *fs =
+		trans->journal->jbd_fs->inode_ref.fs;
 
+	/* If the buffer has already been modified, we should
+	 * flush dirty data in this buffer to disk.*/
+	if (ext4_bcache_test_flag(block->buf, BC_DIRTY)) {
+		/* XXX: i don't want to know whether the call
+		 * succeeds or not. */
+		ext4_block_flush_buf(fs->bdev, block->buf);
+	}
+
 	buf = calloc(1, sizeof(struct jbd_buf));
 	if (!buf)
 		return ENOMEM;
@@ -1170,12 +1177,22 @@
 	uint32_t desc_iblock = 0;
 	uint32_t data_iblock = 0;
 	char *tag_start = NULL, *tag_ptr = NULL;
-	struct jbd_buf *jbd_buf;
+	struct jbd_buf *jbd_buf, *tmp;
 	struct ext4_block desc_block, data_block;
+	struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
 
-	LIST_FOREACH(jbd_buf, &trans->buf_list, buf_node) {
+	LIST_FOREACH_SAFE(jbd_buf, &trans->buf_list, buf_node, tmp) {
 		struct tag_info tag_info;
 		bool uuid_exist = false;
+		if (!ext4_bcache_test_flag(jbd_buf->block.buf,
+					   BC_DIRTY)) {
+			/* The buffer has not been modified, just release
+			 * that jbd_buf. */
+			ext4_block_set(fs->bdev, &jbd_buf->block);
+			LIST_REMOVE(jbd_buf, buf_node);
+			free(jbd_buf);
+			continue;
+		}
 again:
 		if (!desc_iblock) {
 			struct jbd_bhdr *bhdr;
@@ -1430,6 +1447,15 @@
 	rc = jbd_journal_prepare_revoke(journal, trans);
 	if (rc != EOK)
 		goto Finish;
+
+	if (LIST_EMPTY(&trans->buf_list) &&
+	    LIST_EMPTY(&trans->revoke_list)) {
+		/* Since there are no entries in both buffer list
+		 * and revoke entry list, we do not consider trans as
+		 * complete transaction and just return EOK.*/
+		jbd_journal_free_trans(journal, trans, false);
+		goto Finish;
+	}
 
 	rc = jbd_trans_write_commit_block(trans);
 	if (rc != EOK)