aboutsummaryrefslogtreecommitdiffstats
path: root/block/cfq-iosched.c
diff options
context:
space:
mode:
authorVasily Tarasov <vtaras@openvz.org>2007-04-25 06:29:51 -0400
committerJens Axboe <axboe@nelson.home.kernel.dk>2007-04-30 03:01:23 -0400
commit91fac317a34859986a2359a5a5c0e37dc17a9c3d (patch)
tree353b8e5d3415e6244b8d2de67020bbbc94f2032c /block/cfq-iosched.c
parentcc19747977824ece6aa1c56a29e974fef5ec2b32 (diff)
cfq-iosched: get rid of cfqq hash
cfq hash is no more necessary. We always can get cfqq from io context. cfq_get_io_context_noalloc() function is introduced, because we don't want to allocate cic on merging and checking may_queue. In order to identify sync queue we've used hash key = CFQ_KEY_ASYNC. Since hash is eliminated we need to use other criterion: sync flag for queue is added. In all places where we dig in rb_tree we're in current context, so no additional locking is required. Advantages of this patch: no additional memory for hash, no seeking in hash, code is cleaner. But it is necessary now to seek cic in per-ioc rbtree, but it is faster: - most processes work only with few devices - most systems have only few block devices - it is a rb-tree Signed-off-by: Vasily Tarasov <vtaras@openvz.org> Changes by me: - Merge into CFQ devel branch - Get rid of cfq_get_io_context_noalloc() - Fix various bugs with dereferencing cic->cfqq[] with offset other than 0 or 1. - Fix bug in cfqq setup, is_sync condition was reversed. - Fix bug where only bio_sync() is used, we need to check for a READ too Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r--block/cfq-iosched.c167
1 files changed, 67 insertions, 100 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index e859b4966e4c..94f53a1f4677 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -9,7 +9,6 @@
9#include <linux/module.h> 9#include <linux/module.h>
10#include <linux/blkdev.h> 10#include <linux/blkdev.h>
11#include <linux/elevator.h> 11#include <linux/elevator.h>
12#include <linux/hash.h>
13#include <linux/rbtree.h> 12#include <linux/rbtree.h>
14#include <linux/ioprio.h> 13#include <linux/ioprio.h>
15 14
@@ -38,14 +37,6 @@ static int cfq_slice_idle = HZ / 125;
38 37
39#define CFQ_SLICE_SCALE (5) 38#define CFQ_SLICE_SCALE (5)
40 39
41#define CFQ_KEY_ASYNC (0)
42
43/*
44 * for the hash of cfqq inside the cfqd
45 */
46#define CFQ_QHASH_SHIFT 6
47#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT)
48
49#define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private) 40#define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private)
50#define RQ_CFQQ(rq) ((rq)->elevator_private2) 41#define RQ_CFQQ(rq) ((rq)->elevator_private2)
51 42
@@ -62,8 +53,6 @@ static struct completion *ioc_gone;
62#define ASYNC (0) 53#define ASYNC (0)
63#define SYNC (1) 54#define SYNC (1)
64 55
65#define cfq_cfqq_sync(cfqq) ((cfqq)->key != CFQ_KEY_ASYNC)
66
67#define sample_valid(samples) ((samples) > 80) 56#define sample_valid(samples) ((samples) > 80)
68 57
69/* 58/*
@@ -90,11 +79,6 @@ struct cfq_data {
90 struct cfq_rb_root service_tree; 79 struct cfq_rb_root service_tree;
91 unsigned int busy_queues; 80 unsigned int busy_queues;
92 81
93 /*
94 * cfqq lookup hash
95 */
96 struct hlist_head *cfq_hash;
97
98 int rq_in_driver; 82 int rq_in_driver;
99 int sync_flight; 83 int sync_flight;
100 int hw_tag; 84 int hw_tag;
@@ -138,10 +122,6 @@ struct cfq_queue {
138 atomic_t ref; 122 atomic_t ref;
139 /* parent cfq_data */ 123 /* parent cfq_data */
140 struct cfq_data *cfqd; 124 struct cfq_data *cfqd;
141 /* cfqq lookup hash */
142 struct hlist_node cfq_hash;
143 /* hash key */
144 unsigned int key;
145 /* service_tree member */ 125 /* service_tree member */
146 struct rb_node rb_node; 126 struct rb_node rb_node;
147 /* service_tree key */ 127 /* service_tree key */
@@ -186,6 +166,7 @@ enum cfqq_state_flags {
186 CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ 166 CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */
187 CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */ 167 CFQ_CFQQ_FLAG_queue_new, /* queue never been serviced */
188 CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ 168 CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */
169 CFQ_CFQQ_FLAG_sync, /* synchronous queue */
189}; 170};
190 171
191#define CFQ_CFQQ_FNS(name) \ 172#define CFQ_CFQQ_FNS(name) \
@@ -212,11 +193,38 @@ CFQ_CFQQ_FNS(idle_window);
212CFQ_CFQQ_FNS(prio_changed); 193CFQ_CFQQ_FNS(prio_changed);
213CFQ_CFQQ_FNS(queue_new); 194CFQ_CFQQ_FNS(queue_new);
214CFQ_CFQQ_FNS(slice_new); 195CFQ_CFQQ_FNS(slice_new);
196CFQ_CFQQ_FNS(sync);
215#undef CFQ_CFQQ_FNS 197#undef CFQ_CFQQ_FNS
216 198
217static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
218static void cfq_dispatch_insert(request_queue_t *, struct request *); 199static void cfq_dispatch_insert(request_queue_t *, struct request *);
219static struct cfq_queue *cfq_get_queue(struct cfq_data *, unsigned int, struct task_struct *, gfp_t); 200static struct cfq_queue *cfq_get_queue(struct cfq_data *, int,
201 struct task_struct *, gfp_t);
202static struct cfq_io_context *cfq_cic_rb_lookup(struct cfq_data *,
203 struct io_context *);
204
205static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_context *cic,
206 int is_sync)
207{
208 return cic->cfqq[!!is_sync];
209}
210
211static inline void cic_set_cfqq(struct cfq_io_context *cic,
212 struct cfq_queue *cfqq, int is_sync)
213{
214 cic->cfqq[!!is_sync] = cfqq;
215}
216
217/*
218 * We regard a request as SYNC, if it's either a read or has the SYNC bit
219 * set (in which case it could also be direct WRITE).
220 */
221static inline int cfq_bio_sync(struct bio *bio)
222{
223 if (bio_data_dir(bio) == READ || bio_sync(bio))
224 return 1;
225
226 return 0;
227}
220 228
221/* 229/*
222 * scheduler run of queue, if there are requests pending and no one in the 230 * scheduler run of queue, if there are requests pending and no one in the
@@ -235,17 +243,6 @@ static int cfq_queue_empty(request_queue_t *q)
235 return !cfqd->busy_queues; 243 return !cfqd->busy_queues;
236} 244}
237 245
238static inline pid_t cfq_queue_pid(struct task_struct *task, int rw, int is_sync)
239{
240 /*
241 * Use the per-process queue, for read requests and syncronous writes
242 */
243 if (!(rw & REQ_RW) || is_sync)
244 return task->pid;
245
246 return CFQ_KEY_ASYNC;
247}
248
249/* 246/*
250 * Scale schedule slice based on io priority. Use the sync time slice only 247 * Scale schedule slice based on io priority. Use the sync time slice only
251 * if a queue is marked sync and has sync io queued. A sync queue with async 248 * if a queue is marked sync and has sync io queued. A sync queue with async
@@ -608,10 +605,14 @@ static struct request *
608cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio) 605cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
609{ 606{
610 struct task_struct *tsk = current; 607 struct task_struct *tsk = current;
611 pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio), bio_sync(bio)); 608 struct cfq_io_context *cic;
612 struct cfq_queue *cfqq; 609 struct cfq_queue *cfqq;
613 610
614 cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio); 611 cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
612 if (!cic)
613 return NULL;
614
615 cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
615 if (cfqq) { 616 if (cfqq) {
616 sector_t sector = bio->bi_sector + bio_sectors(bio); 617 sector_t sector = bio->bi_sector + bio_sectors(bio);
617 618
@@ -705,23 +706,24 @@ static int cfq_allow_merge(request_queue_t *q, struct request *rq,
705 struct bio *bio) 706 struct bio *bio)
706{ 707{
707 struct cfq_data *cfqd = q->elevator->elevator_data; 708 struct cfq_data *cfqd = q->elevator->elevator_data;
708 const int rw = bio_data_dir(bio); 709 struct cfq_io_context *cic;
709 struct cfq_queue *cfqq; 710 struct cfq_queue *cfqq;
710 pid_t key;
711 711
712 /* 712 /*
713 * Disallow merge of a sync bio into an async request. 713 * Disallow merge of a sync bio into an async request.
714 */ 714 */
715 if ((bio_data_dir(bio) == READ || bio_sync(bio)) && !rq_is_sync(rq)) 715 if (cfq_bio_sync(bio) && !rq_is_sync(rq))
716 return 0; 716 return 0;
717 717
718 /* 718 /*
719 * Lookup the cfqq that this bio will be queued with. Allow 719 * Lookup the cfqq that this bio will be queued with. Allow
720 * merge only if rq is queued there. 720 * merge only if rq is queued there.
721 */ 721 */
722 key = cfq_queue_pid(current, rw, bio_sync(bio)); 722 cic = cfq_cic_rb_lookup(cfqd, current->io_context);
723 cfqq = cfq_find_cfq_hash(cfqd, key, current->ioprio); 723 if (!cic)
724 return 0;
724 725
726 cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio));
725 if (cfqq == RQ_CFQQ(rq)) 727 if (cfqq == RQ_CFQQ(rq))
726 return 1; 728 return 1;
727 729
@@ -1154,37 +1156,9 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
1154 cfq_schedule_dispatch(cfqd); 1156 cfq_schedule_dispatch(cfqd);
1155 } 1157 }
1156 1158
1157 /*
1158 * it's on the empty list and still hashed
1159 */
1160 hlist_del(&cfqq->cfq_hash);
1161 kmem_cache_free(cfq_pool, cfqq); 1159 kmem_cache_free(cfq_pool, cfqq);
1162} 1160}
1163 1161
1164static struct cfq_queue *
1165__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
1166 const int hashval)
1167{
1168 struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
1169 struct hlist_node *entry;
1170 struct cfq_queue *__cfqq;
1171
1172 hlist_for_each_entry(__cfqq, entry, hash_list, cfq_hash) {
1173 const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio);
1174
1175 if (__cfqq->key == key && (__p == prio || !prio))
1176 return __cfqq;
1177 }
1178
1179 return NULL;
1180}
1181
1182static struct cfq_queue *
1183cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
1184{
1185 return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
1186}
1187
1188static void cfq_free_io_context(struct io_context *ioc) 1162static void cfq_free_io_context(struct io_context *ioc)
1189{ 1163{
1190 struct cfq_io_context *__cic; 1164 struct cfq_io_context *__cic;
@@ -1342,7 +1316,7 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
1342 cfqq = cic->cfqq[ASYNC]; 1316 cfqq = cic->cfqq[ASYNC];
1343 if (cfqq) { 1317 if (cfqq) {
1344 struct cfq_queue *new_cfqq; 1318 struct cfq_queue *new_cfqq;
1345 new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, cic->ioc->task, 1319 new_cfqq = cfq_get_queue(cfqd, ASYNC, cic->ioc->task,
1346 GFP_ATOMIC); 1320 GFP_ATOMIC);
1347 if (new_cfqq) { 1321 if (new_cfqq) {
1348 cic->cfqq[ASYNC] = new_cfqq; 1322 cic->cfqq[ASYNC] = new_cfqq;
@@ -1374,16 +1348,16 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc)
1374} 1348}
1375 1349
1376static struct cfq_queue * 1350static struct cfq_queue *
1377cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, 1351cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk,
1378 gfp_t gfp_mask) 1352 gfp_t gfp_mask)
1379{ 1353{
1380 const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
1381 struct cfq_queue *cfqq, *new_cfqq = NULL; 1354 struct cfq_queue *cfqq, *new_cfqq = NULL;
1382 unsigned short ioprio; 1355 struct cfq_io_context *cic;
1383 1356
1384retry: 1357retry:
1385 ioprio = tsk->ioprio; 1358 cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
1386 cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval); 1359 /* cic always exists here */
1360 cfqq = cic_to_cfqq(cic, is_sync);
1387 1361
1388 if (!cfqq) { 1362 if (!cfqq) {
1389 if (new_cfqq) { 1363 if (new_cfqq) {
@@ -1408,20 +1382,20 @@ retry:
1408 1382
1409 memset(cfqq, 0, sizeof(*cfqq)); 1383 memset(cfqq, 0, sizeof(*cfqq));
1410 1384
1411 INIT_HLIST_NODE(&cfqq->cfq_hash);
1412 RB_CLEAR_NODE(&cfqq->rb_node); 1385 RB_CLEAR_NODE(&cfqq->rb_node);
1413 INIT_LIST_HEAD(&cfqq->fifo); 1386 INIT_LIST_HEAD(&cfqq->fifo);
1414 1387
1415 cfqq->key = key;
1416 hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
1417 atomic_set(&cfqq->ref, 0); 1388 atomic_set(&cfqq->ref, 0);
1418 cfqq->cfqd = cfqd; 1389 cfqq->cfqd = cfqd;
1419 1390
1420 if (key != CFQ_KEY_ASYNC) 1391 if (is_sync) {
1421 cfq_mark_cfqq_idle_window(cfqq); 1392 cfq_mark_cfqq_idle_window(cfqq);
1393 cfq_mark_cfqq_sync(cfqq);
1394 }
1422 1395
1423 cfq_mark_cfqq_prio_changed(cfqq); 1396 cfq_mark_cfqq_prio_changed(cfqq);
1424 cfq_mark_cfqq_queue_new(cfqq); 1397 cfq_mark_cfqq_queue_new(cfqq);
1398
1425 cfq_init_prio_data(cfqq); 1399 cfq_init_prio_data(cfqq);
1426 } 1400 }
1427 1401
@@ -1453,6 +1427,9 @@ cfq_cic_rb_lookup(struct cfq_data *cfqd, struct io_context *ioc)
1453 struct cfq_io_context *cic; 1427 struct cfq_io_context *cic;
1454 void *k, *key = cfqd; 1428 void *k, *key = cfqd;
1455 1429
1430 if (unlikely(!ioc))
1431 return NULL;
1432
1456restart: 1433restart:
1457 n = ioc->cic_root.rb_node; 1434 n = ioc->cic_root.rb_node;
1458 while (n) { 1435 while (n) {
@@ -1839,10 +1816,8 @@ static int cfq_may_queue(request_queue_t *q, int rw)
1839{ 1816{
1840 struct cfq_data *cfqd = q->elevator->elevator_data; 1817 struct cfq_data *cfqd = q->elevator->elevator_data;
1841 struct task_struct *tsk = current; 1818 struct task_struct *tsk = current;
1819 struct cfq_io_context *cic;
1842 struct cfq_queue *cfqq; 1820 struct cfq_queue *cfqq;
1843 unsigned int key;
1844
1845 key = cfq_queue_pid(tsk, rw, rw & REQ_RW_SYNC);
1846 1821
1847 /* 1822 /*
1848 * don't force setup of a queue from here, as a call to may_queue 1823 * don't force setup of a queue from here, as a call to may_queue
@@ -1850,7 +1825,11 @@ static int cfq_may_queue(request_queue_t *q, int rw)
1850 * so just lookup a possibly existing queue, or return 'may queue' 1825 * so just lookup a possibly existing queue, or return 'may queue'
1851 * if that fails 1826 * if that fails
1852 */ 1827 */
1853 cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio); 1828 cic = cfq_cic_rb_lookup(cfqd, tsk->io_context);
1829 if (!cic)
1830 return ELV_MQUEUE_MAY;
1831
1832 cfqq = cic_to_cfqq(cic, rw & REQ_RW_SYNC);
1854 if (cfqq) { 1833 if (cfqq) {
1855 cfq_init_prio_data(cfqq); 1834 cfq_init_prio_data(cfqq);
1856 cfq_prio_boost(cfqq); 1835 cfq_prio_boost(cfqq);
@@ -1894,7 +1873,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
1894 struct cfq_io_context *cic; 1873 struct cfq_io_context *cic;
1895 const int rw = rq_data_dir(rq); 1874 const int rw = rq_data_dir(rq);
1896 const int is_sync = rq_is_sync(rq); 1875 const int is_sync = rq_is_sync(rq);
1897 pid_t key = cfq_queue_pid(tsk, rw, is_sync);
1898 struct cfq_queue *cfqq; 1876 struct cfq_queue *cfqq;
1899 unsigned long flags; 1877 unsigned long flags;
1900 1878
@@ -1907,14 +1885,15 @@ cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
1907 if (!cic) 1885 if (!cic)
1908 goto queue_fail; 1886 goto queue_fail;
1909 1887
1910 if (!cic->cfqq[is_sync]) { 1888 cfqq = cic_to_cfqq(cic, is_sync);
1911 cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask); 1889 if (!cfqq) {
1890 cfqq = cfq_get_queue(cfqd, is_sync, tsk, gfp_mask);
1891
1912 if (!cfqq) 1892 if (!cfqq)
1913 goto queue_fail; 1893 goto queue_fail;
1914 1894
1915 cic->cfqq[is_sync] = cfqq; 1895 cic_set_cfqq(cic, cfqq, is_sync);
1916 } else 1896 }
1917 cfqq = cic->cfqq[is_sync];
1918 1897
1919 cfqq->allocated[rw]++; 1898 cfqq->allocated[rw]++;
1920 cfq_clear_cfqq_must_alloc(cfqq); 1899 cfq_clear_cfqq_must_alloc(cfqq);
@@ -2044,14 +2023,12 @@ static void cfq_exit_queue(elevator_t *e)
2044 2023
2045 cfq_shutdown_timer_wq(cfqd); 2024 cfq_shutdown_timer_wq(cfqd);
2046 2025
2047 kfree(cfqd->cfq_hash);
2048 kfree(cfqd); 2026 kfree(cfqd);
2049} 2027}
2050 2028
2051static void *cfq_init_queue(request_queue_t *q) 2029static void *cfq_init_queue(request_queue_t *q)
2052{ 2030{
2053 struct cfq_data *cfqd; 2031 struct cfq_data *cfqd;
2054 int i;
2055 2032
2056 cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node); 2033 cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
2057 if (!cfqd) 2034 if (!cfqd)
@@ -2062,13 +2039,6 @@ static void *cfq_init_queue(request_queue_t *q)
2062 cfqd->service_tree = CFQ_RB_ROOT; 2039 cfqd->service_tree = CFQ_RB_ROOT;
2063 INIT_LIST_HEAD(&cfqd->cic_list); 2040 INIT_LIST_HEAD(&cfqd->cic_list);
2064 2041
2065 cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
2066 if (!cfqd->cfq_hash)
2067 goto out_free;
2068
2069 for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
2070 INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
2071
2072 cfqd->queue = q; 2042 cfqd->queue = q;
2073 2043
2074 init_timer(&cfqd->idle_slice_timer); 2044 init_timer(&cfqd->idle_slice_timer);
@@ -2092,9 +2062,6 @@ static void *cfq_init_queue(request_queue_t *q)
2092 cfqd->cfq_slice_idle = cfq_slice_idle; 2062 cfqd->cfq_slice_idle = cfq_slice_idle;
2093 2063
2094 return cfqd; 2064 return cfqd;
2095out_free:
2096 kfree(cfqd);
2097 return NULL;
2098} 2065}
2099 2066
2100static void cfq_slab_kill(void) 2067static void cfq_slab_kill(void)