summaryrefslogtreecommitdiffstats
path: root/drivers/md/md.c
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.com>2017-10-17 13:46:43 +1100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-07-08 15:30:50 +0200
commitfeabea21655961e6b0f87ad7351a4f99515c6b09 (patch)
tree16cee3bcd7dc566c29abd8a66ffac7c745c7ab9f /drivers/md/md.c
parentcc091f3fbbdb117d819536d6249e34322f991899 (diff)
downloadlinux-stable-feabea21655961e6b0f87ad7351a4f99515c6b09.tar.gz
linux-stable-feabea21655961e6b0f87ad7351a4f99515c6b09.tar.bz2
linux-stable-feabea21655961e6b0f87ad7351a4f99515c6b09.zip
md: move suspend_hi/lo handling into core md code
commit b3143b9a38d5039bcd1f2d1c94039651bfba8043 upstream. responding to ->suspend_lo and ->suspend_hi is similar to responding to ->suspended. It is best to wait in the common core code without incrementing ->active_io. This allows mddev_suspend()/mddev_resume() to work while requests are waiting for suspend_lo/hi to change. This is will be important after a subsequent patch which uses mddev_suspend() to synchronize updating for suspend_lo/hi. So move the code for testing suspend_lo/hi out of raid1.c and raid5.c, and place it in md.c Signed-off-by: NeilBrown <neilb@suse.com> Signed-off-by: Shaohua Li <shli@fb.com> Signed-off-by: Jack Wang <jinpu.wang@profitbricks.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/md/md.c')
-rw-r--r--drivers/md/md.c29
1 files changed, 23 insertions, 6 deletions
diff --git a/drivers/md/md.c b/drivers/md/md.c
index ac27fe200ecd..06ad5d798d73 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -266,16 +266,31 @@ static DEFINE_SPINLOCK(all_mddevs_lock);
* call has finished, the bio has been linked into some internal structure
* and so is visible to ->quiesce(), so we don't need the refcount any more.
*/
+static bool is_suspended(struct mddev *mddev, struct bio *bio)
+{
+ if (mddev->suspended)
+ return true;
+ if (bio_data_dir(bio) != WRITE)
+ return false;
+ if (mddev->suspend_lo >= mddev->suspend_hi)
+ return false;
+ if (bio->bi_iter.bi_sector >= mddev->suspend_hi)
+ return false;
+ if (bio_end_sector(bio) < mddev->suspend_lo)
+ return false;
+ return true;
+}
+
void md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
rcu_read_lock();
- if (mddev->suspended) {
+ if (is_suspended(mddev, bio)) {
DEFINE_WAIT(__wait);
for (;;) {
prepare_to_wait(&mddev->sb_wait, &__wait,
TASK_UNINTERRUPTIBLE);
- if (!mddev->suspended)
+ if (!is_suspended(mddev, bio))
break;
rcu_read_unlock();
schedule();
@@ -4849,10 +4864,11 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len)
goto unlock;
old = mddev->suspend_lo;
mddev->suspend_lo = new;
- if (new >= old)
+ if (new >= old) {
/* Shrinking suspended region */
+ wake_up(&mddev->sb_wait);
mddev->pers->quiesce(mddev, 2);
- else {
+ } else {
/* Expanding suspended region - need to wait */
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
@@ -4892,10 +4908,11 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len)
goto unlock;
old = mddev->suspend_hi;
mddev->suspend_hi = new;
- if (new <= old)
+ if (new <= old) {
/* Shrinking suspended region */
+ wake_up(&mddev->sb_wait);
mddev->pers->quiesce(mddev, 2);
- else {
+ } else {
/* Expanding suspended region - need to wait */
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);