Commit 7a599127 authored by James Bottomley's avatar James Bottomley

fix potential panic due to scsi_init_io failure [axboe@kernel.dk]

This is the problem I have solved (incorrect segments), but it also
shows a nasty bug in SCSI.

If scsi_init_io() fails there, it calls scsi_end_request() which ends
the entire request. That calls __scsi_release_command() which clears
SCpnt->request (its now gone), but you then proceed to
scsi_mlqueue_insert() which ends up doing blk_insert_request() on
SCpnt->request. Boom.

Problem is there are two possible reason to return failure from init_io.
So we need to do the requeue inside init_io.

[patch fixed to work with request prep function]
parent 710471f0
...@@ -727,13 +727,15 @@ struct Scsi_Device_Template *scsi_get_request_dev(struct request *req) ...@@ -727,13 +727,15 @@ struct Scsi_Device_Template *scsi_get_request_dev(struct request *req)
* *
* Arguments: SCpnt - Command descriptor we wish to initialize * Arguments: SCpnt - Command descriptor we wish to initialize
* *
* Returns: 1 on success. * Returns: 0 on success
* BLKPREP_DEFER if the failure is retryable
* BLKPREP_KILL if the failure is fatal
*/ */
static int scsi_init_io(Scsi_Cmnd *SCpnt) static int scsi_init_io(Scsi_Cmnd *SCpnt)
{ {
struct request *req = SCpnt->request; struct request *req = SCpnt->request;
struct scatterlist *sgpnt; struct scatterlist *sgpnt;
int count, gfp_mask; int count, gfp_mask, ret = 0;
/* /*
* if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
...@@ -743,7 +745,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt) ...@@ -743,7 +745,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
SCpnt->request_buffer = req->data; SCpnt->request_buffer = req->data;
req->buffer = req->data; req->buffer = req->data;
SCpnt->use_sg = 0; SCpnt->use_sg = 0;
return 1; return 0;
} }
/* /*
...@@ -763,8 +765,11 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt) ...@@ -763,8 +765,11 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
* if sg table allocation fails, requeue request later. * if sg table allocation fails, requeue request later.
*/ */
sgpnt = scsi_alloc_sgtable(SCpnt, gfp_mask); sgpnt = scsi_alloc_sgtable(SCpnt, gfp_mask);
if (unlikely(!sgpnt)) if (unlikely(!sgpnt)) {
req->flags |= REQ_SPECIAL;
ret = BLKPREP_DEFER;
goto out; goto out;
}
SCpnt->request_buffer = (char *) sgpnt; SCpnt->request_buffer = (char *) sgpnt;
SCpnt->request_bufflen = req->nr_sectors << 9; SCpnt->request_bufflen = req->nr_sectors << 9;
...@@ -781,12 +786,11 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt) ...@@ -781,12 +786,11 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
/* /*
* mapped well, send it off * mapped well, send it off
*/ */
if (unlikely(count > SCpnt->use_sg)) if (count <= SCpnt->use_sg) {
goto incorrect;
SCpnt->use_sg = count; SCpnt->use_sg = count;
return 1; return 0;
}
incorrect:
printk(KERN_ERR "Incorrect number of segments after building list\n"); printk(KERN_ERR "Incorrect number of segments after building list\n");
printk(KERN_ERR "counted %d, received %d\n", count, SCpnt->use_sg); printk(KERN_ERR "counted %d, received %d\n", count, SCpnt->use_sg);
printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors, printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
...@@ -797,8 +801,9 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt) ...@@ -797,8 +801,9 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
*/ */
SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors); SCpnt = scsi_end_request(SCpnt, 0, req->nr_sectors);
BUG_ON(SCpnt); BUG_ON(SCpnt);
ret = BLKPREP_KILL;
out: out:
return 0; return ret;
} }
int scsi_prep_fn(struct request_queue *q, struct request *req) int scsi_prep_fn(struct request_queue *q, struct request *req)
...@@ -872,6 +877,8 @@ int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -872,6 +877,8 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
*/ */
if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
int ret;
/* /*
* This will do a couple of things: * This will do a couple of things:
* 1) Fill in the actual SCSI command. * 1) Fill in the actual SCSI command.
...@@ -891,12 +898,8 @@ int scsi_prep_fn(struct request_queue *q, struct request *req) ...@@ -891,12 +898,8 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
* This sets up the scatter-gather table (allocating if * This sets up the scatter-gather table (allocating if
* required). * required).
*/ */
if (!scsi_init_io(SCpnt)) { if ((ret = scsi_init_io(SCpnt)))
/* Mark it as special --- We already have an return ret;
* allocated command associated with it */
req->flags |= REQ_SPECIAL;
return BLKPREP_DEFER;
}
/* /*
* Initialize the actual SCSI command for this request. * Initialize the actual SCSI command for this request.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment