diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2013-03-19 13:16:42 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2013-03-22 20:13:59 -0400 |
commit | 9114d79569a3fb858a7ecb1f21cb1dec93dc2f21 (patch) | |
tree | 871deca58015097957ca605c55d6589f72f39297 /drivers/block/drbd | |
parent | a937536b868b8369b98967929045f1df54234323 (diff) |
drbd: cleanup bogus assert message
This fixes ASSERT( mdev->state.disk == D_FAILED ) in drivers/block/drbd/drbd_main.c
When we detach from local disk, we let the local refcount hit zero twice.
First, we transition to D_FAILED, so we won't give out new references
to incoming requests; we still may give out *internal* references, though.
Once the refcount hits zero [1] while in D_FAILED, we queue a transition
to D_DISKLESS to our worker. We need to queue it, because we may be in
atomic context when putting the reference.
Once the transition to D_DISKLESS actually happened [2] from worker context,
we don't give out new internal references either.
Between hitting zero the first time [1] and actually transition to
D_DISKLESS [2], there may be a few very short lived internal get/put,
so we may hit zero more than once while being in D_FAILED, or even see a
race where a an internal get_ldev() happened while D_FAILED, but the
corresponding put_ldev() happens just after the transition to D_DISKLESS.
That's why we have the additional test_and_set_bit(GO_DISKLESS,);
and that's why the assert was placed wrong.
Since there was exactly one code path left to drbd_go_diskless(),
and that checks already for D_FAILED, drop that assert,
and fold in the drbd_queue_work().
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'drivers/block/drbd')
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 7 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 7 |
2 files changed, 4 insertions, 10 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 6b51afa1aae1..db504d021a6e 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -1148,7 +1148,6 @@ extern int drbd_bitmap_io_from_worker(struct drbd_conf *mdev, | |||
1148 | char *why, enum bm_flag flags); | 1148 | char *why, enum bm_flag flags); |
1149 | extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); | 1149 | extern int drbd_bmio_set_n_write(struct drbd_conf *mdev); |
1150 | extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); | 1150 | extern int drbd_bmio_clear_n_write(struct drbd_conf *mdev); |
1151 | extern void drbd_go_diskless(struct drbd_conf *mdev); | ||
1152 | extern void drbd_ldev_destroy(struct drbd_conf *mdev); | 1151 | extern void drbd_ldev_destroy(struct drbd_conf *mdev); |
1153 | 1152 | ||
1154 | /* Meta data layout | 1153 | /* Meta data layout |
@@ -2053,9 +2052,11 @@ static inline void put_ldev(struct drbd_conf *mdev) | |||
2053 | if (mdev->state.disk == D_DISKLESS) | 2052 | if (mdev->state.disk == D_DISKLESS) |
2054 | /* even internal references gone, safe to destroy */ | 2053 | /* even internal references gone, safe to destroy */ |
2055 | drbd_ldev_destroy(mdev); | 2054 | drbd_ldev_destroy(mdev); |
2056 | if (mdev->state.disk == D_FAILED) | 2055 | if (mdev->state.disk == D_FAILED) { |
2057 | /* all application IO references gone. */ | 2056 | /* all application IO references gone. */ |
2058 | drbd_go_diskless(mdev); | 2057 | if (!test_and_set_bit(GO_DISKLESS, &mdev->flags)) |
2058 | drbd_queue_work(&mdev->tconn->sender_work, &mdev->go_diskless); | ||
2059 | } | ||
2059 | wake_up(&mdev->misc_wait); | 2060 | wake_up(&mdev->misc_wait); |
2060 | } | 2061 | } |
2061 | } | 2062 | } |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index e98da675f0c1..731a28eedc56 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -3252,13 +3252,6 @@ static int w_go_diskless(struct drbd_work *w, int unused) | |||
3252 | return 0; | 3252 | return 0; |
3253 | } | 3253 | } |
3254 | 3254 | ||
3255 | void drbd_go_diskless(struct drbd_conf *mdev) | ||
3256 | { | ||
3257 | D_ASSERT(mdev->state.disk == D_FAILED); | ||
3258 | if (!test_and_set_bit(GO_DISKLESS, &mdev->flags)) | ||
3259 | drbd_queue_work(&mdev->tconn->sender_work, &mdev->go_diskless); | ||
3260 | } | ||
3261 | |||
3262 | /** | 3255 | /** |
3263 | * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap | 3256 | * drbd_queue_bitmap_io() - Queues an IO operation on the whole bitmap |
3264 | * @mdev: DRBD device. | 3257 | * @mdev: DRBD device. |