]> err.no Git - linux-2.6/blobdiff - drivers/md/md.c
Merge branch 'for-linus' of git://neil.brown.name/md
[linux-2.6] / drivers / md / md.c
index 4bfbc1982cda977ff28ee312fe0a84372b0a833d..8cfadc5bd2ba54f858c8f28c8f17c5db40942891 100644 (file)
@@ -273,6 +273,7 @@ static mddev_t * mddev_find(dev_t unit)
        INIT_LIST_HEAD(&new->all_mddevs);
        init_timer(&new->safemode_timer);
        atomic_set(&new->active, 1);
+       atomic_set(&new->openers, 0);
        spin_lock_init(&new->write_lock);
        init_waitqueue_head(&new->sb_wait);
        init_waitqueue_head(&new->recovery_wait);
@@ -1394,15 +1395,17 @@ static struct super_type super_types[] = {
 
 static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
 {
-       struct list_head *tmp, *tmp2;
        mdk_rdev_t *rdev, *rdev2;
 
-       rdev_for_each(rdev, tmp, mddev1)
-               rdev_for_each(rdev2, tmp2, mddev2)
+       rcu_read_lock();
+       rdev_for_each_rcu(rdev, mddev1)
+               rdev_for_each_rcu(rdev2, mddev2)
                        if (rdev->bdev->bd_contains ==
-                           rdev2->bdev->bd_contains)
+                           rdev2->bdev->bd_contains) {
+                               rcu_read_unlock();
                                return 1;
-
+                       }
+       rcu_read_unlock();
        return 0;
 }
 
@@ -1469,7 +1472,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
                kobject_del(&rdev->kobj);
                goto fail;
        }
-       list_add(&rdev->same_set, &mddev->disks);
+       list_add_rcu(&rdev->same_set, &mddev->disks);
        bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
        return 0;
 
@@ -1494,14 +1497,16 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev)
                return;
        }
        bd_release_from_disk(rdev->bdev, rdev->mddev->gendisk);
-       list_del_init(&rdev->same_set);
+       list_del_rcu(&rdev->same_set);
        printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b));
        rdev->mddev = NULL;
        sysfs_remove_link(&rdev->kobj, "block");
 
        /* We need to delay this, otherwise we can deadlock when
-        * writing to 'remove' to "dev/state"
+        * writing to 'remove' to "dev/state".  We also need
+        * to delay it due to rcu usage.
         */
+       synchronize_rcu();
        INIT_WORK(&rdev->del_work, md_delayed_delete);
        kobject_get(&rdev->kobj);
        schedule_work(&rdev->del_work);
@@ -1557,7 +1562,6 @@ static void export_rdev(mdk_rdev_t * rdev)
        if (rdev->mddev)
                MD_BUG();
        free_disk_sb(rdev);
-       list_del_init(&rdev->same_set);
 #ifndef MODULE
        if (test_bit(AutoDetected, &rdev->flags))
                md_autodetect_dev(rdev->bdev->bd_dev);
@@ -2389,6 +2393,8 @@ static void analyze_sbs(mddev_t * mddev)
 
 }
 
+static void md_safemode_timeout(unsigned long data);
+
 static ssize_t
 safe_delay_show(mddev_t *mddev, char *page)
 {
@@ -2428,9 +2434,12 @@ safe_delay_store(mddev_t *mddev, const char *cbuf, size_t len)
        if (msec == 0)
                mddev->safemode_delay = 0;
        else {
+               unsigned long old_delay = mddev->safemode_delay;
                mddev->safemode_delay = (msec*HZ)/1000;
                if (mddev->safemode_delay == 0)
                        mddev->safemode_delay = 1;
+               if (mddev->safemode_delay < old_delay)
+                       md_safemode_timeout((unsigned long)mddev);
        }
        return len;
 }
@@ -2695,14 +2704,14 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
                break;
        case clear:
                /* stopping an active array */
-               if (atomic_read(&mddev->active) > 1)
+               if (atomic_read(&mddev->openers) > 0)
                        return -EBUSY;
                err = do_md_stop(mddev, 0, 0);
                break;
        case inactive:
                /* stopping an active array */
                if (mddev->pers) {
-                       if (atomic_read(&mddev->active) > 1)
+                       if (atomic_read(&mddev->openers) > 0)
                                return -EBUSY;
                        err = do_md_stop(mddev, 2, 0);
                } else
@@ -3479,7 +3488,7 @@ static void md_safemode_timeout(unsigned long data)
        if (!atomic_read(&mddev->writes_pending)) {
                mddev->safemode = 1;
                if (mddev->external)
-                       sysfs_notify(&mddev->kobj, NULL, "array_state");
+                       set_bit(MD_NOTIFY_ARRAY_STATE, &mddev->flags);
        }
        md_wakeup_thread(mddev->thread);
 }
@@ -3816,7 +3825,7 @@ static int do_md_stop(mddev_t * mddev, int mode, int is_open)
        int err = 0;
        struct gendisk *disk = mddev->gendisk;
 
