ide: replace the global ide_lock spinlock by per-hwgroup spinlocks
PATCH 1/1 ide: replace the global ide_lock spinlock by per-hwgroup spinlocks
From: Bartlomiej Zolnierkiewicz <[email protected]>
Subject: [PATCH] ide: replace the global ide_lock spinlock by per-hwgroup spinlocks
Now that (almost) all host drivers have been fixed not to abuse ide_lock and core code usage of ide_lock has been sanitized we may safely replace ide_lock by per-hwgroup locks.
This patch is partially based on earlier patch from Ravikiran G Thirumalai.
While at it:
- don't use deprecated HWIF() and HWGROUP() macros
- update locking documentation in ide.h
---
this is against 2.6.27 + pata tree + pre-patchset posted on Wednesday
(http://lkml.org/lkml/2008/10/8/221)
drivers/ide/ide-io.c | 33 ++++++++++++++--------------- drivers/ide/ide-iops.c | 48 ++++++++++++++++++++----------------------- drivers/ide/ide-park.c | 16 +++++++------- drivers/ide/ide-probe.c | 24 +++++++++++---------- drivers/ide/ide.c | 8 ++----- drivers/ide/legacy/umc8672.c | 11 ++++++--- drivers/scsi/ide-scsi.c | 32 ++++++++++++++++++---------- include/linux/ide.h | 12 ++++++---- 8 files changed, 98 insertions(+), 86 deletions(-)
drivers/ide/ide-io.c +16 -17
@@ -906,7 +906,7 @@ repeat:/* * Issue a new request to a drive from hwgroup -* Caller must have already done spin_lock_irqsave(&ide_lock, ..); +* Caller must have already done spin_lock_irqsave(&hwgroup->lock, ..); * * A hwgroup is a serialized group of IDE interfaces. Usually there is * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
@@ -918,7 +918,7 @@ repeat:* possibly along with many other devices. This is especially common in * PCI-based systems with off-board IDE controller cards. * -* The IDE driver uses the single global ide_lock spinlock to protect +* The IDE driver uses a per-hwgroup spinlock to protect * access to the request queues, and to protect the hwgroup->busy flag. * * The first thread into the driver for a particular hwgroup sets the
@@ -934,7 +934,7 @@ repeat:* will start the next request from the queue. If no more work remains, * the driver will clear the hwgroup->busy flag and exit. * -* The ide_lock (spinlock) is used to protect all access to the +* The per-hwgroup spinlock is used to protect all access to the * hwgroup->busy flag, but is otherwise not needed for most processing in * the driver. This makes the driver much more friendlier to shared IRQs * than previous designs, while remaining 100% (?) SMP safe and capable.
@@ -950,7 +950,7 @@ static void ide_do_request (ide_hwgroup_/* for atari only: POSSIBLY BROKEN HERE(?) */ ide_get_lock (ide_intr, hwgroup); -/* caller must own ide_lock */ +/* caller must own hwgroup->lock */ BUG_ON (!irqs_disabled ());while (!hwgroup->busy) {
@@ -1070,11 +1070,11 @@ static void ide_do_request (ide_hwgroup_*/ if (masked_irq !=IDE_NO_IRQ && hwif->irq != masked_irq)disable_irq_nosync (hwif->irq); -spin_unlock (&ide_lock); +spin_unlock (&hwgroup->lock);local_irq_enable_in_hardirq ();/* allow other IRQs while we start this request */ startstop =start_request (drive, rq); -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);if (masked_irq !=IDE_NO_IRQ && hwif->irq != masked_irq)enable_irq (hwif->irq);if (startstop == ide_stopped)
@@ -1172,7 +1172,7 @@ void ide_timer_expiry (unsigned long datunsigned long flags;unsigned long wait =-1 ; -spin_lock_irqsave (&ide_lock, flags); +spin_lock_irqsave (&hwgroup->lock, flags);if (((handler = hwgroup->handler) ==NULL ) || (hwgroup->req_gen != hwgroup->req_gen_timer)) {
@@ -1205,7 +1205,7 @@ void ide_timer_expiry (unsigned long dat hwgroup->timer.expires = jiffies + wait; hwgroup->req_gen_timer = hwgroup->req_gen;add_timer (&hwgroup->timer); -spin_unlock_irqrestore (&ide_lock, flags); +spin_unlock_irqrestore (&hwgroup->lock, flags);return ; } }
@@ -1215,7 +1215,7 @@ void ide_timer_expiry (unsigned long dat* the handler() function, which means we need to * globally mask the specific IRQ: */ -spin_unlock (&ide_lock); +spin_unlock (&hwgroup->lock); hwif =HWIF (drive);/* disable_irq_nosync ?? */ disable_irq (hwif->irq);
@@ -1239,14 +1239,14 @@ void ide_timer_expiry (unsigned long dat hwif->tp_ops->read_status(hwif)); } drive->service_time = jiffies - drive->service_start; -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);enable_irq (hwif->irq);if (startstop == ide_stopped) hwgroup->busy =0 ; } }ide_do_request (hwgroup,IDE_NO_IRQ ); -spin_unlock_irqrestore (&ide_lock, flags); +spin_unlock_irqrestore (&hwgroup->lock, flags); }/**
@@ -1339,14 +1339,13 @@ irqreturn_t ide_intr (int irq, void *dev {unsigned long flags;ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; -ide_hwif_t *hwif; +ide_hwif_t *hwif = hwgroup->hwif;ide_drive_t *drive;ide_handler_t *handler;ide_startstop_t startstop;irqreturn_t irq_ret =IRQ_NONE ; -spin_lock_irqsave (&ide_lock, flags); - hwif = hwgroup->hwif; +spin_lock_irqsave (&hwgroup->lock, flags);if (!ide_ack_intr (hwif)) goto out;
@@ -1416,7 +1415,7 @@ irqreturn_t ide_intr (int irq, void *dev hwgroup->handler =NULL ; hwgroup->req_gen++;del_timer (&hwgroup->timer); -spin_unlock (&ide_lock); +spin_unlock (&hwgroup->lock);if (hwif->port_ops && hwif->port_ops->clear_irq) hwif->port_ops->clear_irq (drive);
@@ -1427,7 +1426,7 @@ irqreturn_t ide_intr (int irq, void *dev/* service this interrupt, may set handler for next interrupt */ startstop =handler (drive); -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);/* * Note that handler() may have set things up for another * interrupt to occur soon, but it cannot happen until
@@ -1448,7 +1447,7 @@ irqreturn_t ide_intr (int irq, void *dev out_handled: irq_ret =IRQ_HANDLED ; out: -spin_unlock_irqrestore (&ide_lock, flags); +spin_unlock_irqrestore (&hwgroup->lock, flags);return irq_ret; }
drivers/ide/ide-iops.c +23 -25
114 lines not on this page · raw message
drivers/ide/ide-park.c +8 -8
@@ -7,17 +7,16 @@ DECLARE_WAIT_QUEUE_HEAD(ide_park_wq);static int issue_park_cmd (ide_drive_t *drive,unsigned long timeout) { +ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;struct request_queue *q = drive->queue;struct request *rq;int rc; timeout += jiffies; -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);if (drive->dev_flags &IDE_DFLAG_PARKED ) { -ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; -int reset_timer; +int reset_timer =time_before (timeout, drive->sleep); - reset_timer =time_before (timeout, drive->sleep); drive->sleep = timeout;wake_up_all (&ide_park_wq); if (reset_timer && hwgroup->sleeping &&
@@ -26,10 +25,10 @@ static int issue_park_cmd(ide_drive_t *d hwgroup->busy =0 ;__blk_run_queue (q); } -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock);return 0 ; } -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); rq =blk_get_request (q,READ , __GFP_WAIT); rq->cmd[0 ] =REQ_PARK_HEADS ;
@@ -61,20 +60,21 @@ ssize_t ide_park_show(struct device *dev char *buf) {ide_drive_t *drive =to_ide_device (dev); +ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;unsigned long now;unsigned int msecs;if (drive->dev_flags &IDE_DFLAG_NO_UNLOAD )return -EOPNOTSUPP ; -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock); now = jiffies;if (drive->dev_flags &IDE_DFLAG_PARKED &&time_after (drive->sleep, now)) msecs =jiffies_to_msecs (drive->sleep - now);else msecs =0 ; -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock);return snprintf (buf,20 ,"%u\n" , msecs); }
drivers/ide/ide-probe.c +13 -11
@@ -905,7 +905,8 @@ static int ide_init_queue(ide_drive_t *d* do not. */ - q =blk_init_queue_node (do_ide_request, &ide_lock,hwif_to_node (hwif)); + q =blk_init_queue_node (do_ide_request, &hwif->hwgroup->lock, +hwif_to_node (hwif));if (!q)return 1 ;
@@ -946,7 +947,7 @@ static void ide_add_drive_to_hwgroup(ide {ide_hwgroup_t *hwgroup = drive->hwif->hwgroup; -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);if (!hwgroup->drive) {/* first drive for hwgroup. */ drive->next = drive;
@@ -956,7 +957,7 @@ static void ide_add_drive_to_hwgroup(ide drive->next = hwgroup->drive->next; hwgroup->drive->next = drive; } -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); }/*
@@ -1001,7 +1002,7 @@ void ide_remove_port_from_hwgroup(ide_hw ide_ports[hwif->index] =NULL ; -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);/* * Remove us from the hwgroup, and free * the hwgroup if we were the only member
@@ -1029,7 +1030,7 @@ void ide_remove_port_from_hwgroup(ide_hw }BUG_ON (hwgroup->hwif == hwif); } -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); }/*
@@ -1091,11 +1092,11 @@ static int init_irq (ide_hwif_t *hwif)* linked list, the first entry is the hwif that owns * hwgroup->handler - do not change that. */ -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock); hwif->next = hwgroup->hwif->next; hwgroup->hwif->next = hwif;BUG_ON (hwif->next == hwif); -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); }else { hwgroup =kmalloc_node (sizeof (*hwgroup),GFP_KERNEL |__GFP_ZERO,hwif_to_node (hwif));
@@ -1262,20 +1263,21 @@ static void ide_remove_drive_from_hwgroustatic void drive_release_dev (struct device *dev) {ide_drive_t *drive =container_of (dev, ide_drive_t, gendev); +ide_hwgroup_t *hwgroup = drive->hwif->hwgroup;ide_proc_unregister_device (drive); -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);ide_remove_drive_from_hwgroup (drive);kfree (drive->id); drive->id =NULL ; drive->dev_flags &= ~IDE_DFLAG_PRESENT ;/* Messed up locking ... */ -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock);blk_cleanup_queue (drive->queue); -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock); drive->queue =NULL ; -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock);complete (&drive->gendev_rel_comp); }
drivers/ide/ide.c +3 -5
@@ -74,9 +74,6 @@ static const u8 ide_hwif_to_major[] = {DEFINE_MUTEX (ide_cfg_mtx); -__cacheline_aligned_in_smp DEFINE_SPINLOCK (ide_lock ); -EXPORT_SYMBOL (ide_lock); -static void ide_port_init_devices_data (ide_hwif_t *);/*
@@ -333,6 +330,7 @@ static int set_pio_mode_abuse(ide_hwif_tstatic int set_pio_mode (ide_drive_t *drive,int arg) {ide_hwif_t *hwif = drive->hwif; +ide_hwgroup_t *hwgroup = hwif->hwgroup;const struct ide_port_ops *port_ops = hwif->port_ops;if (arg <0 || arg >255 )
@@ -347,9 +345,9 @@ static int set_pio_mode(ide_drive_t *driunsigned long flags;/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */ -spin_lock_irqsave (&ide_lock, flags); +spin_lock_irqsave (&hwgroup->lock, flags); port_ops->set_pio_mode (drive, arg); -spin_unlock_irqrestore (&ide_lock, flags); +spin_unlock_irqrestore (&hwgroup->lock, flags); }else port_ops->set_pio_mode (drive, arg); }else {
drivers/ide/legacy/umc8672.c +7 -4
@@ -107,18 +107,21 @@ static void umc_set_speeds(u8 speeds[])static void umc_set_pio_mode (ide_drive_t *drive,const u8 pio) {ide_hwif_t *hwif = drive->hwif; -unsigned long flags; +ide_hwgroup_t *mate_hwgroup = hwif->mate ? hwif->mate->hwgroup :NULL ; +unsigned long uninitialized_var (flags );printk ("%s: setting umc8672 to PIO mode%d (speed %d)\n" , drive->name, pio, pio_to_umc[pio]); -spin_lock_irqsave (&ide_lock, flags); -if (hwif->mate && hwif->mate->hwgroup->handler) { +if (mate_hwgroup) +spin_lock_irqsave (&mate_hwgroup->lock, flags); +if (mate_hwgroup && mate_hwgroup->handler) {printk (KERN_ERR "umc8672: other interface is busy: exiting tune_umc()\n" ); }else { current_speeds[drive->name[2 ] -'a' ] = pio_to_umc[pio];umc_set_speeds (current_speeds); } -spin_unlock_irqrestore (&ide_lock, flags); +if (mate_hwgroup) +spin_unlock_irqrestore (&mate_hwgroup->lock, flags); }static const struct ide_port_ops umc8672_port_ops = {
drivers/scsi/ide-scsi.c +21 -11
@@ -584,6 +584,8 @@ static int idescsi_eh_abort (struct scsi {idescsi_scsi_t *scsi =scsihost_to_idescsi (cmd->device->host);ide_drive_t *drive = scsi->drive; +ide_hwif_t *hwif; +ide_hwgroup_t *hwgroup;int busy;int ret =FAILED ;
@@ -600,13 +602,16 @@ static int idescsi_eh_abort (struct scsi goto no_drive; } -/* First give it some more time, how much is "right" is hard to say :-( */ + hwif = drive->hwif; + hwgroup = hwif->hwgroup; - busy =ide_wait_not_busy (HWIF (drive),100 );/* FIXME - uses mdelay which causes latency? */ +/* First give it some more time, how much is "right" is hard to say :-( +FIXME - uses mdelay which causes latency? */ + busy =ide_wait_not_busy (hwif,100 );if (test_bit (IDESCSI_LOG_CMD , &scsi->log))printk (KERN_WARNING "ide-scsi: drive did%s become ready\n" , busy?" not" :"" ); -spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock);/* If there is no pc running we're done (our interrupt took care of it) */ pc = drive->pc;
@@ -635,7 +640,7 @@ static int idescsi_eh_abort (struct scsi } ide_unlock: -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); no_drive:if (test_bit (IDESCSI_LOG_CMD , &scsi->log))printk (KERN_WARNING "ide-scsi: abort returns %s\n" , ret ==SUCCESS ?"success" :"failed" );
@@ -648,6 +653,7 @@ static int idescsi_eh_reset (struct scsistruct request *req;idescsi_scsi_t *scsi =scsihost_to_idescsi (cmd->device->host);ide_drive_t *drive = scsi->drive; +ide_hwgroup_t *hwgroup;int ready =0 ;int ret =SUCCESS ;
@@ -664,14 +670,18 @@ static int idescsi_eh_reset (struct scsireturn FAILED ; } + hwgroup = drive->hwif->hwgroup; +spin_lock_irq (cmd->device->host->host_lock); -spin_lock (&ide_lock); +spin_lock (&hwgroup->lock); pc = drive->pc; +if (pc) + req = pc->rq; -if (pc ==NULL || (req = pc->rq) !=HWGROUP (drive)->rq || !HWGROUP (drive)->handler) { +if (pc ==NULL || req != hwgroup->rq || hwgroup->handler ==NULL ) {printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n" ); -spin_unlock (&ide_lock); +spin_unlock (&hwgroup->lock);spin_unlock_irq (cmd->device->host->host_lock);return FAILED ; }
@@ -691,10 +701,10 @@ static int idescsi_eh_reset (struct scsiBUG (); } -HWGROUP (drive)->rq =NULL ; -HWGROUP (drive)->handler =NULL ; -HWGROUP (drive)->busy =1 ;/* will set this to zero when ide reset finished */ -spin_unlock (&ide_lock); + hwgroup->rq =NULL ; + hwgroup->handler =NULL ; + hwgroup->busy =1 ;/* will set this to zero when ide reset finished */ +spin_unlock (&hwgroup->lock);ide_do_reset (drive);
include/linux/ide.h +7 -5
@@ -909,6 +909,8 @@ typedef struct hwgroup_s {int req_gen;int req_gen_timer; + +spinlock_t lock; } ide_hwgroup_t;typedef struct ide_driver_s ide_driver_t ;
@@ -1600,13 +1602,13 @@ extern struct mutex ide_cfg_mtx;/* * Structure locking: * -* ide_cfg_mtx and ide_lock together protect changes to -* ide_hwif_t->{next,hwgroup} +* ide_cfg_mtx and hwgroup->lock together protect changes to +* ide_hwif_t->next * ide_drive_t->next * -* ide_hwgroup_t->busy: ide_lock -* ide_hwgroup_t->hwif: ide_lock -* ide_hwif_t->mate: constant, no locking +* ide_hwgroup_t->busy: hwgroup->lock +* ide_hwgroup_t->hwif: hwgroup->lock +* ide_hwif_t->{hwgroup,mate}: constant, no locking * ide_drive_t->hwif: constant, no locking */
Quoted 13 lines · Bartlomiej Zolnierkiewicz
From: Bartlomiej Zolnierkiewicz <[email protected]>
Subject: [PATCH] ide: replace the globalide_lockspinlock by per-hwgroup spinlocksNow that (almost) all host drivers have been fixed not to abuse
ide_lockand core code usage ofide_lockhas been sanitized we may safely replaceide_lockby per-hwgroup locks.This patch is partially based on earlier patch from Ravikiran G Thirumalai.
While at it:
- don't use deprecatedHWIF()andHWGROUP()macros
- update locking documentation inide.h
Quoted 8 lines
Cc Vaibhav V. Nivargi <[email protected]>Cc Alok N. Kataria <[email protected]>Cc Ravikiran Thirumalai <[email protected]>Cc Shai Fultheim <[email protected]>Signed-off-by Bartlomiej Zolnierkiewicz <[email protected]>---
this is against 2.6.27 + pata tree + pre-patchset posted on Wednesday
(http://lkml.org/lkml/2008/10/8/221)
I've only had a casual look at this patch, but there is one thing:
[...]
Quoted 4 lines
Index:
b/drivers/ide/ide-probe.c
===================================================================drivers/ide/ide-probe.c +0
-0
[...]
Quoted 4 lines
drivers/ide/ide-probe.c +0
-0@@ -1091,11 +1092,11 @@ static int init_irq (ide_hwif_t *hwif)* linked list, the first entry is the hwif that owns * hwgroup->handler - do not change that. */
drivers/ide/ide-probe.c static int init_irq (ide_hwif_t *hwif) · line 1102
Quoted 10 lines
drivers/ide/ide-probe.c +2
-2-spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock); hwif->next = hwgroup->hwif->next; hwgroup->hwif->next = hwif;BUG_ON (hwif->next == hwif); -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); }else { hwgroup =kmalloc_node (sizeof (*hwgroup),GFP_KERNEL |__GFP_ZERO,hwif_to_node (hwif));
Something like
spin_lock_init(&hwgroup->lock);
should go into this else clause too.
Regards,
Elias
Quoted 48 lines · Elias Oltmanns
Quoted 13 lines · Bartlomiej Zolnierkiewicz
From: Bartlomiej Zolnierkiewicz <[email protected]>
Subject: [PATCH] ide: replace the globalide_lockspinlock by per-hwgroup spinlocksNow that (almost) all host drivers have been fixed not to abuse
ide_lockand core code usage ofide_lockhas been sanitized we may safely replaceide_lockby per-hwgroup locks.This patch is partially based on earlier patch from Ravikiran G Thirumalai.
While at it:
- don't use deprecatedHWIF()andHWGROUP()macros
- update locking documentation inide.hQuoted 8 lines
Cc Vaibhav V. Nivargi <[email protected]>Cc Alok N. Kataria <[email protected]>Cc Ravikiran Thirumalai <[email protected]>Cc Shai Fultheim <[email protected]>Signed-off-by Bartlomiej Zolnierkiewicz <[email protected]>---
this is against 2.6.27 + pata tree + pre-patchset posted on Wednesday
(http://lkml.org/lkml/2008/10/8/221)I've only had a casual look at this patch, but there is one thing:
[...]
Quoted 4 lines
Index:
b/drivers/ide/ide-probe.c
===================================================================drivers/ide/ide-probe.c +0
-0[...]
Quoted 4 lines
drivers/ide/ide-probe.c +0
-0@@ -1091,11 +1092,11 @@ static int init_irq (ide_hwif_t *hwif)* linked list, the first entry is the hwif that owns * hwgroup->handler - do not change that. */ drivers/ide/ide-probe.c static int init_irq (ide_hwif_t *hwif) · line 1102
Quoted 10 lines
drivers/ide/ide-probe.c +2
-2-spin_lock_irq (&ide_lock); +spin_lock_irq (&hwgroup->lock); hwif->next = hwgroup->hwif->next; hwgroup->hwif->next = hwif;BUG_ON (hwif->next == hwif); -spin_unlock_irq (&ide_lock); +spin_unlock_irq (&hwgroup->lock); }else { hwgroup =kmalloc_node (sizeof (*hwgroup),GFP_KERNEL |__GFP_ZERO,hwif_to_node (hwif));Something like
Quoted 3 lines
spin_lock_init(&hwgroup->lock);should go into this else clause too.
Thanks!
I fixed this in v2, obvious interdiff:
...
v2:
Add missing spin_lock_init(&hwgroup->lock). (Noticed by Elias Oltmanns)
...
drivers/ide/ide-probe.c +2 -0
@@ -1103,6 +1103,8 @@if (hwgroup ==NULL ) goto out_up; +spin_lock_init (&hwgroup->lock); + hwif->hwgroup = hwgroup; hwgroup->hwif = hwif->next = hwif;