diff options
| author | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-01-02 10:12:50 -0500 |
|---|---|---|
| committer | Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> | 2009-01-02 10:12:50 -0500 |
| commit | 201bffa46466b4afdf7d29db8eca3fa5decb39c8 (patch) | |
| tree | 47e7d85563690547b67748092e587be1f31046b5 | |
| parent | 631de3708d595d153e8a510a3608689290f4c0ed (diff) | |
ide: use per-device request queue locks (v2)
* Move hack for flush requests from choose_drive() to do_ide_request().
* Add ide_plug_device() helper and convert core IDE code from using
per-hwgroup lock as a request lock to use the ->queue_lock instead.
* Remove no longer needed:
- choose_drive() function
- WAKEUP() macro
- 'sleeping' flag from ide_hwif_t
- 'service_{start,time}' fields from ide_drive_t
This patch results in much simpler and more maintainable code
(besides being a scalability improvement).
v2:
* Fixes/improvements based on review from Elias:
- take as many requests off the queue as possible
- remove now redundant BUG_ON()
Cc: Elias Oltmanns <eo@nebensachen.de>
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
| -rw-r--r-- | drivers/ide/ide-io.c | 214 | ||||
| -rw-r--r-- | drivers/ide/ide-park.c | 13 | ||||
| -rw-r--r-- | drivers/ide/ide-probe.c | 3 | ||||
| -rw-r--r-- | include/linux/ide.h | 4 |
4 files changed, 77 insertions, 157 deletions
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index ab480042757a..bb3248abf47d 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c | |||
| @@ -667,85 +667,10 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) | |||
| 667 | drive->sleep = timeout + jiffies; | 667 | drive->sleep = timeout + jiffies; |
| 668 | drive->dev_flags |= IDE_DFLAG_SLEEPING; | 668 | drive->dev_flags |= IDE_DFLAG_SLEEPING; |
| 669 | } | 669 | } |
| 670 | |||
| 671 | EXPORT_SYMBOL(ide_stall_queue); | 670 | EXPORT_SYMBOL(ide_stall_queue); |
| 672 | 671 | ||
| 673 | #define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time) | ||
| 674 | |||
| 675 | /** | ||
| 676 | * choose_drive - select a drive to service | ||
| 677 | * @hwgroup: hardware group to select on | ||
| 678 | * | ||
| 679 | * choose_drive() selects the next drive which will be serviced. | ||
| 680 | * This is necessary because the IDE layer can't issue commands | ||
| 681 | * to both drives on the same cable, unlike SCSI. | ||
| 682 | */ | ||
| 683 | |||
| 684 | static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) | ||
| 685 | { | ||
| 686 | ide_drive_t *drive, *best; | ||
| 687 | |||
| 688 | repeat: | ||
| 689 | best = NULL; | ||
| 690 | drive = hwgroup->drive; | ||
| 691 | |||
| 692 | /* | ||
| 693 | * drive is doing pre-flush, ordered write, post-flush sequence. even | ||
| 694 | * though that is 3 requests, it must be seen as a single transaction. | ||
| 695 | * we must not preempt this drive until that is complete | ||
| 696 | */ | ||
| 697 | if (blk_queue_flushing(drive->queue)) { | ||
| 698 | /* | ||
| 699 | * small race where queue could get replugged during | ||
| 700 | * the 3-request flush cycle, just yank the plug since | ||
| 701 | * we want it to finish asap | ||
| 702 | */ | ||
| 703 | blk_remove_plug(drive->queue); | ||
| 704 | return drive; | ||
| 705 | } | ||
| 706 | |||
| 707 | do { | ||
| 708 | u8 dev_s = !!(drive->dev_flags & IDE_DFLAG_SLEEPING); | ||
| 709 | u8 best_s = (best && !!(best->dev_flags & IDE_DFLAG_SLEEPING)); | ||
| 710 | |||
| 711 | if ((dev_s == 0 || time_after_eq(jiffies, drive->sleep)) && | ||
| 712 | !elv_queue_empty(drive->queue)) { | ||
| 713 | if (best == NULL || | ||
| 714 | (dev_s && (best_s == 0 || time_before(drive->sleep, best->sleep))) || | ||
| 715 | (best_s == 0 && time_before(WAKEUP(drive), WAKEUP(best)))) { | ||
| 716 | if (!blk_queue_plugged(drive->queue)) | ||
| 717 | best = drive; | ||
| 718 | } | ||
| 719 | } | ||
| 720 | } while ((drive = drive->next) != hwgroup->drive); | ||
| 721 | |||
| 722 | if (best && (best->dev_flags & IDE_DFLAG_NICE1) && | ||
| 723 | (best->dev_flags & IDE_DFLAG_SLEEPING) == 0 && | ||
| 724 | best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { | ||
| 725 | long t = (signed long)(WAKEUP(best) - jiffies); | ||
| 726 | if (t >= WAIT_MIN_SLEEP) { | ||
| 727 | /* | ||
| 728 | * We *may* have some time to spare, but first let's see if | ||
| 729 | * someone can potentially benefit from our nice mood today.. | ||
| 730 | */ | ||
| 731 | drive = best->next; | ||
| 732 | do { | ||
| 733 | if ((drive->dev_flags & IDE_DFLAG_SLEEPING) == 0 | ||
| 734 | && time_before(jiffies - best->service_time, WAKEUP(drive)) | ||
| 735 | && time_before(WAKEUP(drive), jiffies + t)) | ||
| 736 | { | ||
| 737 | ide_stall_queue(best, min_t(long, t, 10 * WAIT_MIN_SLEEP)); | ||
| 738 | goto repeat; | ||
| 739 | } | ||
| 740 | } while ((drive = drive->next) != best); | ||
| 741 | } | ||
| 742 | } | ||
| 743 | return best; | ||
| 744 | } | ||
| 745 | |||
| 746 | /* | 672 | /* |
| 747 | * Issue a new request to a drive from hwgroup | 673 | * Issue a new request to a drive from hwgroup |
| 748 | * Caller must have already done spin_lock_irqsave(&hwgroup->lock, ..); | ||
| 749 | * | 674 | * |
| 750 | * A hwgroup is a serialized group of IDE interfaces. Usually there is | 675 | * A hwgroup is a serialized group of IDE interfaces. Usually there is |
| 751 | * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640) | 676 | * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640) |
| @@ -757,8 +682,7 @@ repeat: | |||
| 757 | * possibly along with many other devices. This is especially common in | 682 | * possibly along with many other devices. This is especially common in |
| 758 | * PCI-based systems with off-board IDE controller cards. | 683 | * PCI-based systems with off-board IDE controller cards. |
| 759 | * | 684 | * |
| 760 | * The IDE driver uses a per-hwgroup spinlock to protect | 685 | * The IDE driver uses a per-hwgroup lock to protect the hwgroup->busy flag. |
| 761 | * access to the request queues, and to protect the hwgroup->busy flag. | ||
| 762 | * | 686 | * |
| 763 | * The first thread into the driver for a particular hwgroup sets the | 687 | * The first thread into the driver for a particular hwgroup sets the |
| 764 | * hwgroup->busy flag to indicate that this hwgroup is now active, | 688 | * hwgroup->busy flag to indicate that this hwgroup is now active, |
| @@ -780,61 +704,38 @@ repeat: | |||
| 780 | */ | 704 | */ |
| 781 | void do_ide_request(struct request_queue *q) | 705 | void do_ide_request(struct request_queue *q) |
| 782 | { | 706 | { |
| 783 | ide_drive_t *orig_drive = q->queuedata; | 707 | ide_drive_t *drive = q->queuedata; |
| 784 | ide_hwgroup_t *hwgroup = orig_drive->hwif->hwgroup; | 708 | ide_hwif_t *hwif = drive->hwif; |
| 785 | ide_drive_t *drive; | 709 | ide_hwgroup_t *hwgroup = hwif->hwgroup; |
| 786 | ide_hwif_t *hwif; | ||
| 787 | struct request *rq; | 710 | struct request *rq; |
| 788 | ide_startstop_t startstop; | 711 | ide_startstop_t startstop; |
| 789 | 712 | ||
| 790 | /* caller must own hwgroup->lock */ | 713 | /* |
| 791 | BUG_ON(!irqs_disabled()); | 714 | * drive is doing pre-flush, ordered write, post-flush sequence. even |
| 792 | 715 | * though that is 3 requests, it must be seen as a single transaction. | |
| 793 | while (!ide_lock_hwgroup(hwgroup)) { | 716 | * we must not preempt this drive until that is complete |
| 794 | drive = choose_drive(hwgroup); | 717 | */ |
| 795 | if (drive == NULL) { | 718 | if (blk_queue_flushing(q)) |
| 796 | int sleeping = 0; | ||
| 797 | unsigned long sleep = 0; /* shut up, gcc */ | ||
| 798 | hwgroup->rq = NULL; | ||
| 799 | drive = hwgroup->drive; | ||
| 800 | do { | ||
| 801 | if ((drive->dev_flags & IDE_DFLAG_SLEEPING) && | ||
| 802 | (sleeping == 0 || | ||
| 803 | time_before(drive->sleep, sleep))) { | ||
| 804 | sleeping = 1; | ||
| 805 | sleep = drive->sleep; | ||
| 806 | } | ||
| 807 | } while ((drive = drive->next) != hwgroup->drive); | ||
| 808 | if (sleeping) { | ||
| 809 | /* | 719 | /* |
| 810 | * Take a short snooze, and then wake up this hwgroup again. | 720 | * small race where queue could get replugged during |
| 811 | * This gives other hwgroups on the same a chance to | 721 | * the 3-request flush cycle, just yank the plug since |
| 812 | * play fairly with us, just in case there are big differences | 722 | * we want it to finish asap |
| 813 | * in relative throughputs.. don't want to hog the cpu too much. | ||
| 814 | */ | 723 | */ |
| 815 | if (time_before(sleep, jiffies + WAIT_MIN_SLEEP)) | 724 | blk_remove_plug(q); |
| 816 | sleep = jiffies + WAIT_MIN_SLEEP; | ||
| 817 | #if 1 | ||
| 818 | if (timer_pending(&hwgroup->timer)) | ||
| 819 | printk(KERN_CRIT "ide_set_handler: timer already active\n"); | ||
| 820 | #endif | ||
| 821 | /* so that ide_timer_expiry knows what to do */ | ||
| 822 | hwgroup->sleeping = 1; | ||
| 823 | hwgroup->req_gen_timer = hwgroup->req_gen; | ||
| 824 | mod_timer(&hwgroup->timer, sleep); | ||
| 825 | /* we purposely leave hwgroup locked | ||
| 826 | * while sleeping */ | ||
| 827 | } else | ||
| 828 | ide_unlock_hwgroup(hwgroup); | ||
| 829 | 725 | ||
| 830 | /* no more work for this hwgroup (for now) */ | 726 | spin_unlock_irq(q->queue_lock); |
| 831 | goto plug_device; | 727 | spin_lock_irq(&hwgroup->lock); |
| 832 | } | ||
| 833 | 728 | ||
| 834 | if (drive != orig_drive) | 729 | if (!ide_lock_hwgroup(hwgroup)) { |
| 835 | goto plug_device; | 730 | repeat: |
| 731 | hwgroup->rq = NULL; | ||
| 836 | 732 | ||
| 837 | hwif = drive->hwif; | 733 | if (drive->dev_flags & IDE_DFLAG_SLEEPING) { |
| 734 | if (time_before(drive->sleep, jiffies)) { | ||
| 735 | ide_unlock_hwgroup(hwgroup); | ||
| 736 | goto plug_device; | ||
| 737 | } | ||
| 738 | } | ||
| 838 | 739 | ||
| 839 | if (hwif != hwgroup->hwif) { | 740 | if (hwif != hwgroup->hwif) { |
| 840 | /* | 741 | /* |
| @@ -847,16 +748,20 @@ void do_ide_request(struct request_queue *q) | |||
| 847 | hwgroup->hwif = hwif; | 748 | hwgroup->hwif = hwif; |
| 848 | hwgroup->drive = drive; | 749 | hwgroup->drive = drive; |
| 849 | drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED); | 750 | drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED); |
| 850 | drive->service_start = jiffies; | ||
| 851 | 751 | ||
| 752 | spin_unlock_irq(&hwgroup->lock); | ||
| 753 | spin_lock_irq(q->queue_lock); | ||
| 852 | /* | 754 | /* |
| 853 | * we know that the queue isn't empty, but this can happen | 755 | * we know that the queue isn't empty, but this can happen |
