diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 66 |
1 files changed, 43 insertions, 23 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 0d3b70de3d80..a55a9bd75bd1 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -154,6 +154,8 @@ struct cfq_queue { | |||
154 | unsigned long rb_key; | 154 | unsigned long rb_key; |
155 | /* prio tree member */ | 155 | /* prio tree member */ |
156 | struct rb_node p_node; | 156 | struct rb_node p_node; |
157 | /* prio tree root we belong to, if any */ | ||
158 | struct rb_root *p_root; | ||
157 | /* sorted list of pending requests */ | 159 | /* sorted list of pending requests */ |
158 | struct rb_root sort_list; | 160 | struct rb_root sort_list; |
159 | /* if fifo isn't expired, next request to serve */ | 161 | /* if fifo isn't expired, next request to serve */ |
@@ -558,10 +560,10 @@ static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq, | |||
558 | } | 560 | } |
559 | 561 | ||
560 | static struct cfq_queue * | 562 | static struct cfq_queue * |
561 | cfq_prio_tree_lookup(struct cfq_data *cfqd, int ioprio, sector_t sector, | 563 | cfq_prio_tree_lookup(struct cfq_data *cfqd, struct rb_root *root, |
562 | struct rb_node **ret_parent, struct rb_node ***rb_link) | 564 | sector_t sector, struct rb_node **ret_parent, |
565 | struct rb_node ***rb_link) | ||
563 | { | 566 | { |
564 | struct rb_root *root = &cfqd->prio_trees[ioprio]; | ||
565 | struct rb_node **p, *parent; | 567 | struct rb_node **p, *parent; |
566 | struct cfq_queue *cfqq = NULL; | 568 | struct cfq_queue *cfqq = NULL; |
567 | 569 | ||
@@ -584,34 +586,38 @@ cfq_prio_tree_lookup(struct cfq_data *cfqd, int ioprio, sector_t sector, | |||
584 | else | 586 | else |
585 | break; | 587 | break; |
586 | p = n; | 588 | p = n; |
589 | cfqq = NULL; | ||
587 | } | 590 | } |
588 | 591 | ||
589 | *ret_parent = parent; | 592 | *ret_parent = parent; |
590 | if (rb_link) | 593 | if (rb_link) |
591 | *rb_link = p; | 594 | *rb_link = p; |
592 | return NULL; | 595 | return cfqq; |
593 | } | 596 | } |
594 | 597 | ||
595 | static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq) | 598 | static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq) |
596 | { | 599 | { |
597 | struct rb_root *root = &cfqd->prio_trees[cfqq->ioprio]; | ||
598 | struct rb_node **p, *parent; | 600 | struct rb_node **p, *parent; |
599 | struct cfq_queue *__cfqq; | 601 | struct cfq_queue *__cfqq; |
600 | 602 | ||
601 | if (!RB_EMPTY_NODE(&cfqq->p_node)) | 603 | if (cfqq->p_root) { |
602 | rb_erase_init(&cfqq->p_node, root); | 604 | rb_erase(&cfqq->p_node, cfqq->p_root); |
605 | cfqq->p_root = NULL; | ||
606 | } | ||
603 | 607 | ||
604 | if (cfq_class_idle(cfqq)) | 608 | if (cfq_class_idle(cfqq)) |
605 | return; | 609 | return; |
606 | if (!cfqq->next_rq) | 610 | if (!cfqq->next_rq) |
607 | return; | 611 | return; |
608 | 612 | ||
609 | __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->ioprio, cfqq->next_rq->sector, | 613 | cfqq->p_root = &cfqd->prio_trees[cfqq->org_ioprio]; |
614 | __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, cfqq->next_rq->sector, | ||
610 | &parent, &p); | 615 | &parent, &p); |
611 | BUG_ON(__cfqq); | 616 | if (!__cfqq) { |
612 | 617 | rb_link_node(&cfqq->p_node, parent, p); | |
613 | rb_link_node(&cfqq->p_node, parent, p); | 618 | rb_insert_color(&cfqq->p_node, cfqq->p_root); |
614 | rb_insert_color(&cfqq->p_node, root); | 619 | } else |
620 | cfqq->p_root = NULL; | ||
615 | } | 621 | } |
616 | 622 | ||
617 | /* | 623 | /* |
@@ -656,8 +662,10 @@ static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) | |||
656 | 662 | ||
657 | if (!RB_EMPTY_NODE(&cfqq->rb_node)) | 663 | if (!RB_EMPTY_NODE(&cfqq->rb_node)) |
658 | cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); | 664 | cfq_rb_erase(&cfqq->rb_node, &cfqd->service_tree); |
659 | if (!RB_EMPTY_NODE(&cfqq->p_node)) | 665 | if (cfqq->p_root) { |
660 | rb_erase_init(&cfqq->p_node, &cfqd->prio_trees[cfqq->ioprio]); | 666 | rb_erase(&cfqq->p_node, cfqq->p_root); |
667 | cfqq->p_root = NULL; | ||
668 | } | ||
661 | 669 | ||
662 | BUG_ON(!cfqd->busy_queues); | 670 | BUG_ON(!cfqd->busy_queues); |
663 | cfqd->busy_queues--; | 671 | cfqd->busy_queues--; |
@@ -947,20 +955,24 @@ static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd, | |||
947 | return cfqd->last_position - rq->sector; | 955 | return cfqd->last_position - rq->sector; |
948 | } | 956 | } |
949 | 957 | ||
958 | #define CIC_SEEK_THR 8 * 1024 | ||
959 | #define CIC_SEEKY(cic) ((cic)->seek_mean > CIC_SEEK_THR) | ||
960 | |||
950 | static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq) | 961 | static inline int cfq_rq_close(struct cfq_data *cfqd, struct request *rq) |
951 | { | 962 | { |
952 | struct cfq_io_context *cic = cfqd->active_cic; | 963 | struct cfq_io_context *cic = cfqd->active_cic; |
964 | sector_t sdist = cic->seek_mean; | ||
953 | 965 | ||
954 | if (!sample_valid(cic->seek_samples)) | 966 | if (!sample_valid(cic->seek_samples)) |
955 | return 0; | 967 | sdist = CIC_SEEK_THR; |
956 | 968 | ||
957 | return cfq_dist_from_last(cfqd, rq) <= cic->seek_mean; | 969 | return cfq_dist_from_last(cfqd, rq) <= sdist; |
958 | } | 970 | } |
959 | 971 | ||
960 | static struct cfq_queue *cfqq_close(struct cfq_data *cfqd, | 972 | static struct cfq_queue *cfqq_close(struct cfq_data *cfqd, |
961 | struct cfq_queue *cur_cfqq) | 973 | struct cfq_queue *cur_cfqq) |
962 | { | 974 | { |
963 | struct rb_root *root = &cfqd->prio_trees[cur_cfqq->ioprio]; | 975 | struct rb_root *root = &cfqd->prio_trees[cur_cfqq->org_ioprio]; |
964 | struct rb_node *parent, *node; | 976 | struct rb_node *parent, *node; |
965 | struct cfq_queue *__cfqq; | 977 | struct cfq_queue *__cfqq; |
966 | sector_t sector = cfqd->last_position; | 978 | sector_t sector = cfqd->last_position; |
@@ -972,8 +984,7 @@ static struct cfq_queue *cfqq_close(struct cfq_data *cfqd, | |||
972 | * First, if we find a request starting at the end of the last | 984 | * First, if we find a request starting at the end of the last |
973 | * request, choose it. | 985 | * request, choose it. |
974 | */ | 986 | */ |
975 | __cfqq = cfq_prio_tree_lookup(cfqd, cur_cfqq->ioprio, | 987 | __cfqq = cfq_prio_tree_lookup(cfqd, root, sector, &parent, NULL); |
976 | sector, &parent, NULL); | ||
977 | if (__cfqq) | 988 | if (__cfqq) |
978 | return __cfqq; | 989 | return __cfqq; |
979 | 990 | ||
@@ -1039,9 +1050,6 @@ static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd, | |||
1039 | return cfqq; | 1050 | return cfqq; |
1040 | } | 1051 | } |
1041 | 1052 | ||
1042 | |||
1043 | #define CIC_SEEKY(cic) ((cic)->seek_mean > (8 * 1024)) | ||
1044 | |||
1045 | static void cfq_arm_slice_timer(struct cfq_data *cfqd) | 1053 | static void cfq_arm_slice_timer(struct cfq_data *cfqd) |
1046 | { | 1054 | { |
1047 | struct cfq_queue *cfqq = cfqd->active_queue; | 1055 | struct cfq_queue *cfqq = cfqd->active_queue; |
@@ -1908,7 +1916,9 @@ cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic, | |||
1908 | sector_t sdist; | 1916 | sector_t sdist; |
1909 | u64 total; | 1917 | u64 total; |
1910 | 1918 | ||
1911 | if (cic->last_request_pos < rq->sector) | 1919 | if (!cic->last_request_pos) |
1920 | sdist = 0; | ||
1921 | else if (cic->last_request_pos < rq->sector) | ||
1912 | sdist = rq->sector - cic->last_request_pos; | 1922 | sdist = rq->sector - cic->last_request_pos; |
1913 | else | 1923 | else |
1914 | sdist = cic->last_request_pos - rq->sector; | 1924 | sdist = cic->last_request_pos - rq->sector; |
@@ -2443,12 +2453,22 @@ static void cfq_exit_queue(struct elevator_queue *e) | |||
2443 | static void *cfq_init_queue(struct request_queue *q) | 2453 | static void *cfq_init_queue(struct request_queue *q) |
2444 | { | 2454 | { |
2445 | struct cfq_data *cfqd; | 2455 | struct cfq_data *cfqd; |
2456 | int i; | ||
2446 | 2457 | ||
2447 | cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); | 2458 | cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL | __GFP_ZERO, q->node); |
2448 | if (!cfqd) | 2459 | if (!cfqd) |
2449 | return NULL; | 2460 | return NULL; |
2450 | 2461 | ||
2451 | cfqd->service_tree = CFQ_RB_ROOT; | 2462 | cfqd->service_tree = CFQ_RB_ROOT; |
2463 | |||
2464 | /* | ||
2465 | * Not strictly needed (since RB_ROOT just clears the node and we | ||
2466 | * zeroed cfqd on alloc), but better be safe in case someone decides | ||
2467 | * to add magic to the rb code | ||
2468 | */ | ||
2469 | for (i = 0; i < CFQ_PRIO_LISTS; i++) | ||
2470 | cfqd->prio_trees[i] = RB_ROOT; | ||
2471 | |||
2452 | INIT_LIST_HEAD(&cfqd->cic_list); | 2472 | INIT_LIST_HEAD(&cfqd->cic_list); |
2453 | 2473 | ||
2454 | cfqd->queue = q; | 2474 | cfqd->queue = q; |