Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cfq: don't use icq_get_changed()

cfq caches the associated cfqq's for a given cic. The cache needs to
be flushed if the cic's ioprio or blkcg has changed. It is currently
done by requiring the changing action to set the respective
ICQ_*_CHANGED bit in the icq and testing it from cfq_set_request(),
which involves iterating through all the affected icqs.

All cfq wants to know is whether ioprio and/or blkcg have changed
since the last flush and can be easily achieved by just remembering
the current ioprio and blkcg ID in cic.

This patch adds cic->{ioprio|blkcg_id}, updates all ioprio users to
use the remembered value instead, and updates cfq_set_request() path
such that, instead of using icq_get_changed(), the current values are
compared against the remembered ones and trigger appropriate flush
action if not. Condition tests are moved inside both _changed
functions which are now named check_ioprio_changed() and
check_blkcg_changed().

ioprio.h::task_ioprio*() can't be used anymore and replaced with
open-coded IOPRIO_CLASS_NONE case in cfq_async_queue_prio().

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Tejun Heo and committed by
Jens Axboe
598971bf abede6da

+45 -40
+40 -23
block/cfq-iosched.c
··· 218 218 struct io_cq icq; /* must be the first member */ 219 219 struct cfq_queue *cfqq[2]; 220 220 struct cfq_ttime ttime; 221 + int ioprio; /* the current ioprio */ 222 + #ifdef CONFIG_CFQ_GROUP_IOSCHED 223 + uint64_t blkcg_id; /* the current blkcg ID */ 224 + #endif 221 225 }; 222 226 223 227 /* ··· 2572 2568 if (!cfq_cfqq_prio_changed(cfqq)) 2573 2569 return; 2574 2570 2575 - ioprio_class = IOPRIO_PRIO_CLASS(cic->icq.ioc->ioprio); 2571 + ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); 2576 2572 switch (ioprio_class) { 2577 2573 default: 2578 2574 printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class); ··· 2584 2580 cfqq->ioprio_class = task_nice_ioclass(tsk); 2585 2581 break; 2586 2582 case IOPRIO_CLASS_RT: 2587 - cfqq->ioprio = task_ioprio(cic->icq.ioc); 2583 + cfqq->ioprio = IOPRIO_PRIO_DATA(cic->ioprio); 2588 2584 cfqq->ioprio_class = IOPRIO_CLASS_RT; 2589 2585 break; 2590 2586 case IOPRIO_CLASS_BE: 2591 - cfqq->ioprio = task_ioprio(cic->icq.ioc); 2587 + cfqq->ioprio = IOPRIO_PRIO_DATA(cic->ioprio); 2592 2588 cfqq->ioprio_class = IOPRIO_CLASS_BE; 2593 2589 break; 2594 2590 case IOPRIO_CLASS_IDLE: ··· 2606 2602 cfq_clear_cfqq_prio_changed(cfqq); 2607 2603 } 2608 2604 2609 - static void changed_ioprio(struct cfq_io_cq *cic, struct bio *bio) 2605 + static void check_ioprio_changed(struct cfq_io_cq *cic, struct bio *bio) 2610 2606 { 2607 + int ioprio = cic->icq.ioc->ioprio; 2611 2608 struct cfq_data *cfqd = cic_to_cfqd(cic); 2612 2609 struct cfq_queue *cfqq; 2613 2610 2614 - if (unlikely(!cfqd)) 2611 + /* 2612 + * Check whether ioprio has changed. The condition may trigger 2613 + * spuriously on a newly created cic but there's no harm. 2614 + */ 2615 + if (unlikely(!cfqd) || likely(cic->ioprio == ioprio)) 2615 2616 return; 2616 2617 2617 2618 cfqq = cic->cfqq[BLK_RW_ASYNC]; ··· 2633 2624 cfqq = cic->cfqq[BLK_RW_SYNC]; 2634 2625 if (cfqq) 2635 2626 cfq_mark_cfqq_prio_changed(cfqq); 2627 + 2628 + cic->ioprio = ioprio; 2636 2629 } 2637 2630 2638 2631 static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, ··· 2658 2647 } 2659 2648 2660 2649 #ifdef CONFIG_CFQ_GROUP_IOSCHED 2661 - static void changed_cgroup(struct cfq_io_cq *cic) 2650 + static void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) 2662 2651 { 2663 - struct cfq_queue *sync_cfqq = cic_to_cfqq(cic, 1); 2664 2652 struct cfq_data *cfqd = cic_to_cfqd(cic); 2665 - struct request_queue *q; 2653 + struct cfq_queue *sync_cfqq; 2654 + uint64_t id; 2666 2655 2667 - if (unlikely(!cfqd)) 2656 + rcu_read_lock(); 2657 + id = bio_blkio_cgroup(bio)->id; 2658 + rcu_read_unlock(); 2659 + 2660 + /* 2661 + * Check whether blkcg has changed. The condition may trigger 2662 + * spuriously on a newly created cic but there's no harm. 2663 + */ 2664 + if (unlikely(!cfqd) || likely(cic->blkcg_id == id)) 2668 2665 return; 2669 2666 2670 - q = cfqd->queue; 2671 - 2667 + sync_cfqq = cic_to_cfqq(cic, 1); 2672 2668 if (sync_cfqq) { 2673 2669 /* 2674 2670 * Drop reference to sync queue. A new sync queue will be ··· 2685 2667 cic_set_cfqq(cic, NULL, 1); 2686 2668 cfq_put_queue(sync_cfqq); 2687 2669 } 2670 + 2671 + cic->blkcg_id = id; 2688 2672 } 2673 + #else 2674 + static inline void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) { } 2689 2675 #endif /* CONFIG_CFQ_GROUP_IOSCHED */ 2690 2676 2691 2677 static struct cfq_queue * ··· 2753 2731 switch (ioprio_class) { 2754 2732 case IOPRIO_CLASS_RT: 2755 2733 return &cfqd->async_cfqq[0][ioprio]; 2734 + case IOPRIO_CLASS_NONE: 2735 + ioprio = IOPRIO_NORM; 2736 + /* fall through */ 2756 2737 case IOPRIO_CLASS_BE: 2757 2738 return &cfqd->async_cfqq[1][ioprio]; 2758 2739 case IOPRIO_CLASS_IDLE: ··· 2769 2744 cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, 2770 2745 struct bio *bio, gfp_t gfp_mask) 2771 2746 { 2772 - const int ioprio = task_ioprio(cic->icq.ioc); 2773 - const int ioprio_class = task_ioprio_class(cic->icq.ioc); 2747 + const int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); 2748 + const int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); 2774 2749 struct cfq_queue **async_cfqq = NULL; 2775 2750 struct cfq_queue *cfqq = NULL; 2776 2751 ··· 3328 3303 const int rw = rq_data_dir(rq); 3329 3304 const bool is_sync = rq_is_sync(rq); 3330 3305 struct cfq_queue *cfqq; 3331 - unsigned int changed; 3332 3306 3333 3307 might_sleep_if(gfp_mask & __GFP_WAIT); 3334 3308 3335 3309 spin_lock_irq(q->queue_lock); 3336 3310 3337 - /* handle changed notifications */ 3338 - changed = icq_get_changed(&cic->icq); 3339 - if (unlikely(changed & ICQ_IOPRIO_CHANGED)) 3340 - changed_ioprio(cic, bio); 3341 - #ifdef CONFIG_CFQ_GROUP_IOSCHED 3342 - if (unlikely(changed & ICQ_CGROUP_CHANGED)) 3343 - changed_cgroup(cic); 3344 - #endif 3345 - 3311 + check_ioprio_changed(cic, bio); 3312 + check_blkcg_changed(cic, bio); 3346 3313 new_queue: 3347 3314 cfqq = cic_to_cfqq(cic, is_sync); 3348 3315 if (!cfqq || cfqq == &cfqd->oom_cfqq) {
+5 -17
include/linux/ioprio.h
··· 42 42 }; 43 43 44 44 /* 45 + * Fallback BE priority 46 + */ 47 + #define IOPRIO_NORM (4) 48 + 49 + /* 45 50 * if process has set io priority explicitly, use that. if not, convert 46 51 * the cpu scheduler nice value to an io priority 47 52 */ 48 - #define IOPRIO_NORM (4) 49 - static inline int task_ioprio(struct io_context *ioc) 50 - { 51 - if (ioprio_valid(ioc->ioprio)) 52 - return IOPRIO_PRIO_DATA(ioc->ioprio); 53 - 54 - return IOPRIO_NORM; 55 - } 56 - 57 - static inline int task_ioprio_class(struct io_context *ioc) 58 - { 59 - if (ioprio_valid(ioc->ioprio)) 60 - return IOPRIO_PRIO_CLASS(ioc->ioprio); 61 - 62 - return IOPRIO_CLASS_BE; 63 - } 64 - 65 53 static inline int task_nice_ioprio(struct task_struct *task) 66 54 { 67 55 return (task_nice(task) + 20) / 5;