aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.linux-foundation.org>2008-01-06 13:17:12 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-01-06 13:17:12 -0500
commit7b3d9545f9ac8b31528dd2d6d8ec8d19922917b8 (patch)
treee8af5ec41abf8ec3a678b5643de5580db417d16f /drivers/scsi/scsi.c
parent911833440b498e3e4fe2f12c1ae2bd44400c7004 (diff)
Revert "scsi: revert "[SCSI] Get rid of scsi_cmnd->done""
This reverts commit ac40532ef0b8649e6f7f83859ea0de1c4ed08a19, which gets us back the original cleanup of 6f5391c283d7fdcf24bf40786ea79061919d1e1d. It turns out that the bug that was triggered by that commit was apparently not actually triggered by that commit at all, and just the testing conditions had changed enough to make it appear to be due to it. The real problem seems to have been found by Peter Osterlund: "pktcdvd sets it [block device size] when opening the /dev/pktcdvd device, but when the drive is later opened as /dev/scd0, there is nothing that sets it back. (Btw, 40944 is possible if the disk is a CDRW that was formatted with "cdrwtool -m 10236".) The problem is that pktcdvd opens the cd device in non-blocking mode when pktsetup is run, and doesn't close it again until pktsetup -d is run. The effect is that if you meanwhile open the cd device, blkdev.c:do_open() doesn't call bd_set_size() because bdev->bd_openers is non-zero." In particular, to repeat the bug (regardless of whether commit 6f5391c283d7fdcf24bf40786ea79061919d1e1d is applied or not): " 1. Start with an empty drive. 2. pktsetup 0 /dev/scd0 3. Insert a CD containing an isofs filesystem. 4. mount /dev/pktcdvd/0 /mnt/tmp 5. umount /mnt/tmp 6. Press the eject button. 7. Insert a DVD containing a non-writable filesystem. 8. mount /dev/scd0 /mnt/tmp 9. find /mnt/tmp -type f -print0 | xargs -0 sha1sum >/dev/null 10. If the DVD contains data beyond the physical size of a CD, you get I/O errors in the terminal, and dmesg reports lots of "attempt to access beyond end of device" errors." which in turn is because the nested open after the media change won't cause the size to be set properly (because the original open still holds the block device, and we only do the bd_set_size() when we don't have other people holding the device open). The proper fix for that is probably to just do something like bdev->bd_inode->i_size = (loff_t)get_capacity(disk)<<9; in fs/block_dev.c:do_open() even for the cases where we're not the original opener (but *not* call bd_set_size(), since that will also change the block size of the device). Cc: Peter Osterlund <petero2@telia.com> Cc: James Bottomley <James.Bottomley@HansenPartnership.com> Cc: Matthew Wilcox <matthew@wil.cx> Cc: Ingo Molnar <mingo@elte.hu> Cc: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/scsi/scsi.c')
-rw-r--r--drivers/scsi/scsi.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 7ceb8209e5df..0fb1709ce5e3 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -59,6 +59,7 @@
59#include <scsi/scsi_cmnd.h> 59#include <scsi/scsi_cmnd.h>
60#include <scsi/scsi_dbg.h> 60#include <scsi/scsi_dbg.h>
61#include <scsi/scsi_device.h> 61#include <scsi/scsi_device.h>
62#include <scsi/scsi_driver.h>
62#include <scsi/scsi_eh.h> 63#include <scsi/scsi_eh.h>
63#include <scsi/scsi_host.h> 64#include <scsi/scsi_host.h>
64#include <scsi/scsi_tcq.h> 65#include <scsi/scsi_tcq.h>
@@ -367,9 +368,8 @@ void scsi_log_send(struct scsi_cmnd *cmd)
367 scsi_print_command(cmd); 368 scsi_print_command(cmd);
368 if (level > 3) { 369 if (level > 3) {
369 printk(KERN_INFO "buffer = 0x%p, bufflen = %d," 370 printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
370 " done = 0x%p, queuecommand 0x%p\n", 371 " queuecommand 0x%p\n",
371 scsi_sglist(cmd), scsi_bufflen(cmd), 372 scsi_sglist(cmd), scsi_bufflen(cmd),
372 cmd->done,
373 cmd->device->host->hostt->queuecommand); 373 cmd->device->host->hostt->queuecommand);
374 374
375 } 375 }
@@ -654,6 +654,12 @@ void __scsi_done(struct scsi_cmnd *cmd)
654 blk_complete_request(rq); 654 blk_complete_request(rq);
655} 655}
656 656
657/* Move this to a header if it becomes more generally useful */
658static struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd)
659{
660 return *(struct scsi_driver **)cmd->request->rq_disk->private_data;
661}
662
657/* 663/*
658 * Function: scsi_finish_command 664 * Function: scsi_finish_command
659 * 665 *
@@ -665,6 +671,8 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
665{ 671{
666 struct scsi_device *sdev = cmd->device; 672 struct scsi_device *sdev = cmd->device;
667 struct Scsi_Host *shost = sdev->host; 673 struct Scsi_Host *shost = sdev->host;
674 struct scsi_driver *drv;
675 unsigned int good_bytes;
668 676
669 scsi_device_unbusy(sdev); 677 scsi_device_unbusy(sdev);
670 678
@@ -690,7 +698,13 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
690 "Notifying upper driver of completion " 698 "Notifying upper driver of completion "
691 "(result %x)\n", cmd->result)); 699 "(result %x)\n", cmd->result));
692 700
693 cmd->done(cmd); 701 good_bytes = cmd->request_bufflen;
702 if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) {
703 drv = scsi_cmd_to_driver(cmd);
704 if (drv->done)
705 good_bytes = drv->done(cmd);
706 }
707 scsi_io_completion(cmd, good_bytes);
694} 708}
695EXPORT_SYMBOL(scsi_finish_command); 709EXPORT_SYMBOL(scsi_finish_command);
696 710