fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / fs / ext3 / super.c
index 690f3f6..8353d33 100644 (file)
@@ -16,7 +16,6 @@
  *        David S. Miller (davem@caip.rutgers.edu), 1995
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/string.h>
 #include <linux/fs.h>
 #include <linux/mount.h>
 #include <linux/namei.h>
 #include <linux/quotaops.h>
+#include <linux/seq_file.h>
+
 #include <asm/uaccess.h>
+
 #include "xattr.h"
 #include "acl.h"
+#include "namei.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);
+                              unsigned int);
 static void ext3_commit_super (struct super_block * sb,
                               struct ext3_super_block * es,
                               int sync);
@@ -53,18 +57,18 @@ static int ext3_sync_fs(struct super_block *sb, int wait);
 static const char *ext3_decode_error(struct super_block * sb, int errno,
                                     char nbuf[16]);
 static int ext3_remount (struct super_block * sb, int * flags, char * data);
-static int ext3_statfs (struct super_block * sb, struct kstatfs * buf);
+static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf);
 static void ext3_unlockfs(struct super_block *sb);
 static void ext3_write_super (struct super_block * sb);
 static void ext3_write_super_lockfs(struct super_block *sb);
 
-/* 
+/*
  * Wrappers for journal_start/end.
  *
  * The only special thing we need to do here is to make sure that all
  * journal_end calls result in the superblock being marked dirty, so
  * that sync() will call the filesystem's write_super callback if
- * appropriate. 
+ * appropriate.
  */
 handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
 {
@@ -86,11 +90,11 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
        return journal_start(journal, nblocks);
 }
 
