diff mbox series

[04/15] mke2fs, dumpe2fs: make fast commit blocks configurable

Message ID 20201120191606.2224881-5-harshadshirwadkar@gmail.com
State Superseded
Headers show
Series Fast commits support for e2fsprogs | expand

Commit Message

harshad shirwadkar Nov. 20, 2020, 7:15 p.m. UTC
This patch makes number of fast commit blocks configurable. Also, the
number of fast commit blocks can now be seen in dumpe2fs output.

$ ./misc/mke2fs -O fast_commit -t ext4 image
mke2fs 1.46-WIP (20-Mar-2020)
Discarding device blocks: done
Creating filesystem with 5120 1k blocks and 1280 inodes
Allocating group tables: done
Writing inode tables: done
Creating journal (1040 blocks): done
Writing superblocks and filesystem accounting information: done

$ ./misc/dumpe2fs image
dumpe2fs 1.46-WIP (20-Mar-2020)
...
Journal features:         (none)
Total journal size:       1040k
Total journal blocks:     1040
Max transaction length:   1024
Fast commit length:       16
Journal sequence:         0x00000001
Journal start:            0

$ ./misc/mke2fs -O fast_commit -t ext4 image -J fast_commit_size=256,size=1
mke2fs 1.46-WIP (20-Mar-2020)
Creating filesystem with 5120 1k blocks and 1280 inodes
Allocating group tables: done
Writing inode tables: done
Creating journal (1280 blocks): done
Writing superblocks and filesystem accounting information: done

$ ./misc/dumpe2fs image
dumpe2fs 1.46-WIP (20-Mar-2020)
...
Journal features:         (none)
Total journal size:       1280k
Total journal blocks:     1280
Max transaction length:   1024
Fast commit length:       256
Journal sequence:         0x00000001
Journal start:            0

Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
---
 e2fsck/unix.c          |  8 ++--
 lib/e2p/e2p.h          |  1 +
 lib/e2p/ljs.c          | 16 +++++--
 lib/ext2fs/ext2fs.h    | 21 ++++++---
 lib/ext2fs/mkjournal.c | 99 +++++++++++++++++++++++++++++-------------
 misc/dumpe2fs.c        | 10 ++++-
 misc/mke2fs.c          | 24 +++++++---
 misc/tune2fs.c         |  8 ++--
 misc/util.c            | 63 ++++++++++++++++++++-------
 misc/util.h            |  4 +-
 10 files changed, 185 insertions(+), 69 deletions(-)

Comments

Theodore Ts'o Dec. 2, 2020, 6:29 p.m. UTC | #1
On Fri, Nov 20, 2020 at 11:15:55AM -0800, Harshad Shirwadkar wrote:
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index a8a6e091..01132245 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -1625,15 +1631,18 @@ extern errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
>  extern errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
>  				     blk64_t *ret_blk, int *ret_count);
>  extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
> -						  __u32 num_blocks, int flags,
> -						  char  **ret_jsb);
> +						  __u32 num_blocks, __u32 num_fc_blks,
> +						  int flags, char  **ret_jsb);
> +extern errcode_t ext2fs_split_journal_size(ext2_filsys fs, blk_t *journal_blks,
> +					   blk_t *fc_blks, blk_t total_blks);
>  extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
>  					   ext2_filsys journal_dev);
>  extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks,
> -					  int flags);
> +					  blk_t num_fc_blocks, int flags);
>  extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
> -					   blk64_t goal, int flags);
> -extern int ext2fs_default_journal_size(__u64 num_blocks);
> +				    blk_t num_fc_blocks,
> +				    blk64_t goal, int flags);
> +extern errcode_t ext2fs_default_journal_size(int *journal_size, int *fc_size, ext2_filsys fs);
>  extern int ext2fs_journal_sb_start(int blocksize);
>  

We must never change the type or function signature of anything which
is exported via a shared library.  Otherwise, if someone grabs a new
mke2fs binary, and somehow fails to run against an older version of
libext2fs.so, Much Hilarity will ensue.

It's also possible that there may be some other userspace application
which is shipped separately from e2fsprogs --- maybe in some company's
userspace program which has never been published and might be living
in some Perforce depot for all we know --- that might be using a
published interface.  So even without shared libraries, we don't want
to break those applications when that company imports the newer
version of e2fsprogs into their code base.

