diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2013-02-28 04:30:19 -0500 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-11-25 11:22:03 -0500 |
commit | 7dbb4386b90a13a7b0cab12aae184e5e04c536c3 (patch) | |
tree | 6a2d4915247505c314e8b3cceb2e1eeb45980cba | |
parent | f85d9f2d02cdcd1b79e00fccd667b37b251ba3ac (diff) |
drbd: make suspend_io() / resume_io() must be thread and recursion safe
Avoid to prematurely resume application IO: don't set/clear a single
bit, but inc/dec an atomic counter.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 4 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 8 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_state.c | 2 |
3 files changed, 8 insertions, 6 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index a26265375e1e..df3d89d5777a 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -500,7 +500,6 @@ enum { | |||
500 | 500 | ||
501 | MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */ | 501 | MD_NO_FUA, /* Users wants us to not use FUA/FLUSH on meta data dev */ |
502 | 502 | ||
503 | SUSPEND_IO, /* suspend application io */ | ||
504 | BITMAP_IO, /* suspend application io; | 503 | BITMAP_IO, /* suspend application io; |
505 | once no more io in flight, start bitmap io */ | 504 | once no more io in flight, start bitmap io */ |
506 | BITMAP_IO_QUEUED, /* Started bitmap IO */ | 505 | BITMAP_IO_QUEUED, /* Started bitmap IO */ |
@@ -880,6 +879,7 @@ struct drbd_device { | |||
880 | atomic_t rs_pending_cnt; /* RS request/data packets on the wire */ | 879 | atomic_t rs_pending_cnt; /* RS request/data packets on the wire */ |
881 | atomic_t unacked_cnt; /* Need to send replies for */ | 880 | atomic_t unacked_cnt; /* Need to send replies for */ |
882 | atomic_t local_cnt; /* Waiting for local completion */ | 881 | atomic_t local_cnt; /* Waiting for local completion */ |
882 | atomic_t suspend_cnt; | ||
883 | 883 | ||
884 | /* Interval tree of pending local requests */ | 884 | /* Interval tree of pending local requests */ |
885 | struct rb_root read_requests; | 885 | struct rb_root read_requests; |
@@ -2263,7 +2263,7 @@ static inline bool may_inc_ap_bio(struct drbd_device *device) | |||
2263 | 2263 | ||
2264 | if (drbd_suspended(device)) | 2264 | if (drbd_suspended(device)) |
2265 | return false; | 2265 | return false; |
2266 | if (test_bit(SUSPEND_IO, &device->flags)) | 2266 | if (atomic_read(&device->suspend_cnt)) |
2267 | return false; | 2267 | return false; |
2268 | 2268 | ||
2269 | /* to avoid potential deadlock or bitmap corruption, | 2269 | /* to avoid potential deadlock or bitmap corruption, |
diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 613778994b23..c7cd3df8107e 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c | |||
@@ -865,9 +865,11 @@ char *ppsize(char *buf, unsigned long long size) | |||
865 | * and can be long lived. | 865 | * and can be long lived. |
866 | * This changes an device->flag, is triggered by drbd internals, | 866 | * This changes an device->flag, is triggered by drbd internals, |
867 | * and should be short-lived. */ | 867 | * and should be short-lived. */ |
868 | /* It needs to be a counter, since multiple threads might | ||
869 | independently suspend and resume IO. */ | ||
868 | void drbd_suspend_io(struct drbd_device *device) | 870 | void drbd_suspend_io(struct drbd_device *device) |
869 | { | 871 | { |
870 | set_bit(SUSPEND_IO, &device->flags); | 872 | atomic_inc(&device->suspend_cnt); |
871 | if (drbd_suspended(device)) | 873 | if (drbd_suspended(device)) |
872 | return; | 874 | return; |
873 | wait_event(device->misc_wait, !atomic_read(&device->ap_bio_cnt)); | 875 | wait_event(device->misc_wait, !atomic_read(&device->ap_bio_cnt)); |
@@ -875,8 +877,8 @@ void drbd_suspend_io(struct drbd_device *device) | |||
875 | 877 | ||
876 | void drbd_resume_io(struct drbd_device *device) | 878 | void drbd_resume_io(struct drbd_device *device) |
877 | { | 879 | { |
878 | clear_bit(SUSPEND_IO, &device->flags); | 880 | if (atomic_dec_and_test(&device->suspend_cnt)) |
879 | wake_up(&device->misc_wait); | 881 | wake_up(&device->misc_wait); |
880 | } | 882 | } |
881 | 883 | ||
882 | /** | 884 | /** |
diff --git a/drivers/block/drbd/drbd_state.c b/drivers/block/drbd/drbd_state.c index f022e99f9855..5a7ef7873b67 100644 --- a/drivers/block/drbd/drbd_state.c +++ b/drivers/block/drbd/drbd_state.c | |||
@@ -1484,7 +1484,7 @@ int drbd_bitmap_io_from_worker(struct drbd_device *device, | |||
1484 | D_ASSERT(device, current == first_peer_device(device)->connection->worker.task); | 1484 | D_ASSERT(device, current == first_peer_device(device)->connection->worker.task); |
1485 | 1485 | ||
1486 | /* open coded non-blocking drbd_suspend_io(device); */ | 1486 | /* open coded non-blocking drbd_suspend_io(device); */ |
1487 | set_bit(SUSPEND_IO, &device->flags); | 1487 | atomic_inc(&device->suspend_cnt); |
1488 | 1488 | ||
1489 | drbd_bm_lock(device, why, flags); | 1489 | drbd_bm_lock(device, why, flags); |
1490 | rv = io_fn(device); | 1490 | rv = io_fn(device); |