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

Commit 8c0bacca authored by Boaz Harrosh's avatar Boaz Harrosh Committed by James Bottomley
Browse files

[SCSI] libosd: fix blk_put_request called from within request_end_io



A fix for a very serious and stupid bug in osd_initiator. It
used to call blk_put_request() regardless of if it was from
the end_io callback or if called after a sync execution.
It should call the unlocked version __blk_put_request() instead.

Also fixed is the remove of _abort_unexecuted_bios hack, and use of
blk_end_request(,-ERROR,) to deallocate half baked requests. I've
audited the code and it should be safe.

Reported and
Tested-by: default avatarXu Yang <onlyxuyang@qq.com>
Signed-off-by: default avatarBoaz Harrosh <bharrosh@panasas.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent a9bddd74
Loading
Loading
Loading
Loading
+24 −18
Original line number Original line Diff line number Diff line
@@ -338,20 +338,6 @@ struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp)
}
}
EXPORT_SYMBOL(osd_start_request);
EXPORT_SYMBOL(osd_start_request);


/*
 * If osd_finalize_request() was called but the request was not executed through
 * the block layer, then we must release BIOs.
 */
static void _abort_unexecuted_bios(struct request *rq)
{
	struct bio *bio;

	while ((bio = rq->bio) != NULL) {
		rq->bio = bio->bi_next;
		bio_endio(bio, 0);
	}
}

static void _osd_free_seg(struct osd_request *or __unused,
static void _osd_free_seg(struct osd_request *or __unused,
	struct _osd_req_data_segment *seg)
	struct _osd_req_data_segment *seg)
{
{
@@ -363,9 +349,30 @@ static void _osd_free_seg(struct osd_request *or __unused,
	seg->alloc_size = 0;
	seg->alloc_size = 0;
}
}


static void _put_request(struct request *rq , bool is_async)
{
	if (is_async) {
		WARN_ON(rq->bio);
		__blk_put_request(rq->q, rq);
	} else {
		/*
		 * If osd_finalize_request() was called but the request was not
		 * executed through the block layer, then we must release BIOs.
		 * TODO: Keep error code in or->async_error. Need to audit all
		 *       code paths.
		 */
		if (unlikely(rq->bio))
			blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq));
		else
			blk_put_request(rq);
	}
}

void osd_end_request(struct osd_request *or)
void osd_end_request(struct osd_request *or)
{
{
	struct request *rq = or->request;
	struct request *rq = or->request;
	/* IMPORTANT: make sure this agrees with osd_execute_request_async */
	bool is_async = (or->request->end_io_data == or);


	_osd_free_seg(or, &or->set_attr);
	_osd_free_seg(or, &or->set_attr);
	_osd_free_seg(or, &or->enc_get_attr);
	_osd_free_seg(or, &or->enc_get_attr);
@@ -373,12 +380,11 @@ void osd_end_request(struct osd_request *or)


	if (rq) {
	if (rq) {
		if (rq->next_rq) {
		if (rq->next_rq) {
			_abort_unexecuted_bios(rq->next_rq);
			_put_request(rq->next_rq, is_async);
			blk_put_request(rq->next_rq);
			rq->next_rq = NULL;
		}
		}


		_abort_unexecuted_bios(rq);
		_put_request(rq, is_async);
		blk_put_request(rq);
	}
	}
	_osd_request_free(or);
	_osd_request_free(or);
}
}