aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorKai Makisara <Kai.Makisara@kolumbus.fi>2007-02-03 06:21:29 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2007-02-03 09:05:47 -0500
commit9abe16c670bd3d4ab5519257514f9f291383d104 (patch)
tree2c3015288e282a95a82e5a6198fe9df78b0d1478 /drivers/scsi
parent07c861d6d9ca3dc58e225bcfe2da0f378af6fa6c (diff)
[SCSI] st: fix Tape dies if wrong block size used, bug 7919
On Thu, 1 Feb 2007, Andrew Morton wrote: > On Thu, 1 Feb 2007 15:34:29 -0800 > bugme-daemon@bugzilla.kernel.org wrote: > > > http://bugzilla.kernel.org/show_bug.cgi?id=7919 > > > > Summary: Tape dies if wrong block size used > > Kernel Version: 2.6.20-rc5 > > Status: NEW > > Severity: normal > > Owner: scsi_drivers-other@kernel-bugs.osdl.org > > Submitter: dmartin@sccd.ctc.edu > > > > > > Most recent kernel where this bug did *NOT* occur: 2.6.17.14 > > > > Other Kernels Tested and Results: > > > > OK 2.6.15.7 > > OK 2.6.16.37 > > OK 2.6.17.14 > > BAD 2.6.18.6 > > BAD 2.6.18-1.2869.fc6 > > BAD 2.6.19.2 + > > BAD 2.6.20-rc5 > > > > NOTE: 2.6.18-1.2869.fc6 is a Fedora modified kernel, all others are from kernel.org > > ... > > Steps to reproduce: > > Get a Adaptec AHA-2940U/UW/D / AIC-7881U card and a tape drive, > > install a recent kernel > > set the tape block size - mt setblk 4096 > > read from or write to tape using wrong block size - tar -b 7 -cvf /dev/tape foo > > Write does not trigger this bug because the driver refuses in fixed block mode writes that are not a multiple of the block size. Read does trigger it in my system. The bug is not associated with any specific HBA. st tries to do direct i/o in fixed block mode with reads that are not a multiple of tape block size. The patch in this message fixes the st problem by switching to using the driver buffer up to the next close of the device file in fixed block mode if the user asks for a read like this. I don't know why the bug has surfaced only after 2.6.17 although the st problem is old. There may be another bug in the block subsystem and this patch works around it. However, the patch fixes a problem in st and in this way it is a valid fix. This patch may also fix the bug 7900. The patch compiles and is lightly tested. Signed-off-by: Kai Makisara <kai.makisara@kolumbus.fi> Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/st.c23
-rw-r--r--drivers/scsi/st.h3
2 files changed, 15 insertions, 11 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index e016e0906e1a..fba8b204e310 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -9,7 +9,7 @@
9 Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, 9 Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
10 Michael Schaefer, J"org Weule, and Eric Youngdale. 10 Michael Schaefer, J"org Weule, and Eric Youngdale.
11 11
12 Copyright 1992 - 2006 Kai Makisara 12 Copyright 1992 - 2007 Kai Makisara
13 email Kai.Makisara@kolumbus.fi 13 email Kai.Makisara@kolumbus.fi
14 14
15 Some small formal changes - aeb, 950809 15 Some small formal changes - aeb, 950809
@@ -17,7 +17,7 @@
17 Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support 17 Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
18 */ 18 */
19 19
20static const char *verstr = "20061107"; 20static const char *verstr = "20070203";
21 21
22#include <linux/module.h> 22#include <linux/module.h>
23 23
@@ -1168,6 +1168,7 @@ static int st_open(struct inode *inode, struct file *filp)
1168 STps = &(STp->ps[i]); 1168 STps = &(STp->ps[i]);
1169 STps->rw = ST_IDLE; 1169 STps->rw = ST_IDLE;
1170 } 1170 }
1171 STp->try_dio_now = STp->try_dio;
1171 STp->recover_count = 0; 1172 STp->recover_count = 0;
1172 DEB( STp->nbr_waits = STp->nbr_finished = 0; 1173 DEB( STp->nbr_waits = STp->nbr_finished = 0;
1173 STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; ) 1174 STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )
@@ -1400,9 +1401,9 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
1400 struct st_buffer *STbp = STp->buffer; 1401 struct st_buffer *STbp = STp->buffer;
1401 1402
1402 if (is_read) 1403 if (is_read)
1403 i = STp->try_dio && try_rdio; 1404 i = STp->try_dio_now && try_rdio;
1404 else 1405 else
1405 i = STp->try_dio && try_wdio; 1406 i = STp->try_dio_now && try_wdio;
1406 1407
1407 if (i && ((unsigned long)buf & queue_dma_alignment( 1408 if (i && ((unsigned long)buf & queue_dma_alignment(
1408 STp->device->request_queue)) == 0) { 1409 STp->device->request_queue)) == 0) {
@@ -1599,7 +1600,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
1599 STm->do_async_writes && STps->eof < ST_EOM_OK; 1600 STm->do_async_writes && STps->eof < ST_EOM_OK;
1600 1601
1601 if (STp->block_size != 0 && STm->do_buffer_writes && 1602 if (STp->block_size != 0 && STm->do_buffer_writes &&
1602 !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK && 1603 !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK &&
1603 STbp->buffer_bytes < STbp->buffer_size) { 1604 STbp->buffer_bytes < STbp->buffer_size) {
1604 STp->dirty = 1; 1605 STp->dirty = 1;
1605 /* Don't write a buffer that is not full enough. */ 1606 /* Don't write a buffer that is not full enough. */
@@ -1769,7 +1770,7 @@ static long read_tape(struct scsi_tape *STp, long count,
1769 if (STp->block_size == 0) 1770 if (STp->block_size == 0)
1770 blks = bytes = count; 1771 blks = bytes = count;
1771 else { 1772 else {
1772 if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) { 1773 if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) {
1773 blks = (STp->buffer)->buffer_blocks; 1774 blks = (STp->buffer)->buffer_blocks;
1774 bytes = blks * STp->block_size; 1775 bytes = blks * STp->block_size;
1775 } else { 1776 } else {
@@ -1948,10 +1949,12 @@ st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
1948 goto out; 1949 goto out;
1949 1950
1950 STm = &(STp->modes[STp->current_mode]); 1951 STm = &(STp->modes[STp->current_mode]);
1951 if (!(STm->do_read_ahead) && STp->block_size != 0 && 1952 if (STp->block_size != 0 && (count % STp->block_size) != 0) {
1952 (count % STp->block_size) != 0) { 1953 if (!STm->do_read_ahead) {
1953 retval = (-EINVAL); /* Read must be integral number of blocks */ 1954 retval = (-EINVAL); /* Read must be integral number of blocks */
1954 goto out; 1955 goto out;
1956 }
1957 STp->try_dio_now = 0; /* Direct i/o can't handle split blocks */
1955 } 1958 }
1956 1959
1957 STps = &(STp->ps[STp->partition]); 1960 STps = &(STp->ps[STp->partition]);
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 05a5cae126ec..50f3deb1f9ed 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -117,7 +117,8 @@ struct scsi_tape {
117 unsigned char cln_sense_value; 117 unsigned char cln_sense_value;
118 unsigned char cln_sense_mask; 118 unsigned char cln_sense_mask;
119 unsigned char use_pf; /* Set Page Format bit in all mode selects? */ 119 unsigned char use_pf; /* Set Page Format bit in all mode selects? */
120 unsigned char try_dio; /* try direct i/o? */ 120 unsigned char try_dio; /* try direct i/o in general? */
121 unsigned char try_dio_now; /* try direct i/o before next close? */
121 unsigned char c_algo; /* compression algorithm */ 122 unsigned char c_algo; /* compression algorithm */
122 unsigned char pos_unknown; /* after reset position unknown */ 123 unsigned char pos_unknown; /* after reset position unknown */
123 int tape_type; 124 int tape_type;