aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2006-02-28 03:35:11 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-28 03:38:02 -0500
commit7b14e3b52fe5a2fb1dfa2f1f7dae4fd5f7d3fc47 (patch)
tree93a65fa0c9e5a10dea118a9594651264f08e58c6 /block
parenta8b76b491510b7591c584838d0d7922f9ffe5c2c (diff)
[PATCH] cfq-iosched: slice expiry fixups
During testing of SLES10, we encountered a hang in the CFQ io scheduler. Turns out the deferred slice expiry logic is buggy, so remove that for now. We could be left with an idle queue that would never wake up. So kill that logic, always expire immediately. Also fix a potential timer race condition. Patch looks bigger than it is, because it moves a function. Signed-off-by: Jens Axboe <axboe@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'block')
-rw-r--r--block/cfq-iosched.c151
1 files changed, 60 insertions, 91 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 74fae2daf87e..c8dbe38c81c8 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -239,7 +239,6 @@ enum cfqq_state_flags {
239 CFQ_CFQQ_FLAG_fifo_expire, 239 CFQ_CFQQ_FLAG_fifo_expire,
240 CFQ_CFQQ_FLAG_idle_window, 240 CFQ_CFQQ_FLAG_idle_window,
241 CFQ_CFQQ_FLAG_prio_changed, 241 CFQ_CFQQ_FLAG_prio_changed,
242 CFQ_CFQQ_FLAG_expired,
243}; 242};
244 243
245#define CFQ_CFQQ_FNS(name) \ 244#define CFQ_CFQQ_FNS(name) \
@@ -264,7 +263,6 @@ CFQ_CFQQ_FNS(must_dispatch);
264CFQ_CFQQ_FNS(fifo_expire); 263CFQ_CFQQ_FNS(fifo_expire);
265CFQ_CFQQ_FNS(idle_window); 264CFQ_CFQQ_FNS(idle_window);
266CFQ_CFQQ_FNS(prio_changed); 265CFQ_CFQQ_FNS(prio_changed);
267CFQ_CFQQ_FNS(expired);
268#undef CFQ_CFQQ_FNS 266#undef CFQ_CFQQ_FNS
269 267
270enum cfq_rq_state_flags { 268enum cfq_rq_state_flags {
@@ -336,7 +334,7 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
336 */ 334 */
337static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) 335static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
338{ 336{
339 if (!cfqd->rq_in_driver && cfqd->busy_queues) 337 if (cfqd->busy_queues)
340 kblockd_schedule_work(&cfqd->unplug_work); 338 kblockd_schedule_work(&cfqd->unplug_work);
341} 339}
342 340
@@ -736,13 +734,63 @@ __cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
736 cfqq->slice_left = 0; 734 cfqq->slice_left = 0;
737 cfq_clear_cfqq_must_alloc_slice(cfqq); 735 cfq_clear_cfqq_must_alloc_slice(cfqq);
738 cfq_clear_cfqq_fifo_expire(cfqq); 736 cfq_clear_cfqq_fifo_expire(cfqq);
739 cfq_clear_cfqq_expired(cfqq);
740 } 737 }
741 738
742 cfqd->active_queue = cfqq; 739 cfqd->active_queue = cfqq;
743} 740}
744 741
745/* 742/*
743 * current cfqq expired its slice (or was too idle), select new one
744 */
745static void
746__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
747 int preempted)
748{
749 unsigned long now = jiffies;
750
751 if (cfq_cfqq_wait_request(cfqq))
752 del_timer(&cfqd->idle_slice_timer);
753
754 if (!preempted && !cfq_cfqq_dispatched(cfqq)) {
755 cfqq->service_last = now;
756 cfq_schedule_dispatch(cfqd);
757 }
758
759 cfq_clear_cfqq_must_dispatch(cfqq);
760 cfq_clear_cfqq_wait_request(cfqq);
761
762 /*
763 * store what was left of this slice, if the queue idled out
764 * or was preempted
765 */
766 if (time_after(cfqq->slice_end, now))
767 cfqq->slice_left = cfqq->slice_end - now;
768 else
769 cfqq->slice_left = 0;
770
771 if (cfq_cfqq_on_rr(cfqq))
772 cfq_resort_rr_list(cfqq, preempted);
773
774 if (cfqq == cfqd->active_queue)
775 cfqd->active_queue = NULL;
776
777 if (cfqd->active_cic) {
778 put_io_context(cfqd->active_cic->ioc);
779 cfqd->active_cic = NULL;
780 }
781
782 cfqd->dispatch_slice = 0;
783}
784
785static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
786{
787 struct cfq_queue *cfqq = cfqd->active_queue;
788
789 if (cfqq)
790 __cfq_slice_expired(cfqd, cfqq, preempted);
791}
792
793/*
746 * 0 794 * 0
747 * 0,1 795 * 0,1
748 * 0,1,2 796 * 0,1,2
@@ -801,16 +849,7 @@ static int cfq_get_next_prio_level(struct cfq_data *cfqd)
801 849
802static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd) 850static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
803{ 851{
804 struct cfq_queue *cfqq; 852 struct cfq_queue *cfqq = NULL;
805
806 /*
807 * if current queue is expired but not done with its requests yet,
808 * wait for that to happen
809 */
810 if ((cfqq = cfqd->active_queue) != NULL) {
811 if (cfq_cfqq_expired(cfqq) && cfq_cfqq_dispatched(cfqq))
812 return NULL;
813 }
814 853
815 /* 854 /*
816 * if current list is non-empty, grab first entry. if it is empty, 855 * if current list is non-empty, grab first entry. if it is empty,
@@ -837,66 +876,11 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
837 return cfqq; 876 return cfqq;
838} 877}
839 878
840/*
841 * current cfqq expired its slice (or was too idle), select new one
842 */
843static void
844__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
845 int preempted)
846{
847 unsigned long now = jiffies;
848
849 if (cfq_cfqq_wait_request(cfqq))
850 del_timer(&cfqd->idle_slice_timer);
851
852 if (!preempted && !cfq_cfqq_dispatched(cfqq))
853 cfqq->service_last = now;
854
855 cfq_clear_cfqq_must_dispatch(cfqq);
856 cfq_clear_cfqq_wait_request(cfqq);
857
858 /*
859 * store what was left of this slice, if the queue idled out
860 * or was preempted
861 */
862 if (time_after(cfqq->slice_end, now))
863 cfqq->slice_left = cfqq->slice_end - now;
864 else
865 cfqq->slice_left = 0;
866
867 if (cfq_cfqq_on_rr(cfqq))
868 cfq_resort_rr_list(cfqq, preempted);
869
870 if (cfqq == cfqd->active_queue)
871 cfqd->active_queue = NULL;
872
873 if (cfqd->active_cic) {
874 put_io_context(cfqd->active_cic->ioc);
875 cfqd->active_cic = NULL;
876 }
877
878 cfqd->dispatch_slice = 0;
879}
880
881static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
882{
883 struct cfq_queue *cfqq = cfqd->active_queue;
884
885 if (cfqq) {
886 /*
887 * use deferred expiry, if there are requests in progress as
888 * not to disturb the slice of the next queue
889 */
890 if (cfq_cfqq_dispatched(cfqq))
891 cfq_mark_cfqq_expired(cfqq);
892 else
893 __cfq_slice_expired(cfqd, cfqq, preempted);
894 }
895}
896
897static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) 879static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
898 880
899{ 881{
882 unsigned long sl;
883
900 WARN_ON(!RB_EMPTY(&cfqq->sort_list)); 884 WARN_ON(!RB_EMPTY(&cfqq->sort_list));
901 WARN_ON(cfqq != cfqd->active_queue); 885 WARN_ON(cfqq != cfqd->active_queue);
902 886
@@ -916,13 +900,8 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
916 cfq_mark_cfqq_must_dispatch(cfqq); 900 cfq_mark_cfqq_must_dispatch(cfqq);
917 cfq_mark_cfqq_wait_request(cfqq); 901 cfq_mark_cfqq_wait_request(cfqq);
918 902
919 if (!timer_pending(&cfqd->idle_slice_timer)) { 903 sl = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
920 unsigned long slice_left = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle); 904 mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
921
922 cfqd->idle_slice_timer.expires = jiffies + slice_left;
923 add_timer(&cfqd->idle_slice_timer);
924 }
925
926 return 1; 905 return 1;
927} 906}
928 907
@@ -1006,9 +985,6 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
1006 if (!cfqq) 985 if (!cfqq)
1007 goto new_queue; 986 goto new_queue;
1008 987
1009 if (cfq_cfqq_expired(cfqq))
1010 goto new_queue;
1011
1012 /* 988 /*
1013 * slice has expired 989 * slice has expired
1014 */ 990 */
@@ -1181,10 +1157,8 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
1181 BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); 1157 BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
1182 BUG_ON(cfq_cfqq_on_rr(cfqq)); 1158 BUG_ON(cfq_cfqq_on_rr(cfqq));
1183 1159
1184 if (unlikely(cfqd->active_queue == cfqq)) { 1160 if (unlikely(cfqd->active_queue == cfqq))
1185 __cfq_slice_expired(cfqd, cfqq, 0); 1161 __cfq_slice_expired(cfqd, cfqq, 0);
1186 cfq_schedule_dispatch(cfqd);
1187 }
1188 1162
1189 cfq_put_cfqd(cfqq->cfqd); 1163 cfq_put_cfqd(cfqq->cfqd);
1190 1164
@@ -1245,10 +1219,8 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic)
1245 1219
1246 spin_lock(q->queue_lock); 1220 spin_lock(q->queue_lock);
1247 1221
1248 if (unlikely(cic->cfqq == cfqd->active_queue)) { 1222 if (unlikely(cic->cfqq == cfqd->active_queue))
1249 __cfq_slice_expired(cfqd, cic->cfqq, 0); 1223 __cfq_slice_expired(cfqd, cic->cfqq, 0);
1250 cfq_schedule_dispatch(cfqd);
1251 }
1252 1224
1253 cfq_put_queue(cic->cfqq); 1225 cfq_put_queue(cic->cfqq);
1254 cic->cfqq = NULL; 1226 cic->cfqq = NULL;
@@ -1715,10 +1687,7 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
1715 cfqq->service_last = now; 1687 cfqq->service_last = now;
1716 cfq_resort_rr_list(cfqq, 0); 1688 cfq_resort_rr_list(cfqq, 0);
1717 } 1689 }
1718 if (cfq_cfqq_expired(cfqq)) { 1690 cfq_schedule_dispatch(cfqd);
1719 __cfq_slice_expired(cfqd, cfqq, 0);
1720 cfq_schedule_dispatch(cfqd);
1721 }
1722 } 1691 }
1723 1692
1724 if (cfq_crq_is_sync(crq)) 1693 if (cfq_crq_is_sync(crq))