aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-09-07 11:44:01 -0400
committerJames Bottomley <James.Bottomley@suse.de>2010-12-21 12:23:52 -0600
commit3ff5588d3f8afad65ded52ac0e4191462fe034cb (patch)
treed75858a35c3f9042dc234e17772fe9d713e2ca9c
parent29687512c0b084957112cc2c0743ce34cd0d5055 (diff)
[SCSI] sd: improve logic and efficiecy of media-change detection
This patch (as1415) improves the formerly incomprehensible logic in sd_media_changed() (the current code refers to "changed" as a state, whereas in fact it is a relation between two states). It also adds a big comment so that everyone can understand what is really going on. The patch also improves efficiency by not reporting a media change when no medium was ever present. If no medium was present the last time we checked and there's still no medium, it's not necessary to tell the caller that a change occurred. Doing so merely causes the caller to attempt to revalidate a non-existent disk, which is a waste of time. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
-rw-r--r--drivers/scsi/sd.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 956496182c8..26f9d54a9c9 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -583,7 +583,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
* quietly refuse to do anything to a changed disc until
* the changed bit has been reset
*/
- /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+ /* printk("SCSI disk has been changed or is not present. Prohibiting further I/O.\n"); */
goto out;
}
@@ -1023,7 +1023,6 @@ static int sd_media_changed(struct gendisk *disk)
*/
if (!scsi_device_online(sdp)) {
set_media_not_present(sdkp);
- retval = 1;
goto out;
}
@@ -1054,7 +1053,6 @@ static int sd_media_changed(struct gendisk *disk)
/* 0x3a is medium not present */
sshdr->asc == 0x3a)) {
set_media_not_present(sdkp);
- retval = 1;
goto out;
}
@@ -1065,12 +1063,27 @@ static int sd_media_changed(struct gendisk *disk)
*/
sdkp->media_present = 1;
- retval = sdp->changed;
- sdp->changed = 0;
out:
- if (retval != sdkp->previous_state)
+ /*
+ * Report a media change under the following conditions:
+ *
+ * Medium is present now and wasn't present before.
+ * Medium wasn't present before and is present now.
+ * Medium was present at all times, but it changed while
+ * we weren't looking (sdp->changed is set).
+ *
+ * If there was no medium before and there is no medium now then
+ * don't report a change, even if a medium was inserted and removed
+ * while we weren't looking.
+ */
+ retval = (sdkp->media_present != sdkp->previous_state ||
+ (sdkp->media_present && sdp->changed));
+ if (retval)
sdev_evt_send_simple(sdp, SDEV_EVT_MEDIA_CHANGE, GFP_KERNEL);
- sdkp->previous_state = retval;
+ sdkp->previous_state = sdkp->media_present;
+
+ /* sdp->changed indicates medium was changed or is not present */
+ sdp->changed = !sdkp->media_present;
kfree(sshdr);
return retval;
}