diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2010-07-09 17:28:10 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-10-14 12:31:43 -0400 |
commit | d28fd092a55b504a0d699b65802a995086d70647 (patch) | |
tree | 80071a61faa7e38cd6df6be155dd99e0f455a821 /drivers | |
parent | e756414f7daa93b862f1670dd0a6aaa676ea71e3 (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.c | 42 |
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 | ||
956 | fail_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 | |||
979 | fail_free_complete: | 971 | fail_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); |