Merge tag 'v3.10.87' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / md / md.c
index a2dda416c9cbd6740388821fa8f08fc5cbf6da0b..ed0c6a6b79818fef2fe0d818e16c810270e73020 100644 (file)
@@ -33,6 +33,7 @@
 */
 
 #include <linux/kthread.h>
+#include <linux/freezer.h>
 #include <linux/blkdev.h>
 #include <linux/sysctl.h>
 #include <linux/seq_file.h>
@@ -5628,9 +5629,9 @@ static int get_bitmap_file(struct mddev * mddev, void __user * arg)
        int err = -ENOMEM;
 
        if (md_allow_write(mddev))
-               file = kmalloc(sizeof(*file), GFP_NOIO);
+               file = kzalloc(sizeof(*file), GFP_NOIO);
        else
-               file = kmalloc(sizeof(*file), GFP_KERNEL);
+               file = kzalloc(sizeof(*file), GFP_KERNEL);
 
        if (!file)
                goto out;
@@ -6221,7 +6222,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
            mddev->ctime         != info->ctime         ||
            mddev->level         != info->level         ||
 /*         mddev->layout        != info->layout        || */
-           !mddev->persistent   != info->not_persistent||
+           mddev->persistent    != !info->not_persistent ||
            mddev->chunk_sectors != info->chunk_size >> 9 ||
            /* ignore bottom 8 bits of state, and allow SB_BITMAP_PRESENT to change */
            ((state^info->state) & 0xfffffe00)
@@ -7338,8 +7339,10 @@ void md_do_sync(struct md_thread *thread)
        /* just incase thread restarts... */
        if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
                return;
-       if (mddev->ro) /* never try to sync a read-only array */
+       if (mddev->ro) {/* never try to sync a read-only array */
+               set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                return;
+       }
 
        if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
                if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
@@ -7369,11 +7372,14 @@ void md_do_sync(struct md_thread *thread)
         *
         */
 
+       set_freezable();
+
        do {
                mddev->curr_resync = 2;
 
        try_again:
-               if (kthread_should_stop())
+
+               if (kthread_freezable_should_stop(NULL))
                        set_bit(MD_RECOVERY_INTR, &mddev->recovery);
 
                if (test_bit(MD_RECOVERY_INTR, &mddev->recovery))
@@ -7395,6 +7401,9 @@ void md_do_sync(struct md_thread *thread)
                                         * time 'round when curr_resync == 2
                                         */
                                        continue;
+
+                               try_to_freeze();
+
                                /* We need to wait 'interruptible' so as not to
                                 * contribute to the load average, and not to
                                 * be caught by 'softlockup'
@@ -7407,6 +7416,7 @@ void md_do_sync(struct md_thread *thread)
                                               " share one or more physical units)\n",
                                               desc, mdname(mddev), mdname(mddev2));
                                        mddev_put(mddev2);
+                                       try_to_freeze();
                                        if (signal_pending(current))
                                                flush_signals(current);
                                        schedule();
@@ -7445,6 +7455,19 @@ void md_do_sync(struct md_thread *thread)
                            rdev->recovery_offset < j)
                                j = rdev->recovery_offset;
                rcu_read_unlock();
+
+               /* If there is a bitmap, we need to make sure all
+                * writes that started before we added a spare
+                * complete before we start doing a recovery.
+                * Otherwise the write might complete and (via
+                * bitmap_endwrite) set a bit in the bitmap after the
+                * recovery has checked that bit and skipped that
+                * region.
+                */
+               if (mddev->bitmap) {
+                       mddev->pers->quiesce(mddev, 1);
+                       mddev->pers->quiesce(mddev, 0);
+               }
        }
 
        printk(KERN_INFO "md: %s of RAID array %s\n", desc, mdname(mddev));
@@ -7524,7 +7547,7 @@ void md_do_sync(struct md_thread *thread)
                                                 || kthread_should_stop());
                }
 
-               if (kthread_should_stop())
+               if (kthread_freezable_should_stop(NULL))
                        goto interrupted;
 
                sectors = mddev->pers->sync_request(mddev, j, &skipped,
@@ -7568,8 +7591,7 @@ void md_do_sync(struct md_thread *thread)
                        last_mark = next;
                }
 
-
-               if (kthread_should_stop())
+               if (kthread_freezable_should_stop(NULL))
                        goto interrupted;
 
 
@@ -7746,8 +7768,10 @@ no_add:
  */
 void md_check_recovery(struct mddev *mddev)
 {
-       if (mddev->suspended)
+#ifdef CONFIG_FREEZER
+       if (mddev->suspended || unlikely(atomic_read(&system_freezing_cnt)))
                return;
+#endif
 
        if (mddev->bitmap)
                bitmap_daemon_work(mddev);
@@ -7788,6 +7812,7 @@ void md_check_recovery(struct mddev *mddev)
                        /* There is no thread, but we need to call
                         * ->spare_active and clear saved_raid_disk
                         */
+                       set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                        md_reap_sync_thread(mddev);
                        clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                        goto unlock;
@@ -8481,7 +8506,8 @@ static int md_notify_reboot(struct notifier_block *this,
                if (mddev_trylock(mddev)) {
                        if (mddev->pers)
                                __md_stop_writes(mddev);
-                       mddev->safemode = 2;
+                       if (mddev->persistent)
+                               mddev->safemode = 2;
                        mddev_unlock(mddev);
                }
                need_delay = 1;