]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/ext4/super.c
ext4: Change the default behaviour on error
[linux-2.6-omap-h63xx.git] / fs / ext4 / super.c
index 0e829cc8a18adbaadbc470cf3912e0a9c945ae85..effd375ece8049b55135c6444df3c31e6be557ab 100644 (file)
 #include <linux/quotaops.h>
 #include <linux/seq_file.h>
 #include <linux/log2.h>
+#include <linux/crc16.h>
 
 #include <asm/uaccess.h>
 
 #include "xattr.h"
 #include "acl.h"
 #include "namei.h"
+#include "group.h"
 
 static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
                             unsigned long journal_devnum);
@@ -68,31 +70,31 @@ static void ext4_write_super_lockfs(struct super_block *sb);
 ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
                               struct ext4_group_desc *bg)
 {
-       return le32_to_cpu(bg->bg_block_bitmap) |
+       return le32_to_cpu(bg->bg_block_bitmap_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-                (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
+               (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
 }
 
 ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
                               struct ext4_group_desc *bg)
 {
-       return le32_to_cpu(bg->bg_inode_bitmap) |
+       return le32_to_cpu(bg->bg_inode_bitmap_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-                (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
+               (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
 }
 
 ext4_fsblk_t ext4_inode_table(struct super_block *sb,
                              struct ext4_group_desc *bg)
 {
-       return le32_to_cpu(bg->bg_inode_table) |
+       return le32_to_cpu(bg->bg_inode_table_lo) |
                (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
-                (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
+               (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
 }
 
 void ext4_block_bitmap_set(struct super_block *sb,
                           struct ext4_group_desc *bg, ext4_fsblk_t blk)
 {
-       bg->bg_block_bitmap = cpu_to_le32((u32)blk);
+       bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk);
        if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
                bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
 }
@@ -100,7 +102,7 @@ void ext4_block_bitmap_set(struct super_block *sb,
 void ext4_inode_bitmap_set(struct super_block *sb,
                           struct ext4_group_desc *bg, ext4_fsblk_t blk)
 {
-       bg->bg_inode_bitmap  = cpu_to_le32((u32)blk);
+       bg->bg_inode_bitmap_lo  = cpu_to_le32((u32)blk);
        if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
                bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
 }
@@ -108,7 +110,7 @@ void ext4_inode_bitmap_set(struct super_block *sb,
 void ext4_inode_table_set(struct super_block *sb,
                          struct ext4_group_desc *bg, ext4_fsblk_t blk)
 {
-       bg->bg_inode_table = cpu_to_le32((u32)blk);
+       bg->bg_inode_table_lo = cpu_to_le32((u32)blk);
        if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
                bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
 }
@@ -371,6 +373,66 @@ void ext4_update_dynamic_rev(struct super_block *sb)
         */
 }
 
+int ext4_update_compat_feature(handle_t *handle,
+                                       struct super_block *sb, __u32 compat)
+{
+       int err = 0;
+       if (!EXT4_HAS_COMPAT_FEATURE(sb, compat)) {
+               err = ext4_journal_get_write_access(handle,
+                               EXT4_SB(sb)->s_sbh);
+               if (err)
+                       return err;
+               EXT4_SET_COMPAT_FEATURE(sb, compat);
+               sb->s_dirt = 1;
+               handle->h_sync = 1;
+               BUFFER_TRACE(EXT4_SB(sb)->s_sbh,
+                                       "call ext4_journal_dirty_met adata");
+               err = ext4_journal_dirty_metadata(handle,
+                               EXT4_SB(sb)->s_sbh);
+       }
+       return err;
+}
+
+int ext4_update_rocompat_feature(handle_t *handle,
+                                       struct super_block *sb, __u32 rocompat)
+{
+       int err = 0;
+       if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, rocompat)) {
+               err = ext4_journal_get_write_access(handle,
+                               EXT4_SB(sb)->s_sbh);
+               if (err)
+                       return err;
+               EXT4_SET_RO_COMPAT_FEATURE(sb, rocompat);
+               sb->s_dirt = 1;
+               handle->h_sync = 1;
+               BUFFER_TRACE(EXT4_SB(sb)->s_sbh,
+                                       "call ext4_journal_dirty_met adata");
+               err = ext4_journal_dirty_metadata(handle,
+                               EXT4_SB(sb)->s_sbh);
+       }
+       return err;
+}
+
+int ext4_update_incompat_feature(handle_t *handle,
+                                       struct super_block *sb, __u32 incompat)
+{
+       int err = 0;
+       if (!EXT4_HAS_INCOMPAT_FEATURE(sb, incompat)) {
+               err = ext4_journal_get_write_access(handle,
+                               EXT4_SB(sb)->s_sbh);
+               if (err)
+                       return err;
+               EXT4_SET_INCOMPAT_FEATURE(sb, incompat);
+               sb->s_dirt = 1;
+               handle->h_sync = 1;
+               BUFFER_TRACE(EXT4_SB(sb)->s_sbh,
+                                       "call ext4_journal_dirty_met adata");
+               err = ext4_journal_dirty_metadata(handle,
+                               EXT4_SB(sb)->s_sbh);
+       }
+       return err;
+}
+
 /*
  * Open the external journal device
  */
@@ -626,16 +688,16 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
            le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) {
                seq_printf(seq, ",resgid=%u", sbi->s_resgid);
        }
-       if (test_opt(sb, ERRORS_CONT)) {
+       if (test_opt(sb, ERRORS_RO)) {
                int def_errors = le16_to_cpu(es->s_errors);
 
                if (def_errors == EXT4_ERRORS_PANIC ||
-                   def_errors == EXT4_ERRORS_RO) {
-                       seq_puts(seq, ",errors=continue");
+                   def_errors == EXT4_ERRORS_CONTINUE) {
+                       seq_puts(seq, ",errors=remount-ro");
                }
        }
-       if (test_opt(sb, ERRORS_RO))
-               seq_puts(seq, ",errors=remount-ro");
+       if (test_opt(sb, ERRORS_CONT))
+               seq_puts(seq, ",errors=continue");
        if (test_opt(sb, ERRORS_PANIC))
                seq_puts(seq, ",errors=panic");
        if (test_opt(sb, NO_UID32))
@@ -644,7 +706,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",debug");
        if (test_opt(sb, OLDALLOC))
                seq_puts(seq, ",oldalloc");
-#ifdef CONFIG_EXT4_FS_XATTR
+#ifdef CONFIG_EXT4DEV_FS_XATTR
        if (test_opt(sb, XATTR_USER))
                seq_puts(seq, ",user_xattr");
        if (!test_opt(sb, XATTR_USER) &&
@@ -652,7 +714,7 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
                seq_puts(seq, ",nouser_xattr");
        }
 #endif
-#ifdef CONFIG_EXT4_FS_POSIX_ACL
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
        if (test_opt(sb, POSIX_ACL))
                seq_puts(seq, ",acl");
        if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
@@ -684,13 +746,10 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
 }
 
 
-static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
+static struct inode *ext4_nfs_get_inode(struct super_block *sb,
+               u64 ino, u32 generation)
 {
-       __u32 *objp = vobjp;
-       unsigned long ino = objp[0];
-       __u32 generation = objp[1];
        struct inode *inode;
-       struct dentry *result;
 
        if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
                return ERR_PTR(-ESTALE);
@@ -713,15 +772,22 @@ static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
                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;
+
+       return inode;
+}
+
+static struct dentry *ext4_fh_to_dentry(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_dentry(sb, fid, fh_len, fh_type,
+                                   ext4_nfs_get_inode);
+}
+
+static struct dentry *ext4_fh_to_parent(struct super_block *sb, struct fid *fid,
+               int fh_len, int fh_type)
+{
+       return generic_fh_to_parent(sb, fid, fh_len, fh_type,
+                                   ext4_nfs_get_inode);
 }
 
 #ifdef CONFIG_QUOTA
@@ -790,9 +856,10 @@ static const struct super_operations ext4_sops = {
 #endif
 };
 
-static struct export_operations ext4_export_ops = {
+static const struct export_operations ext4_export_ops = {
+       .fh_to_dentry = ext4_fh_to_dentry,
+       .fh_to_parent = ext4_fh_to_parent,
        .get_parent = ext4_get_parent,
-       .get_dentry = ext4_get_dentry,
 };
 
 enum {
@@ -1037,7 +1104,7 @@ static int parse_options (char *options, struct super_block *sb,
                        if (option < 0)
                                return 0;
                        if (option == 0)
-                               option = JBD_DEFAULT_MAX_COMMIT_AGE;
+                               option = JBD2_DEFAULT_MAX_COMMIT_AGE;
                        sbi->s_commit_interval = HZ * option;
                        break;
                case Opt_data_journal:
@@ -1308,6 +1375,43 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
        return res;
 }
 
+__le16 ext4_group_desc_csum(struct ext4_sb_info *sbi, __u32 block_group,
+                           struct ext4_group_desc *gdp)
+{
+       __u16 crc = 0;
+
+       if (sbi->s_es->s_feature_ro_compat &
+           cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+               int offset = offsetof(struct ext4_group_desc, bg_checksum);
+               __le32 le_group = cpu_to_le32(block_group);
+
+               crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
+               crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
+               crc = crc16(crc, (__u8 *)gdp, offset);
+               offset += sizeof(gdp->bg_checksum); /* skip checksum */
+               /* for checksum of struct ext4_group_desc do the rest...*/
+               if ((sbi->s_es->s_feature_incompat &
+                    cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
+                   offset < le16_to_cpu(sbi->s_es->s_desc_size))
+                       crc = crc16(crc, (__u8 *)gdp + offset,
+                                   le16_to_cpu(sbi->s_es->s_desc_size) -
+                                       offset);
+       }
+
+       return cpu_to_le16(crc);
+}
+
+int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group,
+                               struct ext4_group_desc *gdp)
+{
+       if ((sbi->s_es->s_feature_ro_compat &
+            cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
+           (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
+               return 0;
+
+       return 1;
+}
+
 /* Called at mount-time, super-block is locked */
 static int ext4_check_descriptors (struct super_block * sb)
 {
@@ -1319,13 +1423,17 @@ static int ext4_check_descriptors (struct super_block * sb)
        ext4_fsblk_t inode_table;
        struct ext4_group_desc * gdp = NULL;
        int desc_block = 0;
-       int i;
+       int flexbg_flag = 0;
+       ext4_group_t i;
+
+       if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+               flexbg_flag = 1;
 
        ext4_debug ("Checking group descriptors");
 
        for (i = 0; i < sbi->s_groups_count; i++)
        {
-               if (i == sbi->s_groups_count - 1)
+               if (i == sbi->s_groups_count - 1 || flexbg_flag)
                        last_block = ext4_blocks_count(sbi->s_es) - 1;
                else
                        last_block = first_block +
@@ -1338,7 +1446,7 @@ static int ext4_check_descriptors (struct super_block * sb)
                if (block_bitmap < first_block || block_bitmap > last_block)
                {
                        ext4_error (sb, "ext4_check_descriptors",
-                                   "Block bitmap for group %d"
+                                   "Block bitmap for group %lu"
                                    " not in group (block %llu)!",
                                    i, block_bitmap);
                        return 0;
@@ -1347,7 +1455,7 @@ static int ext4_check_descriptors (struct super_block * sb)
                if (inode_bitmap < first_block || inode_bitmap > last_block)
                {
                        ext4_error (sb, "ext4_check_descriptors",
-                                   "Inode bitmap for group %d"
+                                   "Inode bitmap for group %lu"
                                    " not in group (block %llu)!",
                                    i, inode_bitmap);
                        return 0;
@@ -1357,12 +1465,20 @@ static int ext4_check_descriptors (struct super_block * sb)
                    inode_table + sbi->s_itb_per_group - 1 > last_block)
                {
                        ext4_error (sb, "ext4_check_descriptors",
-                                   "Inode table for group %d"
+                                   "Inode table for group %lu"
                                    " not in group (block %llu)!",
                                    i, inode_table);
                        return 0;
                }
-               first_block += EXT4_BLOCKS_PER_GROUP(sb);
+               if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
+                       ext4_error(sb, __FUNCTION__,
+                                  "Checksum for group %lu failed (%u!=%u)\n",
+                                   i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
+                                   gdp)), le16_to_cpu(gdp->bg_checksum));
+                       return 0;
+               }
+               if (!flexbg_flag)
+                       first_block += EXT4_BLOCKS_PER_GROUP(sb);
                gdp = (struct ext4_group_desc *)
                        ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
        }
@@ -1372,7 +1488,6 @@ static int ext4_check_descriptors (struct super_block * sb)
        return 1;
 }
 
-
 /* ext4_orphan_cleanup() walks a singly-linked list of inodes (starting at
  * the superblock) which were deleted from all directories, but held open by
  * a process at the time of a crash.  We walk the list and try to delete these
@@ -1485,20 +1600,95 @@ static void ext4_orphan_cleanup (struct super_block * sb,
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
 }
+/*
+ * Maximal extent format file size.
+ * Resulting logical blkno at s_maxbytes must fit in our on-disk
+ * extent format containers, within a sector_t, and within i_blocks
+ * in the vfs.  ext4 inode has 48 bits of i_block in fsblock units,
+ * so that won't be a limiting factor.
+ *
+ * Note, this does *not* consider any metadata overhead for vfs i_blocks.
+ */
+static loff_t ext4_max_size(int blkbits)
+{
+       loff_t res;
+       loff_t upper_limit = MAX_LFS_FILESIZE;
+
+       /* small i_blocks in vfs inode? */
+       if (sizeof(blkcnt_t) < sizeof(u64)) {
+               /*
+                * CONFIG_LSF is not enabled implies the inode
+                * i_block represent total blocks in 512 bytes
+                * 32 == size of vfs inode i_blocks * 8
+                */
+               upper_limit = (1LL << 32) - 1;
+
+               /* total blocks in file system block size */
+               upper_limit >>= (blkbits - 9);
+               upper_limit <<= blkbits;
+       }
+
+       /* 32-bit extent-start container, ee_block */
+       res = 1LL << 32;
+       res <<= blkbits;
+       res -= 1;
+
+       /* Sanity check against vm- & vfs- imposed limits */
+       if (res > upper_limit)
+               res = upper_limit;
+
+       return res;
+}
 
 /*
- * 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.
- * We need to be 1 filesystem block less than the 2^32 sector limit.
+ * Maximal bitmap file size.  There is a direct, and {,double-,triple-}indirect
+ * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
+ * We need to be 1 filesystem block less than the 2^48 sector limit.
  */
-static loff_t ext4_max_size(int bits)
+static loff_t ext4_max_bitmap_size(int bits)
 {
        loff_t res = EXT4_NDIR_BLOCKS;
-       /* This constant is calculated to be the largest file size for a
-        * dense, 4k-blocksize file such that the total number of
+       int meta_blocks;
+       loff_t upper_limit;
+       /* This is calculated to be the largest file size for a
+        * dense, bitmapped 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;
+        * does not exceed 2^48 -1
+        * __u32 i_blocks_lo and _u16 i_blocks_high representing the
+        * total number of  512 bytes blocks of the file
+        */
+
+       if (sizeof(blkcnt_t) < sizeof(u64)) {
+               /*
+                * CONFIG_LSF is not enabled implies the inode
+                * i_block represent total blocks in 512 bytes
+                * 32 == size of vfs inode i_blocks * 8
+                */
+               upper_limit = (1LL << 32) - 1;
+
+               /* total blocks in file system block size */
+               upper_limit >>= (bits - 9);
+
+       } else {
+               /*
+                * We use 48 bit ext4_inode i_blocks
+                * With EXT4_HUGE_FILE_FL set the i_blocks
+                * represent total number of blocks in
+                * file system block size
+                */
+               upper_limit = (1LL << 48) - 1;
+
+       }
+
+       /* indirect blocks */
+       meta_blocks = 1;
+       /* double indirect blocks */
+       meta_blocks += 1 + (1LL << (bits-2));
+       /* tripple indirect blocks */
+       meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2)));
+
+       upper_limit -= meta_blocks;
+       upper_limit <<= bits;
 
        res += 1LL << (bits-2);
        res += 1LL << (2*(bits-2));
@@ -1506,6 +1696,10 @@ static loff_t ext4_max_size(int bits)
        res <<= bits;
        if (res > upper_limit)
                res = upper_limit;
+
+       if (res > MAX_LFS_FILESIZE)
+               res = MAX_LFS_FILESIZE;
+
        return res;
 }
 
@@ -1513,7 +1707,7 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb,
                                ext4_fsblk_t logical_sb_block, int nr)
 {
        struct ext4_sb_info *sbi = EXT4_SB(sb);
-       unsigned long bg, first_meta_bg;
+       ext4_group_t bg, first_meta_bg;
        int has_super = 0;
 
        first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
@@ -1529,6 +1723,9 @@ static ext4_fsblk_t descriptor_loc(struct super_block *sb,
 
 
 static int ext4_fill_super (struct super_block *sb, void *data, int silent)
+                               __releases(kernel_sem)
+                               __acquires(kernel_sem)
+
 {
        struct buffer_head * bh;
        struct ext4_super_block *es = NULL;
@@ -1567,6 +1764,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                goto out_fail;
        }
 
+       if (!sb_set_blocksize(sb, blocksize)) {
+               printk(KERN_ERR "EXT4-fs: bad blocksize %d.\n", blocksize);
+               goto out_fail;
+       }
+
        /*
         * The ext4 superblock will not be buffer aligned for other than 1kB
         * block sizes.  We need to calculate the offset from buffer start.
@@ -1617,10 +1819,10 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
 
        if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC)
                set_opt(sbi->s_mount_opt, ERRORS_PANIC);
-       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_RO)
-               set_opt(sbi->s_mount_opt, ERRORS_RO);
-       else
+       else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE)
                set_opt(sbi->s_mount_opt, ERRORS_CONT);
+       else
+               set_opt(sbi->s_mount_opt, ERRORS_RO);
 
        sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
        sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -1666,6 +1868,19 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                       sb->s_id, le32_to_cpu(features));
                goto failed_mount;
        }
+       if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+               /*
+                * Large file size enabled file system can only be
+                * mount if kernel is build with CONFIG_LSF
+                */
+               if (sizeof(root->i_blocks) < sizeof(u64) &&
+                               !(sb->s_flags & MS_RDONLY)) {
+                       printk(KERN_ERR "EXT4-fs: %s: Filesystem with huge "
+                                       "files cannot be mounted read-write "
+                                       "without CONFIG_LSF.\n", sb->s_id);
+                       goto failed_mount;
+               }
+       }
        blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
 
        if (blocksize < EXT4_MIN_BLOCK_SIZE ||
@@ -1707,6 +1922,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                }
        }
 
+       sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits);
        sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
 
        if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
@@ -1726,19 +1942,11 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE)
                        sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2);
        }
