]>
Commit | Line | Data |
---|---|---|
e2b52abc GKH |
1 | From a8733c7baf457b071528e385a0b7d4aaec79287c Mon Sep 17 00:00:00 2001 |
2 | From: James Bottomley <James.Bottomley@suse.de> | |
3 | Date: Fri, 17 Dec 2010 15:36:34 -0500 | |
4 | Subject: [SCSI] fix medium error problems with some arrays which can cause data corruption | |
5 | ||
6 | From: James Bottomley <James.Bottomley@suse.de> | |
7 | ||
8 | commit a8733c7baf457b071528e385a0b7d4aaec79287c upstream. | |
9 | ||
10 | Our current handling of medium error assumes that data is returned up | |
11 | to the bad sector. This assumption holds good for all disk devices, | |
12 | all DIF arrays and most ordinary arrays. However, an LSI array engine | |
13 | was recently discovered which reports a medium error without returning | |
14 | any data. This means that when we report good data up to the medium | |
15 | error, we've reported junk originally in the buffer as good. Worse, | |
16 | if the read consists of requested data plus a readahead, and the error | |
17 | occurs in readahead, we'll just strip off the readahead and report | |
18 | junk up to userspace as good data with no error. | |
19 | ||
20 | The fix for this is to have the error position computation take into | |
21 | account the amount of data returned by the driver using the scsi | |
22 | residual data. Unfortunately, not every driver fills in this data, | |
23 | but for those who don't, it's set to zero, which means we'll think a | |
24 | full set of data was transferred and the behaviour will be identical | |
25 | to the prior behaviour of the code (believe the buffer up to the error | |
26 | sector). All modern drivers seem to set the residual, so that should | |
27 | fix up the LSI failure/corruption case. | |
28 | ||
29 | Reported-by: Douglas Gilbert <dgilbert@interlog.com> | |
30 | Signed-off-by: James Bottomley <James.Bottomley@suse.de> | |
31 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
32 | ||
33 | --- | |
34 | drivers/scsi/sd.c | 9 ++++++++- | |
35 | 1 file changed, 8 insertions(+), 1 deletion(-) | |
36 | ||
37 | --- a/drivers/scsi/sd.c | |
38 | +++ b/drivers/scsi/sd.c | |
39 | @@ -1153,6 +1153,12 @@ static unsigned int sd_completed_bytes(s | |
40 | u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512); | |
41 | u64 bad_lba; | |
42 | int info_valid; | |
43 | + /* | |
44 | + * resid is optional but mostly filled in. When it's unused, | |
45 | + * its value is zero, so we assume the whole buffer transferred | |
46 | + */ | |
47 | + unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd); | |
48 | + unsigned int good_bytes; | |
49 | ||
50 | if (scmd->request->cmd_type != REQ_TYPE_FS) | |
51 | return 0; | |
52 | @@ -1186,7 +1192,8 @@ static unsigned int sd_completed_bytes(s | |
53 | /* This computation should always be done in terms of | |
54 | * the resolution of the device's medium. | |
55 | */ | |
56 | - return (bad_lba - start_lba) * scmd->device->sector_size; | |
57 | + good_bytes = (bad_lba - start_lba) * scmd->device->sector_size; | |
58 | + return min(good_bytes, transferred); | |
59 | } | |
60 | ||
61 | /** |