--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * fs/ext4/fast_commit.c
+ *
+ * Written by Harshad Shirwadkar <harshadshirwadkar@gmail.com>
+ *
+ * Ext4 fast commits routines.
+ */
+#include "ext4_jbd2.h"
+
+void ext4_fc_init(struct super_block *sb, journal_t *journal)
+{
+       if (!test_opt2(sb, JOURNAL_FAST_COMMIT))
+               return;
+       if (jbd2_fc_init(journal, EXT4_NUM_FC_BLKS)) {
+               pr_warn("Error while enabling fast commits, turning off.");
+               ext4_clear_feature_fast_commit(sb);
+       }
+}
 
        if (!journal->j_wbuf)
                goto err_cleanup;
 
+       if (journal->j_fc_wbufsize > 0) {
+               journal->j_fc_wbuf = kmalloc_array(journal->j_fc_wbufsize,
+                                       sizeof(struct buffer_head *),
+                                       GFP_KERNEL);
+               if (!journal->j_fc_wbuf)
+                       goto err_cleanup;
+       }
+
        bh = getblk_unmovable(journal->j_dev, start, journal->j_blocksize);
        if (!bh) {
                pr_err("%s: Cannot get buffer for journal superblock\n",
 
 err_cleanup:
        kfree(journal->j_wbuf);
+       kfree(journal->j_fc_wbuf);
        jbd2_journal_destroy_revoke(journal);
        kfree(journal);
        return NULL;
 }
 
+int jbd2_fc_init(journal_t *journal, int num_fc_blks)
+{
+       journal->j_fc_wbufsize = num_fc_blks;
+       journal->j_fc_wbuf = kmalloc_array(journal->j_fc_wbufsize,
+                               sizeof(struct buffer_head *), GFP_KERNEL);
+       if (!journal->j_fc_wbuf)
+               return -ENOMEM;
+       return 0;
+}
+EXPORT_SYMBOL(jbd2_fc_init);
+
 /* jbd2_journal_init_dev and jbd2_journal_init_inode:
  *
  * Create a journal structure assigned some fixed set of disk blocks to
        }
 
        journal->j_first = first;
-       journal->j_last = last;
 
-       journal->j_head = first;
-       journal->j_tail = first;
-       journal->j_free = last - first;
+       if (jbd2_has_feature_fast_commit(journal) &&
+           journal->j_fc_wbufsize > 0) {
+               journal->j_fc_last = last;
+               journal->j_last = last - journal->j_fc_wbufsize;
+               journal->j_fc_first = journal->j_last + 1;
+               journal->j_fc_off = 0;
+       } else {
+               journal->j_last = last;
+       }
+
+       journal->j_head = journal->j_first;
+       journal->j_tail = journal->j_first;
+       journal->j_free = journal->j_last - journal->j_first;
 
        journal->j_tail_sequence = journal->j_transaction_sequence;
        journal->j_commit_sequence = journal->j_transaction_sequence - 1;
        journal->j_tail_sequence = be32_to_cpu(sb->s_sequence);
        journal->j_tail = be32_to_cpu(sb->s_start);
        journal->j_first = be32_to_cpu(sb->s_first);
-       journal->j_last = be32_to_cpu(sb->s_maxlen);
        journal->j_errno = be32_to_cpu(sb->s_errno);
 
+       if (jbd2_has_feature_fast_commit(journal) &&
+           journal->j_fc_wbufsize > 0) {
+               journal->j_fc_last = be32_to_cpu(sb->s_maxlen);
+               journal->j_last = journal->j_fc_last - journal->j_fc_wbufsize;
+               journal->j_fc_first = journal->j_last + 1;
+               journal->j_fc_off = 0;
+       } else {
+               journal->j_last = be32_to_cpu(sb->s_maxlen);
+       }
+
        return 0;
 }
 
         */
        journal->j_flags &= ~JBD2_ABORT;
 
+       if (journal->j_fc_wbufsize > 0)
+               jbd2_journal_set_features(journal, 0, 0,
+                                         JBD2_FEATURE_INCOMPAT_FAST_COMMIT);
        /* OK, we've finished with the dynamic journal bits:
         * reinitialise the dynamic contents of the superblock in memory
         * and reset them on disk. */
                jbd2_journal_destroy_revoke(journal);
        if (journal->j_chksum_driver)
                crypto_free_shash(journal->j_chksum_driver);
+       if (journal->j_fc_wbufsize > 0)
+               kfree(journal->j_fc_wbuf);
        kfree(journal->j_wbuf);
        kfree(journal);
 
 
         */
        unsigned long           j_last;
 
+       /**
+        * @j_fc_first:
+        *
+        * The block number of the first fast commit block in the journal
+        * [j_state_lock].
+        */
+       unsigned long           j_fc_first;
+
+       /**
+        * @j_fc_off:
+        *
+        * Number of fast commit blocks currently allocated.
+        * [j_state_lock].
+        */
+       unsigned long           j_fc_off;
+
+       /**
+        * @j_fc_last:
+        *
+        * The block number one beyond the last fast commit block in the journal
+        * [j_state_lock].
+        */
+       unsigned long           j_fc_last;
+
        /**
         * @j_dev: Device where we store the journal.
         */
         */
        struct buffer_head      **j_wbuf;
 
+       /**
+        * @j_fc_wbuf: Array of fast commit bhs for
+        * jbd2_journal_commit_transaction.
+        */
+       struct buffer_head      **j_fc_wbuf;
+
        /**
         * @j_wbufsize:
         *
         */
        int                     j_wbufsize;
 
+       /**
+        * @j_fc_wbufsize:
+        *
+        * Size of @j_fc_wbuf array.
+        */
+       int                     j_fc_wbufsize;
+
        /**
         * @j_last_sync_writer:
         *
 extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *);
 extern int jbd2_cleanup_journal_tail(journal_t *);
 
+/* Fast commit related APIs */
+int jbd2_fc_init(journal_t *journal, int num_fc_blks);
 /*
  * is_journal_abort
  *