OSDN Git Service

Merge 4.4.147 into android-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / fs / ext4 / super.c
index bd8831b..a26b71d 100644 (file)
@@ -688,6 +688,7 @@ __acquires(bitlock)
        }
 
        ext4_unlock_group(sb, grp);
+       ext4_commit_super(sb, 1);
        ext4_handle_error(sb);
        /*
         * We only get here in the ERRORS_RO case; relocking the group
@@ -2100,6 +2101,7 @@ static int ext4_check_descriptors(struct super_block *sb,
        struct ext4_sb_info *sbi = EXT4_SB(sb);
        ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
        ext4_fsblk_t last_block;
+       ext4_fsblk_t last_bg_block = sb_block + ext4_bg_num_gdb(sb, 0);
        ext4_fsblk_t block_bitmap;
        ext4_fsblk_t inode_bitmap;
        ext4_fsblk_t inode_table;
@@ -2129,6 +2131,16 @@ static int ext4_check_descriptors(struct super_block *sb,
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                                 "Block bitmap for group %u overlaps "
                                 "superblock", i);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               return 0;
+               }
+               if (block_bitmap >= sb_block + 1 &&
+                   block_bitmap <= last_bg_block) {
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Block bitmap for group %u overlaps "
+                                "block group descriptors", i);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               return 0;
                }
                if (block_bitmap < first_block || block_bitmap > last_block) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2141,6 +2153,16 @@ static int ext4_check_descriptors(struct super_block *sb,
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                                 "Inode bitmap for group %u overlaps "
                                 "superblock", i);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               return 0;
+               }
+               if (inode_bitmap >= sb_block + 1 &&
+                   inode_bitmap <= last_bg_block) {
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Inode bitmap for group %u overlaps "
+                                "block group descriptors", i);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               return 0;
                }
                if (inode_bitmap < first_block || inode_bitmap > last_block) {
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
@@ -2153,6 +2175,16 @@ static int ext4_check_descriptors(struct super_block *sb,
                        ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
                                 "Inode table for group %u overlaps "
                                 "superblock", i);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               return 0;
+               }
+               if (inode_table >= sb_block + 1 &&
+                   inode_table <= last_bg_block) {
+                       ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: "
+                                "Inode table for group %u overlaps "
+                                "block group descriptors", i);
+                       if (!(sb->s_flags & MS_RDONLY))
+                               return 0;
                }
                if (inode_table < first_block ||
                    inode_table + sbi->s_itb_per_group - 1 > last_block) {
@@ -2204,6 +2236,7 @@ static void ext4_orphan_cleanup(struct super_block *sb,
        unsigned int s_flags = sb->s_flags;
        int nr_orphans = 0, nr_truncates = 0;
 #ifdef CONFIG_QUOTA
+       int quota_update = 0;
        int i;
 #endif
        if (!es->s_last_orphan) {
@@ -2242,14 +2275,32 @@ static void ext4_orphan_cleanup(struct super_block *sb,
 #ifdef CONFIG_QUOTA
        /* Needed for iput() to work correctly and not trash data */
        sb->s_flags |= MS_ACTIVE;
-       /* Turn on quotas so that they are updated correctly */
+
+       /*
+        * Turn on quotas which were not enabled for read-only mounts if
+        * filesystem has quota feature, so that they are updated correctly.
+        */
+       if (ext4_has_feature_quota(sb) && (s_flags & MS_RDONLY)) {
+               int ret = ext4_enable_quotas(sb);
+
+               if (!ret)
+                       quota_update = 1;
+               else
+                       ext4_msg(sb, KERN_ERR,
+                               "Cannot turn on quotas: error %d", ret);
+       }
+
+       /* Turn on journaled quotas used for old sytle */
        for (i = 0; i < EXT4_MAXQUOTAS; i++) {
                if (EXT4_SB(sb)->s_qf_names[i]) {
                        int ret = ext4_quota_on_mount(sb, i);
-                       if (ret < 0)
+
+                       if (!ret)
+                               quota_update = 1;
+                       else
                                ext4_msg(sb, KERN_ERR,
                                        "Cannot turn on journaled "
-                                       "quota: error %d", ret);
+                                       "quota: type %d: error %d", i, ret);
                }
        }
 #endif
@@ -2308,10 +2359,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,
                ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up",
                       PLURAL(nr_truncates));
 #ifdef CONFIG_QUOTA
-       /* Turn quotas off */
-       for (i = 0; i < EXT4_MAXQUOTAS; i++) {
-               if (sb_dqopt(sb)->files[i])
-                       dquot_quota_off(sb, i);
+       /* Turn off quotas if they were enabled for orphan cleanup */
+       if (quota_update) {
+               for (i = 0; i < EXT4_MAXQUOTAS; i++) {
+                       if (sb_dqopt(sb)->files[i])
+                               dquot_quota_off(sb, i);
+               }
        }
 #endif
        sb->s_flags = s_flags; /* Restore MS_RDONLY status */
@@ -2477,9 +2530,9 @@ static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
 
        if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
                ret = sbi->s_stripe;
-       else if (stripe_width <= sbi->s_blocks_per_group)
+       else if (stripe_width && stripe_width <= sbi->s_blocks_per_group)
                ret = stripe_width;
-       else if (stride <= sbi->s_blocks_per_group)
+       else if (stride && stride <= sbi->s_blocks_per_group)
                ret = stride;
        else
                ret = 0;
@@ -2813,13 +2866,22 @@ static ext4_group_t ext4_has_uninit_itable(struct super_block *sb)
        ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count;
        struct ext4_group_desc *gdp = NULL;
 
+       if (!ext4_has_group_desc_csum(sb))
+               return ngroups;
+
        for (group = 0; group < ngroups; group++) {
                gdp = ext4_get_group_desc(sb, group, NULL);
                if (!gdp)
                        continue;
 
-               if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)))
+               if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))
+                       continue;
+               if (group != 0)
                        break;
