ChangeLog, Makefile.in, dumpe2fs.c, jfs_user.h, mke2fs.c, tune2fs.c:
  tune2fs.c: Changed the external journal code so that it simply adds a
  	filesystem to a journal; the journal must have bene created via
  	"mke2fs -O journal_dev /dev/XXX".
  mke2fs.c: Add support for creating an external journal device by using
  	the command "mke2fs -O journal_dev /dev/XXX".  Also changed the
  	external journal code so -j device=/dev/XXX it simply adds a
  	filesystem to that journal; the journal must have been created via
  	separate step.
  dumpe2fs.c (print_journal_information): Add support for dumping
  	information about an external journal device.

diff --git a/misc/ChangeLog b/misc/ChangeLog
index 8d85d4f..a36582f 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,3 +1,18 @@
+2001-01-15  Theodore Ts'o  <tytso@valinux.com>
+
+	* tune2fs.c: Changed the external journal code so that it simply
+		adds a filesystem to a journal; the journal must have bene
+		created via "mke2fs -O journal_dev /dev/XXX".
+
+	* mke2fs.c: Add support for creating an external journal device by
+		using the command "mke2fs -O journal_dev /dev/XXX".  Also
+		changed the external journal code so -j device=/dev/XXX it
+		simply adds a filesystem to that journal; the journal must
+		have been created via separate step.
+
+	* dumpe2fs.c (print_journal_information): Add support for dumping
+		information about an external journal device.
+
 2001-01-14  Theodore Ts'o  <tytso@valinux.com>
 
 	* mke2fs.c: Add new filesystem types, largefile and largefile4,
diff --git a/misc/Makefile.in b/misc/Makefile.in
index bc76132..02d1d16 100644
--- a/misc/Makefile.in
+++ b/misc/Makefile.in
@@ -87,8 +87,8 @@
 uuidgen: $(UUIDGEN_OBJS) $(DEPLIBUUID)
 	$(CC) $(ALL_LDFLAGS) -o uuidgen $(UUIDGEN_OBJS) $(LIBUUID)
 
-dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS_E2P)
-	$(CC) $(ALL_LDFLAGS) -o dumpe2fs $(DUMPE2FS_OBJS) $(LIBS_E2P)
+dumpe2fs: $(DUMPE2FS_OBJS) $(DEPLIBS_E2P) $(DEPLIBUUID)
+	$(CC) $(ALL_LDFLAGS) -o dumpe2fs $(DUMPE2FS_OBJS) $(LIBS_E2P) $(LIBUUID)
 
 fsck: $(FSCK_OBJS)
 	$(CC) $(ALL_LDFLAGS) -o fsck $(FSCK_OBJS) $(LIBS)
diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c
index 17bf4c1..53ef32a 100644
--- a/misc/dumpe2fs.c
+++ b/misc/dumpe2fs.c
@@ -36,6 +36,7 @@
 
 #include "ext2fs/ext2fs.h"
 #include "e2p/e2p.h"
+#include "jfs_user.h"
 
 #include "../version.h"
 #include "nls-enable.h"
@@ -207,6 +208,46 @@
 	return (*cp == 1);
 }
 
