ext4_journal: add trans parameter to jbd_trans_get_access routine.
[lwext4.git] / lwext4 / ext4_journal.c
index 598d1754431fdf29d7ab5ee0e426f620a948b41d..ada92ff754229942ce503210ec526c7f48b5798a 100644 (file)
@@ -975,6 +975,46 @@ int jbd_journal_start(struct jbd_fs *jbd_fs,
        return jbd_write_sb(jbd_fs);
 }
 
+static void jbd_journal_flush_trans(struct jbd_trans *trans)
+{
+       struct jbd_buf *jbd_buf, *tmp;
+       struct jbd_journal *journal = trans->journal;
+       struct ext4_fs *fs = journal->jbd_fs->inode_ref.fs;
+       LIST_FOREACH_SAFE(jbd_buf, &trans->buf_list, buf_node,
+                       tmp) {
+               struct ext4_block block = jbd_buf->block;
+               ext4_block_flush_buf(fs->bdev, block.buf);
+       }
+}
+
+static void
+jbd_journal_skip_pure_revoke(struct jbd_journal *journal,
+                            struct jbd_trans *trans)
+{
+       journal->start = trans->start_iblock +
+               trans->alloc_blocks;
+       wrap(&journal->jbd_fs->sb, journal->start);
+       journal->trans_id = trans->trans_id + 1;
+       jbd_journal_free_trans(journal,
+                       trans, false);
+       jbd_journal_write_sb(journal);
+}
+
+static void jbd_journal_flush_all_trans(struct jbd_journal *journal)
+{
+       struct jbd_trans *trans;
+       while ((trans = TAILQ_FIRST(&journal->cp_queue))) {
+               if (!trans->data_cnt) {
+                       TAILQ_REMOVE(&journal->cp_queue,
+                                       trans,
+                                       trans_node);
+                       jbd_journal_skip_pure_revoke(journal, trans);
+               } else
+                       jbd_journal_flush_trans(trans);
+
+       }
+}
+
 /**@brief  Stop accessing the journal.
  * @param  journal current journal session
  * @return standard error code*/
@@ -986,9 +1026,10 @@ int jbd_journal_stop(struct jbd_journal *journal)
 
        /* Commit all the transactions to the journal.*/
        jbd_journal_commit_all(journal);
+
        /* Make sure that journalled content have reached
         * the disk.*/
-       ext4_block_cache_flush(jbd_fs->inode_ref.fs->bdev);
+       jbd_journal_flush_all_trans(journal);
 
        features_incompatible =
                ext4_get32(&jbd_fs->inode_ref.fs->sb,
@@ -1024,7 +1065,7 @@ static uint32_t jbd_journal_alloc_block(struct jbd_journal *journal,
        /* If there is no space left, flush all journalled
         * blocks to disk first.*/
        if (journal->last == journal->start)
-               ext4_block_cache_flush(journal->jbd_fs->inode_ref.fs->bdev);
+               jbd_journal_flush_all_trans(journal);
 
        return start_block;
 }
@@ -1051,25 +1092,36 @@ static void jbd_trans_end_write(struct ext4_bcache *bc __unused,
                          int res,
                          void *arg);
 
-/**@brief  Add block to a transaction and gain
- *         access to it before making any modications.
+/**@brief  gain access to it before making any modications.
+ * @param  journal current journal session
  * @param  trans transaction
- * @param  block block descriptor
- * @return standard error code*/
-int jbd_trans_add_block(struct jbd_trans *trans,
-                       struct ext4_block *block)
+ * @param  block descriptor
+ * @return standard error code.*/
+int jbd_trans_get_access(struct jbd_journal *journal,
+                        struct jbd_trans *trans,
+                        struct ext4_block *block)
 {
-       struct jbd_buf *buf;
-       struct ext4_fs *fs =
-               trans->journal->jbd_fs->inode_ref.fs;
+       int r = EOK;
+       struct ext4_fs *fs = 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);
+       if (ext4_bcache_test_flag(block->buf, BC_DIRTY) &&
+           block->buf->end_write == jbd_trans_end_write &&
+           block->buf->end_write_arg != trans) {
+               r = ext4_block_flush_buf(fs->bdev, block->buf);
        }
+       return r;
+}
+
+/**@brief  Add block to a transaction and mark it dirty.
+ * @param  trans transaction
+ * @param  block block descriptor
+ * @return standard error code*/
+int jbd_trans_set_block_dirty(struct jbd_trans *trans,
+                             struct ext4_block *block)
+{
+       struct jbd_buf *buf;
 
        buf = calloc(1, sizeof(struct jbd_buf));
        if (!buf)
@@ -1086,6 +1138,8 @@ int jbd_trans_add_block(struct jbd_trans *trans,
 
        trans->data_cnt++;
        LIST_INSERT_HEAD(&trans->buf_list, buf, buf_node);
+
+       ext4_bcache_set_dirty(block->buf);
        return EOK;
 }
 
@@ -1394,6 +1448,9 @@ static void jbd_trans_end_write(struct ext4_bcache *bc __unused,
        if (res != EOK)
                trans->error = res;
 
+       LIST_REMOVE(jbd_buf, buf_node);
+       free(jbd_buf);
+
        /* Clear the end_write and end_write_arg fields. */
        buf->end_write = NULL;
        buf->end_write_arg = NULL;
@@ -1416,12 +1473,8 @@ static void jbd_trans_end_write(struct ext4_bcache *bc __unused,
                                        TAILQ_REMOVE(&journal->cp_queue,
                                                     trans,
                                                     trans_node);
-                                       journal->start = trans->start_iblock +
-                                               trans->alloc_blocks;
-                                       wrap(&journal->jbd_fs->sb, journal->start);
-                                       journal->trans_id = trans->trans_id + 1;
-                                       jbd_journal_free_trans(journal,
-                                                              trans, false);
+                                       jbd_journal_skip_pure_revoke(journal,
+                                                                    trans);
                                } else {
                                        journal->start = trans->start_iblock;
                                        wrap(&journal->jbd_fs->sb, journal->start);