md: protect against NULL reference when waiting to start a raid10.
[linux-block.git] / drivers / md / md.c
index 4e957f3140a81c64a75982d8764436962d929a15..e71c5fa527f59ec3e6ea5fd6ce7d09746bfc437e 100644 (file)
@@ -371,10 +371,15 @@ static void md_end_flush(struct bio *bio, int err)
        bio_put(bio);
 }
 
-static void submit_flushes(mddev_t *mddev)
+static void md_submit_flush_data(struct work_struct *ws);
+
+static void submit_flushes(struct work_struct *ws)
 {
+       mddev_t *mddev = container_of(ws, mddev_t, flush_work);
        mdk_rdev_t *rdev;
 
+       INIT_WORK(&mddev->flush_work, md_submit_flush_data);
+       atomic_set(&mddev->flush_pending, 1);
        rcu_read_lock();
        list_for_each_entry_rcu(rdev, &mddev->disks, same_set)
                if (rdev->raid_disk >= 0 &&
@@ -397,6 +402,8 @@ static void submit_flushes(mddev_t *mddev)
                        rdev_dec_pending(rdev, mddev);
                }
        rcu_read_unlock();
+       if (atomic_dec_and_test(&mddev->flush_pending))
+               queue_work(md_wq, &mddev->flush_work);
 }
 
 static void md_submit_flush_data(struct work_struct *ws)
@@ -404,8 +411,6 @@ static void md_submit_flush_data(struct work_struct *ws)
        mddev_t *mddev = container_of(ws, mddev_t, flush_work);
        struct bio *bio = mddev->flush_bio;
 
-       atomic_set(&mddev->flush_pending, 1);
-
        if (bio->bi_size == 0)
                /* an empty barrier - all done */
                bio_endio(bio, 0);
@@ -414,10 +419,9 @@ static void md_submit_flush_data(struct work_struct *ws)
                if (mddev->pers->make_request(mddev, bio))
                        generic_make_request(bio);
        }
-       if (atomic_dec_and_test(&mddev->flush_pending)) {
-               mddev->flush_bio = NULL;
-               wake_up(&mddev->sb_wait);
-       }
+
+       mddev->flush_bio = NULL;
+       wake_up(&mddev->sb_wait);
 }
 
 void md_flush_request(mddev_t *mddev, struct bio *bio)
@@ -429,13 +433,8 @@ void md_flush_request(mddev_t *mddev, struct bio *bio)
        mddev->flush_bio = bio;
        spin_unlock_irq(&mddev->write_lock);
 
-       atomic_set(&mddev->flush_pending, 1);
-       INIT_WORK(&mddev->flush_work, md_submit_flush_data);
-
-       submit_flushes(mddev);
-
-       if (atomic_dec_and_test(&mddev->flush_pending))
-               queue_work(md_wq, &mddev->flush_work);
+       INIT_WORK(&mddev->flush_work, submit_flushes);
+       queue_work(md_wq, &mddev->flush_work);
 }
 EXPORT_SYMBOL(md_flush_request);
 
@@ -706,7 +705,7 @@ static struct mdk_personality *find_pers(int level, char *clevel)
 /* return the offset of the super block in 512byte sectors */
 static inline sector_t calc_dev_sboffset(struct block_device *bdev)
 {
-       sector_t num_sectors = bdev->bd_inode->i_size / 512;
+       sector_t num_sectors = i_size_read(bdev->bd_inode) / 512;
        return MD_NEW_SIZE_SECTORS(num_sectors);
 }
 
@@ -1337,7 +1336,7 @@ super_90_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
        md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
                       rdev->sb_page);
        md_super_wait(rdev->mddev);
-       return num_sectors / 2; /* kB for sysfs */
+       return num_sectors;
 }
 
 
@@ -1386,7 +1385,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
         */
        switch(minor_version) {
        case 0:
-               sb_start = rdev->bdev->bd_inode->i_size >> 9;
+               sb_start = i_size_read(rdev->bdev->bd_inode) >> 9;
                sb_start -= 8*2;
                sb_start &= ~(sector_t)(4*2-1);
                break;
@@ -1472,7 +1471,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
                        ret = 0;
        }
        if (minor_version)
-               rdev->sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+               rdev->sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
                        le64_to_cpu(sb->data_offset);
        else
                rdev->sectors = rdev->sb_start;
