aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBoaz Harrosh <bharrosh@panasas.com>2009-03-31 13:05:29 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-04-03 10:22:56 -0400
commit8c0baccadc86d9f07e663dd255751dd70e461ba3 (patch)
tree334d6d79b8159042779a458bf90c20292aa56efb /drivers
parenta9bddd74630b2a1f2dedc537417c372b2d9edc76 (diff)
[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: Xu Yang <onlyxuyang@qq.com> Signed-off-by: Boaz Harrosh <bharrosh@panasas.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/osd/osd_initiator.c42
1 files changed, 24 insertions, 18 deletions
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c
index 552f58b655d1..2a5f0777148d 100644
--- a/drivers/scsi/osd/osd_initiator.c
+++ b/drivers/scsi/osd/osd_initiator.c
@@ -338,20 +338,6 @@ struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp)
338} 338}
339EXPORT_SYMBOL(osd_start_request); 339EXPORT_SYMBOL(osd_start_request);
340 340
341/*
342 * If osd_finalize_request() was called but the request was not executed through
343 * the block layer, then we must release BIOs.
344 */
345static void _abort_unexecuted_bios(struct request *rq)
346{
347 struct bio *bio;
348
349 while ((bio = rq->bio) != NULL) {
350 rq->bio = bio->bi_next;
351 bio_endio(bio, 0);
352 }
353}
354
355static void _osd_free_seg(struct osd_request *or __unused, 341static void _osd_free_seg(struct osd_request *or __unused,
356 struct _osd_req_data_segment *seg) 342 struct _osd_req_data_segment *seg)
357{ 343{
@@ -363,9 +349,30 @@ static void _osd_free_seg(struct osd_request *or __unused,
363 seg->alloc_size = 0; 349 seg->alloc_size = 0;
364} 350}
365 351
352static void _put_request(struct request *rq , bool is_async)
353{
354 if (is_async) {
355 WARN_ON(rq->bio);
356 __blk_put_request(rq->q, rq);
357 } else {
358 /*
359 * If osd_finalize_request() was called but the request was not
360 * executed through the block layer, then we must release BIOs.
361 * TODO: Keep error code in or->async_error. Need to audit all
362 * code paths.
363 */
364 if (unlikely(rq->bio))
365 blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq));
366 else
367 blk_put_request(rq);
368 }
369}
370
366void osd_end_request(struct osd_request *or) 371void osd_end_request(struct osd_request *or)
367{ 372{
368 struct request *rq = or->request; 373 struct request *rq = or->request;
374 /* IMPORTANT: make sure this agrees with osd_execute_request_async */
375 bool is_async = (or->request->end_io_data == or);
369 376
370 _osd_free_seg(or, &or->set_attr); 377 _osd_free_seg(or, &or->set_attr);
371 _osd_free_seg(or, &or->enc_get_attr); 378 _osd_free_seg(or, &or->enc_get_attr);
@@ -373,12 +380,11 @@ void osd_end_request(struct osd_request *or)
373 380
374 if (rq) { 381 if (rq) {
375 if (rq->next_rq) { 382 if (rq->next_rq) {
376 _abort_unexecuted_bios(rq->next_rq); 383 _put_request(rq->next_rq, is_async);
377 blk_put_request(rq->next_rq); 384 rq->next_rq = NULL;
378 } 385 }
379 386
380 _abort_unexecuted_bios(rq); 387 _put_request(rq, is_async);
381 blk_put_request(rq);
382 } 388 }
383 _osd_request_free(or); 389 _osd_request_free(or);
384} 390}