-/* 
+/*
  * The only special thing we need to do here is to make sure that all
  * journal_stop calls result in the superblock being marked dirty, so
  * that sync() will call the filesystem's write_super callback if
- * appropriate. 
+ * appropriate.
  */
 int __ext3_journal_stop(const char *where, handle_t *handle)
 {
@@ -155,20 +159,21 @@ static void ext3_handle_error(struct super_block *sb)
        if (sb->s_flags & MS_RDONLY)
                return;
 
-       if (test_opt (sb, ERRORS_RO)) {
-               printk (KERN_CRIT "Remounting filesystem read-only\n");
-               sb->s_flags |= MS_RDONLY;
-       } else {
+       if (!test_opt (sb, ERRORS_CONT)) {
                journal_t *journal = EXT3_SB(sb)->s_journal;
 
                EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT;
                if (journal)
                        journal_abort(journal, -EIO);
        }
+       if (test_opt (sb, ERRORS_RO)) {
+               printk (KERN_CRIT "Remounting filesystem read-only\n");
+               sb->s_flags |= MS_RDONLY;
+       }
+       ext3_commit_super(sb, es, 1);
        if (test_opt(sb, ERRORS_PANIC))
                panic("EXT3-fs (device %s): panic forced after error\n",
                        sb->s_id);
-       ext3_commit_super(sb, es, 1);
 }
 
 void ext3_error (struct super_block * sb, const char * function,
@@ -225,8 +230,16 @@ void __ext3_std_error (struct super_block * sb, const char * function,
                       int errno)
 {
        char nbuf[16];
-       const char *errstr = ext3_decode_error(sb, errno, nbuf);
+       const char *errstr;
 
+       /* Special case: if the error is EROFS, and we're not already
+        * inside a transaction, then there's really no point in logging
+        * an error. */
+       if (errno == -EROFS && journal_current_handle() == NULL &&
+           (sb->s_flags & MS_RDONLY))
+               return;
+
+       errstr = ext3_decode_error(sb, errno, nbuf);
        printk (KERN_CRIT "EXT3-fs error (device %s) in %s: %s\n",
                sb->s_id, function, errstr);
 
@@ -357,16 +370,16 @@ static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi)
 {
        struct list_head *l;
 
-       printk(KERN_ERR "sb orphan head is %d\n", 
+       printk(KERN_ERR "sb orphan head is %d\n",
               le32_to_cpu(sbi->s_es->s_last_orphan));
 
        printk(KERN_ERR "sb_info orphan list:\n");
        list_for_each(l, &sbi->s_orphan) {
                struct inode *inode = orphan_list_entry(l);
                printk(KERN_ERR "  "
-                      "inode %s:%ld at %p: mode %o, nlink %d, next %d\n",
+                      "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
                       inode->i_sb->s_id, inode->i_ino, inode,
-                      inode->i_mode, inode->i_nlink, 
+                      inode->i_mode, inode->i_nlink,
                       NEXT_ORPHAN(inode));
        }
 }
@@ -395,10 +408,8 @@ static void ext3_put_super (struct super_block * sb)
        percpu_counter_destroy(&sbi->s_dirs_counter);
        brelse(sbi->s_sbh);
 #ifdef CONFIG_QUOTA
-       for (i = 0; i < MAXQUOTAS; i++) {
-               if (sbi->s_qf_names[i])
-                       kfree(sbi->s_qf_names[i]);
-       }
+       for (i = 0; i < MAXQUOTAS; i++)
+               kfree(sbi->s_qf_names[i]);
 #endif
 
        /* Debugging code just in case the in-memory inode orphan list
@@ -425,7 +436,7 @@ static void ext3_put_super (struct super_block * sb)
        return;
 }
 
-static kmem_cache_t *ext3_inode_cachep;
+static struct kmem_cache *ext3_inode_cachep;
 
 /*
  * Called inside transaction, so use GFP_NOFS
@@ -434,14 +445,14 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
 {
        struct ext3_inode_info *ei;
 
-       ei = kmem_cache_alloc(ext3_inode_cachep, SLAB_NOFS);
+       ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS);
        if (!ei)
                return NULL;
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
        ei->i_acl = EXT3_ACL_NOT_CACHED;
        ei->i_default_acl = EXT3_ACL_NOT_CACHED;
 #endif
-       ei->i_rsv_window.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
+       ei->i_block_alloc_info = NULL;
        ei->vfs_inode.i_version = 1;
        return &ei->vfs_inode;
 }
@@ -451,7 +462,7 @@ static void ext3_destroy_inode(struct inode *inode)
        kmem_cache_free(ext3_inode_cachep, EXT3_I(inode));
 }
 
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
 {
        struct ext3_inode_info *ei = (struct ext3_inode_info *) foo;
 
@@ -461,16 +472,17 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
 #ifdef CONFIG_EXT3_FS_XATTR
                init_rwsem(&ei->xattr_sem);
 #endif
-               init_MUTEX(&ei->truncate_sem);
+               mutex_init(&ei->truncate_mutex);
                inode_init_once(&ei->vfs_inode);
        }
 }
+
 static int init_inodecache(void)
 {
        ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
                                             sizeof(struct ext3_inode_info),
-                                            0, SLAB_RECLAIM_ACCOUNT,
+                                            0, (SLAB_RECLAIM_ACCOUNT|
+                                               SLAB_MEM_SPREAD),
                                             init_once, NULL);
        if (ext3_inode_cachep == NULL)
                return -ENOMEM;
@@ -479,29 +491,111 @@ static int init_inodecache(void)
 
 static void destroy_inodecache(void)
 {
-       if (kmem_cache_destroy(ext3_inode_cachep))
-               printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
+       kmem_cache_destroy(ext3_inode_cachep);
 }
 
 static void ext3_clear_inode(struct inode *inode)
 {
+       struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info;
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
-       if (EXT3_I(inode)->i_acl &&
-           EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
-               posix_acl_release(EXT3_I(inode)->i_acl);
-               EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
-       }
-       if (EXT3_I(inode)->i_default_acl &&
-           EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
-               posix_acl_release(EXT3_I(inode)->i_default_acl);
-               EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
-       }
+       if (EXT3_I(inode)->i_acl &&
+                       EXT3_I(inode)->i_acl != EXT3_ACL_NOT_CACHED) {
+               posix_acl_release(EXT3_I(inode)->i_acl);
+               EXT3_I(inode)->i_acl = EXT3_ACL_NOT_CACHED;
+       }
+       if (EXT3_I(inode)->i_default_acl &&
+                       EXT3_I(inode)->i_default_acl != EXT3_ACL_NOT_CACHED) {
+               posix_acl_release(EXT3_I(inode)->i_default_acl);
+               EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
+       }
 #endif
        ext3_discard_reservation(inode);
+       EXT3_I(inode)->i_block_alloc_info = NULL;
+       if (unlikely(rsv))
+               kfree(rsv);
 }
 
-#ifdef CONFIG_QUOTA
+static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb)
+{
+#if defined(CONFIG_QUOTA)
+       struct ext3_sb_info *sbi = EXT3_SB(sb);
+
+       if (sbi->s_jquota_fmt)
+               seq_printf(seq, ",jqfmt=%s",
+               (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
+
+       if (sbi->s_qf_names[USRQUOTA])
+               seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+       if (sbi->s_qf_names[GRPQUOTA])
+               seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+       if (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA)
+               seq_puts(seq, ",usrquota");
+
+       if (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)
+               seq_puts(seq, ",grpquota");
+#endif
+}
+
+static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+       struct super_block *sb = vfs->mnt_sb;
 
+       if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA)
+               seq_puts(seq, ",data=journal");
+       else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA)
+               seq_puts(seq, ",data=ordered");
+       else if (test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)
+               seq_puts(seq, ",data=writeback");
+
+       ext3_show_quota_options(seq, sb);
+
+       return 0;
+}
+
+
+static struct dentry *ext3_get_dentry(struct super_block *sb, void *vobjp)
+{
+       __u32 *objp = vobjp;
+       unsigned long ino = objp[0];
+       __u32 generation = objp[1];
+       struct inode *inode;
+       struct dentry *result;
+
+       if (ino < EXT3_FIRST_INO(sb) && ino != EXT3_ROOT_INO)
+               return ERR_PTR(-ESTALE);
+       if (ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count))
+               return ERR_PTR(-ESTALE);
+
+       /* iget isn't really right if the inode is currently unallocated!!
+        *
+        * ext3_read_inode will return a bad_inode if the inode had been
+        * deleted, so we should be safe.
+        *
+        * Currently we don't know the generation for parent directory, so
+        * a generation of 0 means "accept any"
+        */
+       inode = iget(sb, ino);
+       if (inode == NULL)
+               return ERR_PTR(-ENOMEM);
+       if (is_bad_inode(inode) ||
+           (generation && inode->i_generation != generation)) {
+               iput(inode);
+               return ERR_PTR(-ESTALE);
+       }
+       /* now to find a dentry.
+        * If possible, get a well-connected one
+        */
+       result = d_alloc_anon(inode);
+       if (!result) {
+               iput(inode);
+               return ERR_PTR(-ENOMEM);
+       }
+       return result;
+}
+
+#ifdef CONFIG_QUOTA
 #define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
 #define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
 
@@ -560,28 +654,30 @@ static struct super_operations ext3_sops = {
        .statfs         = ext3_statfs,
        .remount_fs     = ext3_remount,
        .clear_inode    = ext3_clear_inode,
+       .show_options   = ext3_show_options,
 #ifdef CONFIG_QUOTA
        .quota_read     = ext3_quota_read,
        .quota_write    = ext3_quota_write,
 #endif
 };
 
-struct dentry *ext3_get_parent(struct dentry *child);
 static struct export_operations ext3_export_ops = {
        .get_parent = ext3_get_parent,
+       .get_dentry = ext3_get_dentry,
 };
 
 enum {
        Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
        Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
-       Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+       Opt_nouid32, 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_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
+       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,
-       Opt_tagxid, Opt_barrier, Opt_ignore, Opt_err, Opt_resize,
+       Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
+       Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
+       Opt_grpquota, Opt_tag, Opt_notag, Opt_tagid
 };
 
 static match_table_t tokens = {
@@ -600,7 +696,6 @@ static match_table_t tokens = {
        {Opt_nouid32, "nouid32"},
        {Opt_nocheck, "nocheck"},
        {Opt_nocheck, "check=none"},
-       {Opt_check, "check"},
        {Opt_debug, "debug"},
        {Opt_oldalloc, "oldalloc"},
        {Opt_orlov, "orlov"},
@@ -611,9 +706,12 @@ static match_table_t tokens = {
        {Opt_reservation, "reservation"},
        {Opt_noreservation, "noreservation"},
        {Opt_noload, "noload"},
+       {Opt_nobh, "nobh"},
+       {Opt_bh, "bh"},
        {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"},
@@ -624,24 +722,28 @@ static match_table_t tokens = {
        {Opt_grpjquota, "grpjquota=%s"},
        {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
        {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
-       {Opt_tagxid, "tagxid"},
-       {Opt_ignore, "grpquota"},
-       {Opt_ignore, "noquota"},
-       {Opt_ignore, "quota"},
-       {Opt_ignore, "usrquota"},
+       {Opt_grpquota, "grpquota"},
+       {Opt_noquota, "noquota"},
+       {Opt_quota, "quota"},
+       {Opt_usrquota, "usrquota"},
        {Opt_barrier, "barrier=%u"},
+       {Opt_tag, "tag"},
+       {Opt_notag, "notag"},
+       {Opt_tagid, "tagid=%u"},
+       {Opt_tag, "tagxid"},
        {Opt_err, NULL},
        {Opt_resize, "resize"},
 };
 
-static unsigned long get_sb_block(void **data)
+static ext3_fsblk_t get_sb_block(void **data)
 {
-       unsigned long   sb_block;
-       char            *options = (char *) *data;
+       ext3_fsblk_t    sb_block;
+       char            *options = (char *) *data;
 
        if (!options || strncmp(options, "sb=", 3) != 0)
                return 1;       /* Default location */
        options += 3;
+       /*todo: use simple_strtoll with >32bit ext3 */
        sb_block = simple_strtoul(options, &options, 0);
        if (*options && *options != ',') {
                printk("EXT3-fs: Invalid sb specification: %s\n",
@@ -654,8 +756,9 @@ static unsigned long get_sb_block(void **data)
        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 int *inum, unsigned long *journal_devnum,
+                         ext3_fsblk_t *n_blocks_count, int is_remount)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
        char * p;
@@ -721,24 +824,20 @@ static int parse_options (char * options, struct super_block *sb,
                case Opt_nouid32:
                        set_opt (sbi->s_mount_opt, NO_UID32);
                        break;
-#ifndef CONFIG_INOXID_NONE
-               case Opt_tagxid:
-                       if (is_remount) {
-                               printk(KERN_ERR "EXT3-fs: cannot specify "
-                                      "tagxid on remount\n");
-                               return 0;
-                       }
-                       set_opt (sbi->s_mount_opt, TAG_XID);
+#ifndef CONFIG_TAGGING_NONE
+               case Opt_tag:
+                       set_opt (sbi->s_mount_opt, TAGGED);
+                       break;
+               case Opt_notag:
+                       clear_opt (sbi->s_mount_opt, TAGGED);
                        break;
 #endif
-               case Opt_check:
-#ifdef CONFIG_EXT3_CHECK
-                       set_opt (sbi->s_mount_opt, CHECK);
-#else
-                       printk(KERN_ERR
-                              "EXT3 Check option not supported\n");
-#endif
+#ifdef CONFIG_PROPAGATE
+               case Opt_tagid:
+                       /* use args[0] */
+                       set_opt (sbi->s_mount_opt, TAGGED);
                        break;
+#endif
                case Opt_nocheck:
                        clear_opt (sbi->s_mount_opt, CHECK);
                        break;
@@ -806,6 +905,16 @@ static int parse_options (char * options, struct super_block *sb,
                                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;
@@ -877,6 +986,7 @@ set_qf_name:
                                sbi->s_qf_names[qtype] = NULL;
                                return 0;
                        }
+                       set_opt(sbi->s_mount_opt, QUOTA);
                        break;
                case Opt_offusrjquota:
                        qtype = USRQUOTA;
@@ -890,10 +1000,11 @@ clear_qf_name:
                                        "quota turned on.\n");
                                return 0;
                        }
-                       if (sbi->s_qf_names[qtype]) {
-                               kfree(sbi->s_qf_names[qtype]);
-                               sbi->s_qf_names[qtype] = NULL;
-                       }
+                       /*
+                        * The space will be released later when all options
+                        * are confirmed to be correct
+                        */
+                       sbi->s_qf_names[qtype] = NULL;
                        break;
                case Opt_jqfmt_vfsold:
                        sbi->s_jquota_fmt = QFMT_VFS_OLD;
@@ -901,7 +1012,29 @@ clear_qf_name:
                case Opt_jqfmt_vfsv0:
                        sbi->s_jquota_fmt = QFMT_VFS_V0;
                        break;
+               case Opt_quota:
+               case Opt_usrquota:
+                       set_opt(sbi->s_mount_opt, QUOTA);
+                       set_opt(sbi->s_mount_opt, USRQUOTA);
+                       break;
+               case Opt_grpquota:
+                       set_opt(sbi->s_mount_opt, QUOTA);
+                       set_opt(sbi->s_mount_opt, GRPQUOTA);
+                       break;
+               case Opt_noquota:
+                       if (sb_any_quota_enabled(sb)) {
+                               printk(KERN_ERR "EXT3-fs: Cannot change quota "
+                                       "options when quota turned on.\n");
+                               return 0;
+                       }
+                       clear_opt(sbi->s_mount_opt, QUOTA);
+                       clear_opt(sbi->s_mount_opt, USRQUOTA);
+                       clear_opt(sbi->s_mount_opt, GRPQUOTA);
+                       break;
 #else
+               case Opt_quota:
+               case Opt_usrquota:
+               case Opt_grpquota:
                case Opt_usrjquota:
                case Opt_grpjquota:
                case Opt_offusrjquota:
@@ -912,6 +1045,8 @@ clear_qf_name:
                                "EXT3-fs: journalled quota options not "
                                "supported.\n");
                        break;
+               case Opt_noquota:
+                       break;
 #endif
                case Opt_abort:
                        set_opt(sbi->s_mount_opt, ABORT);
@@ -927,14 +1062,21 @@ clear_qf_name:
                case Opt_ignore:
                        break;
                case Opt_resize:
-                       if (!n_blocks_count) {
+                       if (!is_remount) {
                                printk("EXT3-fs: resize option only available "
                                        "for remount\n");
                                return 0;
                        }
-                       match_int(&args[0], &option);
+                       if (match_int(&args[0], &option) != 0)
+                               return 0;
                        *n_blocks_count = option;
                        break;
+               case Opt_nobh:
+                       set_opt(sbi->s_mount_opt, NOBH);
+                       break;
+               case Opt_bh:
+                       clear_opt(sbi->s_mount_opt, NOBH);
+                       break;
                default:
                        printk (KERN_ERR
                                "EXT3-fs: Unrecognized mount option \"%s\" "
@@ -943,14 +1085,38 @@ clear_qf_name:
                }
        }
 #ifdef CONFIG_QUOTA
-       if (!sbi->s_jquota_fmt && (sbi->s_qf_names[USRQUOTA] ||
-           sbi->s_qf_names[GRPQUOTA])) {
-               printk(KERN_ERR
-                       "EXT3-fs: journalled quota format not specified.\n");
-               return 0;
+       if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+               if ((sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA) &&
+                    sbi->s_qf_names[USRQUOTA])
+                       clear_opt(sbi->s_mount_opt, USRQUOTA);
+
+               if ((sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA) &&
+                    sbi->s_qf_names[GRPQUOTA])
+                       clear_opt(sbi->s_mount_opt, GRPQUOTA);
+
+               if ((sbi->s_qf_names[USRQUOTA] &&
+                               (sbi->s_mount_opt & EXT3_MOUNT_GRPQUOTA)) ||
+                   (sbi->s_qf_names[GRPQUOTA] &&
+                               (sbi->s_mount_opt & EXT3_MOUNT_USRQUOTA))) {
+                       printk(KERN_ERR "EXT3-fs: old and new quota "
+                                       "format mixing.\n");
+                       return 0;
+               }
+
+               if (!sbi->s_jquota_fmt) {
+                       printk(KERN_ERR "EXT3-fs: journalled quota format "
+                                       "not specified.\n");
+                       return 0;
+               }
+       } else {
+               if (sbi->s_jquota_fmt) {
+                       printk(KERN_ERR "EXT3-fs: journalled quota format "
+                                       "specified with no journalling "
+                                       "enabled.\n");
+                       return 0;
+               }
        }
 #endif
-
        return 1;
 }
 
@@ -1019,12 +1185,6 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
        } else {
                printk("internal journal\n");
        }
-#ifdef CONFIG_EXT3_CHECK
-       if (test_opt (sb, CHECK)) {
-               ext3_check_blocks_bitmap (sb);
-               ext3_check_inodes_bitmap (sb);
-       }
-#endif
        return res;
 }
 
@@ -1032,7 +1192,8 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
 static int ext3_check_descriptors (struct super_block * sb)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
+       ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
+       ext3_fsblk_t last_block;
        struct ext3_group_desc * gdp = NULL;
        int desc_block = 0;
        int i;
@@ -1041,12 +1202,17 @@ static int ext3_check_descriptors (struct super_block * sb)
 
        for (i = 0; i < sbi->s_groups_count; i++)
        {
+               if (i == sbi->s_groups_count - 1)
+                       last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
+               else
+                       last_block = first_block +
+                               (EXT3_BLOCKS_PER_GROUP(sb) - 1);
+
                if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
                        gdp = (struct ext3_group_desc *)
                                        sbi->s_group_desc[desc_block++]->b_data;
-               if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
-                   le32_to_cpu(gdp->bg_block_bitmap) >=
-                               block + EXT3_BLOCKS_PER_GROUP(sb))
+               if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
+                   le32_to_cpu(gdp->bg_block_bitmap) > last_block)
                {
                        ext3_error (sb, "ext3_check_descriptors",
                                    "Block bitmap for group %d"
@@ -1055,9 +1221,8 @@ static int ext3_check_descriptors (struct super_block * sb)
                                        le32_to_cpu(gdp->bg_block_bitmap));
                        return 0;
                }
-               if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
-                   le32_to_cpu(gdp->bg_inode_bitmap) >=
-                               block + EXT3_BLOCKS_PER_GROUP(sb))
+               if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block ||
+                   le32_to_cpu(gdp->bg_inode_bitmap) > last_block)
                {
                        ext3_error (sb, "ext3_check_descriptors",
                                    "Inode bitmap for group %d"
@@ -1066,9 +1231,9 @@ static int ext3_check_descriptors (struct super_block * sb)
                                        le32_to_cpu(gdp->bg_inode_bitmap));
                        return 0;
                }
-               if (le32_to_cpu(gdp->bg_inode_table) < block ||
-                   le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >=
-                   block + EXT3_BLOCKS_PER_GROUP(sb))
+               if (le32_to_cpu(gdp->bg_inode_table) < first_block ||
+                   le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >
+                   last_block)
                {
                        ext3_error (sb, "ext3_check_descriptors",
                                    "Inode table for group %d"
@@ -1077,7 +1242,7 @@ static int ext3_check_descriptors (struct super_block * sb)
                                        le32_to_cpu(gdp->bg_inode_table));
                        return 0;
                }
-               block += EXT3_BLOCKS_PER_GROUP(sb);
+               first_block += EXT3_BLOCKS_PER_GROUP(sb);
                gdp++;
        }
 
@@ -1117,6 +1282,12 @@ static void ext3_orphan_cleanup (struct super_block * sb,
                return;
        }
 
+       if (bdev_read_only(sb->s_bdev)) {
+               printk(KERN_ERR "EXT3-fs: write access "
+                       "unavailable, skipping orphan cleanup.\n");
+               return;
+       }
+
        if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) {
                if (es->s_last_orphan)
                        jbd_debug(1, "Errors on filesystem, "
@@ -1159,17 +1330,17 @@ static void ext3_orphan_cleanup (struct super_block * sb,
                DQUOT_INIT(inode);
                if (inode->i_nlink) {
                        printk(KERN_DEBUG
-                               "%s: truncating inode %ld to %Ld bytes\n",
+                               "%s: truncating inode %lu to %Ld bytes\n",
                                __FUNCTION__, inode->i_ino, inode->i_size);
-                       jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
+                       jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
                                  inode->i_ino, inode->i_size);
                        ext3_truncate(inode);
                        nr_truncates++;
                } else {
                        printk(KERN_DEBUG
-                               "%s: deleting unreferenced inode %ld\n",
+                               "%s: deleting unreferenced inode %lu\n",
                                __FUNCTION__, inode->i_ino);
-                       jbd_debug(2, "deleting unreferenced inode %ld\n",
+                       jbd_debug(2, "deleting unreferenced inode %lu\n",
                                  inode->i_ino);
                        nr_orphans++;
                }
@@ -1194,8 +1365,6 @@ static void ext3_orphan_cleanup (struct super_block * sb,
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
 }
 
-#define log2(n) ffz(~(n))
-
 /*
  * Maximal file size.  There is a direct, and {,double-,triple-}indirect
  * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
@@ -1204,24 +1373,29 @@ static void ext3_orphan_cleanup (struct super_block * sb,
 static loff_t ext3_max_size(int bits)
 {
        loff_t res = EXT3_NDIR_BLOCKS;
+       /* This constant is calculated to be the largest file size for a
+        * dense, 4k-blocksize file such that the total number of
+        * sectors in the file, including data and all indirect blocks,
+        * does not exceed 2^32. */
+       const loff_t upper_limit = 0x1ff7fffd000LL;
+
        res += 1LL << (bits-2);
        res += 1LL << (2*(bits-2));
        res += 1LL << (3*(bits-2));
        res <<= bits;
-       if (res > (512LL << 32) - (1 << bits))
-               res = (512LL << 32) - (1 << bits);
+       if (res > upper_limit)
+               res = upper_limit;
        return res;
 }
 
-static unsigned long descriptor_loc(struct super_block *sb,
-                                   unsigned long logic_sb_block,
+static ext3_fsblk_t descriptor_loc(struct super_block *sb,
+                                   ext3_fsblk_t logic_sb_block,
                                    int nr)
 {
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long bg, first_data_block, first_meta_bg;
+       unsigned long bg, first_meta_bg;
        int has_super = 0;
 
-       first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
 
        if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) ||
@@ -1230,7 +1404,7 @@ static unsigned long descriptor_loc(struct super_block *sb,
        bg = sbi->s_desc_per_block * nr;
        if (ext3_bg_has_super(sb, bg))
                has_super = 1;
-       return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
+       return (has_super + ext3_group_first_block_no(sb, bg));
 }
 
 
@@ -1239,11 +1413,12 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        struct buffer_head * bh;
        struct ext3_super_block *es = NULL;
        struct ext3_sb_info *sbi;
-       unsigned long block;
-       unsigned long sb_block = get_sb_block(&data);
-       unsigned long logic_sb_block;
+       ext3_fsblk_t block;
+       ext3_fsblk_t sb_block = get_sb_block(&data);
+       ext3_fsblk_t logic_sb_block;
        unsigned long offset = 0;
-       unsigned long journal_inum = 0;
+       unsigned int journal_inum = 0;
+       unsigned long journal_devnum = 0;
        unsigned long def_mount_opts;
        struct inode *root;
        int blocksize;
@@ -1253,11 +1428,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        int needs_recovery;
        __le32 features;
 
-       sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+       sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
        if (!sbi)
                return -ENOMEM;
        sb->s_fs_info = sbi;
-       memset(sbi, 0, sizeof(*sbi));
        sbi->s_mount_opt = 0;
        sbi->s_resuid = EXT3_DEF_RESUID;
        sbi->s_resgid = EXT3_DEF_RESGID;
@@ -1303,10 +1477,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                set_opt(sbi->s_mount_opt, GRPID);
        if (def_mount_opts & EXT3_DEFM_UID16)
                set_opt(sbi->s_mount_opt, NO_UID32);
+#ifdef CONFIG_EXT3_FS_XATTR
        if (def_mount_opts & EXT3_DEFM_XATTR_USER)
                set_opt(sbi->s_mount_opt, XATTR_USER);
+#endif
+#ifdef CONFIG_EXT3_FS_POSIX_ACL
        if (def_mount_opts & EXT3_DEFM_ACL)
                set_opt(sbi->s_mount_opt, POSIX_ACL);
+#endif
        if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA)
                sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA;
        else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED)
@@ -1318,17 +1496,20 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
        else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
                set_opt(sbi->s_mount_opt, ERRORS_RO);
+       else
+               set_opt(sbi->s_mount_opt, ERRORS_CONT);
 
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
 
        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;
 
-       if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_TAG_XID)
-               sb->s_flags |= MS_TAGXID;
+       if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_TAGGED)
+               sb->s_flags |= MS_TAGGED;
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
@@ -1337,7 +1518,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
            (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
             EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
             EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U)))
