libata: switch pio task from workqueue to slow-work libata-pio
authorJens Axboe <jens.axboe@oracle.com>
Thu, 27 Aug 2009 11:26:05 +0000 (13:26 +0200)
committerJens Axboe <jens.axboe@oracle.com>
Thu, 27 Aug 2009 11:55:29 +0000 (13:55 +0200)
A workqueue isn't a good fit for the pio task:

- It does not require per-CPU support, thus wasting many threads.
- The pio task would like to have more than one thread per CPU
  in some cases, for the single CPU case of having more than one
  pio device active.

So convert to slow-work instead, this is now possible with support
for delayed slow work and cancellation.

Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
drivers/ata/Kconfig
drivers/ata/libata-core.c
drivers/ata/libata-sff.c
drivers/ata/libata.h
include/linux/libata.h

index b17c57f850329a02973f4849500759e13a7f7e17..9369e6dc331c3bf01c570659942e15b769bbef4d 100644 (file)
@@ -8,6 +8,7 @@ menuconfig ATA
        depends on BLOCK
        depends on !(M32R || M68K) || BROKEN
        select SCSI
+       select SLOW_WORK
        ---help---
          If you want to use a ATA hard disk, ATA tape drive, ATA CD-ROM or
          any other ATA device under Linux, say Y and make sure that you know
index 072ba5ea138f8363a4b108091d0295353792e09a..285fc52025dff854dc7917d318425567dd61f72c 100644 (file)
@@ -95,7 +95,6 @@ static void ata_dev_xfermask(struct ata_device *dev);
 static unsigned long ata_dev_blacklisted(const struct ata_device *dev);
 
 unsigned int ata_print_id = 1;
-static struct workqueue_struct *ata_wq;
 
 struct workqueue_struct *ata_aux_wq;
 
@@ -1700,7 +1699,7 @@ void ata_pio_queue_task(struct ata_port *ap, void *data, unsigned long delay)
        ap->port_task_data = data;
 
        /* may fail if ata_port_flush_task() in progress */
-       queue_delayed_work(ata_wq, &ap->port_task, msecs_to_jiffies(delay));
+       delayed_slow_work_enqueue(&ap->port_task, msecs_to_jiffies(delay));
 }
 
 /**
@@ -1717,7 +1716,7 @@ void ata_port_flush_task(struct ata_port *ap)
 {
        DPRINTK("ENTER\n");
 
-       cancel_rearming_delayed_work(&ap->port_task);
+       cancel_delayed_slow_work(&ap->port_task);
 
        if (ata_msg_ctl(ap))
                ata_port_printk(ap, KERN_DEBUG, "%s: EXIT\n", __func__);
@@ -5600,6 +5599,14 @@ int sata_link_init_spd(struct ata_link *link)
        return 0;
 }
 
+static const struct slow_work_ops ata_work_ops_sff = {
+       .execute        = ata_pio_task,
+};
+
+static const struct slow_work_ops ata_work_ops = {
+       .execute        = NULL, /* what's the point of this?! */
+};
+
 /**
  *     ata_port_alloc - allocate and initialize basic ATA port resources
  *     @host: ATA host this allocated port belongs to
@@ -5641,9 +5648,9 @@ struct ata_port *ata_port_alloc(struct ata_host *host)
 #endif
 
 #ifdef CONFIG_ATA_SFF
-       INIT_DELAYED_WORK(&ap->port_task, ata_pio_task);
+       delayed_slow_work_init(&ap->port_task, &ata_work_ops_sff);
 #else
-       INIT_DELAYED_WORK(&ap->port_task, NULL);
+       delayed_slow_work_init(&ap->port_task, &ata_work_ops);
 #endif
        INIT_DELAYED_WORK(&ap->hotplug_task, ata_scsi_hotplug);
        INIT_WORK(&ap->scsi_rescan_task, ata_scsi_dev_rescan);
@@ -6580,19 +6587,15 @@ static int __init ata_init(void)
 {
        ata_parse_force_param();
 
-       ata_wq = create_workqueue("ata");
-       if (!ata_wq)
-               goto free_force_tbl;
-
        ata_aux_wq = create_singlethread_workqueue("ata_aux");
        if (!ata_aux_wq)
-               goto free_wq;
+               goto free_force_tbl;
+
+       slow_work_register_user(THIS_MODULE);
 
        printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
        return 0;
 
-free_wq:
-       destroy_workqueue(ata_wq);
 free_force_tbl:
        kfree(ata_force_tbl);
        return -ENOMEM;
@@ -6601,8 +6604,8 @@ free_force_tbl:
 static void __exit ata_exit(void)
 {
        kfree(ata_force_tbl);
-       destroy_workqueue(ata_wq);
        destroy_workqueue(ata_aux_wq);
+       slow_work_unregister_user(THIS_MODULE);
 }
 
 subsys_initcall(ata_init);
index bbbb1fab17557cea8c169a9e7820c9e49d0697a7..f795ab716f751577f56023cc931a3b88f86c80fd 100644 (file)
@@ -1454,7 +1454,7 @@ fsm_start:
 }
 EXPORT_SYMBOL_GPL(ata_sff_hsm_move);
 
-void ata_pio_task(struct work_struct *work)
+void ata_pio_task(struct slow_work *work)
 {
        struct ata_port *ap =
                container_of(work, struct ata_port, port_task.work);
index 89a1e0018e71472c6544810de175fdd71142af34..d48d14da6e18672c95ce802002d60538c5259f25 100644 (file)
@@ -202,7 +202,7 @@ static inline int sata_pmp_attach(struct ata_device *dev)
 extern void ata_dev_select(struct ata_port *ap, unsigned int device,
                            unsigned int wait, unsigned int can_sleep);
 extern u8 ata_irq_on(struct ata_port *ap);
-extern void ata_pio_task(struct work_struct *work);
+extern void ata_pio_task(struct slow_work *work);
 #endif /* CONFIG_ATA_SFF */
 
 #endif /* __LIBATA_H__ */
index e5b6e33c65710a6f82593387e1f8e18663394ff4..6830c82f5c038c8816eaaea2e106c0b52f760d58 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/io.h>
 #include <linux/ata.h>
 #include <linux/workqueue.h>
+#include <linux/slow-work.h>
 #include <scsi/scsi_host.h>
 #include <linux/acpi.h>
 #include <linux/cdrom.h>
@@ -734,7 +735,7 @@ struct ata_port {
        struct device           *dev;
 
        void                    *port_task_data;
-       struct delayed_work     port_task;
+       struct delayed_slow_work        port_task;
        struct delayed_work     hotplug_task;
        struct work_struct      scsi_rescan_task;