[PATCH] md: Handle overflow of mdu_array_info_t->size better
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / md / md.c
index 7145cd150f7b2cac4f00c40f9efef5a36b5fad15..8f161743e18f2d6e1dab930e567de975879a6798 100644 (file)
@@ -1161,6 +1161,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
 
        sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors);
 
+       sb->raid_disks = cpu_to_le32(mddev->raid_disks);
+       sb->size = cpu_to_le64(mddev->size);
+
        if (mddev->bitmap && mddev->bitmap_file == NULL) {
                sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
                sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
@@ -2686,14 +2689,6 @@ static int do_md_stop(mddev_t * mddev, int ro)
                        set_disk_ro(disk, 1);
        }
 
-       bitmap_destroy(mddev);
-       if (mddev->bitmap_file) {
-               atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
-               fput(mddev->bitmap_file);
-               mddev->bitmap_file = NULL;
-       }
-       mddev->bitmap_offset = 0;
-
        /*
         * Free resources if final stop
         */
@@ -2703,6 +2698,14 @@ static int do_md_stop(mddev_t * mddev, int ro)
                struct gendisk *disk;
                printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
 
+               bitmap_destroy(mddev);
+               if (mddev->bitmap_file) {
+                       atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
+                       fput(mddev->bitmap_file);
+                       mddev->bitmap_file = NULL;
+               }
+               mddev->bitmap_offset = 0;
+
                ITERATE_RDEV(mddev,rdev,tmp)
                        if (rdev->raid_disk >= 0) {
                                char nm[20];
@@ -2939,6 +2942,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
        info.ctime         = mddev->ctime;
        info.level         = mddev->level;
        info.size          = mddev->size;
+       if (info.size != mddev->size) /* overflow */
+               info.size = -1;
        info.nr_disks      = nr;
        info.raid_disks    = mddev->raid_disks;
        info.md_minor      = mddev->md_minor;
@@ -3465,7 +3470,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
                bdev = bdget_disk(mddev->gendisk, 0);
                if (bdev) {
                        mutex_lock(&bdev->bd_inode->i_mutex);
-                       i_size_write(bdev->bd_inode, mddev->array_size << 10);
+                       i_size_write(bdev->bd_inode, (loff_t)mddev->array_size << 10);
                        mutex_unlock(&bdev->bd_inode->i_mutex);
                        bdput(bdev);
                }
@@ -3485,17 +3490,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks)
        if (mddev->sync_thread)
                return -EBUSY;
        rv = mddev->pers->reshape(mddev, raid_disks);
-       if (!rv) {
-               struct block_device *bdev;
-
-               bdev = bdget_disk(mddev->gendisk, 0);
-               if (bdev) {
-                       mutex_lock(&bdev->bd_inode->i_mutex);
-                       i_size_write(bdev->bd_inode, mddev->array_size << 10);
-                       mutex_unlock(&bdev->bd_inode->i_mutex);
-                       bdput(bdev);
-               }
-       }
        return rv;
 }
 
@@ -3531,7 +3525,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                )
                return -EINVAL;
        /* Check there is only one change */
-       if (mddev->size != info->size) cnt++;
+       if (info->size >= 0 && mddev->size != info->size) cnt++;
        if (mddev->raid_disks != info->raid_disks) cnt++;
        if (mddev->layout != info->layout) cnt++;
        if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) cnt++;
@@ -3548,7 +3542,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
                else
                        return mddev->pers->reconfig(mddev, info->layout, -1);
        }
-       if (mddev->size != info->size)
+       if (info->size >= 0 && mddev->size != info->size)
                rv = update_size(mddev, info->size);
 
        if (mddev->raid_disks    != info->raid_disks)