That means that we can define new functions (and they should be
prefixed with ext2fs_ to avoid namespace polution), but we must not
modify existing functions.  We can either do something like, say,
ext2fs_default_journal_size2() or perhaps better in this case, we
could define a new function ext2fs_default_journal_params(), and then
define ext2fs_default_journal_size() in terms of the new function.

> @@ -2122,6 +2131,8 @@ static inline unsigned int ext2_dir_htree_level(ext2_filsys fs)
>  	return EXT4_HTREE_LEVEL_COMPAT;
>  }
>  
> +#define max(a, b) ((a) > (b) ? (a) : (b))
> +
>  #ifdef __cplusplus
>  }
>  #endif

Please don't define max() in ext2fs.h, since that's a public header
file, and we don't want cause problems for applciations which may have
their own max() definition.

There is the ext2fsP.h header file which is private to the ext2fs
library, or you could define a new function or cpp macros in
libsupport, if it's really necessary for multiple e2fsprogs
applications.  Or maybe max() is so simple that we can just have it
defined in those .c files where it's needed....


> diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
> index f47f71e6..74d0c7fc 100644
> --- a/lib/ext2fs/mkjournal.c
> +++ b/lib/ext2fs/mkjournal.c
> +errcode_t ext2fs_split_journal_size(ext2_filsys fs, blk_t *journal_blks,
> +		blk_t *fc_blks, blk_t total_blks)
> +{
> +	if (total_blks < JBD2_MIN_JOURNAL_BLOCKS)
> +		return EXT2_ET_JOURNAL_TOO_SMALL;
> +
> +	if (!ext2fs_has_feature_fast_commit(fs->super)) {
> +		*journal_blks = total_blks;
> +		*fc_blks = 0;
> +		return 0;
> +	}
> +	*journal_blks = ext2fs_blocks_count(fs->super) *
> +			EXT2_JOURNAL_TO_FC_BLKS_RATIO /
> +			(EXT2_JOURNAL_TO_FC_BLKS_RATIO + 1);
> +	*journal_blks = max(JBD2_MIN_JOURNAL_BLOCKS, *journal_blks);
> +	*fc_blks = total_blks - *journal_blks;
> +	return 0;
> +}

Maybe we should just have a ext2fs_default_journal_params structure,
and do this as part of a new "ext2fs_get_journal_params"?  If the
number of journal blocks or fast commit blocks is zero, then we can
have the function fill in an appropriate default value, perhaps?

Cheers,

						- Ted
diff mbox series

Patch

diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 1cb51672..3162896a 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -1388,7 +1388,7 @@  int main (int argc, char *argv[])
 	blk64_t		orig_superblock = ~(blk64_t)0;
 	struct problem_context pctx;
 	int flags, run_result, was_changed;
-	int journal_size;
+	int journal_size, journal_fc_size;
 	int sysval, sys_page_size = 4096;
 	int old_bitmaps;
 	__u32 features[3];
