drbd: fix list corruption (recent regression)
The commit 288f422ec1
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>
This commit is contained in:
parent
e756414f7d
commit
d28fd092a5
1 changed files with 17 additions and 25 deletions
|
@ -917,31 +917,8 @@ allocate_barrier:
|
||||||
/* check this request on the collision detection hash tables.
|
/* check this request on the collision detection hash tables.
|
||||||
* if we have a conflict, just complete it here.
|
* if we have a conflict, just complete it here.
|
||||||
* THINK do we want to check reads, too? (I don't think so...) */
|
* THINK do we want to check reads, too? (I don't think so...) */
|
||||||
if (rw == WRITE && _req_conflicts(req)) {
|
if (rw == WRITE && _req_conflicts(req))
|
||||||
/* this is a conflicting request.
|
goto fail_conflicting;
|
||||||
* even though it may have been only _partially_
|
|
||||||
* overlapping with one of the currently pending requests,
|
|
||||||
* without even submitting or sending it, we will
|
|
||||||
* pretend that it was successfully served right now.
|
|
||||||
*/
|
|
||||||
if (local) {
|
|
||||||
bio_put(req->private_bio);
|
|
||||||
req->private_bio = NULL;
|
|
||||||
drbd_al_complete_io(mdev, req->sector);
|
|
||||||
put_ldev(mdev);
|
|
||||||
local = 0;
|
|
||||||
}
|
|
||||||
if (remote)
|
|
||||||
dec_ap_pending(mdev);
|
|
||||||
_drbd_end_io_acct(mdev, req);
|
|
||||||
/* THINK: do we want to fail it (-EIO), or pretend success? */
|
|
||||||
bio_endio(req->master_bio, 0);
|
|
||||||
req->master_bio = NULL;
|
|
||||||
dec_ap_bio(mdev);
|
|
||||||
drbd_req_free(req);
|
|
||||||
remote = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
list_add_tail(&req->tl_requests, &mdev->newest_tle->requests);
|
list_add_tail(&req->tl_requests, &mdev->newest_tle->requests);
|
||||||
|
|
||||||
|
@ -976,6 +953,21 @@ allocate_barrier:
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_conflicting:
|
||||||
|
/* this is a conflicting request.
|
||||||
|
* even though it may have been only _partially_
|
||||||
|
* overlapping with one of the currently pending requests,
|
||||||
|
* without even submitting or sending it, we will
|
||||||
|
* pretend that it was successfully served right now.
|
||||||
|
*/
|
||||||
|
_drbd_end_io_acct(mdev, req);
|
||||||
|
spin_unlock_irq(&mdev->req_lock);
|
||||||
|
if (remote)
|
||||||
|
dec_ap_pending(mdev);
|
||||||
|
/* THINK: do we want to fail it (-EIO), or pretend success?
|
||||||
|
* this pretends success. */
|
||||||
|
err = 0;
|
||||||
|
|
||||||
fail_free_complete:
|
fail_free_complete:
|
||||||
if (rw == WRITE && local)
|
if (rw == WRITE && local)
|
||||||
drbd_al_complete_io(mdev, sector);
|
drbd_al_complete_io(mdev, sector);
|
||||||
|
|
Reference in a new issue