Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d28fd092 authored by Lars Ellenberg's avatar Lars Ellenberg Committed by Philipp Reisner
Browse files

drbd: fix list corruption (recent regression)



The commit 288f422e
 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: default avatarPhilipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: default avatarLars Ellenberg <lars.ellenberg@linbit.com>
parent e756414f
Loading
Loading
Loading
Loading
+17 −25
Original line number Original line Diff line number Diff line
@@ -917,31 +917,8 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)
	/* 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 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio)


	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);