@@ -1912,7 +1912,7 @@  print_unsupp_features:
 	    (ctx->flags & E2F_FLAG_JOURNAL_INODE)) {
 		if (fix_problem(ctx, PR_6_RECREATE_JOURNAL, &pctx)) {
 			if (journal_size < 1024)
-				journal_size = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super));
+				ext2fs_default_journal_size(&journal_size, &journal_fc_size, fs);
 			if (journal_size < 0) {
 				ext2fs_clear_feature_journal(fs->super);
 				fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
@@ -1923,8 +1923,8 @@  print_unsupp_features:
 			log_out(ctx, _("Creating journal (%d blocks): "),
 			       journal_size);
 			fflush(stdout);
-			retval = ext2fs_add_journal_inode(fs,
-							  journal_size, 0);
+			retval = ext2fs_add_journal_inode(fs, journal_size,
+					journal_fc_size, 0);
 			if (retval) {
 				log_out(ctx, "%s: while trying to create "
 					"journal\n", error_message(retval));
diff --git a/lib/e2p/e2p.h b/lib/e2p/e2p.h
index 90efb624..65702a7e 100644
--- a/lib/e2p/e2p.h
+++ b/lib/e2p/e2p.h
@@ -47,6 +47,7 @@  void print_fs_state (FILE * f, unsigned short state);
 int setflags (int fd, unsigned long flags);
 int setversion (int fd, unsigned long version);
 
+#define E2P_LIST_JOURNAL_FLAG_FC		0x1
 void e2p_list_journal_super(FILE *f, char *journal_sb_buf,
 			    int exp_block_size, int flags);
 
diff --git a/lib/e2p/ljs.c b/lib/e2p/ljs.c
index 4ffe9b61..9f866c7e 100644
--- a/lib/e2p/ljs.c
+++ b/lib/e2p/ljs.c
@@ -54,7 +54,12 @@  void e2p_list_journal_super(FILE *f, char *journal_sb_buf,
 	unsigned int size;
 	int j, printed = 0;
 	unsigned int i, nr_users;
+	int num_fc_blks = 0;
+	int journal_blks = 0;
 
+	if (flags & E2P_LIST_JOURNAL_FLAG_FC)
+		num_fc_blks = jbd2_journal_get_num_fc_blks((journal_superblock_t *)journal_sb_buf);
+	journal_blks = ntohl(jsb->s_maxlen) - num_fc_blks;
 	fprintf(f, "%s", "Journal features:        ");
 	for (i=0, mask_ptr=&jsb->s_feature_compat; i <3; i++,mask_ptr++) {
 		mask = e2p_be32(*mask_ptr);
@@ -68,7 +73,7 @@  void e2p_list_journal_super(FILE *f, char *journal_sb_buf,
 	if (printed == 0)
 		fprintf(f, " (none)");
 	fputc('\n', f);
-	fputs("Journal size:             ", f);
+	fputs("Total journal size:       ", f);
 	size = (ntohl(jsb->s_blocksize) / 1024) * ntohl(jsb->s_maxlen);
 	if (size < 8192)
 		fprintf(f, "%uk\n", size);
@@ -78,8 +83,13 @@  void e2p_list_journal_super(FILE *f, char *journal_sb_buf,
 	if (exp_block_size != (int) ntohl(jsb->s_blocksize))
 		fprintf(f, "Journal block size:       %u\n",
 			(unsigned int)ntohl(jsb->s_blocksize));
-	fprintf(f, "Journal length:           %u\n",
-		(unsigned int)ntohl(jsb->s_maxlen));
+	fprintf(f, "Total journal blocks:     %u\n",
+		(unsigned int)(journal_blks + num_fc_blks));
+	fprintf(f, "Max transaction length:   %u\n",
+		(unsigned int)journal_blks);
+	fprintf(f, "Fast commit length:       %u\n",
+		(unsigned int)num_fc_blks);
+
 	if (ntohl(jsb->s_first) != 1)
 		fprintf(f, "Journal first block:      %u\n",
 			(unsigned int)ntohl(jsb->s_first));
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index a8a6e091..01132245 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -220,6 +220,12 @@  typedef struct ext2_file *ext2_file_t;
 #define EXT2_MKJOURNAL_LAZYINIT	0x0000002 /* don't zero journal inode before use*/
 #define EXT2_MKJOURNAL_NO_MNT_CHECK 0x0000004 /* don't check mount status */
 
+/*
+ * Normal journal area size to fast commit area size ratio. This is used to
+ * set default size of fast commit area.
+ */
+#define EXT2_JOURNAL_TO_FC_BLKS_RATIO		64
+
 struct blk_alloc_ctx;
 struct opaque_ext2_group_desc;
 
@@ -1625,15 +1631,18 @@  extern errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
 extern errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
 				     blk64_t *ret_blk, int *ret_count);
 extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
-						  __u32 num_blocks, int flags,
-						  char  **ret_jsb);
+						  __u32 num_blocks, __u32 num_fc_blks,
+						  int flags, char  **ret_jsb);
+extern errcode_t ext2fs_split_journal_size(ext2_filsys fs, blk_t *journal_blks,
+					   blk_t *fc_blks, blk_t total_blks);
 extern errcode_t ext2fs_add_journal_device(ext2_filsys fs,
 					   ext2_filsys journal_dev);
 extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks,
-					  int flags);
+					  blk_t num_fc_blocks, int flags);
 extern errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
-					   blk64_t goal, int flags);
-extern int ext2fs_default_journal_size(__u64 num_blocks);
+				    blk_t num_fc_blocks,
+				    blk64_t goal, int flags);
+extern errcode_t ext2fs_default_journal_size(int *journal_size, int *fc_size, ext2_filsys fs);
 extern int ext2fs_journal_sb_start(int blocksize);
 
 /* openfs.c */