-               printk(KERN_WARNING 
+               printk(KERN_WARNING
                       "EXT3-fs warning: feature flags set on rev 0 fs, "
                       "running e2fsck is recommended\n");
        /*
@@ -1363,7 +1544,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
 
        if (blocksize < EXT3_MIN_BLOCK_SIZE ||
            blocksize > EXT3_MAX_BLOCK_SIZE) {
-               printk(KERN_ERR 
+               printk(KERN_ERR
                       "EXT3-fs: Unsupported filesystem blocksize %d on %s.\n",
                       blocksize, sb->s_id);
                goto failed_mount;
@@ -1387,14 +1568,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
                bh = sb_bread(sb, logic_sb_block);
                if (!bh) {
-                       printk(KERN_ERR 
+                       printk(KERN_ERR
                               "EXT3-fs: Can't read superblock on 2nd try.\n");
                        goto failed_mount;
                }
                es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
                sbi->s_es = es;
                if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) {
-                       printk (KERN_ERR 
+                       printk (KERN_ERR
                                "EXT3-fs: Magic mismatch, very weird !\n");
                        goto failed_mount;
                }
@@ -1439,8 +1620,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc);
        sbi->s_sbh = bh;
        sbi->s_mount_state = le16_to_cpu(es->s_state);
-       sbi->s_addr_per_block_bits = log2(EXT3_ADDR_PER_BLOCK(sb));
-       sbi->s_desc_per_block_bits = log2(EXT3_DESC_PER_BLOCK(sb));
+       sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb));
+       sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb));
        for (i=0; i < 4; i++)
                sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
        sbi->s_def_hash_version = es->s_def_hash_version;
@@ -1464,12 +1645,21 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
+       if (le32_to_cpu(es->s_blocks_count) >
+                   (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+               printk(KERN_ERR "EXT3-fs: filesystem on %s:"
+                       " too large to mount safely\n", sb->s_id);
+               if (sizeof(sector_t) < 8)
+                       printk(KERN_WARNING "EXT3-fs: CONFIG_LBD not "
+                                       "enabled\n");
+               goto failed_mount;
+       }
+
        if (EXT3_BLOCKS_PER_GROUP(sb) == 0)
                goto cantfind_ext3;
-       sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
-                              le32_to_cpu(es->s_first_data_block) +
-                              EXT3_BLOCKS_PER_GROUP(sb) - 1) /
-                             EXT3_BLOCKS_PER_GROUP(sb);
+       sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
+                              le32_to_cpu(es->s_first_data_block) - 1)
+                                      / EXT3_BLOCKS_PER_GROUP(sb)) + 1;
        db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
                   EXT3_DESC_PER_BLOCK(sb);
        sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
@@ -1479,9 +1669,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                goto failed_mount;
        }
 
-       percpu_counter_init(&sbi->s_freeblocks_counter);
-       percpu_counter_init(&sbi->s_freeinodes_counter);
-       percpu_counter_init(&sbi->s_dirs_counter);
        bgl_lock_init(&sbi->s_blockgroup_lock);
 
        for (i = 0; i < db_count; i++) {
@@ -1495,12 +1682,20 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                }
        }
        if (!ext3_check_descriptors (sb)) {
-               printk (KERN_ERR "EXT3-fs: group descriptors corrupted !\n");
+               printk(KERN_ERR "EXT3-fs: group descriptors corrupted!\n");
                goto failed_mount2;
        }
        sbi->s_gdb_count = db_count;
        get_random_bytes(&sbi->s_next_generation, sizeof(u32));
        spin_lock_init(&sbi->s_next_gen_lock);
+
+       percpu_counter_init(&sbi->s_freeblocks_counter,
+               ext3_count_free_blocks(sb));
+       percpu_counter_init(&sbi->s_freeinodes_counter,
+               ext3_count_free_inodes(sb));
+       percpu_counter_init(&sbi->s_dirs_counter,
+               ext3_count_dirs(sb));
+
        /* per fileystem reservation list head & lock */
        spin_lock_init(&sbi->s_rsv_window_lock);
        sbi->s_rsv_window_root = RB_ROOT;
@@ -1510,8 +1705,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
         * _much_ simpler. */
        sbi->s_rsv_window_head.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
        sbi->s_rsv_window_head.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
-       atomic_set(&sbi->s_rsv_window_head.rsv_alloc_hit, 0);
-       atomic_set(&sbi->s_rsv_window_head.rsv_goal_size, 0);
+       sbi->s_rsv_window_head.rsv_alloc_hit = 0;
+       sbi->s_rsv_window_head.rsv_goal_size = 0;
        ext3_rsv_window_add(sb, &sbi->s_rsv_window_head);
 
        /*
@@ -1538,17 +1733,17 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
         */
        if (!test_opt(sb, NOLOAD) &&
            EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
-               if (ext3_load_journal(sb, es))
-                       goto failed_mount2;
+               if (ext3_load_journal(sb, es, journal_devnum))
+                       goto failed_mount3;
        } else if (journal_inum) {
                if (ext3_create_journal(sb, es, journal_inum))
-                       goto failed_mount2;
+                       goto failed_mount3;
        } else {
                if (!silent)
                        printk (KERN_ERR
                                "ext3: No journal on filesystem on %s\n",
                                sb->s_id);
-               goto failed_mount2;
+               goto failed_mount3;
        }
 
        /* We have now updated the journal if required, so we can
@@ -1571,12 +1766,19 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                    (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) {
                        printk(KERN_ERR "EXT3-fs: Journal does not support "
                               "requested data journaling mode\n");
-                       goto failed_mount3;
+                       goto failed_mount4;
                }
        default:
                break;
        }
 
+       if (test_opt(sb, NOBH)) {
+               if (!(test_opt(sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA)) {
+                       printk(KERN_WARNING "EXT3-fs: Ignoring nobh option - "
+                               "its supported only with writeback mode\n");
+                       clear_opt(sbi->s_mount_opt, NOBH);
+               }
+       }
        /*
         * The journal_load will have done any necessary log recovery,
         * so we can safely mount the rest of the filesystem now.
@@ -1587,13 +1789,13 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
        if (!sb->s_root) {
                printk(KERN_ERR "EXT3-fs: get root inode failed\n");
                iput(root);
-               goto failed_mount3;
+               goto failed_mount4;
        }
        if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
                dput(sb->s_root);
                sb->s_root = NULL;
                printk(KERN_ERR "EXT3-fs: corrupt root inode, run e2fsck\n");
-               goto failed_mount3;
+               goto failed_mount4;
        }
 
        ext3_setup_super (sb, es, sb->s_flags & MS_RDONLY);
@@ -1616,13 +1818,6 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
                test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered":
                "writeback");
 
-       percpu_counter_mod(&sbi->s_freeblocks_counter,
-               ext3_count_free_blocks(sb));
-       percpu_counter_mod(&sbi->s_freeinodes_counter,
-               ext3_count_free_inodes(sb));
-       percpu_counter_mod(&sbi->s_dirs_counter,
-               ext3_count_dirs(sb));
-
        lock_kernel();
        return 0;
 
@@ -1632,8 +1827,12 @@ cantfind_ext3:
                       sb->s_id);
        goto failed_mount;
 
-failed_mount3:
+failed_mount4:
        journal_destroy(sbi->s_journal);
+failed_mount3:
+       percpu_counter_destroy(&sbi->s_freeblocks_counter);
+       percpu_counter_destroy(&sbi->s_freeinodes_counter);
+       percpu_counter_destroy(&sbi->s_dirs_counter);
 failed_mount2:
        for (i = 0; i < db_count; i++)
                brelse(sbi->s_group_desc[i]);
@@ -1655,7 +1854,7 @@ out_fail:
 /*
  * Setup any per-fs journal parameters now.  We'll do this both on
  * initial mount, once the journal has been initialised but before we've
- * done any recovery; and again on any subsequent remount. 
+ * done any recovery; and again on any subsequent remount.
  */
 static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
 {
@@ -1675,7 +1874,8 @@ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
        spin_unlock(&journal->j_state_lock);
 }
 
-static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
+static journal_t *ext3_get_journal(struct super_block *sb,
+                                  unsigned int journal_inum)
 {
        struct inode *journal_inode;
        journal_t *journal;
@@ -1720,10 +1920,10 @@ static journal_t *ext3_get_dev_journal(struct super_block *sb,
 {
        struct buffer_head * bh;
        journal_t *journal;
-       int start;
-       int len;
+       ext3_fsblk_t start;
+       ext3_fsblk_t len;
        int hblock, blocksize;
-       unsigned long sb_block;
+       ext3_fsblk_t sb_block;
        unsigned long offset;
        struct ext3_super_block * es;
        struct block_device *bdev;
@@ -1805,15 +2005,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));
+       unsigned int journal_inum = le32_to_cpu(es->s_journal_inum);
+       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);
 
        /*
@@ -1872,12 +2081,22 @@ static int ext3_load_journal(struct super_block * sb,
 
        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;
 }
 
 static int ext3_create_journal(struct super_block * sb,
                               struct ext3_super_block * es,
-                              int journal_inum)
+                              unsigned int journal_inum)
 {
        journal_t *journal;
 
@@ -1890,7 +2109,7 @@ static int ext3_create_journal(struct super_block * sb,
        if (!(journal = ext3_get_journal(sb, journal_inum)))
                return -EINVAL;
 
-       printk(KERN_INFO "EXT3-fs: creating new journal on inode %d\n",
+       printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n",
               journal_inum);
 
        if (journal_create(journal)) {
@@ -2019,7 +2238,7 @@ int ext3_force_commit(struct super_block *sb)
 
 static void ext3_write_super (struct super_block * sb)
 {
-       if (down_trylock(&sb->s_lock) == 0)
+       if (mutex_trylock(&sb->s_lock) != 0)
                BUG();
        sb->s_dirt = 0;
 }
@@ -2077,17 +2296,42 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 {
        struct ext3_super_block * es;
        struct ext3_sb_info *sbi = EXT3_SB(sb);
-       unsigned long tmp;
-       unsigned long n_blocks_count = 0;
+       ext3_fsblk_t n_blocks_count = 0;
+       unsigned long old_sb_flags;
+       struct ext3_mount_options old_opts;
+       int err;
+#ifdef CONFIG_QUOTA
+       int i;
+#endif
+
+       /* Store the original options */
+       old_sb_flags = sb->s_flags;
+       old_opts.s_mount_opt = sbi->s_mount_opt;
+       old_opts.s_resuid = sbi->s_resuid;
+       old_opts.s_resgid = sbi->s_resgid;
+       old_opts.s_commit_interval = sbi->s_commit_interval;
+#ifdef CONFIG_QUOTA
+       old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
+       for (i = 0; i < MAXQUOTAS; i++)
+               old_opts.s_qf_names[i] = sbi->s_qf_names[i];
+#endif
 
        /*
         * Allow the "check" option to be passed as a remount option.
         */
-       if (!parse_options(data, sb, &tmp, &n_blocks_count, 1))
-               return -EINVAL;
+       if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) {
+               err = -EINVAL;
+               goto restore_opts;
+       }
 
        if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
                ext3_abort(sb, __FUNCTION__, "Abort forced by user");
