diff options
author | Boaz Harrosh <bharrosh@panasas.com> | 2009-03-31 13:05:29 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-04-03 10:22:56 -0400 |
commit | 8c0baccadc86d9f07e663dd255751dd70e461ba3 (patch) | |
tree | 334d6d79b8159042779a458bf90c20292aa56efb /drivers | |
parent | a9bddd74630b2a1f2dedc537417c372b2d9edc76 (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.c | 42 |
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 | } |
339 | EXPORT_SYMBOL(osd_start_request); | 339 | EXPORT_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 | */ | ||
345 | static 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 | |||
355 | static void _osd_free_seg(struct osd_request *or __unused, | 341 | static 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 | ||
352 | static 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 | |||
366 | void osd_end_request(struct osd_request *or) | 371 | void 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 | } |