@@ -2122,6 +2131,8 @@  static inline unsigned int ext2_dir_htree_level(ext2_filsys fs)
 	return EXT4_HTREE_LEVEL_COMPAT;
 }
 
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
index f47f71e6..74d0c7fc 100644
--- a/lib/ext2fs/mkjournal.c
+++ b/lib/ext2fs/mkjournal.c
@@ -12,6 +12,7 @@ 
 #include "config.h"
 #include <stdio.h>
 #include <string.h>
+#include <assert.h>
 #if HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -39,13 +40,32 @@ 
 
 #include "kernel-jbd.h"
 
+errcode_t ext2fs_split_journal_size(ext2_filsys fs, blk_t *journal_blks,
+		blk_t *fc_blks, blk_t total_blks)
+{
+	if (total_blks < JBD2_MIN_JOURNAL_BLOCKS)
+		return EXT2_ET_JOURNAL_TOO_SMALL;
+
+	if (!ext2fs_has_feature_fast_commit(fs->super)) {
+		*journal_blks = total_blks;
+		*fc_blks = 0;
+		return 0;
+	}
+	*journal_blks = ext2fs_blocks_count(fs->super) *
+			EXT2_JOURNAL_TO_FC_BLKS_RATIO /
+			(EXT2_JOURNAL_TO_FC_BLKS_RATIO + 1);
+	*journal_blks = max(JBD2_MIN_JOURNAL_BLOCKS, *journal_blks);
+	*fc_blks = total_blks - *journal_blks;
+	return 0;
+}
+
 /*
  * This function automatically sets up the journal superblock and
  * returns it as an allocated block.
  */
 errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