+       if ((sbi->s_mount_opt & EXT3_MOUNT_TAGGED) &&
+               !(sb->s_flags & MS_TAGGED)) {
+               printk("EXT3-fs: %s: tagging not permitted on remount.\n",
+                       sb->s_id);
+               return -EINVAL;
+       }
 
        sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
                ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
@@ -2098,8 +2342,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
 
        if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
                n_blocks_count > le32_to_cpu(es->s_blocks_count)) {
-               if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
-                       return -EROFS;
+               if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) {
+                       err = -EROFS;
+                       goto restore_opts;
+               }
 
                if (*flags & MS_RDONLY) {
                        /*
@@ -2126,7 +2372,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                                       "remount RDWR because of unsupported "
                                       "optional features (%x).\n",
                                       sb->s_id, le32_to_cpu(ret));
-                               return -EROFS;
+                               err = -EROFS;
+                               goto restore_opts;
                        }
                        /*
                         * Mounting a RDONLY partition read-write, so reread
@@ -2136,20 +2383,46 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
                         */
                        ext3_clear_journal_err(sb, es);
                        sbi->s_mount_state = le16_to_cpu(es->s_state);
-                       if ((ret = ext3_group_extend(sb, es, n_blocks_count)))
-                               return ret;
+                       if ((err = ext3_group_extend(sb, es, n_blocks_count)))
+                               goto restore_opts;
                        if (!ext3_setup_super (sb, es, 0))
                                sb->s_flags &= ~MS_RDONLY;
                }
        }