+static void print_journal_information(ext2_filsys fs)
+{
+	errcode_t	retval;
+	char		buf[1024];
+	char		str[80];
+	int		i;
+	journal_superblock_t	*jsb;
+
+	/* Get the journal superblock */
+	if ((retval = io_channel_read_blk(fs->io, 1, -1024, buf))) {
+		com_err(program_name, retval,
+			_("while reading journal superblock"));
+		exit(1);
+	}
+	jsb = (journal_superblock_t *) buf;
+	if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
+	    (jsb->s_header.h_blocktype !=
+	     (unsigned) ntohl(JFS_SUPERBLOCK_V2))) {
+		com_err(program_name, 0,
+			_("Couldn't find journal superblock magic numbers"));
+		exit(1);
+	}
+
+	fputs("\n", stdout);
+	printf("Journal block size:       %d\n", ntohl(jsb->s_blocksize));
+	printf("Journal length:           %d\n", ntohl(jsb->s_maxlen));
+	printf("Journal first block:      %d\n", ntohl(jsb->s_first));
+	printf("Journal sequence:         0x%08x\n", ntohl(jsb->s_sequence));
+	printf("Journal start:            %d\n", ntohl(jsb->s_start));
+	printf("Journal number of users:  %d\n", ntohl(jsb->s_nr_users));
+	for (i=0; i < ntohl(jsb->s_nr_users); i++) {
+		if (i)
+			printf("                          ");
+		else
+			printf("Journal users:            ");
+		uuid_unparse(&jsb->s_users[i*16], str);
+		printf("%s\n", str);
+	}
+}
+
 int main (int argc, char ** argv)
 {
 	errcode_t	retval;
@@ -215,6 +256,7 @@
 	int		use_superblock = 0;
 	int		use_blocksize = 0;
 	int		force = 0;
+	int		flags;
 	int		header_only = 0;
 	int		big_endian;
 	int		c;
@@ -267,9 +309,11 @@
 	device_name = argv[optind++];
 	if (use_superblock && !use_blocksize)
 		use_blocksize = 1024;
-	retval = ext2fs_open (device_name, force ? EXT2_FLAG_FORCE : 0,
-			      use_superblock, use_blocksize,
-			      unix_io_manager, &fs);
+	flags = EXT2_FLAG_JOURNAL_DEV_OK;
+	if (force)
+		flags |= EXT2_FLAG_FORCE;
+	retval = ext2fs_open (device_name, flags, use_superblock,
+			      use_blocksize, unix_io_manager, &fs);
 	if (retval) {
 		com_err (program_name, retval, _("while trying to open %s"),
 			 device_name);
@@ -285,6 +329,12 @@
 		if (big_endian)
 			printf(_("Note: This is a byte-swapped filesystem\n"));
 		list_super (fs->super);
+		if (fs->super->s_feature_incompat &
+		      EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+			print_journal_information(fs);
+			ext2fs_close(fs);
+			exit(0);
+		}
 		list_bad_blocks (fs);
 		if (header_only) {
 			ext2fs_close (fs);
diff --git a/misc/jfs_user.h b/misc/jfs_user.h
new file mode 100644
index 0000000..17a82c7
--- /dev/null
+++ b/misc/jfs_user.h
@@ -0,0 +1,9 @@
+#ifndef _JFS_USER_H
+#define _JFS_USER_H
+
+typedef unsigned short kdev_t;
+
+#include <linux/jfs.h>
+
+
+#endif /* _JFS_USER_H */
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index b72ea1b..a52d632 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -67,22 +67,23 @@
 const char * device_name /* = NULL */;
 
 /* Command line options */
-int	cflag /* = 0 */ ;
-int	verbose /* = 0 */ ;
-int	quiet /* = 0 */ ;
-int	super_only /* = 0 */ ;
-int	force /* = 0 */ ;
-int	noaction /* = 0 */ ;
-int	journal_size /* = 0 */ ;
-int	journal_flags /* = 0 */ ;
-char	*bad_blocks_filename /* = 0 */ ;
-__u32	fs_stride /* = 0 */ ;
+int	cflag;
+int	verbose;
+int	quiet;
+int	super_only;
+int	force;
+int	noaction;
+int	journal_size;
+int	journal_flags;
+char	*bad_blocks_filename;
+__u32	fs_stride;
 
 struct ext2_super_block param;
-char *creator_os /* = NULL */ ;
-char *volume_label /* = NULL */ ;
-char *mount_dir /* = NULL */ ;
-char *journal_device /* = NULL */ ;
+char *creator_os;
+char *volume_label;
+char *mount_dir;
+char *journal_device;
+int sync_kludge;	/* Set using the MKE2FS_SYNC env. option */
 
 static void usage(void)
 {
@@ -307,60 +308,143 @@
 	badblocks_list_iterate_end(bb_iter);
 }
 
-static void write_inode_tables(ext2_filsys fs)
+/*
+ * These functions implement a generalized progress meter.
+ */
+struct progress_struct {
+	char		format[20];
+	char		backup[80];
+	__u32		max;
+};
+
+static void progress_init(struct progress_struct *progress,
+			  char *label,__u32 max)
 {
-	errcode_t	retval;
-	blk_t		blk;
-	int		i, j, num, count;
-	char		*buf;
-	char		format[20], backup[80];
-	int		sync_kludge = 0;
-	char		*mke2fs_sync;
+	int	i;
 
-	mke2fs_sync = getenv("MKE2FS_SYNC");
-	if (mke2fs_sync)
-		sync_kludge = atoi(mke2fs_sync);
-
-	buf = malloc(fs->blocksize * STRIDE_LENGTH);
-	if (!buf) {
-		com_err("malloc", ENOMEM,
-			_("while allocating zeroizing buffer"));
-		exit(1);
-	}
-	memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+	memset(progress, 0, sizeof(struct progress_struct));
+	if (quiet)
+		return;
 
 	/*
 	 * Figure out how many digits we need
 	 */
-	i = int_log10(fs->group_desc_count);
-	sprintf(format, "%%%dd/%%%dld", i, i);
-	memset(backup, '\b', sizeof(backup)-1);
-	backup[sizeof(backup)-1] = 0;
-	if ((2*i)+1 < sizeof(backup))
-		backup[(2*i)+1] = 0;
+	i = int_log10(max);
+	sprintf(progress->format, "%%%dd/%%%dld", i, i);
+	memset(progress->backup, '\b', sizeof(progress->backup)-1);
+	progress->backup[sizeof(progress->backup)-1] = 0;
+	if ((2*i)+1 < sizeof(progress->backup))
+		progress->backup[(2*i)+1] = 0;
+	progress->max = max;
 
-	if (!quiet)
-		printf(_("Writing inode tables: "));
+	fputs(label, stdout);
+	fflush(stdout);
+}
+
+static void progress_update(struct progress_struct *progress, __u32 val)
+{
+	if (progress->format[0] == 0)
+		return;
+	printf(progress->format, val, progress->max);
+	fputs(progress->backup, stdout);
+}
+
+static void progress_close(struct progress_struct *progress)
+{
+	if (progress->format[0] == 0)
+		return;
+	fputs(_("done                            \n"), stdout);
+}
+
+
+/*
+ * Helper function which zeros out _num_ blocks starting at _blk_.  In
+ * case of an error, the details of the error is returned via _ret_blk_
+ * and _ret_count_ if they are non-NULL pointers.  Returns 0 on
+ * success, and an error code on an error.
+ *
+ * As a special case, if the first argument is NULL, then it will
+ * attempt to free the static zeroizing buffer.  (This is to keep
+ * programs that check for memory leaks happy.)
+ */
+static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num,
+			     struct progress_struct *progress,
+			     blk_t *ret_blk, int *ret_count)
+{
+	int		j, count, next_update, next_update_incr;
+	static char	*buf;
+	errcode_t	retval;
+
+	/* If fs is null, clean up the static buffer and return */
+	if (!fs) {
+		if (buf) {
+			free(buf);
+			buf = 0;
+		}
+		return 0;
+	}
+	/* Allocate the zeroizing buffer if necessary */
+	if (!buf) {
+		buf = malloc(fs->blocksize * STRIDE_LENGTH);
+		if (!buf) {
+			com_err("malloc", ENOMEM,
+				_("while allocating zeroizing buffer"));
+			exit(1);
+		}
+		memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
+	}
+	/* OK, do the write loop */
+	next_update = 0;
+	next_update_incr = num / 100;
+	if (next_update_incr < 1)
+		next_update_incr = 1;
+	for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
+		if (num-j > STRIDE_LENGTH)
+			count = STRIDE_LENGTH;
+		else
+			count = num - j;
+		retval = io_channel_write_blk(fs->io, blk, count, buf);
+		if (retval) {
+			if (ret_count)
+				*ret_count = count;
+			if (ret_blk)
+				*ret_blk = blk;
+			return retval;
+		}
+		if (progress && j > next_update) {
+			next_update += num / 100;
+			progress_update(progress, blk);
+		}
+	}
+	return 0;
+}	
+
+static void write_inode_tables(ext2_filsys fs)
+{
+	errcode_t	retval;
+	blk_t		blk;
+	int		i, num;
+	struct progress_struct progress;
+
+	if (quiet)
+		memset(&progress, 0, sizeof(progress));
+	else
+		progress_init(&progress, _("Writing inode tables: "),
+			      fs->group_desc_count);
+
 	for (i = 0; i < fs->group_desc_count; i++) {
-		if (!quiet)
-			printf(format, i, fs->group_desc_count);
+		progress_update(&progress, i);
 		
 		blk = fs->group_desc[i].bg_inode_table;
 		num = fs->inode_blocks_per_group;
-		
-		for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) {
-			if (num-j > STRIDE_LENGTH)
-				count = STRIDE_LENGTH;
-			else
-				count = num - j;
-			retval = io_channel_write_blk(fs->io, blk, count, buf);
-			if (retval)
-				printf(_("Warning: could not write %d blocks "
-				       "in inode table starting at %d: %s\n"),
-				       count, blk, error_message(retval));
+
+		retval = zero_blocks(fs, blk, num, 0, &blk, &num);
+		if (retval) {
+			printf(_("\nCould not write %d blocks "
+				 "in inode table starting at %d: %s\n"),
+			       num, blk, error_message(retval));
+			exit(1);
 		}
-		if (!quiet) 
-			fputs(backup, stdout);
 		if (sync_kludge) {
 			if (sync_kludge == 1)
 				sync();
@@ -368,9 +452,8 @@
 				sync();
 		}
 	}
-	free(buf);
-	if (!quiet)
-		fputs(_("done                            \n"), stdout);
+	zero_blocks(0, 0, 0, 0, 0, 0);
+	progress_close(&progress);
 }
 
 static void create_root_dir(ext2_filsys fs)
@@ -480,7 +563,45 @@
 		printf(_("Warning: could not erase sector %d: %s\n"), sect,
 		       error_message(retval));
 }