-					   __u32 num_blocks, int flags,
-					   char  **ret_jsb)
+					   __u32 num_blocks, __u32 num_fc_blks,
+					   int flags, char  **ret_jsb)
 {
 	errcode_t		retval;
 	journal_superblock_t	*jsb;
@@ -64,10 +84,11 @@  errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
 	else
 		jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
 	jsb->s_blocksize = htonl(fs->blocksize);
-	jsb->s_maxlen = htonl(num_blocks);
+	jsb->s_maxlen = htonl(num_blocks + num_fc_blks);
 	jsb->s_nr_users = htonl(1);
 	jsb->s_first = htonl(1);
 	jsb->s_sequence = htonl(1);
+	jsb->s_num_fc_blks = htonl(num_fc_blks);
 	memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
 	/*
 	 * If we're creating an external journal device, we need to
@@ -88,14 +109,16 @@  errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
  * filesystems.
  */
 static errcode_t write_journal_file(ext2_filsys fs, char *filename,
-				    blk_t num_blocks, int flags)
+				    blk_t num_blocks, blk_t num_fc_blocks,
+				    int flags)
 {
 	errcode_t	retval;
 	char		*buf = 0;
 	int		fd, ret_size;
 	blk_t		i;
 
-	if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
+	if ((retval = ext2fs_create_journal_superblock(fs, num_blocks,
+						       num_fc_blocks, flags,
 						       &buf)))
 		return retval;
 
@@ -119,7 +142,7 @@  static errcode_t write_journal_file(ext2_filsys fs, char *filename,
 	if (flags & EXT2_MKJOURNAL_LAZYINIT)
 		goto success;
 
-	for (i = 1; i < num_blocks; i++) {
+	for (i = 1; i < num_blocks + num_fc_blocks; i++) {
 		ret_size = write(fd, buf, fs->blocksize);
 		if (ret_size < 0) {
 			retval = errno;
@@ -262,7 +285,8 @@  static blk64_t get_midpoint_journal_block(ext2_filsys fs)
  * This function creates a journal using direct I/O routines.
  */
 static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
-				     blk_t num_blocks, blk64_t goal, int flags)
+				     blk_t num_blocks, blk_t num_fc_blocks,
+				     blk64_t goal, int flags)
 {
 	char			*buf;
 	errcode_t		retval;
@@ -271,7 +295,8 @@  static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
 	int			falloc_flags = EXT2_FALLOCATE_FORCE_INIT;
 	blk64_t			zblk;
 
-	if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
+	if ((retval = ext2fs_create_journal_superblock(fs, num_blocks,
+						       num_fc_blocks, flags,
 						       &buf)))
 		return retval;
 
@@ -295,7 +320,8 @@  static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
 	if (!(flags & EXT2_MKJOURNAL_LAZYINIT))
 		falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS;
 
-	inode_size = (unsigned long long)fs->blocksize * num_blocks;
+	inode_size = (unsigned long long)fs->blocksize *
+			(num_blocks + num_fc_blocks);
 	inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
 	inode.i_links_count = 1;
 	inode.i_mode = LINUX_S_IFREG | 0600;
@@ -304,7 +330,7 @@  static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
 		goto out2;
 
 	retval = ext2fs_fallocate(fs, falloc_flags, journal_ino,
-				  &inode, goal, 0, num_blocks);
+				  &inode, goal, 0, num_blocks + num_fc_blocks);
 	if (retval)
 		goto out2;
 
@@ -337,25 +363,34 @@  out2:
  *
  * n.b. comments assume 4k blocks
  */
-int ext2fs_default_journal_size(__u64 num_blocks)
+errcode_t ext2fs_default_journal_size(int *journal_size, int *fc_size, ext2_filsys fs)
 {
+	__u64 num_blocks = ext2fs_blocks_count(fs->super);
+
 	if (num_blocks < 2048)
-		return -1;
+		return EXT2_ET_TOOSMALL;
 	if (num_blocks < 32768)		/* 128 MB */
-		return (1024);			/* 4 MB */
-	if (num_blocks < 256*1024)	/* 1 GB */
-		return (4096);			/* 16 MB */
-	if (num_blocks < 512*1024)	/* 2 GB */
-		return (8192);			/* 32 MB */
-	if (num_blocks < 4096*1024)	/* 16 GB */
-		return (16384);			/* 64 MB */
-	if (num_blocks < 8192*1024)	/* 32 GB */
-		return (32768);			/* 128 MB */
-	if (num_blocks < 16384*1024)	/* 64 GB */
-		return (65536);			/* 256 MB */
-	if (num_blocks < 32768*1024)	/* 128 GB */
-		return (131072);		/* 512 MB */
-	return 262144;				/* 1 GB */
+		*journal_size = 1024;		/* 4 MB */
+	else if (num_blocks < 256*1024)		/* 1 GB */
+		*journal_size = 4096;		/* 16 MB */
+	else if (num_blocks < 512*1024)	/* 2 GB */
+		*journal_size = 8192;		/* 32 MB */
+	else if (num_blocks < 4096*1024)	/* 16 GB */
+		*journal_size = 16384;		/* 64 MB */
+	else if (num_blocks < 8192*1024)	/* 32 GB */
+		*journal_size = 32768;		/* 128 MB */
+	else if (num_blocks < 16384*1024)	/* 64 GB */
+		*journal_size = 65536;		/* 256 MB */
+	else if (num_blocks < 32768*1024)	/* 128 GB */
+		*journal_size = 131072;		/* 512 MB */
+	else
+		*journal_size = 262144;	/* 1 GB */
+
+	*fc_size = ext2fs_has_feature_fast_commit(fs->super) ?
+		*journal_size / EXT2_JOURNAL_TO_FC_BLKS_RATIO : 0;
+	assert(*journal_size + *fc_size < num_blocks);
+
+	return 0;
 }
 
 int ext2fs_journal_sb_start(int blocksize)
@@ -435,6 +470,7 @@  errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
  * functions if it is not.
  */
 errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
+				    blk_t num_fc_blocks,
 				    blk64_t goal, int flags)
 {
 	errcode_t		retval;
@@ -486,7 +522,8 @@  errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
 		 * filesystems is extremely rare these days...  Ignore it. */
 		flags &= ~EXT2_MKJOURNAL_LAZYINIT;
 
-		if ((retval = write_journal_file(fs, jfile, num_blocks, flags)))
+		if ((retval = write_journal_file(fs, jfile,
+			num_blocks, num_fc_blocks, flags)))
 			goto errout;
 
 		/* Get inode number of the journal file */
@@ -528,7 +565,8 @@  errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
 		}
 		journal_ino = EXT2_JOURNAL_INO;
 		if ((retval = write_journal_inode(fs, journal_ino,
-						  num_blocks, goal, flags)))
+						  num_blocks, num_fc_blocks,
+						  goal, flags)))
 			return retval;
 	}
 
