ext4 / jbd2: add fast commit initialization
authorHarshad Shirwadkar <harshadshirwadkar@gmail.com>
Thu, 15 Oct 2020 20:37:55 +0000 (13:37 -0700)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 22 Oct 2020 03:22:26 +0000 (23:22 -0400)
This patch adds fast commit area trackers in the journal_t
structure. These are initialized via the jbd2_fc_init() routine that
this patch adds. This patch also adds ext4/fast_commit.c and
ext4/fast_commit.h files for fast commit code that will be added in
subsequent patches in this series.

Reported-by: kernel test robot <lkp@intel.com>
Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
Link: https://lore.kernel.org/r/20201015203802.3597742-4-harshadshirwadkar@gmail.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/Makefile
fs/ext4/ext4.h
fs/ext4/fast_commit.c [new file with mode: 0644]
fs/ext4/fast_commit.h [new file with mode: 0644]
fs/ext4/super.c
fs/jbd2/journal.c
include/linux/jbd2.h

index 2e42f47..49e7af6 100644 (file)
@@ -10,7 +10,7 @@ ext4-y        := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \
                indirect.o inline.o inode.o ioctl.o mballoc.o migrate.o \
                mmp.o move_extent.o namei.o page-io.o readpage.o resize.o \
                super.o symlink.o sysfs.o xattr.o xattr_hurd.o xattr_trusted.o \
-               xattr_user.o
+               xattr_user.o fast_commit.o
 
 ext4-$(CONFIG_EXT4_FS_POSIX_ACL)       += acl.o
 ext4-$(CONFIG_EXT4_FS_SECURITY)                += xattr_security.o
index 02d7dc3..2c412d3 100644 (file)
@@ -963,6 +963,7 @@ do {                                                                               \
 #endif /* defined(__KERNEL__) || defined(__linux__) */
 
 #include "extents_status.h"
+#include "fast_commit.h"
 
 /*
  * Lock subclasses for i_data_sem in the ext4_inode_info structure.
@@ -2678,6 +2679,9 @@ extern int ext4_init_inode_table(struct super_block *sb,
                                 ext4_group_t group, int barrier);
 extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
 
+/* fast_commit.c */
+
+void ext4_fc_init(struct super_block *sb, journal_t *journal);
 /* mballoc.c */
 extern const struct seq_operations ext4_mb_seq_groups_ops;
 extern long ext4_mb_stats;
diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
new file mode 100644 (file)
index 0000000..0dad8bd
--- /dev/null
@@ -0,0 +1,20 @@
+// 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);
+       }
+}
diff --git a/fs/ext4/fast_commit.h b/fs/ext4/fast_commit.h
new file mode 100644 (file)
index 0000000..8362bf5
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __FAST_COMMIT_H__
+#define __FAST_COMMIT_H__
+
+/* Number of blocks in journal area to allocate for fast commits */
+#define EXT4_NUM_FC_BLKS               256
+
+#endif /* __FAST_COMMIT_H__ */
index 66423c5..41da649 100644 (file)
@@ -5170,6 +5170,7 @@ static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
        journal->j_commit_interval = sbi->s_commit_interval;
        journal->j_min_batch_time = sbi->s_min_batch_time;
        journal->j_max_batch_time = sbi->s_max_batch_time;
+       ext4_fc_init(sb, journal);
 
        write_lock(&journal->j_state_lock);
        if (test_opt(sb, BARRIER))
index c060040..4497bfb 100644 (file)
@@ -1181,6 +1181,14 @@ static journal_t *journal_init_common(struct block_device *bdev,
        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",
@@ -1194,11 +1202,23 @@ static journal_t *journal_init_common(struct block_device *bdev,
 
 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
@@ -1316,11 +1336,20 @@ static int journal_reset(journal_t *journal)
        }
 
        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;
@@ -1665,9 +1694,18 @@ static int load_superblock(journal_t *journal)
        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;
 }
 
@@ -1728,6 +1766,9 @@ int jbd2_journal_load(journal_t *journal)
         */
        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. */
@@ -1811,6 +1852,8 @@ int jbd2_journal_destroy(journal_t *journal)
                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);
 
index 0685cc9..008629b 100644 (file)
@@ -919,6 +919,30 @@ struct journal_s
        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 block_device     *j_dev;
@@ -1069,6 +1093,12 @@ struct journal_s
        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:
         *
         * Size of @j_wbuf array.
@@ -1076,6 +1106,13 @@ struct journal_s
        int                     j_wbufsize;
 
        /**
+        * @j_fc_wbufsize:
+        *
+        * Size of @j_fc_wbuf array.
+        */
+       int                     j_fc_wbufsize;
+
+       /**
         * @j_last_sync_writer:
         *
         * The pid of the last person to run a synchronous operation
@@ -1535,6 +1572,8 @@ void __jbd2_log_wait_for_space(journal_t *journal);
 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
  *