serial: core: Preserve termios c_cflag for console resume
[firefly-linux-kernel-4.4.55.git] / drivers / md / md.c
index 681d1099a2d58936864b3b63610a31f38a908219..aaf77b07bb727960557e075f17f9f4fd11485a26 100644 (file)
@@ -1118,6 +1118,7 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
        rdev->raid_disk = -1;
        clear_bit(Faulty, &rdev->flags);
        clear_bit(In_sync, &rdev->flags);
+       clear_bit(Bitmap_sync, &rdev->flags);
        clear_bit(WriteMostly, &rdev->flags);
 
        if (mddev->raid_disks == 0) {
@@ -1196,6 +1197,8 @@ static int super_90_validate(struct mddev *mddev, struct md_rdev *rdev)
                 */
                if (ev1 < mddev->bitmap->events_cleared)
                        return 0;
+               if (ev1 < mddev->events)
+                       set_bit(Bitmap_sync, &rdev->flags);
        } else {
                if (ev1 < mddev->events)
                        /* just a hot-add of a new device, leave raid_disk at -1 */
@@ -1604,6 +1607,7 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
        rdev->raid_disk = -1;
        clear_bit(Faulty, &rdev->flags);
        clear_bit(In_sync, &rdev->flags);
+       clear_bit(Bitmap_sync, &rdev->flags);
        clear_bit(WriteMostly, &rdev->flags);
 
        if (mddev->raid_disks == 0) {
@@ -1686,6 +1690,8 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *rdev)
                 */
                if (ev1 < mddev->bitmap->events_cleared)
                        return 0;
+               if (ev1 < mddev->events)
+                       set_bit(Bitmap_sync, &rdev->flags);
        } else {
                if (ev1 < mddev->events)
                        /* just a hot-add of a new device, leave raid_disk at -1 */
@@ -2829,6 +2835,7 @@ slot_store(struct md_rdev *rdev, const char *buf, size_t len)
                else
                        rdev->saved_raid_disk = -1;
                clear_bit(In_sync, &rdev->flags);
+               clear_bit(Bitmap_sync, &rdev->flags);
                err = rdev->mddev->pers->
                        hot_add_disk(rdev->mddev, rdev);
                if (err) {
@@ -3619,6 +3626,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
                mddev->in_sync = 1;
                del_timer_sync(&mddev->safemode_timer);
        }
+       blk_set_stacking_limits(&mddev->queue->limits);
        pers->run(mddev);
        set_bit(MD_CHANGE_DEVS, &mddev->flags);
        mddev_resume(mddev);
@@ -5268,8 +5276,8 @@ static void md_clean(struct mddev *mddev)
 
 static void __md_stop_writes(struct mddev *mddev)
 {
+       set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
        if (mddev->sync_thread) {
-               set_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
                set_bit(MD_RECOVERY_INTR, &mddev->recovery);
                md_reap_sync_thread(mddev);
        }
@@ -5760,6 +5768,7 @@ static int add_new_disk(struct mddev * mddev, mdu_disk_info_t *info)
                            info->raid_disk < mddev->raid_disks) {
                                rdev->raid_disk = info->raid_disk;
                                set_bit(In_sync, &rdev->flags);
+                               clear_bit(Bitmap_sync, &rdev->flags);
                        } else
                                rdev->raid_disk = -1;
                } else
@@ -7329,8 +7338,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))
@@ -7436,6 +7447,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));
@@ -7693,24 +7717,11 @@ static int remove_and_add_spares(struct mddev *mddev,
                if (test_bit(Faulty, &rdev->flags))
                        continue;
                if (mddev->ro &&
-                   rdev->saved_raid_disk < 0)
+                   ! (rdev->saved_raid_disk >= 0 &&
+                      !test_bit(Bitmap_sync, &rdev->flags)))
                        continue;
 
                rdev->recovery_offset = 0;
-               if (rdev->saved_raid_disk >= 0 && mddev->in_sync) {
-                       spin_lock_irq(&mddev->write_lock);
-                       if (mddev->in_sync)
-                               /* OK, this device, which is in_sync,
-                                * will definitely be noticed before
-                                * the next write, so recovery isn't
-                                * needed.
-                                */
-                               rdev->recovery_offset = mddev->recovery_cp;
-                       spin_unlock_irq(&mddev->write_lock);
-               }
-               if (mddev->ro && rdev->recovery_offset != MaxSector)
-                       /* not safe to add this disk now */
-                       continue;
                if (mddev->pers->
                    hot_add_disk(mddev, rdev) == 0) {
                        if (sysfs_link_rdev(mddev, rdev))
@@ -7788,9 +7799,13 @@ void md_check_recovery(struct mddev *mddev)
                         * As we only add devices that are already in-sync,
                         * we can activate the spares immediately.
                         */
-                       clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
                        remove_and_add_spares(mddev, NULL);
-                       mddev->pers->spare_active(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;
                }
 
@@ -8086,6 +8101,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
        u64 *p;
        int lo, hi;
        int rv = 1;
+       unsigned long flags;
 
        if (bb->shift < 0)
                /* badblocks are disabled */
@@ -8100,7 +8116,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
                sectors = next - s;
        }
 
-       write_seqlock_irq(&bb->lock);
+       write_seqlock_irqsave(&bb->lock, flags);
 
        p = bb->page;
        lo = 0;
@@ -8216,7 +8232,7 @@ static int md_set_badblocks(struct badblocks *bb, sector_t s, int sectors,
        bb->changed = 1;
        if (!acknowledged)
                bb->unacked_exist = 1;
-       write_sequnlock_irq(&bb->lock);
+       write_sequnlock_irqrestore(&bb->lock, flags);
 
        return rv;
 }
@@ -8481,7 +8497,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;