Commit 19b723218bde79c60a394a3caee9eb156ac2d356
Committed by
Jeff Garzik
1 parent
44901a9684
Exists in
master
and in
39 other branches
libata: fix last_reset timestamp handling
ehc->last_reset is used to ensure that resets are not issued too close to each other. It's initialized to jiffies minus one minute on EH entry. However, when new links are initialized after PMP is probed, new links have zero for this timestamp resulting in long wait depending on the current jiffies. This patch makes last_set considered iff ATA_EHI_DID_RESET is set, in which case last_reset is always initialized. As an added precaution, WARN_ON() is added so that warning is printed if last_reset is in future. This problem is spotted and debugged by Shane Huang. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Shane Huang <Shane.Huang@amd.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Showing 1 changed file with 11 additions and 10 deletions Side-by-side Diff
drivers/ata/libata-eh.c
... | ... | @@ -610,9 +610,6 @@ |
610 | 610 | if (ata_ncq_enabled(dev)) |
611 | 611 | ehc->saved_ncq_enabled |= 1 << devno; |
612 | 612 | } |
613 | - | |
614 | - /* set last reset timestamp to some time in the past */ | |
615 | - ehc->last_reset = jiffies - 60 * HZ; | |
616 | 613 | } |
617 | 614 | |
618 | 615 | ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS; |
619 | 616 | |
... | ... | @@ -2281,17 +2278,21 @@ |
2281 | 2278 | if (link->flags & ATA_LFLAG_NO_SRST) |
2282 | 2279 | softreset = NULL; |
2283 | 2280 | |
2284 | - now = jiffies; | |
2285 | - deadline = ata_deadline(ehc->last_reset, ATA_EH_RESET_COOL_DOWN); | |
2286 | - if (time_before(now, deadline)) | |
2287 | - schedule_timeout_uninterruptible(deadline - now); | |
2281 | + /* make sure each reset attemp is at least COOL_DOWN apart */ | |
2282 | + if (ehc->i.flags & ATA_EHI_DID_RESET) { | |
2283 | + now = jiffies; | |
2284 | + WARN_ON(time_after(ehc->last_reset, now)); | |
2285 | + deadline = ata_deadline(ehc->last_reset, | |
2286 | + ATA_EH_RESET_COOL_DOWN); | |
2287 | + if (time_before(now, deadline)) | |
2288 | + schedule_timeout_uninterruptible(deadline - now); | |
2289 | + } | |
2288 | 2290 | |
2289 | 2291 | spin_lock_irqsave(ap->lock, flags); |
2290 | 2292 | ap->pflags |= ATA_PFLAG_RESETTING; |
2291 | 2293 | spin_unlock_irqrestore(ap->lock, flags); |
2292 | 2294 | |
2293 | 2295 | ata_eh_about_to_do(link, NULL, ATA_EH_RESET); |
2294 | - ehc->last_reset = jiffies; | |
2295 | 2296 | |
2296 | 2297 | ata_link_for_each_dev(dev, link) { |
2297 | 2298 | /* If we issue an SRST then an ATA drive (not ATAPI) |
... | ... | @@ -2379,7 +2380,6 @@ |
2379 | 2380 | /* |
2380 | 2381 | * Perform reset |
2381 | 2382 | */ |
2382 | - ehc->last_reset = jiffies; | |
2383 | 2383 | if (ata_is_host_link(link)) |
2384 | 2384 | ata_eh_freeze_port(ap); |
2385 | 2385 | |
... | ... | @@ -2391,6 +2391,7 @@ |
2391 | 2391 | reset == softreset ? "soft" : "hard"); |
2392 | 2392 | |
2393 | 2393 | /* mark that this EH session started with reset */ |
2394 | + ehc->last_reset = jiffies; | |
2394 | 2395 | if (reset == hardreset) |
2395 | 2396 | ehc->i.flags |= ATA_EHI_DID_HARDRESET; |
2396 | 2397 | else |
... | ... | @@ -2535,7 +2536,7 @@ |
2535 | 2536 | ata_eh_done(link, NULL, ATA_EH_RESET); |
2536 | 2537 | if (slave) |
2537 | 2538 | ata_eh_done(slave, NULL, ATA_EH_RESET); |
2538 | - ehc->last_reset = jiffies; | |
2539 | + ehc->last_reset = jiffies; /* update to completion time */ | |
2539 | 2540 | ehc->i.action |= ATA_EH_REVALIDATE; |
2540 | 2541 | |
2541 | 2542 | rc = 0; |