+#ifdef CONFIG_QUOTA
+       /* Release old quota file names */
+       for (i = 0; i < MAXQUOTAS; i++)
+               if (old_opts.s_qf_names[i] &&
+                   old_opts.s_qf_names[i] != sbi->s_qf_names[i])
+                       kfree(old_opts.s_qf_names[i]);
+#endif
        return 0;
+restore_opts:
+       sb->s_flags = old_sb_flags;
+       sbi->s_mount_opt = old_opts.s_mount_opt;
+       sbi->s_resuid = old_opts.s_resuid;
+       sbi->s_resgid = old_opts.s_resgid;
+       sbi->s_commit_interval = old_opts.s_commit_interval;
+#ifdef CONFIG_QUOTA
+       sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
+       for (i = 0; i < MAXQUOTAS; i++) {
+               if (sbi->s_qf_names[i] &&
+                   old_opts.s_qf_names[i] != sbi->s_qf_names[i])
+                       kfree(sbi->s_qf_names[i]);
+               sbi->s_qf_names[i] = old_opts.s_qf_names[i];
+       }
+#endif
+       return err;
 }
 
-static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
+static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf)
 {
-       struct ext3_super_block *es = EXT3_SB(sb)->s_es;
-       unsigned long overhead;
+       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;
+       u64 fsid;
 
        if (test_opt (sb, MINIX_DF))
                overhead = 0;
@@ -2189,13 +2462,17 @@ static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
        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_bfree = ext3_count_free_blocks (sb);
+       buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
        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 = ext3_count_free_inodes (sb);
+       buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
        buf->f_namelen = EXT3_NAME_LEN;
+       fsid = le64_to_cpup((void *)es->s_uuid) ^
+              le64_to_cpup((void *)es->s_uuid + sizeof(u64));
+       buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL;
+       buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL;
        return 0;
 }
 
