aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2010-07-09 17:28:10 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2010-10-14 12:31:43 -0400
commitd28fd092a55b504a0d699b65802a995086d70647 (patch)
tree80071a61faa7e38cd6df6be155dd99e0f455a821 /drivers
parente756414f7daa93b862f1670dd0a6aaa676ea71e3 (diff)
drbd: fix list corruption (recent regression)
The commit 288f422ec13667de40b278535d2a5fb5c77352c4 drbd: Track all IO requests on the TL, not writes only moved a list_add_tail(req, ) into a region where req may have just been freed due to conflict detection. Fix this by adding a proper cleanup section for that code path. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/block/drbd/drbd_req.c42
1 files changed, 17 insertions, 25 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index 4e1e10d67c4b..3b61d767d9c4 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -917,31 +917,8 @@ allocate_barrier:
917 /* check this request on the collision detection hash tables. 917 /* check this request on the collision detection hash tables.
918 * if we have a conflict, just complete it here. 918 * if we have a conflict, just complete it here.
919 * THINK do we want to check reads, too? (I don't think so...) */ 919 * THINK do we want to check reads, too? (I don't think so...) */
920 if (rw == WRITE && _req_conflicts(req)) { 920 if (rw == WRITE && _req_conflicts(req))
921 /* this is a conflicting request. 921 goto fail_conflicting;
922 * even though it may have been only _partially_
923 * overlapping with one of the currently pending requests,
924 * without even submitting or sending it, we will
925 * pretend that it was successfully served right now.
926 */
927 if (local) {
928 bio_put(req->private_bio);
929 req->private_bio = NULL;
930 drbd_al_complete_io(mdev, req->sector);
931 put_ldev(mdev);
932 local = 0;
933 }
934 if (remote)
935 dec_ap_pending(mdev);
936 _drbd_end_io_acct(mdev, req);
937 /* THINK: do we want to fail it (-EIO), or pretend success? */
938 bio_endio(req->master_bio, 0);
939 req->master_bio = NULL;
940 dec_ap_bio(mdev);
941 drbd_req_free(req);
942 remote = 0;
943 }
944
945 922
946 list_add_tail(&req->tl_requests, &mdev->newest_tle->requests); 923 list_add_tail(&req->tl_requests, &mdev->newest_tle->requests);
947 924
@@ -976,6 +953,21 @@ allocate_barrier:
976 953
977 return 0; 954 return 0;
978 955
956fail_conflicting:
957 /* this is a conflicting request.
958 * even though it may have been only _partially_
959 * overlapping with one of the currently pending requests,
960 * without even submitting or sending it, we will
961 * pretend that it was successfully served right now.
962 */
963 _drbd_end_io_acct(mdev, req);
964 spin_unlock_irq(&mdev->req_lock);
965 if (remote)
966 dec_ap_pending(mdev);
967 /* THINK: do we want to fail it (-EIO), or pretend success?
968 * this pretends success. */
969 err = 0;
970
979fail_free_complete: 971fail_free_complete:
980 if (rw == WRITE && local) 972 if (rw == WRITE && local)
981 drbd_al_complete_io(mdev, sector); 973 drbd_al_complete_io(mdev, sector);