@@ -1680,7 +1679,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
                return 0; /* component must fit device */
        if (rdev->sb_start < rdev->data_offset) {
                /* minor versions 1 and 2; superblock before data */
-               max_sectors = rdev->bdev->bd_inode->i_size >> 9;
+               max_sectors = i_size_read(rdev->bdev->bd_inode) >> 9;
                max_sectors -= rdev->data_offset;
                if (!num_sectors || num_sectors > max_sectors)
                        num_sectors = max_sectors;
@@ -1690,7 +1689,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
        } else {
                /* minor version 0; superblock after data */
                sector_t sb_start;
-               sb_start = (rdev->bdev->bd_inode->i_size >> 9) - 8*2;
+               sb_start = (i_size_read(rdev->bdev->bd_inode) >> 9) - 8*2;
                sb_start &= ~(sector_t)(4*2 - 1);
                max_sectors = rdev->sectors + sb_start - rdev->sb_start;
                if (!num_sectors || num_sectors > max_sectors)
@@ -1704,7 +1703,7 @@ super_1_rdev_size_change(mdk_rdev_t *rdev, sector_t num_sectors)
        md_super_write(rdev->mddev, rdev, rdev->sb_start, rdev->sb_size,
                       rdev->sb_page);
        md_super_wait(rdev->mddev);
-       return num_sectors / 2; /* kB for sysfs */
+       return num_sectors;
 }
 
 static struct super_type super_types[] = {
@@ -2584,7 +2583,7 @@ rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len)
                        if (!sectors)
                                return -EBUSY;
                } else if (!sectors)
-                       sectors = (rdev->bdev->bd_inode->i_size >> 9) -
+                       sectors = (i_size_read(rdev->bdev->bd_inode) >> 9) -
                                rdev->data_offset;
        }
        if (sectors < my_mddev->dev_sectors)
@@ -2797,7 +2796,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi
 
        kobject_init(&rdev->kobj, &rdev_ktype);
 
-       size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS;
+       size = i_size_read(rdev->bdev->bd_inode) >> BLOCK_SIZE_BITS;
        if (!size) {
                printk(KERN_WARNING 
                        "md: %s has zero or unknown size, marking faulty!\n",
@@ -4338,6 +4337,8 @@ static int md_alloc(dev_t dev, char *name)
        if (mddev->kobj.sd &&
            sysfs_create_group(&mddev->kobj, &md_bitmap_group))
                printk(KERN_DEBUG "pointless warning\n");
+
+       blk_queue_flush(mddev->queue, REQ_FLUSH | REQ_FUA);
  abort:
        mutex_unlock(&disks_mutex);
        if (!error && mddev->kobj.sd) {
@@ -5158,7 +5159,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                                PTR_ERR(rdev));
                        return PTR_ERR(rdev);
                }
-               /* set save_raid_disk if appropriate */
+               /* set saved_raid_disk if appropriate */
                if (!mddev->persistent) {
                        if (info->state & (1<<MD_DISK_SYNC)  &&
                            info->raid_disk < mddev->raid_disks)
@@ -5168,7 +5169,10 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
                } else
                        super_types[mddev->major_version].
                                validate_super(mddev, rdev);
-               rdev->saved_raid_disk = rdev->raid_disk;
+               if (test_bit(In_sync, &rdev->flags))
+                       rdev->saved_raid_disk = rdev->raid_disk;
+               else
+                       rdev->saved_raid_disk = -1;
 
                clear_bit(In_sync, &rdev->flags); /* just to be sure */
                if (info->state & (1<<MD_DISK_WRITEMOSTLY))
@@ -5235,8 +5239,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
 
                if (!mddev->persistent) {
                        printk(KERN_INFO "md: nonpersistent superblock ...\n");
-                       rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
-               } else 
+                       rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
+               } else
                        rdev->sb_start = calc_dev_sboffset(rdev->bdev);
                rdev->sectors = rdev->sb_start;
 
@@ -5306,7 +5310,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
        if (mddev->persistent)
                rdev->sb_start = calc_dev_sboffset(rdev->bdev);
        else
-               rdev->sb_start = rdev->bdev->bd_inode->i_size / 512;
+               rdev->sb_start = i_size_read(rdev->bdev->bd_inode) / 512;
 
        rdev->sectors = rdev->sb_start;
 
@@ -6040,9 +6044,8 @@ static int md_thread(void * arg)
                         || kthread_should_stop(),
                         thread->timeout);
 
-               clear_bit(THREAD_WAKEUP, &thread->flags);
-
-               thread->run(thread->mddev);
+               if (test_and_clear_bit(THREAD_WAKEUP, &thread->flags))
+                       thread->run(thread->mddev);
        }
 
        return 0;