@@ -2204,8 +2481,8 @@ static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
  * Process 1                         Process 2
  * ext3_create()                     quota_sync()
  *   journal_start()                   write_dquot()
- *   DQUOT_INIT()                        down(dqio_sem)
- *     down(dqio_sem)                    journal_start()
+ *   DQUOT_INIT()                        down(dqio_mutex)
+ *     down(dqio_mutex)                    journal_start()
  *
  */
 
@@ -2222,7 +2499,7 @@ static int ext3_dquot_initialize(struct inode *inode, int type)
        int ret, err;
 
        /* We may create quota structure so we need to reserve enough blocks */
-       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_initialize(inode, type);
@@ -2238,7 +2515,7 @@ static int ext3_dquot_drop(struct inode *inode)
        int ret, err;
 
        /* We may delete quota structure so we need to reserve enough blocks */
-       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+       handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_drop(inode);
@@ -2256,7 +2533,7 @@ static int ext3_write_dquot(struct dquot *dquot)
 
        inode = dquot_to_inode(dquot);
        handle = ext3_journal_start(inode,
-                                       EXT3_QUOTA_TRANS_BLOCKS);
+                                       EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_commit(dquot);
@@ -2272,7 +2549,7 @@ static int ext3_acquire_dquot(struct dquot *dquot)
        handle_t *handle;
 
        handle = ext3_journal_start(dquot_to_inode(dquot),
-                                       EXT3_QUOTA_INIT_BLOCKS);
+                                       EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_acquire(dquot);
@@ -2288,7 +2565,7 @@ static int ext3_release_dquot(struct dquot *dquot)
        handle_t *handle;
 
        handle = ext3_journal_start(dquot_to_inode(dquot),
-                                       EXT3_QUOTA_INIT_BLOCKS);
+                                       EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb));
        if (IS_ERR(handle))
                return PTR_ERR(handle);
        ret = dquot_release(dquot);