@@ -546,9 +584,10 @@  errout:
 	return retval;
 }
 
-errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
+errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks,
+		blk_t num_fc_blocks, int flags)
 {
-	return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags);
+	return ext2fs_add_journal_inode2(fs, num_blocks, num_fc_blocks, ~0ULL, flags);
 }
 
 
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index d295ba4d..e24dc4e6 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -364,6 +364,7 @@  static void print_inline_journal_information(ext2_filsys fs)
 	errcode_t		retval;
 	ext2_ino_t		ino = fs->super->s_journal_inum;
 	char			buf[1024];
+	int			flags;
 
 	if (fs->flags & EXT2_FLAG_IMAGE_FILE)
 		return;
@@ -392,7 +393,9 @@  static void print_inline_journal_information(ext2_filsys fs)
 			_("Journal superblock magic number invalid!\n"));
 		exit(1);
 	}
-	e2p_list_journal_super(stdout, buf, fs->blocksize, 0);
+	flags = ext2fs_has_feature_fast_commit(fs->super) ?
+			E2P_LIST_JOURNAL_FLAG_FC : 0;
+	e2p_list_journal_super(stdout, buf, fs->blocksize, flags);
 }
 
 static void print_journal_information(ext2_filsys fs)
@@ -400,6 +403,7 @@  static void print_journal_information(ext2_filsys fs)
 	errcode_t	retval;
 	char		buf[1024];
 	journal_superblock_t	*jsb;
+	int		flags;
 
 	/* Get the journal superblock */
 	if ((retval = io_channel_read_blk64(fs->io,
@@ -417,7 +421,9 @@  static void print_journal_information(ext2_filsys fs)
 			_("Couldn't find journal superblock magic numbers"));
 		exit(1);
 	}
-	e2p_list_journal_super(stdout, buf, fs->blocksize, 0);
+	flags = ext2fs_has_feature_fast_commit(fs->super) ?
+			E2P_LIST_JOURNAL_FLAG_FC : 0;
+	e2p_list_journal_super(stdout, buf, fs->blocksize, flags);
 }
 
 static int check_mmp(ext2_filsys fs)
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 8c8f5ea4..2d9a5449 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -93,6 +93,7 @@  static uid_t	root_uid;
 static gid_t	root_gid;
 int	journal_size;
 int	journal_flags;
+int	journal_fc_size;
 static int	lazy_itable_init;
 static int	packed_meta_blocks;
 int		no_copy_xattrs;
@@ -604,9 +605,18 @@  static void create_journal_dev(ext2_filsys fs)
 	char			*buf;
 	blk64_t			blk, err_blk;
 	int			c, count, err_count;
