}
        rdev->size = calc_dev_size(rdev, sb->chunk_size);
 
+       if (rdev->size < sb->size && sb->level > 1)
+               /* "this cannot possibly happen" ... */
+               ret = -EINVAL;
+
  abort:
        return ret;
 }
        rdev->size = le64_to_cpu(sb->data_size)/2;
        if (le32_to_cpu(sb->chunksize))
                rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1);
+
+       if (le32_to_cpu(sb->size) > rdev->size*2)
+               return -EINVAL;
        return 0;
 }
 
                MD_BUG();
                return -EINVAL;
        }
+       /* make sure rdev->size exceeds mddev->size */
+       if (rdev->size && (mddev->size == 0 || rdev->size < mddev->size)) {
+               if (mddev->pers)
+                       /* Cannot change size, so fail */
+                       return -ENOSPC;
+               else
+                       mddev->size = rdev->size;
+       }
        same_pdev = match_dev_unit(mddev, rdev);
        if (same_pdev)
                printk(KERN_WARNING
                if (info->state & (1<<MD_DISK_WRITEMOSTLY))
                        set_bit(WriteMostly, &rdev->flags);
 
-               err = bind_rdev_to_array(rdev, mddev);
-               if (err) {
-                       export_rdev(rdev);
-                       return err;
-               }
-
                if (!mddev->persistent) {
                        printk(KERN_INFO "md: nonpersistent superblock ...\n");
                        rdev->sb_offset = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
                        rdev->sb_offset = calc_dev_sboffset(rdev->bdev);
                rdev->size = calc_dev_size(rdev, mddev->chunk_size);
 
-               if (!mddev->size || (mddev->size > rdev->size))
-                       mddev->size = rdev->size;
+               err = bind_rdev_to_array(rdev, mddev);
+               if (err) {
+                       export_rdev(rdev);
+                       return err;
+               }
        }
 
        return 0;
        size = calc_dev_size(rdev, mddev->chunk_size);
        rdev->size = size;
 
-       if (size < mddev->size) {
-               printk(KERN_WARNING 
-                       "%s: disk size %llu blocks < array size %llu\n",
-                       mdname(mddev), (unsigned long long)size,
-                       (unsigned long long)mddev->size);
-               err = -ENOSPC;
-               goto abort_export;
-       }
-
        if (test_bit(Faulty, &rdev->flags)) {
                printk(KERN_WARNING 
                        "md: can not hot-add faulty %s disk to %s!\n",
        }
        clear_bit(In_sync, &rdev->flags);
        rdev->desc_nr = -1;
-       bind_rdev_to_array(rdev, mddev);
+       err = bind_rdev_to_array(rdev, mddev);
+       if (err)
+               goto abort_export;
 
        /*
         * The rest should better be atomic, we can have disk failures