-	
+
+static void create_journal_dev(ext2_filsys fs)
+{
+	struct progress_struct progress;
+	errcode_t		retval;
+	char			*buf;
+
+	if (quiet)
+		memset(&progress, 0, sizeof(progress));
+	else
+		progress_init(&progress, _("Zeroing journal device: "),
+			      fs->super->s_blocks_count);
+
+#if 0
+	retval = zero_blocks(fs, 0, fs->super->s_blocks_count,
+			     &progress, &blk, &count);
+	if (retval) {
+		com_err("create_journal_dev", retval,
+			"while zeroing journal device (block %u, count %d",
+			blk, count);
+		exit(1);
+	}
+	zero_blocks(0, 0, 0, 0, 0);
+#endif
+	retval = ext2fs_create_journal_superblock(fs,
+				  fs->super->s_blocks_count, 0, &buf);
+	if (retval) {
+		com_err("create_journal_dev", retval,
+			_("while initialization journal superblock"));
+		exit(1);
+	}
+	retval = io_channel_write_blk(fs->io, 1, 1, buf);
+	if (retval) {
+		com_err("create_journal_dev", retval,
+			_("while writing journal superblock"));
+		exit(1);
+	}
+	progress_close(&progress);
+}
 
 static void show_stats(ext2_filsys fs)
 {
@@ -622,7 +743,8 @@
 
 static __u32 ok_features[3] = {
 	0,					/* Compat */
-	EXT2_FEATURE_INCOMPAT_FILETYPE,		/* Incompat */
+	EXT2_FEATURE_INCOMPAT_FILETYPE|		/* Incompat */
+		EXT3_FEATURE_INCOMPAT_JOURNAL_DEV,
 	EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER	/* R/O compat */
 };
 
@@ -670,6 +792,10 @@
 	} else
 		putenv (PATH_SET);
 