@@ -2332,22 +2609,8 @@ static int ext3_write_info(struct super_block *sb, int type)
  */
 static int ext3_quota_on_mount(struct super_block *sb, int type)
 {
-       int err;
-       struct dentry *dentry;
-       struct qstr name = { .name = EXT3_SB(sb)->s_qf_names[type],
-                            .hash = 0,
-                            .len = strlen(EXT3_SB(sb)->s_qf_names[type])};
-
-       dentry = lookup_hash(&name, sb->s_root);
-       if (IS_ERR(dentry))
-               return PTR_ERR(dentry);
-       err = vfs_quota_on_mount(type, EXT3_SB(sb)->s_jquota_fmt, dentry);
-       /* Now invalidate and put the dentry - quota got its own reference
-        * to inode and dentry has at least wrong hash so we had better
-        * throw it away */
-       d_invalidate(dentry);
-       dput(dentry);
-       return err;
+       return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type],
+                       EXT3_SB(sb)->s_jquota_fmt, type);
 }
 
 /*
@@ -2359,6 +2622,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
        int err;
        struct nameidata nd;
 
+       if (!test_opt(sb, QUOTA))
+               return -EINVAL;
        /* Not journalling quota? */
        if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] &&
            !EXT3_SB(sb)->s_qf_names[GRPQUOTA])
@@ -2435,7 +2700,7 @@ static ssize_t ext3_quota_write(struct super_block *sb, int type,
        struct buffer_head *bh;
        handle_t *handle = journal_current_handle();
 
-       down(&inode->i_sem);
+       mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
        while (towrite > 0) {
                tocopy = sb->s_blocksize - offset < towrite ?
                                sb->s_blocksize - offset : towrite;
@@ -2478,16 +2743,16 @@ out:
        inode->i_version++;
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
        ext3_mark_inode_dirty(handle, inode);
-       up(&inode->i_sem);
+       mutex_unlock(&inode->i_mutex);
        return len - towrite;
 }
 
 #endif
 
-static struct super_block *ext3_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data)
+static int ext3_get_sb(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
 {
-       return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super);
+       return get_sb_bdev(fs_type, flags, dev_name, data, ext3_fill_super, mnt);
 }
 
 static struct file_system_type ext3_fs_type = {
@@ -2513,7 +2778,7 @@ static int __init init_ext3_fs(void)
 out:
        destroy_inodecache();
 out1:
-       exit_ext3_xattr();
+       exit_ext3_xattr();
        return err;
 }