md: never advance 'events' counter by more than 1.
[safe/jmp/linux-2.6] / drivers / md / md.c
index c194955..d18805f 100644 (file)
@@ -359,6 +359,7 @@ static mddev_t * mddev_find(dev_t unit)
        else
                new->md_minor = MINOR(unit) >> MdpMinorShift;
 
+       mutex_init(&new->open_mutex);
        mutex_init(&new->reconfig_mutex);
        INIT_LIST_HEAD(&new->disks);
        INIT_LIST_HEAD(&new->all_mddevs);
@@ -1308,7 +1309,12 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
        }
        if (mddev->level != LEVEL_MULTIPATH) {
                int role;
-               role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
+               if (rdev->desc_nr < 0 ||
+                   rdev->desc_nr >= le32_to_cpu(sb->max_dev)) {
+                       role = 0xffff;
+                       rdev->desc_nr = -1;
+               } else
+                       role = le16_to_cpu(sb->dev_roles[rdev->desc_nr]);
                switch(role) {
                case 0xffff: /* spare */
                        break;
@@ -1394,8 +1400,14 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
                if (rdev2->desc_nr+1 > max_dev)
                        max_dev = rdev2->desc_nr+1;
 
-       if (max_dev > le32_to_cpu(sb->max_dev))
+       if (max_dev > le32_to_cpu(sb->max_dev)) {
+               int bmask;
                sb->max_dev = cpu_to_le32(max_dev);
+               rdev->sb_size = max_dev * 2 + 256;
+               bmask = queue_logical_block_size(rdev->bdev->bd_disk->queue)-1;
+               if (rdev->sb_size & bmask)
+                       rdev->sb_size = (rdev->sb_size | bmask) + 1;
+       }
        for (i=0; i<max_dev;i++)
                sb->dev_roles[i] = cpu_to_le16(0xfffe);
        
@@ -1963,17 +1975,14 @@ repeat:
                /* otherwise we have to go forward and ... */
                mddev->events ++;
                if (!mddev->in_sync || mddev->recovery_cp != MaxSector) { /* not clean */
-                       /* .. if the array isn't clean, insist on an odd 'events' */
-                       if ((mddev->events&1)==0) {
-                               mddev->events++;
+                       /* .. if the array isn't clean, an 'even' event must also go
+                        * to spares. */
+                       if ((mddev->events&1)==0)
                                nospares = 0;
-                       }
                } else {
-                       /* otherwise insist on an even 'events' (for clean states) */
-                       if ((mddev->events&1)) {
-                               mddev->events++;
+                       /* otherwise an 'odd' event must go to spares */
+                       if ((mddev->events&1))
                                nospares = 0;
-                       }
                }
        }
 
@@ -3730,17 +3739,8 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len)
 
        mddev->array_sectors = sectors;
        set_capacity(mddev->gendisk, mddev->array_sectors);
-       if (mddev->pers) {
-               struct block_device *bdev = bdget_disk(mddev->gendisk, 0);
-
-               if (bdev) {
-                       mutex_lock(&bdev->bd_inode->i_mutex);
-                       i_size_write(bdev->bd_inode,
-                                    (loff_t)mddev->array_sectors << 9);
-                       mutex_unlock(&bdev->bd_inode->i_mutex);
-                       bdput(bdev);
-               }
-       }
+       if (mddev->pers)
+               revalidate_disk(mddev->gendisk);
 
        return len;
 }
@@ -4230,6 +4230,7 @@ static int do_md_run(mddev_t * mddev)
        md_wakeup_thread(mddev->thread);
        md_wakeup_thread(mddev->sync_thread); /* possibly kick off a reshape */
 
+       revalidate_disk(mddev->gendisk);
        mddev->changed = 1;
        md_new_event(mddev);
        sysfs_notify_dirent(mddev->sysfs_state);
@@ -4301,12 +4302,11 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
        struct gendisk *disk = mddev->gendisk;
        mdk_rdev_t *rdev;
 
+       mutex_lock(&mddev->open_mutex);
        if (atomic_read(&mddev->openers) > is_open) {
                printk("md: %s still in use.\n",mdname(mddev));
-               return -EBUSY;
-       }
-
-       if (mddev->pers) {
+               err = -EBUSY;
+       } else if (mddev->pers) {
 
                if (mddev->sync_thread) {
                        set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
@@ -4364,7 +4364,10 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
                        set_disk_ro(disk, 1);
                clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
        }
-
+out:
+       mutex_unlock(&mddev->open_mutex);
+       if (err)
+               return err;
        /*
         * Free resources if final stop
         */
@@ -4430,7 +4433,6 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
        blk_integrity_unregister(disk);
        md_new_event(mddev);
        sysfs_notify_dirent(mddev->sysfs_state);
-out:
        return err;
 }
 
@@ -5128,18 +5130,8 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
                        return -ENOSPC;
        }
        rv = mddev->pers->resize(mddev, num_sectors);
-       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,
-                                    (loff_t)mddev->array_sectors << 9);
-                       mutex_unlock(&bdev->bd_inode->i_mutex);
-                       bdput(bdev);
-               }
-       }
+       if (!rv)
+               revalidate_disk(mddev->gendisk);
        return rv;
 }
 
@@ -5525,12 +5517,12 @@ static int md_open(struct block_device *bdev, fmode_t mode)
        }
        BUG_ON(mddev != bdev->bd_disk->private_data);
 
-       if ((err = mutex_lock_interruptible_nested(&mddev->reconfig_mutex, 1)))
+       if ((err = mutex_lock_interruptible(&mddev->open_mutex)))
                goto out;
 
        err = 0;
        atomic_inc(&mddev->openers);
-       mddev_unlock(mddev);
+       mutex_unlock(&mddev->open_mutex);
 
        check_disk_change(bdev);
  out: