Re: [Bugme-new] [Bug 7667] New: BUG at drivers/scsi/scsi_lib.c:1118 caused by "pktsetup dvd /dev/sr0"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Christoph Hellwig wrote:
> On Tue, Dec 12, 2006 at 11:38:42AM +0100, Christoph Hellwig wrote:
>> This is because the packet driver tries to send down read/write
>> BLOCK_PC commands that don't use a bio and do not use sg lists.
>> As part of the patch you mentioned I added strict assertations for that
>> case because the scsi layer doesn't handle those anymore.
>>
>> The right fix is to replace all the packet_command stuff in the packet
>> driver by scsi_execute() which needs to be lifted from scsi code to
>> the block code for that.  I'll prepare a patch this weekend unless
>> someone beets me in doing that work.
> 
> Please try the patch below to fix the bug for now.  It's not the
> full way to a generic execute block pc infrastcuture but should fix
> the bug for the time beeing:
> 
> 
> Signed-off-by: Christoph Hellwig <hch@xxxxxx>
> 
> Index: linux-2.6/drivers/block/pktcdvd.c
> ===================================================================
> --- linux-2.6.orig/drivers/block/pktcdvd.c	2006-12-12 11:30:45.000000000 +0100
> +++ linux-2.6/drivers/block/pktcdvd.c	2006-12-12 14:23:37.000000000 +0100
> @@ -765,47 +765,34 @@
>   */
>  static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *cgc)
>  {
> -	char sense[SCSI_SENSE_BUFFERSIZE];
> -	request_queue_t *q;
> +	request_queue_t *q = bdev_get_queue(pd->bdev);
>  	struct request *rq;
> -	DECLARE_COMPLETION_ONSTACK(wait);
> -	int err = 0;
> +	int ret = 0;
>  
> -	q = bdev_get_queue(pd->bdev);
> +	rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ?
> +			     WRITE : READ, __GFP_WAIT);
> +
> +	if (cgc->buflen) {
> +		if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
> +			goto out;
> +	}
> +
> +	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
> +	memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
> +	if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
> +		memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
>  
> -	rq = blk_get_request(q, (cgc->data_direction == CGC_DATA_WRITE) ? WRITE : READ,
> -			     __GFP_WAIT);
> -	rq->errors = 0;
> -	rq->rq_disk = pd->bdev->bd_disk;
> -	rq->bio = NULL;
> -	rq->buffer = NULL;
>  	rq->timeout = 60*HZ;
> -	rq->data = cgc->buffer;
> -	rq->data_len = cgc->buflen;
> -	rq->sense = sense;
> -	memset(sense, 0, sizeof(sense));
> -	rq->sense_len = 0;
>  	rq->cmd_type = REQ_TYPE_BLOCK_PC;
>  	rq->cmd_flags |= REQ_HARDBARRIER;
>  	if (cgc->quiet)
>  		rq->cmd_flags |= REQ_QUIET;
> -	memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
> -	if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
> -		memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
> -	rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
> -
> -	rq->ref_count++;
> -	rq->end_io_data = &wait;
> -	rq->end_io = blk_end_sync_rq;
> -	elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
> -	generic_unplug_device(q);
> -	wait_for_completion(&wait);
> -
> -	if (rq->errors)
> -		err = -EIO;
>  
> +	blk_execute_rq(rq->q, pd->bdev->bd_disk, rq, 0);
> +	ret = rq->errors;
> +out:
>  	blk_put_request(rq);
> -	return err;
> +	return ret;
>  }
>  
>  /*
> -
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
I'm afraid this might not be enough because of code in drivers/ide/ide-cd.c. It does IO off of request->data.

[background]
pkt_generic_packet and ton of other places mainly cd(s), floppy(s), and other ide code paths,
are using what I call BLACK requests. They put some data on request->buffer or request->data
stick it in the Q and than advance on them later down the ladder. Remove of "buffer" and "data" from
struct request will reveal all these places. At one time I had plans to do just that. But 1/2 way through I gave
up, it is too risky, too much Hardware that I don't have, that needs checking.

below patch combined with your patch might get a bit closer for this code path.
At struct request I have changed the name of "data" member to "user_data". than changed the code paths that used
"data" as IO to use request->buffer instead. This is just as bad but is a more common practice.

I suspect there is a problem with what I did in scsi_lib.c Christoph please check me out with the new BUG_ON.
Mainly what you need from below is only the code in ide-cd.c.
(And there are 3-4 places that do exactly like pkt_generic_packet, though I'm not sure they end up through SCSI.
At first I thought this code doesn't either)

diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 9eaee66..f52a4f2 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -257,7 +257,7 @@ static void rq_init(request_queue_t *q,
 	rq->q = q;
 	rq->special = NULL;
 	rq->data_len = 0;
-	rq->data = NULL;
+	rq->user_data = NULL;
 	rq->nr_phys_segments = 0;
 	rq->sense = NULL;
 	rq->end_io = NULL;
@@ -1199,7 +1199,7 @@ void blk_dump_rq_flags(struct request *r
 	printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector,
 						       rq->nr_sectors,
 						       rq->current_nr_sectors);
-	printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len);
+	printk("bio %p, biotail %p, buffer %p, user_data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->user_data, rq->data_len);

 	if (blk_pc_request(rq)) {
 		printk("cdb: ");
@@ -2370,7 +2370,7 @@ int blk_rq_map_user(request_queue_t *q,
 		rq->bio = rq->biotail = bio;
 		blk_rq_bio_prep(q, rq, bio);

-		rq->buffer = rq->data = NULL;
+		rq->buffer = NULL;
 		rq->data_len = len;
 		return 0;
 	}
@@ -2420,7 +2420,7 @@ int blk_rq_map_user_iov(request_queue_t

 	rq->bio = rq->biotail = bio;
 	blk_rq_bio_prep(q, rq, bio);
-	rq->buffer = rq->data = NULL;
+	rq->buffer = NULL;
 	rq->data_len = bio->bi_size;
 	return 0;
 }
@@ -2479,7 +2479,7 @@ int blk_rq_map_kern(request_queue_t *q,
 	rq->bio = rq->biotail = bio;
 	blk_rq_bio_prep(q, rq, bio);

-	rq->buffer = rq->data = NULL;
+	rq->buffer = NULL;
 	rq->data_len = len;
 	return 0;
 }
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index dcd9c71..d163a2c 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -502,7 +502,6 @@ static int __blk_send_generic(request_qu

 	rq = blk_get_request(q, WRITE, __GFP_WAIT);
 	rq->cmd_type = REQ_TYPE_BLOCK_PC;
-	rq->data = NULL;
 	rq->data_len = 0;
 	rq->timeout = BLK_DEFAULT_TIMEOUT;
 	memset(rq->cmd, 0, sizeof(rq->cmd));
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index f2904f6..b72758c 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -360,9 +360,8 @@ static int pkt_generic_packet(struct pkt
 	rq->errors = 0;
 	rq->rq_disk = pd->bdev->bd_disk;
 	rq->bio = NULL;
-	rq->buffer = NULL;
 	rq->timeout = 60*HZ;
-	rq->data = cgc->buffer;
+	rq->buffer = cgc->buffer;
 	rq->data_len = cgc->buflen;
 	rq->sense = sense;
 	memset(sense, 0, sizeof(sense));
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 8821494..00fce03 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -613,14 +613,14 @@ static void cdrom_queue_request_sense(id
 	/* stuff the sense request in front of our current request */
 	cdrom_prepare_request(drive, rq);