+               ext4_error(sb, "Inode table for bg 0 marked as "
+                          "needing zeroing");
+               if (sb->s_flags & MS_RDONLY)
+                       return ngroups;
        }
 
        return group;
@@ -3422,6 +3484,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                         le32_to_cpu(es->s_log_block_size));
                goto failed_mount;
        }
+       if (le32_to_cpu(es->s_log_cluster_size) >
+           (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
+               ext4_msg(sb, KERN_ERR,
+                        "Invalid log cluster size: %u",
+                        le32_to_cpu(es->s_log_cluster_size));
+               goto failed_mount;
+       }
 
        if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) {
                ext4_msg(sb, KERN_ERR,
@@ -3486,6 +3555,11 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
        } else {
                sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
                sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
+               if (sbi->s_first_ino < EXT4_GOOD_OLD_FIRST_INO) {
+                       ext4_msg(sb, KERN_ERR, "invalid first ino: %u",
+                                sbi->s_first_ino);
+                       goto failed_mount;
+               }
                if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
                    (!is_power_of_2(sbi->s_inode_size)) ||
                    (sbi->s_inode_size > blocksize)) {
@@ -3562,13 +3636,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                                 "block size (%d)", clustersize, blocksize);
                        goto failed_mount;
                }
-               if (le32_to_cpu(es->s_log_cluster_size) >
-                   (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) {
-                       ext4_msg(sb, KERN_ERR,
-                                "Invalid log cluster size: %u",
-                                le32_to_cpu(es->s_log_cluster_size));
-                       goto failed_mount;
-               }
                sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) -
                        le32_to_cpu(es->s_log_block_size);
                sbi->s_clusters_per_group =
@@ -3589,10 +3656,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                }
        } else {
                if (clustersize != blocksize) {
-                       ext4_warning(sb, "fragment/cluster size (%d) != "
-                                    "block size (%d)", clustersize,
-                                    blocksize);
-                       clustersize = blocksize;
+                       ext4_msg(sb, KERN_ERR,
+                                "fragment/cluster size (%d) != "
+                                "block size (%d)", clustersize, blocksize);
+                       goto failed_mount;
                }
                if (sbi->s_blocks_per_group > blocksize * 8) {
                        ext4_msg(sb, KERN_ERR,
@@ -3646,6 +3713,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                         ext4_blocks_count(es));
                goto failed_mount;
        }
+       if ((es->s_first_data_block == 0) && (es->s_log_block_size == 0) &&
+           (sbi->s_cluster_ratio == 1)) {
+               ext4_msg(sb, KERN_WARNING, "bad geometry: first data "
+                        "block is 0 with a 1k block and cluster size");
+               goto failed_mount;
+       }
+
        blocks_count = (ext4_blocks_count(es) -
                        le32_to_cpu(es->s_first_data_block) +
                        EXT4_BLOCKS_PER_GROUP(sb) - 1);
@@ -3681,6 +3755,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                ret = -ENOMEM;
                goto failed_mount;
        }
+       if (((u64)sbi->s_groups_count * sbi->s_inodes_per_group) !=
+           le32_to_cpu(es->s_inodes_count)) {
+               ext4_msg(sb, KERN_ERR, "inodes count not valid: %u vs %llu",
+                        le32_to_cpu(es->s_inodes_count),
+                        ((u64)sbi->s_groups_count * sbi->s_inodes_per_group));
+               ret = -EINVAL;
+               goto failed_mount;
+       }
 
        bgl_lock_init(sbi->s_blockgroup_lock);
 
@@ -3694,13 +3776,13 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
                        goto failed_mount2;
                }
        }
+       sbi->s_gdb_count = db_count;
        if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) {
                ext4_msg(sb, KERN_ERR, "group descriptors corrupted!");
                ret = -EFSCORRUPTED;
                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);
 
@@ -4363,6 +4445,14 @@ static int ext4_commit_super(struct super_block *sb, int sync)
 
        if (!sbh || block_device_ejected(sb))
                return error;
+
+       /*
+        * The superblock bh should be mapped, but it might not be if the
+        * device was hot-removed. Not much we can do but fail the I/O.
+        */
+       if (!buffer_mapped(sbh))
+               return error;
+
        if (buffer_write_io_error(sbh)) {
                /*
                 * Oh, dear.  A previous attempt to write the
@@ -5123,6 +5213,9 @@ static int ext4_enable_quotas(struct super_block *sb)
                        err = ext4_quota_enable(sb, type, QFMT_VFS_V1,
                                                DQUOT_USAGE_ENABLED);
                        if (err) {
+                               for (type--; type >= 0; type--)
+                                       dquot_quota_off(sb, type);
+
                                ext4_warning(sb,
                                        "Failed to enable quota tracking "
                                        "(type=%d, err=%d). Please run "