+	int			num_journal_blks = 0, num_fc_blks = 0;
+
+	retval = ext2fs_split_journal_size(fs, &num_journal_blks, &num_fc_blks,
+				ext2fs_blocks_count(fs->super));
+	if (retval) {
+		com_err("create_journal_dev", retval, "%s",
+			_("while splitting the journal size"));
+		exit(1);
+	}
 
 	retval = ext2fs_create_journal_superblock(fs,
-				  ext2fs_blocks_count(fs->super), 0, &buf);
+				  num_journal_blks, num_fc_blks, 0, &buf);
 	if (retval) {
 		com_err("create_journal_dev", retval, "%s",
 			_("while initializing journal superblock"));
@@ -1753,6 +1763,8 @@  profile_error:
 		case 'j':
 			if (!journal_size)
 				journal_size = -1;
+			if (!journal_fc_size)
+				journal_fc_size = -1;
 			break;
 		case 'J':
 			parse_journal_opts(optarg);
@@ -2937,7 +2949,7 @@  int main (int argc, char *argv[])
 	badblocks_list	bb_list = 0;
 	badblocks_iterate	bb_iter;
 	blk_t		blk;
-	unsigned int	journal_blocks = 0;
+	blk_t		journal_blocks = 0, journal_fc_blocks = 0;
 	unsigned int	i, checkinterval;
 	int		max_mnt_count;
 	int		val, hash_alg;
@@ -3047,7 +3059,8 @@  int main (int argc, char *argv[])
 	/* Calculate journal blocks */
 	if (!journal_device && ((journal_size) ||
 	    ext2fs_has_feature_journal(&fs_param)))
-		journal_blocks = figure_journal_size(journal_size, fs);
+		figure_journal_size(&journal_blocks, &journal_fc_blocks,
+			journal_size, journal_fc_size, fs);
 
 	sprintf(opt_string, "tdb_data_size=%d", fs->blocksize <= 4096 ?
 		32768 : fs->blocksize * 8);
@@ -3382,7 +3395,7 @@  int main (int argc, char *argv[])
 		free(journal_device);
 	} else if ((journal_size) ||
 		   ext2fs_has_feature_journal(&fs_param)) {
-		overhead += EXT2FS_NUM_B2C(fs, journal_blocks);
+		overhead += EXT2FS_NUM_B2C(fs, journal_blocks + journal_fc_blocks);
 		if (super_only) {
 			printf("%s", _("Skipping journal creation in super-only mode\n"));
 			fs->super->s_journal_inum = EXT2_JOURNAL_INO;
@@ -3395,10 +3408,11 @@  int main (int argc, char *argv[])
 		}
 		if (!quiet) {
 			printf(_("Creating journal (%u blocks): "),
-			       journal_blocks);
+			       journal_blocks + journal_fc_blocks);
 			fflush(stdout);
 		}
 		retval = ext2fs_add_journal_inode2(fs, journal_blocks,
+						   journal_fc_blocks,
 						   journal_location,
 						   journal_flags);
 		if (retval) {
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 670ed9e0..daee154d 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -102,7 +102,7 @@  static int feature_64bit;
 static int fsck_requested;
 static char *undo_file;
 
-int journal_size, journal_flags;
+int journal_size, journal_fc_size, journal_flags;
 char *journal_device;
 static blk64_t journal_location = ~0LL;
 
@@ -1543,7 +1543,7 @@  mmp_error:
  */
 static int add_journal(ext2_filsys fs)
 {
-	unsigned long journal_blocks;
+	blk_t journal_blocks, journal_fc_blocks;
 	errcode_t	retval;
 	ext2_filsys	jfs;
 	io_manager	io_ptr;
@@ -1589,13 +1589,15 @@  static int add_journal(ext2_filsys fs)
 	} else if (journal_size) {
 		fputs(_("Creating journal inode: "), stdout);
 		fflush(stdout);
-		journal_blocks = figure_journal_size(journal_size, fs);
+		figure_journal_size(&journal_blocks, &journal_fc_blocks,
+				    journal_size, journal_fc_size, fs);
 
 		if (journal_location_string)
 			journal_location =
 				parse_num_blocks2(journal_location_string,
 						  fs->super->s_log_block_size);
 		retval = ext2fs_add_journal_inode2(fs, journal_blocks,
+						   journal_fc_blocks,
 						   journal_location,
 						   journal_flags);
 		if (retval) {
diff --git a/misc/util.c b/misc/util.c
index dcd2f0a7..85f10a70 100644
--- a/misc/util.c
+++ b/misc/util.c
@@ -200,6 +200,14 @@  void parse_journal_opts(const char *opts)
 			journal_size = strtoul(arg, &p, 0);
 			if (*p)
 				journal_usage++;
+		} else if (strcmp(token, "fast_commit_size") == 0) {
+			if (!arg) {
+				journal_usage++;
+				continue;
+			}
+			journal_fc_size = strtoul(arg, &p, 0);
+			if (*p)
+				journal_usage++;
 		} else if (!strcmp(token, "location")) {
 			if (!arg) {
 				journal_usage++;
@@ -229,42 +237,65 @@  void parse_journal_opts(const char *opts)
 	free(buf);
 }
 
+static inline int jsize_to_blks(ext2_filsys fs, int size)
+{
+	return (size * 1024) / (fs->blocksize / 1024);
+}
+
+/* Fast commit size is in KBs */
+static inline int fcsize_to_blks(ext2_filsys fs, int size)
+{
+	return (size * 1024) / (fs->blocksize);
+}
+
 /*
  * Determine the number of journal blocks to use, either via
  * user-specified # of megabytes, or via some intelligently selected
  * defaults.
  *
- * Find a reasonable journal file size (in blocks) given the number of blocks
- * in the filesystem.  For very small filesystems, it is not reasonable to
- * have a journal that fills more than half of the filesystem.
+ * Find a reasonable journal file size (in blocks) given the number of blocks in
+ * the filesystem. For very small filesystems, it is not reasonable to have a
+ * journal that fills more than half of the filesystem.
  */
-unsigned int figure_journal_size(int size, ext2_filsys fs)
+void figure_journal_size(blk_t *j_blocks, blk_t *fc_blocks,
+		int requested_j_size, int requested_fc_size, ext2_filsys fs)
 {
-	int j_blocks;
+	int def_j_blocks, def_fc_blocks, total_blocks;
+	int ret;
 
-	j_blocks = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super));
-	if (j_blocks < 0) {
+	ret = ext2fs_default_journal_size(&def_j_blocks, &def_fc_blocks, fs);
+	if (ret) {
 		fputs(_("\nFilesystem too small for a journal\n"), stderr);
-		return 0;
+		return;
 	}
 
-	if (size > 0) {
-		j_blocks = size * 1024 / (fs->blocksize	/ 1024);
-		if (j_blocks < 1024 || j_blocks > 10240000) {
-			fprintf(stderr, _("\nThe requested journal "
+	*j_blocks = def_j_blocks;
+	*fc_blocks = def_fc_blocks;
+
+	if (requested_j_size > 0 ||
+		(ext2fs_has_feature_fast_commit(fs->super) && requested_fc_size > 0)) {
+		*j_blocks = requested_j_size > 0 ?
+			jsize_to_blks(fs, requested_j_size) : def_j_blocks;
+
+		*fc_blocks = 0;
+		if (ext2fs_has_feature_fast_commit(fs->super))
+			*fc_blocks = requested_fc_size > 0 ?
+				fcsize_to_blks(fs, requested_fc_size) : def_fc_blocks;
+		total_blocks = *j_blocks + *fc_blocks;
+		if (total_blocks < 1024 || total_blocks > 10240000) {
+			fprintf(stderr, _("\nThe total requested journal "
 				"size is %d blocks; it must be\n"
 				"between 1024 and 10240000 blocks.  "
 				"Aborting.\n"),
-				j_blocks);
+				total_blocks);
 			exit(1);
 		}
-		if ((unsigned) j_blocks > ext2fs_free_blocks_count(fs->super) / 2) {
-			fputs(_("\nJournal size too big for filesystem.\n"),
+		if ((unsigned int) total_blocks > ext2fs_free_blocks_count(fs->super) / 2) {
+			fputs(_("\nTotal journal size too big for filesystem.\n"),
 			      stderr);
 			exit(1);
 		}
 	}
-	return j_blocks;
 }
 
 void print_check_message(int mnt, unsigned int check)
diff --git a/misc/util.h b/misc/util.h
index 49b4b9c1..cee812b4 100644
--- a/misc/util.h
+++ b/misc/util.h
@@ -11,6 +11,7 @@ 
  */
 
 extern int	 journal_size;
+extern int	 journal_fc_size;
 extern int	 journal_flags;
 extern char	*journal_device;
 extern char	*journal_location_string;
@@ -22,6 +23,7 @@  extern char *get_progname(char *argv_zero);
 extern void proceed_question(int delay);
 extern void parse_journal_opts(const char *opts);
 extern void check_mount(const char *device, int force, const char *type);
-extern unsigned int figure_journal_size(int size, ext2_filsys fs);
+extern void figure_journal_size(blk_t *j_blocks, blk_t *fc_blocks,
+		int requested_j_size, int requested_fc_size, ext2_filsys fs);
 extern void print_check_message(int, unsigned int);
 extern void dump_mmp_msg(struct mmp_struct *mmp, const char *msg);