-       sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
-                                  le32_to_cpu(es->s_log_frag_size);
-       if (blocksize != sbi->s_frag_size) {
-               printk(KERN_ERR
-                      "EXT4-fs: fragsize %lu != blocksize %u (unsupported)\n",
-                      sbi->s_frag_size, blocksize);
-               goto failed_mount;
-       }
        sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
        if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
                if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
                    sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
-                   sbi->s_desc_size & (sbi->s_desc_size - 1)) {
+                   !is_power_of_2(sbi->s_desc_size)) {
                        printk(KERN_ERR
                               "EXT4-fs: unsupported descriptor size %lu\n",
                               sbi->s_desc_size);
@@ -1747,9 +1955,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
        } else
                sbi->s_desc_size = EXT4_MIN_DESC_SIZE;
        sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
-       sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
        sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
-       if (EXT4_INODE_SIZE(sb) == 0)
+       if (EXT4_INODE_SIZE(sb) == 0 || EXT4_INODES_PER_GROUP(sb) == 0)
                goto cantfind_ext4;
        sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb);
        if (sbi->s_inodes_per_block == 0)
@@ -1771,12 +1978,6 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
                        sbi->s_blocks_per_group);
                goto failed_mount;
        }
-       if (sbi->s_frags_per_group > blocksize * 8) {
-               printk (KERN_ERR
-                       "EXT4-fs: #fragments per group too big: %lu\n",
-                       sbi->s_frags_per_group);
-               goto failed_mount;
-       }
        if (sbi->s_inodes_per_group > blocksize * 8) {
                printk (KERN_ERR
                        "EXT4-fs: #inodes per group too big: %lu\n",
@@ -1796,6 +1997,17 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent)
 
        if (EXT4_BLOCKS_PER_GROUP(sb) == 0)
                goto cantfind_ext4;
+
+       /* ensure blocks_count calculation below doesn't sign-extend */
+       if (ext4_blocks_count(es) + EXT4_BLOCKS_PER_GROUP(sb) <
+           le32_to_cpu(es->s_first_data_block) + 1) {
+               printk(KERN_WARNING "EXT4-fs: bad geometry: block count %llu, "
+                      "first data block %u, blocks per group %lu\n",
+                       ext4_blocks_count(es),
+                       le32_to_cpu(es->s_first_data_block),
+                       EXT4_BLOCKS_PER_GROUP(sb));
+               goto failed_mount;
+       }
        blocks_count = (ext4_blocks_count(es) -
                        le32_to_cpu(es->s_first_data_block) +
                        EXT4_BLOCKS_PER_GROUP(sb) - 1);
@@ -2630,8 +2842,8 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
 
        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;
+       } else if (sbi->s_blocks_last != ext4_blocks_count(es)) {
+               ext4_group_t ngroups = sbi->s_groups_count, i;
                ext4_fsblk_t overhead = 0;
                smp_rmb();
 
@@ -2665,14 +2877,14 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
                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);
+               sbi->s_blocks_last = ext4_blocks_count(es);
        }
 
        buf->f_type = EXT4_SUPER_MAGIC;
        buf->f_bsize = sb->s_blocksize;
        buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
        buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter);
-       es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
+       ext4_free_blocks_count_set(es, buf->f_bfree);
        buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
        if (buf->f_bfree < ext4_r_blocks_count(es))
                buf->f_bavail = 0;
@@ -2867,7 +3079,7 @@ static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
                               size_t len, loff_t off)
 {
        struct inode *inode = sb_dqopt(sb)->files[type];
-       sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
+       ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
        int err = 0;
        int offset = off & (sb->s_blocksize - 1);
        int tocopy;
@@ -2905,7 +3117,7 @@ static ssize_t ext4_quota_write(struct super_block *sb, int type,
                                const char *data, size_t len, loff_t off)
 {
        struct inode *inode = sb_dqopt(sb)->files[type];
-       sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
+       ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
        int err = 0;
        int offset = off & (sb->s_blocksize - 1);
        int tocopy;