diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2010-09-04 19:13:24 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-10-14 12:38:34 -0400 |
commit | 1d53f09e170e477de67babd7a10e277479260d51 (patch) | |
tree | c795de9e5aeaf8324eeb25ea20c7b94f573bca83 /drivers/block/drbd | |
parent | 435f07402b3165b90592073bc0f8c6f8fa160ff9 (diff) |
drbd: fix potential kernel BUG (NULL deref)
BUG trace would look like:
lc_find
drbd_rs_complete_io
got_OVResult
drbd_asender
Could be triggered by explicit, or IO-error policy based,
detach during online-verify.
We may only dereference mdev->resync, if we first get_ldev(), as the
disk may break any time, causing mdev->resync to disappear once all
ldev references have been returned.
Already in flight online-verify requests or replies may still come in,
which we then need to ignore.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 15 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_worker.c | 10 |
2 files changed, 19 insertions, 6 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 2c3edf0ac5ca..e4e4eddf04f2 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -4241,10 +4241,13 @@ static int got_IsInSync(struct drbd_conf *mdev, struct p_header80 *h) | |||
4241 | 4241 | ||
4242 | update_peer_seq(mdev, be32_to_cpu(p->seq_num)); | 4242 | update_peer_seq(mdev, be32_to_cpu(p->seq_num)); |
4243 | 4243 | ||
4244 | drbd_rs_complete_io(mdev, sector); | 4244 | if (get_ldev(mdev)) { |
4245 | drbd_set_in_sync(mdev, sector, blksize); | 4245 | drbd_rs_complete_io(mdev, sector); |
4246 | /* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */ | 4246 | drbd_set_in_sync(mdev, sector, blksize); |
4247 | mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT); | 4247 | /* rs_same_csums is supposed to count in units of BM_BLOCK_SIZE */ |
4248 | mdev->rs_same_csum += (blksize >> BM_BLOCK_SHIFT); | ||
4249 | put_ldev(mdev); | ||
4250 | } | ||
4248 | dec_rs_pending(mdev); | 4251 | dec_rs_pending(mdev); |
4249 | atomic_add(blksize >> 9, &mdev->rs_sect_in); | 4252 | atomic_add(blksize >> 9, &mdev->rs_sect_in); |
4250 | 4253 | ||
@@ -4423,6 +4426,9 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) | |||
4423 | else | 4426 | else |
4424 | ov_oos_print(mdev); | 4427 | ov_oos_print(mdev); |
4425 | 4428 | ||
4429 | if (!get_ldev(mdev)) | ||
4430 | return TRUE; | ||
4431 | |||
4426 | drbd_rs_complete_io(mdev, sector); | 4432 | drbd_rs_complete_io(mdev, sector); |
4427 | dec_rs_pending(mdev); | 4433 | dec_rs_pending(mdev); |
4428 | 4434 | ||
@@ -4437,6 +4443,7 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header80 *h) | |||
4437 | drbd_resync_finished(mdev); | 4443 | drbd_resync_finished(mdev); |
4438 | } | 4444 | } |
4439 | } | 4445 | } |
4446 | put_ldev(mdev); | ||
4440 | return TRUE; | 4447 | return TRUE; |
4441 | } | 4448 | } |
4442 | 4449 | ||
diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c index 01743193f321..c72a5fc1c88e 100644 --- a/drivers/block/drbd/drbd_worker.c +++ b/drivers/block/drbd/drbd_worker.c | |||
@@ -1027,7 +1027,10 @@ int w_e_end_csum_rs_req(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1027 | return 1; | 1027 | return 1; |
1028 | } | 1028 | } |
1029 | 1029 | ||
1030 | drbd_rs_complete_io(mdev, e->sector); | 1030 | if (get_ldev(mdev)) { |
1031 | drbd_rs_complete_io(mdev, e->sector); | ||
1032 | put_ldev(mdev); | ||
1033 | } | ||
1031 | 1034 | ||
1032 | di = e->digest; | 1035 | di = e->digest; |
1033 | 1036 | ||
@@ -1134,7 +1137,10 @@ int w_e_end_ov_reply(struct drbd_conf *mdev, struct drbd_work *w, int cancel) | |||
1134 | 1137 | ||
1135 | /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all | 1138 | /* after "cancel", because after drbd_disconnect/drbd_rs_cancel_all |
1136 | * the resync lru has been cleaned up already */ | 1139 | * the resync lru has been cleaned up already */ |
1137 | drbd_rs_complete_io(mdev, e->sector); | 1140 | if (get_ldev(mdev)) { |
1141 | drbd_rs_complete_io(mdev, e->sector); | ||
1142 | put_ldev(mdev); | ||
1143 | } | ||
1138 | 1144 | ||
1139 | di = e->digest; | 1145 | di = e->digest; |
1140 | 1146 | ||