-       if (atomic_read(&mddev->active) > 1 + is_open) {
+       if (atomic_read(&mddev->openers) > is_open) {
                printk("md: %s still in use.\n",mdname(mddev));
                return -EBUSY;
        }
@@ -4061,8 +4070,10 @@ static void autorun_devices(int part)
                /* on success, candidates will be empty, on error
                 * it won't...
                 */
-               rdev_for_each_list(rdev, tmp, candidates)
+               rdev_for_each_list(rdev, tmp, candidates) {
+                       list_del_init(&rdev->same_set);
                        export_rdev(rdev);
+               }
                mddev_put(mddev);
        }
        printk(KERN_INFO "md: ... autorun DONE.\n");
@@ -4628,6 +4639,11 @@ static int update_size(mddev_t *mddev, sector_t num_sectors)
         */
        if (mddev->sync_thread)
                return -EBUSY;
+       if (mddev->bitmap)
+               /* Sorry, cannot grow a bitmap yet, just remove it,
+                * grow, and re-add.
+                */
+               return -EBUSY;
        rdev_for_each(rdev, tmp, mddev) {
                sector_t avail;
                avail = rdev->size * 2;
@@ -5014,6 +5030,7 @@ static int md_open(struct inode *inode, struct file *file)
 
        err = 0;
        mddev_get(mddev);
+       atomic_inc(&mddev->openers);
        mddev_unlock(mddev);
 
        check_disk_change(inode->i_bdev);
@@ -5026,6 +5043,7 @@ static int md_release(struct inode *inode, struct file * file)
        mddev_t *mddev = inode->i_bdev->bd_disk->private_data;
 
        BUG_ON(!mddev);
+       atomic_dec(&mddev->openers);
        mddev_put(mddev);
 
        return 0;
@@ -5526,12 +5544,12 @@ int unregister_md_personality(struct mdk_personality *p)
 static int is_mddev_idle(mddev_t *mddev)
 {
        mdk_rdev_t * rdev;
-       struct list_head *tmp;
        int idle;
        long curr_events;
 
        idle = 1;
-       rdev_for_each(rdev, tmp, mddev) {
+       rcu_read_lock();
+       rdev_for_each_rcu(rdev, mddev) {
                struct gendisk *disk = rdev->bdev->bd_contains->bd_disk;
                curr_events = disk_stat_read(disk, sectors[0]) + 
                                disk_stat_read(disk, sectors[1]) - 
@@ -5563,6 +5581,7 @@ static int is_mddev_idle(mddev_t *mddev)
                        idle = 0;
                }
        }
+       rcu_read_unlock();
        return idle;
 }
 
@@ -5984,10 +6003,11 @@ static int remove_and_add_spares(mddev_t *mddev)
                        }
                }
 
-       if (mddev->degraded) {
+       if (mddev->degraded && ! mddev->ro) {
                rdev_for_each(rdev, rtmp, mddev) {
                        if (rdev->raid_disk >= 0 &&
-                           !test_bit(In_sync, &rdev->flags))
+                           !test_bit(In_sync, &rdev->flags) &&
+                           !test_bit(Blocked, &rdev->flags))
                                spares++;
                        if (rdev->raid_disk < 0
                            && !test_bit(Faulty, &rdev->flags)) {
@@ -6042,6 +6062,9 @@ void md_check_recovery(mddev_t *mddev)
        if (mddev->bitmap)
                bitmap_daemon_work(mddev->bitmap);
 
+       if (test_and_clear_bit(MD_NOTIFY_ARRAY_STATE, &mddev->flags))
+               sysfs_notify(&mddev->kobj, NULL, "array_state");
+
        if (mddev->ro)
                return;
 
@@ -6054,6 +6077,8 @@ void md_check_recovery(mddev_t *mddev)
                flush_signals(current);
        }
 
+       if (mddev->ro && !test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
+               return;
        if ( ! (
                (mddev->flags && !mddev->external) ||
                test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
@@ -6067,6 +6092,15 @@ void md_check_recovery(mddev_t *mddev)
        if (mddev_trylock(mddev)) {
                int spares = 0;
 
+               if (mddev->ro) {
+                       /* Only thing we do on a ro array is remove
+                        * failed devices.
+                        */
+                       remove_and_add_spares(mddev);
+                       clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+                       goto unlock;
+               }
+
                if (!mddev->external) {
                        int did_change = 0;
                        spin_lock_irq(&mddev->write_lock);
@@ -6104,7 +6138,8 @@ void md_check_recovery(mddev_t *mddev)
                        /* resync has finished, collect result */
                        md_unregister_thread(mddev->sync_thread);
                        mddev->sync_thread = NULL;
-                       if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
+                       if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery) &&
+                           !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
                                /* success...*/
                                /* activate any spares */
                                if (mddev->pers->spare_active(mddev))
@@ -6156,6 +6191,7 @@ void md_check_recovery(mddev_t *mddev)
                } else if ((spares = remove_and_add_spares(mddev))) {
                        clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
                        clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+                       clear_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
                        set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
                } else if (mddev->recovery_cp < MaxSector) {
                        set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
@@ -6219,7 +6255,11 @@ static int md_notify_reboot(struct notifier_block *this,
 
                for_each_mddev(mddev, tmp)
                        if (mddev_trylock(mddev)) {
-                               do_md_stop (mddev, 1, 0);
+                               /* Force a switch to readonly even array
+                                * appears to still be in use.  Hence
+                                * the '100'.
+                                */
+                               do_md_stop (mddev, 1, 100);
                                mddev_unlock(mddev);
                        }
                /*