Re: Prevent busy looping

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Tejun Heo <htejun@xxxxxxxxx> wrote:
> Tejun Heo wrote:
>> Alan Cox wrote:
>
>>>> Elias's synthetic test case triggered infinite loop because it wasn't
>>>> a proper ->qc_defer().  ->qc_defer() should never defer commands when
>>>> the target is idle.
>>> Target or host ? We *do* defer commands in the case of an idle channel
>>> when dealing with certain simplex controllers that can only issue one
>>> command per host not one per cable (and in fact in the general case we
>>> can defer commands due to activity on the other drive on the cable).
>> 
>> The term was confusing.  I used target to mean both device
>> (ATA_DEFER_LINK) and host (ATA_DEFER_PORT).  Hmmm... in simplex case,
>> yeah, blocked counters need to be > 1.  We'll need to increase blocked
>> counts after all.  I'll test blocked counts of 2 w/ PMP and make sure it
>> doesn't incur unnecessary delays and post the patch.
>
> Setting blocked counts to 2 makes simplex scheduling starve one of the
> drives.  When a drive loses competition, it retries only after plug
> delay and of course it loses most of the time.  For now, it seems we'll
> have to live with busy loops (which doesn't lock up the machine) for
> simplex controllers.  Ewww... :-(

Since I'm a little confused by your comment, please explain again. Do
you mean to say that busy looping doesn't lock up the machine in general
or merely in the case of a simplex configuration?

The reason why I'm asking is this: The whole point of my synthetic
->qc_defer() function was to prove that command deferral could (under
certain conditions) lead to busy looping which *did* lock up my machine.
Lock up in this context means that there was no response whatsoever to
key presses and even timers didn't fire anymore. I can see your point
that my ->qc_defer() function doesn't reflect reality very well because
the device is idle at the time and therefore no interrupts can be
expected from there. However, I still think that interrupts won't even
be processed once busy looping has started (in some configurations at
least).

You can find a slightly modified version of my synthetic ->qc_defer()
function below (apply to 2.6.26-rc5) which demonstrates that at least
soft interrupts don't get serviced anymore once the busy looping has
started. Considering this, how can I be sure that an interrupt of the
target would be processed, even if it was not idle?

Regards,

Elias

 drivers/ata/ata_piix.c |   37 +++++++++++++++++++++++++++++++++++++
 1 files changed, 37 insertions(+), 0 deletions(-)


diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index 81b7ae3..9816daa 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -167,6 +167,7 @@ static int ich_pata_cable_detect(struct ata_port *ap);
 static u8 piix_vmw_bmdma_status(struct ata_port *ap);
 static int piix_sidpr_scr_read(struct ata_port *ap, unsigned int reg, u32 *val);
 static int piix_sidpr_scr_write(struct ata_port *ap, unsigned int reg, u32 val);
+static int piix_qc_defer(struct ata_queued_cmd *qc);
 #ifdef CONFIG_PM
 static int piix_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg);
 static int piix_pci_device_resume(struct pci_dev *pdev);
@@ -299,6 +300,7 @@ static struct ata_port_operations piix_pata_ops = {
 	.set_piomode		= piix_set_piomode,
 	.set_dmamode		= piix_set_dmamode,
 	.prereset		= piix_pata_prereset,
+	.qc_defer		= piix_qc_defer,
 };
 
 static struct ata_port_operations piix_vmw_ops = {
@@ -314,6 +316,7 @@ static struct ata_port_operations ich_pata_ops = {
 
 static struct ata_port_operations piix_sata_ops = {
 	.inherits		= &ata_bmdma_port_ops,
+	.qc_defer		= piix_qc_defer,
 };
 
 static struct ata_port_operations piix_sidpr_sata_ops = {
@@ -323,6 +326,40 @@ static struct ata_port_operations piix_sidpr_sata_ops = {
 	.scr_write		= piix_sidpr_scr_write,
 };
 
+static unsigned int defer_count = 0;
+static struct timer_list defer_timer;
+
+static void piix_defer_timeout(unsigned long data)
+{
+	struct ata_port *ap = (struct ata_port *)data;
+
+	spin_lock_bh(ap->lock);
+	defer_count = 0;
+	spin_unlock_bh(ap->lock);
+}
+
+static int piix_qc_defer(struct ata_queued_cmd *qc)
+{
+	static struct ata_port *ap = NULL;
+#define PIIX_QC_DEFER_THRESHOLD 2000
+
+	if (!ap) {
+		ap = qc->ap;
+		defer_timer.data = (unsigned long)ap;
+		defer_timer.function = piix_defer_timeout;
+		init_timer(&defer_timer);
+	} else if (ap != qc->ap)
+		return 0;
+
+	defer_count++;
+	if (defer_count < PIIX_QC_DEFER_THRESHOLD)
+		return 0;
+
+        if (defer_count == PIIX_QC_DEFER_THRESHOLD)
+		mod_timer(&defer_timer, msecs_to_jiffies(5));
+	return ATA_DEFER_LINK;
+}
+
 static const struct piix_map_db ich5_map_db = {
 	.mask = 0x7,
 	.port_enable = 0x3,
--
To unsubscribe from this list: send the line "unsubscribe linux-ide" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Filesystems]     [Linux SCSI]     [Linux RAID]     [Git]     [Kernel Newbies]     [Linux Newbie]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Samba]     [Device Mapper]

  Powered by Linux