aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/sd.c
diff options
context:
space:
mode:
authorJames Bottomley <JBottomley@Parallels.com>2013-04-24 17:02:53 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-05-02 19:15:54 -0400
commit39c60a0948cc06139e2fbfe084f83cb7e7deae3b (patch)
tree7d8b3f42a70e8f0caea47bebc1b113f79753baca /drivers/scsi/sd.c
parent14b06808d2848658517657ae4c97445da1e14890 (diff)
[SCSI] sd: fix array cache flushing bug causing performance problems
Some arrays synchronize their full non volatile cache when the sd driver sends a SYNCHRONIZE CACHE command. Unfortunately, they can have Terrabytes of this and we send a SYNCHRONIZE CACHE for every barrier if an array reports it has a writeback cache. This leads to massive slowdowns on journalled filesystems. The fix is to allow userspace to turn off the writeback cache setting as a temporary measure (i.e. without doing the MODE SELECT to write it back to the device), so even though the device reported it has a writeback cache, the user, knowing that the cache is non volatile and all they care about is filesystem correctness, can turn that bit off in the kernel and avoid the performance ruinous (and safety irrelevant) SYNCHRONIZE CACHE commands. The way you do this is add a 'temporary' prefix when performing the usual cache setting operations, so echo temporary write through > /sys/class/scsi_disk/<disk>/cache_type Reported-by: Ric Wheeler <rwheeler@redhat.com> Cc: <stable@vger.kernel.org> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r--drivers/scsi/sd.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 7992635d405f..82910cc69ba3 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -142,6 +142,7 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
142 char *buffer_data; 142 char *buffer_data;
143 struct scsi_mode_data data; 143 struct scsi_mode_data data;
144 struct scsi_sense_hdr sshdr; 144 struct scsi_sense_hdr sshdr;
145 const char *temp = "temporary ";
145 int len; 146 int len;
146 147
147 if (sdp->type != TYPE_DISK) 148 if (sdp->type != TYPE_DISK)
@@ -150,6 +151,13 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
150 * it's not worth the risk */ 151 * it's not worth the risk */
151 return -EINVAL; 152 return -EINVAL;
152 153
154 if (strncmp(buf, temp, sizeof(temp) - 1) == 0) {
155 buf += sizeof(temp) - 1;
156 sdkp->cache_override = 1;
157 } else {
158 sdkp->cache_override = 0;
159 }
160
153 for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) { 161 for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {
154 len = strlen(sd_cache_types[i]); 162 len = strlen(sd_cache_types[i]);
155 if (strncmp(sd_cache_types[i], buf, len) == 0 && 163 if (strncmp(sd_cache_types[i], buf, len) == 0 &&
@@ -162,6 +170,13 @@ sd_store_cache_type(struct device *dev, struct device_attribute *attr,
162 return -EINVAL; 170 return -EINVAL;
163 rcd = ct & 0x01 ? 1 : 0; 171 rcd = ct & 0x01 ? 1 : 0;
164 wce = ct & 0x02 ? 1 : 0; 172 wce = ct & 0x02 ? 1 : 0;
173
174 if (sdkp->cache_override) {
175 sdkp->WCE = wce;
176 sdkp->RCD = rcd;
177 return count;
178 }
179
165 if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT, 180 if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
166 SD_MAX_RETRIES, &data, NULL)) 181 SD_MAX_RETRIES, &data, NULL))
167 return -EINVAL; 182 return -EINVAL;
@@ -2319,6 +2334,10 @@ sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer)
2319 int old_rcd = sdkp->RCD; 2334 int old_rcd = sdkp->RCD;
2320 int old_dpofua = sdkp->DPOFUA; 2335 int old_dpofua = sdkp->DPOFUA;
2321 2336
2337
2338 if (sdkp->cache_override)
2339 return;
2340
2322 first_len = 4; 2341 first_len = 4;
2323 if (sdp->skip_ms_page_8) { 2342 if (sdp->skip_ms_page_8) {
2324 if (sdp->type == TYPE_RBC) 2343 if (sdp->type == TYPE_RBC)
@@ -2812,6 +2831,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
2812 sdkp->capacity = 0; 2831 sdkp->capacity = 0;
2813 sdkp->media_present = 1; 2832 sdkp->media_present = 1;
2814 sdkp->write_prot = 0; 2833 sdkp->write_prot = 0;
2834 sdkp->cache_override = 0;
2815 sdkp->WCE = 0; 2835 sdkp->WCE = 0;
2816 sdkp->RCD = 0; 2836 sdkp->RCD = 0;
2817 sdkp->ATO = 0; 2837 sdkp->ATO = 0;