+	tmp = getenv("MKE2FS_SYNC");
+	if (tmp)
+		sync_kludge = atoi(tmp);
+	
 	setbuf(stdout, NULL);
 	setbuf(stderr, NULL);
 	initialize_ext2_error_table();
@@ -1009,6 +1135,13 @@
 	if (noaction)
 		exit(0);
 
+	if (fs->super->s_feature_incompat &
+	    EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
+		create_journal_dev(fs);
+		ext2fs_close(fs);
+		exit(0);
+	}
+
 	if (bad_blocks_filename)
 		read_bb_file(fs, &bb_list, bad_blocks_filename);
 	if (cflag)
@@ -1037,25 +1170,35 @@
 	}
 
 	journal_blocks = journal_size * 1024 / (fs->blocksize 	/ 1024);
-	if (journal_device) { 
+	if (journal_device) {
+		ext2_filsys	jfs;
+		
 		if (!force)
 			check_plausibility(journal_device); 
 		check_mount(journal_device, force, _("journal"));
 
+		retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
+				     EXT2_FLAG_JOURNAL_DEV_OK, 0,
+				     fs->blocksize, unix_io_manager, &jfs);
+		if (retval) {
+			com_err(program_name, retval,
+				_("while trying to open journal device %s\n"),
+				journal_device);
+			exit(1);
+		}
 		if (!quiet)
 			printf(_("Creating journal on device %s: "), 
 			       journal_device);
-		retval = ext2fs_add_journal_device(fs, journal_device,
-						   journal_blocks,
-						   journal_flags);
-		if(retval) { 
+		retval = ext2fs_add_journal_device(fs, jfs);
+		if(retval) {
 			com_err (program_name, retval, 
-				 _("while trying to create journal on device %s"), 
+				 _("while trying to add journal to device %s"), 
 				 journal_device);
 			exit(1);
 		}
 		if (!quiet)
 			printf(_("done\n"));
+		ext2fs_close(jfs);
 	} else if (journal_size) {
 		if (!quiet)
 			printf(_("Creating journal (%d blocks): "),
diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 81b06e0..ebdc6ce 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -192,6 +192,7 @@
 {
 	unsigned long journal_blocks;
 	errcode_t	retval;
+	ext2_filsys	jfs;
 
 	if (fs->super->s_feature_compat &
 	    EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
@@ -203,12 +204,20 @@
 	if (journal_device) {
 		check_plausibility(journal_device);
 		check_mount(journal_device, 0, _("journal"));
+		retval = ext2fs_open(journal_device, EXT2_FLAG_RW|
+				     EXT2_FLAG_JOURNAL_DEV_OK, 0,
+				     fs->blocksize, unix_io_manager, &jfs);
+		if (retval) {
+			com_err(program_name, retval,
+				_("while trying to open journal device %s\n"),
+				journal_device);
+			exit(1);
+		}
 		printf(_("Creating journal on device %s: "),
 		       journal_device);
 		fflush(stdout);
-		retval = ext2fs_add_journal_device(fs, journal_device,
-						   journal_blocks,
-						   journal_flags);
+		
+		retval = ext2fs_add_journal_device(fs, jfs);
 		if (retval) {
 			com_err (program_name, retval,
 				 _("while trying to create journal on device %s"),
@@ -216,6 +225,7 @@
 			exit(1);
 		}
 		printf(_("done\n"));
+		ext2fs_close(jfs);
 	} else if (journal_size) {
 		printf(_("Creating journal inode: "));
 		fflush(stdout);