-	rq->data = sense;
+	rq->buffer = sense;
 	rq->cmd[0] = GPCMD_REQUEST_SENSE;
 	rq->cmd[4] = rq->data_len = 18;

 	rq->cmd_type = REQ_TYPE_SENSE;

-	/* NOTE! Save the failed command in "rq->buffer" */
-	rq->buffer = (void *) failed_command;
+	/* NOTE! Save the failed command in "rq->user_data" */
+	rq->user_data = failed_command;

 	(void) ide_do_drive_cmd(drive, rq, ide_preempt);
 }
@@ -632,10 +632,10 @@ static void cdrom_end_request (ide_drive

 	if (blk_sense_request(rq) && uptodate) {
 		/*
-		 * For REQ_TYPE_SENSE, "rq->buffer" points to the original
+		 * For REQ_TYPE_SENSE, "rq->user_data" points to the original
 		 * failed request
 		 */
-		struct request *failed = (struct request *) rq->buffer;
+		struct request *failed = rq->user_data;
 		struct cdrom_info *info = drive->driver_data;
 		void *sense = &info->sense_data;
 		unsigned long flags;
@@ -1441,7 +1441,7 @@ static ide_startstop_t cdrom_pc_intr (id
 		    rq->data_len > 0 &&
 		    rq->data_len <= 5) {
 			while (rq->data_len > 0) {
-				*(unsigned char *)rq->data++ = 0;
+				*(unsigned char *)rq->buffer++ = 0;
 				--rq->data_len;
 			}
 		}
@@ -1468,12 +1468,12 @@ static ide_startstop_t cdrom_pc_intr (id

 	/* The drive wants to be written to. */
 	if ((ireason & 3) == 0) {
-		if (!rq->data) {
+		if (!rq->buffer) {
 			blk_dump_rq_flags(rq, "cdrom_pc_intr, write");
 			goto confused;
 		}
 		/* Transfer the data. */
-		HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);
+		HWIF(drive)->atapi_output_bytes(drive, rq->buffer, thislen);

 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
@@ -1484,18 +1484,18 @@ static ide_startstop_t cdrom_pc_intr (id
 		}

 		/* Keep count of how much data we've moved. */
-		rq->data += thislen;
+		rq->buffer += thislen;
 		rq->data_len -= thislen;
 	}

 	/* Same drill for reading. */
 	else if ((ireason & 3) == 2) {
-		if (!rq->data) {
+		if (!rq->buffer) {
 			blk_dump_rq_flags(rq, "cdrom_pc_intr, write");
 			goto confused;
 		}
 		/* Transfer the data. */
-		HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);
+		HWIF(drive)->atapi_input_bytes(drive, rq->buffer, thislen);

 		/* If we haven't moved enough data to satisfy the drive,
 		   add some padding. */
@@ -1506,7 +1506,7 @@ static ide_startstop_t cdrom_pc_intr (id
 		}

 		/* Keep count of how much data we've moved. */
-		rq->data += thislen;
+		rq->buffer += thislen;
 		rq->data_len -= thislen;

 		if (blk_sense_request(rq))
@@ -1644,7 +1644,7 @@ static void post_transform_command(struc
 	if (req->bio)
 		ibuf = bio_data(req->bio);
 	else
-		ibuf = req->data;
+		ibuf = req->buffer;

 	if (!ibuf)
 		return;
@@ -1662,7 +1662,7 @@ typedef void (xfer_func_t)(ide_drive_t *

 /*
  * best way to deal with dma that is not sector aligned right now... note
- * that in this path we are not using ->data or ->buffer at all. this irs
+ * that in this path we are not using ->buffer at all. this irs
  * can replace cdrom_pc_intr, cdrom_read_intr, and cdrom_write_intr in the
  * future.
  */
@@ -1745,7 +1745,7 @@ static ide_startstop_t cdrom_newpc_intr(
 	 */
 	while (thislen > 0) {
 		int blen = blen = rq->data_len;
-		char *ptr = rq->data;
+		char *ptr = rq->buffer;

 		/*
 		 * bio backed?
@@ -1772,7 +1772,7 @@ static ide_startstop_t cdrom_newpc_intr(
 		if (rq->bio)
 			end_that_request_chunk(rq, 1, blen);
 		else
-			rq->data += blen;
+			rq->buffer += blen;
 	}

 	/*
@@ -2206,7 +2206,7 @@ static int cdrom_read_capacity(ide_drive

 	req.sense = sense;
 	req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
-	req.data = (char *)&capbuf;
+	req.buffer = (char *)&capbuf;
 	req.data_len = sizeof(capbuf);
 	req.cmd_flags |= REQ_QUIET;

@@ -2229,7 +2229,7 @@ static int cdrom_read_tocentry(ide_drive
 	cdrom_prepare_request(drive, &req);

 	req.sense = sense;
-	req.data =  buf;
+	req.buffer =  buf;
 	req.data_len = buflen;
 	req.cmd_flags |= REQ_QUIET;
 	req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
@@ -2324,7 +2324,7 @@ #endif  /* not STANDARD_ATAPI */
 		   If we get an error for the regular case, we assume
 		   a CDI without additional audio tracks. In this case
 		   the readable TOC is empty (CDI tracks are not included)
-		   and only holds the Leadout entry. Heiko Ei�eldt */
+		   and only holds the Leadout entry. Heiko Ei�eldt */
 		ntracks = 0;
 		stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0,
 					   (char *)&toc->hdr,
@@ -2426,7 +2426,7 @@ static int cdrom_read_subchannel(ide_dri
 	cdrom_prepare_request(drive, &req);

 	req.sense = sense;
-	req.data = buf;
+	req.buffer = buf;
 	req.data_len = buflen;
 	req.cmd[0] = GPCMD_READ_SUBCHANNEL;
 	req.cmd[1] = 2;     /* MSF addressing */
@@ -2527,7 +2527,7 @@ static int ide_cdrom_packet(struct cdrom
 	memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
 	if (cgc->sense)
 		memset(cgc->sense, 0, sizeof(struct request_sense));
-	req.data = cgc->buffer;
+	req.buffer = cgc->buffer;
 	req.data_len = cgc->buflen;
 	req.timeout = cgc->timeout;

diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 2614f41..dbf0295 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -141,7 +141,7 @@ enum {

 static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
 {
-	struct request_pm_state *pm = rq->data;
+	struct request_pm_state *pm = rq->user_data;

 	if (drive->media != ide_disk)
 		return;
@@ -167,7 +167,7 @@ static void ide_complete_power_step(ide_

 static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
 {
-	struct request_pm_state *pm = rq->data;
+	struct request_pm_state *pm = rq->user_data;
 	ide_task_t *args = rq->special;

 	memset(args, 0, sizeof(*args));
@@ -433,7 +433,7 @@ void ide_end_drive_cmd (ide_drive_t *dri
 			}
 		}
 	} else if (blk_pm_request(rq)) {
-		struct request_pm_state *pm = rq->data;
+		struct request_pm_state *pm = rq->user_data;
 #ifdef DEBUG_PM
 		printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
 			drive->name, rq->pm->pm_step, stat, err);
@@ -945,7 +945,7 @@ #endif

 static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
 {
-	struct request_pm_state *pm = rq->data;
+	struct request_pm_state *pm = rq->user_data;

 	if (blk_pm_suspend_request(rq) &&
 	    pm->pm_step == ide_pm_state_start_suspend)
@@ -1030,7 +1030,7 @@ #endif
 		    rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
 			return execute_drive_cmd(drive, rq);
 		else if (blk_pm_request(rq)) {
-			struct request_pm_state *pm = rq->data;
+			struct request_pm_state *pm = rq->user_data;
 #ifdef DEBUG_PM
 			printk("%s: start_power_step(step: %d)\n",
 				drive->name, rq->pm->pm_step);
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 287a662..47a6110 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -1223,7 +1223,7 @@ static int generic_ide_suspend(struct de
 	memset(&args, 0, sizeof(args));
 	rq.cmd_type = REQ_TYPE_PM_SUSPEND;
 	rq.special = &args;
-	rq.data = &rqpm;
+	rq.user_data = &rqpm;
 	rqpm.pm_step = ide_pm_state_start_suspend;
 	if (mesg.event == PM_EVENT_PRETHAW)
 		mesg.event = PM_EVENT_FREEZE;
@@ -1244,7 +1244,7 @@ static int generic_ide_resume(struct dev
 	memset(&args, 0, sizeof(args));
 	rq.cmd_type = REQ_TYPE_PM_RESUME;
 	rq.special = &args;
-	rq.data = &rqpm;
+	rq.user_data = &rqpm;
 	rqpm.pm_step = ide_pm_state_start_resume;
 	rqpm.pm_state = PM_EVENT_ON;

diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index fb616c6..bea6e9e 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -351,7 +351,7 @@ static int scsi_req_map_sg(struct reques
 		}
 	}

-	rq->buffer = rq->data = NULL;
+	rq->buffer = NULL;
 	rq->data_len = data_len;
 	return 0;

@@ -1116,12 +1116,11 @@ static int scsi_setup_blk_pc_cmnd(struct
 			return ret;
 	} else {
 		BUG_ON(req->data_len);
-		BUG_ON(req->data);
+		BUG_ON(req->buffer);

 		cmd->request_bufflen = 0;
 		cmd->request_buffer = NULL;
 		cmd->use_sg = 0;
-		req->buffer = NULL;
 	}

 	BUILD_BUG_ON(sizeof(req->cmd) > sizeof(cmd->cmnd));
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 7bfcde2..beb1f8d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -288,7 +288,8 @@ struct request {
 	unsigned short ioprio;

 	void *special;
-	char *buffer;
+	char *buffer;			/* FIXME: Deprecated */
+	void *user_data;		/* FIXME: used to be *data. Deprecated this allready */

 	int tag;
 	int errors;
@@ -303,7 +304,6 @@ struct request {

 	unsigned int data_len;
 	unsigned int sense_len;
-	void *data;
 	void *sense;

 	unsigned int timeout;




-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux