--- /dev/null
+Index: linux-stage/include/linux/ext3_fs.h
+===================================================================
+--- linux-stage.orig/include/linux/ext3_fs.h
++++ linux-stage/include/linux/ext3_fs.h
+@@ -921,6 +921,7 @@ extern unsigned ext3_list_backups(struct
+ unsigned *five, unsigned *seven);
+
+ /* super.c */
++extern void ext3_commit_super (struct super_block *, struct ext3_super_block *, int);
+ extern void ext3_error (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+ extern void __ext3_std_error (struct super_block *, const char *, int);
+Index: linux-stage/fs/ext3/super.c
+===================================================================
+--- linux-stage.orig/fs/ext3/super.c
++++ linux-stage/fs/ext3/super.c
+@@ -47,9 +47,6 @@ static int ext3_load_journal(struct supe
+ unsigned long journal_devnum);
+ static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
+ int);
+-static void ext3_commit_super (struct super_block * sb,
+- struct ext3_super_block * es,
+- int sync);
+ static void ext3_mark_recovery_complete(struct super_block * sb,
+ struct ext3_super_block * es);
+ static void ext3_clear_journal_err(struct super_block * sb,
+@@ -2175,7 +2172,7 @@ static int ext3_create_journal(struct su
+ return 0;
+ }
+
+-static void ext3_commit_super (struct super_block * sb,
++void ext3_commit_super (struct super_block * sb,
+ struct ext3_super_block * es,
+ int sync)
+ {
+Index: linux-stage/fs/ext3/namei.c
+===================================================================
+--- linux-stage.orig/fs/ext3/namei.c
++++ linux-stage/fs/ext3/namei.c
+@@ -1591,7 +1591,7 @@ static int ext3_delete_entry (handle_t *
+ struct buffer_head * bh)
+ {
+ struct ext3_dir_entry_2 * de, * pde;
+- int i;
++ int i, err;
+
+ i = 0;
+ pde = NULL;
+@@ -1601,7 +1601,9 @@ static int ext3_delete_entry (handle_t *
+ return -EIO;
+ if (de == de_del) {
+ BUFFER_TRACE(bh, "get_write_access");
+- ext3_journal_get_write_access(handle, bh);
++ err = ext3_journal_get_write_access(handle, bh);
++ if (err)
++ return err;
+ if (pde)
+ pde->rec_len =
+ cpu_to_le16(le16_to_cpu(pde->rec_len) +
+Index: linux-stage/fs/ext3/inode.c
+===================================================================
+--- linux-stage.orig/fs/ext3/inode.c
++++ linux-stage/fs/ext3/inode.c
+@@ -1838,8 +1838,18 @@ ext3_clear_blocks(handle_t *handle, stru
+ ext3_mark_inode_dirty(handle, inode);
+ ext3_journal_test_restart(handle, inode);
+ if (bh) {
++ int err;
+ BUFFER_TRACE(bh, "retaking write access");
+- ext3_journal_get_write_access(handle, bh);
++ err = ext3_journal_get_write_access(handle, bh);
++ if (err) {
++ struct super_block *sb = inode->i_sb;
++ struct ext3_super_block *es = EXT3_SB(sb)->s_es;
++ printk (KERN_CRIT"EXT3-fs: can't continue truncate\n");
++ EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS;
++ es->s_state |= cpu_to_le16(EXT3_ERROR_FS);
++ ext3_commit_super(sb, es, 1);
++ return;
++ }
+ }
+ }
+
--- /dev/null
+Signed-off-by: Johann Lombardi <johann.lombardi@bull.net>
+
+Index: linux-2.6.9-full/fs/ext3/super.c
+===================================================================
+--- linux-2.6.9-full.orig/fs/ext3/super.c 2006-05-20 01:14:14.000000000 +0400
++++ linux-2.6.9-full/fs/ext3/super.c 2006-05-20 01:17:10.000000000 +0400
+@@ -39,7 +39,8 @@
+ #include "xattr.h"
+ #include "acl.h"
+
+-static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
++static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
++ unsigned long journal_devnum);
+ static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
+ int);
+ static void ext3_commit_super (struct super_block * sb,
+@@ -591,7 +592,7 @@ enum {
+ Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+ Opt_reservation, Opt_noreservation, Opt_noload,
+- Opt_commit, Opt_journal_update, Opt_journal_inum,
++ Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
+ Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+ Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
+ Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
+@@ -630,6 +631,7 @@ static match_table_t tokens = {
+ {Opt_commit, "commit=%u"},
+ {Opt_journal_update, "journal=update"},
+ {Opt_journal_inum, "journal=%u"},
++ {Opt_journal_dev, "journal_dev=%u"},
+ {Opt_abort, "abort"},
+ {Opt_data_journal, "data=journal"},
+ {Opt_data_ordered, "data=ordered"},
+@@ -675,8 +677,9 @@ static unsigned long get_sb_block(void *
+ return sb_block;
+ }
+
+-static int parse_options (char * options, struct super_block *sb,
+- unsigned long * inum, unsigned long *n_blocks_count, int is_remount)
++static int parse_options (char *options, struct super_block *sb,
++ unsigned long *inum, unsigned long *journal_devnum,
++ unsigned long *n_blocks_count, int is_remount)
+ {
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+ char * p;
+@@ -816,6 +819,16 @@ static int parse_options (char * options
+ return 0;
+ *inum = option;
+ break;
++ case Opt_journal_dev:
++ if (is_remount) {
++ printk(KERN_ERR "EXT3-fs: cannot specify "
++ "journal on remount\n");
++ return 0;
++ }
++ if (match_int(&args[0], &option))
++ return 0;
++ *journal_devnum = option;
++ break;
+ case Opt_noload:
+ set_opt (sbi->s_mount_opt, NOLOAD);
+ break;
+@@ -1278,6 +1291,7 @@ static int ext3_fill_super (struct super
+ unsigned long logic_sb_block;
+ unsigned long offset = 0;
+ unsigned long journal_inum = 0;
++ unsigned long journal_devnum = 0;
+ unsigned long def_mount_opts;
+ struct inode *root;
+ int blocksize;
+@@ -1361,7 +1375,8 @@ static int ext3_fill_super (struct super
+
+ set_opt(sbi->s_mount_opt, RESERVATION);
+
+- if (!parse_options ((char *) data, sb, &journal_inum, NULL, 0))
++ if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
++ NULL, 0))
+ goto failed_mount;
+
+ set_sb_time_gran(sb, 1000000000U);
+@@ -1567,7 +1582,7 @@ static int ext3_fill_super (struct super
+ */
+ if (!test_opt(sb, NOLOAD) &&
+ EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+- if (ext3_load_journal(sb, es))
++ if (ext3_load_journal(sb, es, journal_devnum))
+ goto failed_mount2;
+ } else if (journal_inum) {
+ if (ext3_create_journal(sb, es, journal_inum))
+@@ -1831,15 +1846,24 @@ out_bdev:
+ return NULL;
+ }
+
+-static int ext3_load_journal(struct super_block * sb,
+- struct ext3_super_block * es)
++static int ext3_load_journal(struct super_block *sb,
++ struct ext3_super_block *es,
++ unsigned long journal_devnum)
+ {
+ journal_t *journal;
+ int journal_inum = le32_to_cpu(es->s_journal_inum);
+- dev_t journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
++ dev_t journal_dev;
+ int err = 0;
+ int really_read_only;
+
++ if (journal_devnum &&
++ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
++ printk(KERN_INFO "EXT3-fs: external journal device major/minor "
++ "numbers have changed\n");
++ journal_dev = new_decode_dev(journal_devnum);
++ } else
++ journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
++
+ really_read_only = bdev_read_only(sb->s_bdev);
+
+ /*
+@@ -1898,6 +1922,16 @@ static int ext3_load_journal(struct supe
+
+ EXT3_SB(sb)->s_journal = journal;
+ ext3_clear_journal_err(sb, es);
++
++ if (journal_devnum &&
++ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
++ es->s_journal_dev = cpu_to_le32(journal_devnum);
++ sb->s_dirt = 1;
++
++ /* Make sure we flush the recovery flag to disk. */
++ ext3_commit_super(sb, es, 1);
++ }
++
+ return 0;
+ }
+
+@@ -2105,13 +2139,13 @@ int ext3_remount (struct super_block * s
+ {
+ struct ext3_super_block * es;
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+- unsigned long tmp;
++ unsigned long tmp1, tmp2;
+ unsigned long n_blocks_count = 0;
+
+ /*
+ * Allow the "check" option to be passed as a remount option.
+ */
+- if (!parse_options(data, sb, &tmp, &n_blocks_count, 1))
++ if (!parse_options(data, sb, &tmp1, &tmp2, &n_blocks_count, 1))
+ return -EINVAL;
+
+ if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
--- /dev/null
+Index: linux-2.6.18.8/fs/ext3/super.c
+===================================================================
+--- linux-2.6.18.8.orig/fs/ext3/super.c 2007-07-20 16:51:14.000000000 +0200
++++ linux-2.6.18.8/fs/ext3/super.c 2007-07-20 16:54:17.000000000 +0200
+@@ -2572,18 +2572,18 @@ static int ext3_statfs (struct dentry *
+ struct super_block *sb = dentry->d_sb;
+ struct ext3_sb_info *sbi = EXT3_SB(sb);
+ struct ext3_super_block *es = sbi->s_es;
+- ext3_fsblk_t overhead;
+- int i;
+
+- if (test_opt (sb, MINIX_DF))
+- overhead = 0;
+- else {
+- unsigned long ngroups;
+- ngroups = EXT3_SB(sb)->s_groups_count;
++ if (test_opt(sb, MINIX_DF)) {
++ sbi->s_overhead_last = 0;
++ } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
++ unsigned long ngroups = sbi->s_groups_count, i;
++ ext3_fsblk_t overhead = 0;
+ smp_rmb();
+
+ /*
+- * Compute the overhead (FS structures)
++ * Compute the overhead (FS structures). This is constant
++ * for a given filesystem unless the number of block groups
++ * changes so we cache the previous value until it does.
+ */
+
+ /*
+@@ -2605,18 +2605,23 @@ static int ext3_statfs (struct dentry *
+ * Every block group has an inode bitmap, a block
+ * bitmap, and an inode table.
+ */
+- overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group));
++ overhead += ngroups * (2 + sbi->s_itb_per_group);
++ sbi->s_overhead_last = overhead;
++ smp_wmb();
++ sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
+ }
+
+ buf->f_type = EXT3_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+- buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead;
++ buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last;
+ buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
++ es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
+ buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count);
+ if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count))
+ buf->f_bavail = 0;
+ buf->f_files = le32_to_cpu(es->s_inodes_count);
+ buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
++ es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
+ buf->f_namelen = EXT3_NAME_LEN;
+ return 0;
+ }
+Index: linux-2.6.18.8/include/linux/ext3_fs_sb.h
+===================================================================
+--- linux-2.6.18.8.orig/include/linux/ext3_fs_sb.h 2007-07-20 16:51:23.000000000 +0200
++++ linux-2.6.18.8/include/linux/ext3_fs_sb.h 2007-07-20 16:51:43.000000000 +0200
+@@ -45,6 +45,8 @@ struct ext3_sb_info {
+ unsigned long s_gdb_count; /* Number of group descriptor blocks */
+ unsigned long s_desc_per_block; /* Number of group descriptors per block */
+ unsigned long s_groups_count; /* Number of groups in the fs */
++ unsigned long s_overhead_last; /* Last calculated overhead */
++ unsigned long s_blocks_last; /* Last seen block count */
+ struct buffer_head * s_sbh; /* Buffer containing the super block */
+ struct ext3_super_block * s_es; /* Pointer to the super block in the buffer */
+ struct buffer_head ** s_group_desc;