diff options
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 354 |
1 files changed, 175 insertions, 179 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index c8dbe38c81c8..c4a0d5d8d7f0 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -6,21 +6,13 @@ | |||
6 | * | 6 | * |
7 | * Copyright (C) 2003 Jens Axboe <axboe@suse.de> | 7 | * Copyright (C) 2003 Jens Axboe <axboe@suse.de> |
8 | */ | 8 | */ |
9 | #include <linux/kernel.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/blkdev.h> | ||
12 | #include <linux/elevator.h> | ||
13 | #include <linux/bio.h> | ||
14 | #include <linux/config.h> | 9 | #include <linux/config.h> |
15 | #include <linux/module.h> | 10 | #include <linux/module.h> |
16 | #include <linux/slab.h> | 11 | #include <linux/blkdev.h> |
17 | #include <linux/init.h> | 12 | #include <linux/elevator.h> |
18 | #include <linux/compiler.h> | ||
19 | #include <linux/hash.h> | 13 | #include <linux/hash.h> |
20 | #include <linux/rbtree.h> | 14 | #include <linux/rbtree.h> |
21 | #include <linux/mempool.h> | ||
22 | #include <linux/ioprio.h> | 15 | #include <linux/ioprio.h> |
23 | #include <linux/writeback.h> | ||
24 | 16 | ||
25 | /* | 17 | /* |
26 | * tunables | 18 | * tunables |
@@ -47,6 +39,8 @@ static int cfq_slice_idle = HZ / 100; | |||
47 | */ | 39 | */ |
48 | static const int cfq_max_depth = 2; | 40 | static const int cfq_max_depth = 2; |
49 | 41 | ||
42 | static DEFINE_RWLOCK(cfq_exit_lock); | ||
43 | |||
50 | /* | 44 | /* |
51 | * for the hash of cfqq inside the cfqd | 45 | * for the hash of cfqq inside the cfqd |
52 | */ | 46 | */ |
@@ -89,6 +83,9 @@ static kmem_cache_t *crq_pool; | |||
89 | static kmem_cache_t *cfq_pool; | 83 | static kmem_cache_t *cfq_pool; |
90 | static kmem_cache_t *cfq_ioc_pool; | 84 | static kmem_cache_t *cfq_ioc_pool; |
91 | 85 | ||
86 | static atomic_t ioc_count = ATOMIC_INIT(0); | ||
87 | static struct completion *ioc_gone; | ||
88 | |||
92 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR | 89 | #define CFQ_PRIO_LISTS IOPRIO_BE_NR |
93 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) | 90 | #define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) |
94 | #define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE) | 91 | #define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE) |
@@ -109,7 +106,6 @@ static kmem_cache_t *cfq_ioc_pool; | |||
109 | * Per block device queue structure | 106 | * Per block device queue structure |
110 | */ | 107 | */ |
111 | struct cfq_data { | 108 | struct cfq_data { |
112 | atomic_t ref; | ||
113 | request_queue_t *queue; | 109 | request_queue_t *queue; |
114 | 110 | ||
115 | /* | 111 | /* |
@@ -175,6 +171,8 @@ struct cfq_data { | |||
175 | unsigned int cfq_slice_async_rq; | 171 | unsigned int cfq_slice_async_rq; |
176 | unsigned int cfq_slice_idle; | 172 | unsigned int cfq_slice_idle; |
177 | unsigned int cfq_max_depth; | 173 | unsigned int cfq_max_depth; |
174 | |||
175 | struct list_head cic_list; | ||
178 | }; | 176 | }; |
179 | 177 | ||
180 | /* | 178 | /* |
@@ -288,7 +286,7 @@ CFQ_CRQ_FNS(is_sync); | |||
288 | 286 | ||
289 | static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); | 287 | static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short); |
290 | static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); | 288 | static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *); |
291 | static void cfq_put_cfqd(struct cfq_data *cfqd); | 289 | static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask); |
292 | 290 | ||
293 | #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) | 291 | #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) |
294 | 292 | ||
@@ -1160,8 +1158,6 @@ static void cfq_put_queue(struct cfq_queue *cfqq) | |||
1160 | if (unlikely(cfqd->active_queue == cfqq)) | 1158 | if (unlikely(cfqd->active_queue == cfqq)) |
1161 | __cfq_slice_expired(cfqd, cfqq, 0); | 1159 | __cfq_slice_expired(cfqd, cfqq, 0); |
1162 | 1160 | ||
1163 | cfq_put_cfqd(cfqq->cfqd); | ||
1164 | |||
1165 | /* | 1161 | /* |
1166 | * it's on the empty list and still hashed | 1162 | * it's on the empty list and still hashed |
1167 | */ | 1163 | */ |
@@ -1179,7 +1175,7 @@ __cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio, | |||
1179 | 1175 | ||
1180 | hlist_for_each_safe(entry, next, hash_list) { | 1176 | hlist_for_each_safe(entry, next, hash_list) { |
1181 | struct cfq_queue *__cfqq = list_entry_qhash(entry); | 1177 | struct cfq_queue *__cfqq = list_entry_qhash(entry); |
1182 | const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio); | 1178 | const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->org_ioprio_class, __cfqq->org_ioprio); |
1183 | 1179 | ||
1184 | if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY)) | 1180 | if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY)) |
1185 | return __cfqq; | 1181 | return __cfqq; |
@@ -1198,13 +1194,24 @@ static void cfq_free_io_context(struct cfq_io_context *cic) | |||
1198 | { | 1194 | { |
1199 | struct cfq_io_context *__cic; | 1195 | struct cfq_io_context *__cic; |
1200 | struct list_head *entry, *next; | 1196 | struct list_head *entry, *next; |
1197 | int freed = 1; | ||
1201 | 1198 | ||
1202 | list_for_each_safe(entry, next, &cic->list) { | 1199 | list_for_each_safe(entry, next, &cic->list) { |
1203 | __cic = list_entry(entry, struct cfq_io_context, list); | 1200 | __cic = list_entry(entry, struct cfq_io_context, list); |
1204 | kmem_cache_free(cfq_ioc_pool, __cic); | 1201 | kmem_cache_free(cfq_ioc_pool, __cic); |
1202 | freed++; | ||
1205 | } | 1203 | } |
1206 | 1204 | ||
1207 | kmem_cache_free(cfq_ioc_pool, cic); | 1205 | kmem_cache_free(cfq_ioc_pool, cic); |
1206 | if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone) | ||
1207 | complete(ioc_gone); | ||
1208 | } | ||
1209 | |||
1210 | static void cfq_trim(struct io_context *ioc) | ||
1211 | { | ||
1212 | ioc->set_ioprio = NULL; | ||
1213 | if (ioc->cic) | ||
1214 | cfq_free_io_context(ioc->cic); | ||
1208 | } | 1215 | } |
1209 | 1216 | ||
1210 | /* | 1217 | /* |
@@ -1212,25 +1219,37 @@ static void cfq_free_io_context(struct cfq_io_context *cic) | |||
1212 | */ | 1219 | */ |
1213 | static void cfq_exit_single_io_context(struct cfq_io_context *cic) | 1220 | static void cfq_exit_single_io_context(struct cfq_io_context *cic) |
1214 | { | 1221 | { |
1215 | struct cfq_data *cfqd = cic->cfqq->cfqd; | 1222 | struct cfq_data *cfqd = cic->key; |
1216 | request_queue_t *q = cfqd->queue; | 1223 | request_queue_t *q; |
1224 | |||
1225 | if (!cfqd) | ||
1226 | return; | ||
1227 | |||
1228 | q = cfqd->queue; | ||
1217 | 1229 | ||
1218 | WARN_ON(!irqs_disabled()); | 1230 | WARN_ON(!irqs_disabled()); |
1219 | 1231 | ||
1220 | spin_lock(q->queue_lock); | 1232 | spin_lock(q->queue_lock); |
1221 | 1233 | ||
1222 | if (unlikely(cic->cfqq == cfqd->active_queue)) | 1234 | if (cic->cfqq[ASYNC]) { |
1223 | __cfq_slice_expired(cfqd, cic->cfqq, 0); | 1235 | if (unlikely(cic->cfqq[ASYNC] == cfqd->active_queue)) |
1236 | __cfq_slice_expired(cfqd, cic->cfqq[ASYNC], 0); | ||
1237 | cfq_put_queue(cic->cfqq[ASYNC]); | ||
1238 | cic->cfqq[ASYNC] = NULL; | ||
1239 | } | ||
1240 | |||
1241 | if (cic->cfqq[SYNC]) { | ||
1242 | if (unlikely(cic->cfqq[SYNC] == cfqd->active_queue)) | ||
1243 | __cfq_slice_expired(cfqd, cic->cfqq[SYNC], 0); | ||
1244 | cfq_put_queue(cic->cfqq[SYNC]); | ||
1245 | cic->cfqq[SYNC] = NULL; | ||
1246 | } | ||
1224 | 1247 | ||
1225 | cfq_put_queue(cic->cfqq); | 1248 | cic->key = NULL; |
1226 | cic->cfqq = NULL; | 1249 | list_del_init(&cic->queue_list); |
1227 | spin_unlock(q->queue_lock); | 1250 | spin_unlock(q->queue_lock); |
1228 | } | 1251 | } |
1229 | 1252 | ||
1230 | /* | ||
1231 | * Another task may update the task cic list, if it is doing a queue lookup | ||
1232 | * on its behalf. cfq_cic_lock excludes such concurrent updates | ||
1233 | */ | ||
1234 | static void cfq_exit_io_context(struct cfq_io_context *cic) | 1253 | static void cfq_exit_io_context(struct cfq_io_context *cic) |
1235 | { | 1254 | { |
1236 | struct cfq_io_context *__cic; | 1255 | struct cfq_io_context *__cic; |
@@ -1242,12 +1261,14 @@ static void cfq_exit_io_context(struct cfq_io_context *cic) | |||
1242 | /* | 1261 | /* |
1243 | * put the reference this task is holding to the various queues | 1262 | * put the reference this task is holding to the various queues |
1244 | */ | 1263 | */ |
1264 | read_lock(&cfq_exit_lock); | ||
1245 | list_for_each(entry, &cic->list) { | 1265 | list_for_each(entry, &cic->list) { |
1246 | __cic = list_entry(entry, struct cfq_io_context, list); | 1266 | __cic = list_entry(entry, struct cfq_io_context, list); |
1247 | cfq_exit_single_io_context(__cic); | 1267 | cfq_exit_single_io_context(__cic); |
1248 | } | 1268 | } |
1249 | 1269 | ||
1250 | cfq_exit_single_io_context(cic); | 1270 | cfq_exit_single_io_context(cic); |
1271 | read_unlock(&cfq_exit_lock); | ||
1251 | local_irq_restore(flags); | 1272 | local_irq_restore(flags); |
1252 | } | 1273 | } |
1253 | 1274 | ||
@@ -1258,7 +1279,8 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) | |||
1258 | 1279 | ||
1259 | if (cic) { | 1280 | if (cic) { |
1260 | INIT_LIST_HEAD(&cic->list); | 1281 | INIT_LIST_HEAD(&cic->list); |
1261 | cic->cfqq = NULL; | 1282 | cic->cfqq[ASYNC] = NULL; |
1283 | cic->cfqq[SYNC] = NULL; | ||
1262 | cic->key = NULL; | 1284 | cic->key = NULL; |
1263 | cic->last_end_request = jiffies; | 1285 | cic->last_end_request = jiffies; |
1264 | cic->ttime_total = 0; | 1286 | cic->ttime_total = 0; |
@@ -1266,6 +1288,8 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) | |||
1266 | cic->ttime_mean = 0; | 1288 | cic->ttime_mean = 0; |
1267 | cic->dtor = cfq_free_io_context; | 1289 | cic->dtor = cfq_free_io_context; |
1268 | cic->exit = cfq_exit_io_context; | 1290 | cic->exit = cfq_exit_io_context; |
1291 | INIT_LIST_HEAD(&cic->queue_list); | ||
1292 | atomic_inc(&ioc_count); | ||
1269 | } | 1293 | } |
1270 | 1294 | ||
1271 | return cic; | 1295 | return cic; |
@@ -1318,14 +1342,27 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq) | |||
1318 | cfq_clear_cfqq_prio_changed(cfqq); | 1342 | cfq_clear_cfqq_prio_changed(cfqq); |
1319 | } | 1343 | } |
1320 | 1344 | ||
1321 | static inline void changed_ioprio(struct cfq_queue *cfqq) | 1345 | static inline void changed_ioprio(struct cfq_io_context *cic) |
1322 | { | 1346 | { |
1323 | if (cfqq) { | 1347 | struct cfq_data *cfqd = cic->key; |
1324 | struct cfq_data *cfqd = cfqq->cfqd; | 1348 | struct cfq_queue *cfqq; |
1325 | 1349 | if (cfqd) { | |
1326 | spin_lock(cfqd->queue->queue_lock); | 1350 | spin_lock(cfqd->queue->queue_lock); |
1327 | cfq_mark_cfqq_prio_changed(cfqq); | 1351 | cfqq = cic->cfqq[ASYNC]; |
1328 | cfq_init_prio_data(cfqq); | 1352 | if (cfqq) { |
1353 | struct cfq_queue *new_cfqq; | ||
1354 | new_cfqq = cfq_get_queue(cfqd, CFQ_KEY_ASYNC, | ||
1355 | cic->ioc->task, GFP_ATOMIC); | ||
1356 | if (new_cfqq) { | ||
1357 | cic->cfqq[ASYNC] = new_cfqq; | ||
1358 | cfq_put_queue(cfqq); | ||
1359 | } | ||
1360 | } | ||
1361 | cfqq = cic->cfqq[SYNC]; | ||
1362 | if (cfqq) { | ||
1363 | cfq_mark_cfqq_prio_changed(cfqq); | ||
1364 | cfq_init_prio_data(cfqq); | ||
1365 | } | ||
1329 | spin_unlock(cfqd->queue->queue_lock); | 1366 | spin_unlock(cfqd->queue->queue_lock); |
1330 | } | 1367 | } |
1331 | } | 1368 | } |
@@ -1335,24 +1372,32 @@ static inline void changed_ioprio(struct cfq_queue *cfqq) | |||
1335 | */ | 1372 | */ |
1336 | static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) | 1373 | static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio) |
1337 | { | 1374 | { |
1338 | struct cfq_io_context *cic = ioc->cic; | 1375 | struct cfq_io_context *cic; |
1376 | |||
1377 | write_lock(&cfq_exit_lock); | ||
1378 | |||
1379 | cic = ioc->cic; | ||
1339 | 1380 | ||
1340 | changed_ioprio(cic->cfqq); | 1381 | changed_ioprio(cic); |
1341 | 1382 | ||
1342 | list_for_each_entry(cic, &cic->list, list) | 1383 | list_for_each_entry(cic, &cic->list, list) |
1343 | changed_ioprio(cic->cfqq); | 1384 | changed_ioprio(cic); |
1385 | |||
1386 | write_unlock(&cfq_exit_lock); | ||
1344 | 1387 | ||
1345 | return 0; | 1388 | return 0; |
1346 | } | 1389 | } |
1347 | 1390 | ||
1348 | static struct cfq_queue * | 1391 | static struct cfq_queue * |
1349 | cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio, | 1392 | cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, |
1350 | gfp_t gfp_mask) | 1393 | gfp_t gfp_mask) |
1351 | { | 1394 | { |
1352 | const int hashval = hash_long(key, CFQ_QHASH_SHIFT); | 1395 | const int hashval = hash_long(key, CFQ_QHASH_SHIFT); |
1353 | struct cfq_queue *cfqq, *new_cfqq = NULL; | 1396 | struct cfq_queue *cfqq, *new_cfqq = NULL; |
1397 | unsigned short ioprio; | ||
1354 | 1398 | ||
1355 | retry: | 1399 | retry: |
1400 | ioprio = tsk->ioprio; | ||
1356 | cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval); | 1401 | cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval); |
1357 | 1402 | ||
1358 | if (!cfqq) { | 1403 | if (!cfqq) { |
@@ -1381,7 +1426,6 @@ retry: | |||
1381 | hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]); | 1426 | hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]); |
1382 | atomic_set(&cfqq->ref, 0); | 1427 | atomic_set(&cfqq->ref, 0); |
1383 | cfqq->cfqd = cfqd; | 1428 | cfqq->cfqd = cfqd; |
1384 | atomic_inc(&cfqd->ref); | ||
1385 | cfqq->service_last = 0; | 1429 | cfqq->service_last = 0; |
1386 | /* | 1430 | /* |
1387 | * set ->slice_left to allow preemption for a new process | 1431 | * set ->slice_left to allow preemption for a new process |
@@ -1419,6 +1463,7 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
1419 | if (!ioc) | 1463 | if (!ioc) |
1420 | return NULL; | 1464 | return NULL; |
1421 | 1465 | ||
1466 | restart: | ||
1422 | if ((cic = ioc->cic) == NULL) { | 1467 | if ((cic = ioc->cic) == NULL) { |
1423 | cic = cfq_alloc_io_context(cfqd, gfp_mask); | 1468 | cic = cfq_alloc_io_context(cfqd, gfp_mask); |
1424 | 1469 | ||
@@ -1429,11 +1474,13 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
1429 | * manually increment generic io_context usage count, it | 1474 | * manually increment generic io_context usage count, it |
1430 | * cannot go away since we are already holding one ref to it | 1475 | * cannot go away since we are already holding one ref to it |
1431 | */ | 1476 | */ |
1432 | ioc->cic = cic; | ||
1433 | ioc->set_ioprio = cfq_ioc_set_ioprio; | ||
1434 | cic->ioc = ioc; | 1477 | cic->ioc = ioc; |
1435 | cic->key = cfqd; | 1478 | cic->key = cfqd; |
1436 | atomic_inc(&cfqd->ref); | 1479 | read_lock(&cfq_exit_lock); |
1480 | ioc->set_ioprio = cfq_ioc_set_ioprio; | ||
1481 | ioc->cic = cic; | ||
1482 | list_add(&cic->queue_list, &cfqd->cic_list); | ||
1483 | read_unlock(&cfq_exit_lock); | ||
1437 | } else { | 1484 | } else { |
1438 | struct cfq_io_context *__cic; | 1485 | struct cfq_io_context *__cic; |
1439 | 1486 | ||
@@ -1443,6 +1490,20 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
1443 | if (cic->key == cfqd) | 1490 | if (cic->key == cfqd) |
1444 | goto out; | 1491 | goto out; |
1445 | 1492 | ||
1493 | if (unlikely(!cic->key)) { | ||
1494 | read_lock(&cfq_exit_lock); | ||
1495 | if (list_empty(&cic->list)) | ||
1496 | ioc->cic = NULL; | ||
1497 | else | ||
1498 | ioc->cic = list_entry(cic->list.next, | ||
1499 | struct cfq_io_context, | ||
1500 | list); | ||
1501 | read_unlock(&cfq_exit_lock); | ||
1502 | kmem_cache_free(cfq_ioc_pool, cic); | ||
1503 | atomic_dec(&ioc_count); | ||
1504 | goto restart; | ||
1505 | } | ||
1506 | |||
1446 | /* | 1507 | /* |
1447 | * cic exists, check if we already are there. linear search | 1508 | * cic exists, check if we already are there. linear search |
1448 | * should be ok here, the list will usually not be more than | 1509 | * should be ok here, the list will usually not be more than |
@@ -1457,6 +1518,14 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
1457 | cic = __cic; | 1518 | cic = __cic; |
1458 | goto out; | 1519 | goto out; |
1459 | } | 1520 | } |
1521 | if (unlikely(!__cic->key)) { | ||
1522 | read_lock(&cfq_exit_lock); | ||
1523 | list_del(&__cic->list); | ||
1524 | read_unlock(&cfq_exit_lock); | ||
1525 | kmem_cache_free(cfq_ioc_pool, __cic); | ||
1526 | atomic_dec(&ioc_count); | ||
1527 | goto restart; | ||
1528 | } | ||
1460 | } | 1529 | } |
1461 | 1530 | ||
1462 | /* | 1531 | /* |
@@ -1469,8 +1538,10 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
1469 | 1538 | ||
1470 | __cic->ioc = ioc; | 1539 | __cic->ioc = ioc; |
1471 | __cic->key = cfqd; | 1540 | __cic->key = cfqd; |
1472 | atomic_inc(&cfqd->ref); | 1541 | read_lock(&cfq_exit_lock); |
1473 | list_add(&__cic->list, &cic->list); | 1542 | list_add(&__cic->list, &cic->list); |
1543 | list_add(&__cic->queue_list, &cfqd->cic_list); | ||
1544 | read_unlock(&cfq_exit_lock); | ||
1474 | cic = __cic; | 1545 | cic = __cic; |
1475 | } | 1546 | } |
1476 | 1547 | ||
@@ -1890,6 +1961,7 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | |||
1890 | struct cfq_queue *cfqq; | 1961 | struct cfq_queue *cfqq; |
1891 | struct cfq_rq *crq; | 1962 | struct cfq_rq *crq; |
1892 | unsigned long flags; | 1963 | unsigned long flags; |
1964 | int is_sync = key != CFQ_KEY_ASYNC; | ||
1893 | 1965 | ||
1894 | might_sleep_if(gfp_mask & __GFP_WAIT); | 1966 | might_sleep_if(gfp_mask & __GFP_WAIT); |
1895 | 1967 | ||
@@ -1900,14 +1972,14 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | |||
1900 | if (!cic) | 1972 | if (!cic) |
1901 | goto queue_fail; | 1973 | goto queue_fail; |
1902 | 1974 | ||
1903 | if (!cic->cfqq) { | 1975 | if (!cic->cfqq[is_sync]) { |
1904 | cfqq = cfq_get_queue(cfqd, key, tsk->ioprio, gfp_mask); | 1976 | cfqq = cfq_get_queue(cfqd, key, tsk, gfp_mask); |
1905 | if (!cfqq) | 1977 | if (!cfqq) |
1906 | goto queue_fail; | 1978 | goto queue_fail; |
1907 | 1979 | ||
1908 | cic->cfqq = cfqq; | 1980 | cic->cfqq[is_sync] = cfqq; |
1909 | } else | 1981 | } else |
1910 | cfqq = cic->cfqq; | 1982 | cfqq = cic->cfqq[is_sync]; |
1911 | 1983 | ||
1912 | cfqq->allocated[rw]++; | 1984 | cfqq->allocated[rw]++; |
1913 | cfq_clear_cfqq_must_alloc(cfqq); | 1985 | cfq_clear_cfqq_must_alloc(cfqq); |
@@ -1924,7 +1996,7 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio, | |||
1924 | crq->cfq_queue = cfqq; | 1996 | crq->cfq_queue = cfqq; |
1925 | crq->io_context = cic; | 1997 | crq->io_context = cic; |
1926 | 1998 | ||
1927 | if (rw == READ || process_sync(tsk)) | 1999 | if (is_sync) |
1928 | cfq_mark_crq_is_sync(crq); | 2000 | cfq_mark_crq_is_sync(crq); |
1929 | else | 2001 | else |
1930 | cfq_clear_crq_is_sync(crq); | 2002 | cfq_clear_crq_is_sync(crq); |
@@ -2055,15 +2127,35 @@ static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) | |||
2055 | blk_sync_queue(cfqd->queue); | 2127 | blk_sync_queue(cfqd->queue); |
2056 | } | 2128 | } |
2057 | 2129 | ||
2058 | static void cfq_put_cfqd(struct cfq_data *cfqd) | 2130 | static void cfq_exit_queue(elevator_t *e) |
2059 | { | 2131 | { |
2132 | struct cfq_data *cfqd = e->elevator_data; | ||
2060 | request_queue_t *q = cfqd->queue; | 2133 | request_queue_t *q = cfqd->queue; |
2061 | 2134 | ||
2062 | if (!atomic_dec_and_test(&cfqd->ref)) | 2135 | cfq_shutdown_timer_wq(cfqd); |
2063 | return; | 2136 | write_lock(&cfq_exit_lock); |
2137 | spin_lock_irq(q->queue_lock); | ||
2138 | if (cfqd->active_queue) | ||
2139 | __cfq_slice_expired(cfqd, cfqd->active_queue, 0); | ||
2140 | while(!list_empty(&cfqd->cic_list)) { | ||
2141 | struct cfq_io_context *cic = list_entry(cfqd->cic_list.next, | ||
2142 | struct cfq_io_context, | ||
2143 | queue_list); | ||
2144 | if (cic->cfqq[ASYNC]) { | ||
2145 | cfq_put_queue(cic->cfqq[ASYNC]); | ||
2146 | cic->cfqq[ASYNC] = NULL; | ||
2147 | } | ||
2148 | if (cic->cfqq[SYNC]) { | ||
2149 | cfq_put_queue(cic->cfqq[SYNC]); | ||
2150 | cic->cfqq[SYNC] = NULL; | ||
2151 | } | ||
2152 | cic->key = NULL; | ||
2153 | list_del_init(&cic->queue_list); | ||
2154 | } | ||
2155 | spin_unlock_irq(q->queue_lock); | ||
2156 | write_unlock(&cfq_exit_lock); | ||
2064 | 2157 | ||
2065 | cfq_shutdown_timer_wq(cfqd); | 2158 | cfq_shutdown_timer_wq(cfqd); |
2066 | blk_put_queue(q); | ||
2067 | 2159 | ||
2068 | mempool_destroy(cfqd->crq_pool); | 2160 | mempool_destroy(cfqd->crq_pool); |
2069 | kfree(cfqd->crq_hash); | 2161 | kfree(cfqd->crq_hash); |
@@ -2071,14 +2163,6 @@ static void cfq_put_cfqd(struct cfq_data *cfqd) | |||
2071 | kfree(cfqd); | 2163 | kfree(cfqd); |
2072 | } | 2164 | } |
2073 | 2165 | ||
2074 | static void cfq_exit_queue(elevator_t *e) | ||
2075 | { | ||
2076 | struct cfq_data *cfqd = e->elevator_data; | ||
2077 | |||
2078 | cfq_shutdown_timer_wq(cfqd); | ||
2079 | cfq_put_cfqd(cfqd); | ||
2080 | } | ||
2081 | |||
2082 | static int cfq_init_queue(request_queue_t *q, elevator_t *e) | 2166 | static int cfq_init_queue(request_queue_t *q, elevator_t *e) |
2083 | { | 2167 | { |
2084 | struct cfq_data *cfqd; | 2168 | struct cfq_data *cfqd; |
@@ -2097,6 +2181,7 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2097 | INIT_LIST_HEAD(&cfqd->cur_rr); | 2181 | INIT_LIST_HEAD(&cfqd->cur_rr); |
2098 | INIT_LIST_HEAD(&cfqd->idle_rr); | 2182 | INIT_LIST_HEAD(&cfqd->idle_rr); |
2099 | INIT_LIST_HEAD(&cfqd->empty_list); | 2183 | INIT_LIST_HEAD(&cfqd->empty_list); |
2184 | INIT_LIST_HEAD(&cfqd->cic_list); | ||
2100 | 2185 | ||
2101 | cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); | 2186 | cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); |
2102 | if (!cfqd->crq_hash) | 2187 | if (!cfqd->crq_hash) |
@@ -2118,7 +2203,6 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2118 | e->elevator_data = cfqd; | 2203 | e->elevator_data = cfqd; |
2119 | 2204 | ||
2120 | cfqd->queue = q; | 2205 | cfqd->queue = q; |
2121 | atomic_inc(&q->refcnt); | ||
2122 | 2206 | ||
2123 | cfqd->max_queued = q->nr_requests / 4; | 2207 | cfqd->max_queued = q->nr_requests / 4; |
2124 | q->nr_batching = cfq_queued; | 2208 | q->nr_batching = cfq_queued; |
@@ -2133,8 +2217,6 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
2133 | 2217 | ||
2134 | INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q); | 2218 | INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q); |
2135 | 2219 | ||
2136 | atomic_set(&cfqd->ref, 1); | ||
2137 | |||
2138 | cfqd->cfq_queued = cfq_queued; | 2220 | cfqd->cfq_queued = cfq_queued; |
2139 | cfqd->cfq_quantum = cfq_quantum; | 2221 | cfqd->cfq_quantum = cfq_quantum; |
2140 | cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; | 2222 | cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; |
@@ -2193,11 +2275,6 @@ fail: | |||
2193 | /* | 2275 | /* |
2194 | * sysfs parts below --> | 2276 | * sysfs parts below --> |
2195 | */ | 2277 | */ |
2196 | struct cfq_fs_entry { | ||
2197 | struct attribute attr; | ||
2198 | ssize_t (*show)(struct cfq_data *, char *); | ||
2199 | ssize_t (*store)(struct cfq_data *, const char *, size_t); | ||
2200 | }; | ||
2201 | 2278 | ||
2202 | static ssize_t | 2279 | static ssize_t |
2203 | cfq_var_show(unsigned int var, char *page) | 2280 | cfq_var_show(unsigned int var, char *page) |
@@ -2215,8 +2292,9 @@ cfq_var_store(unsigned int *var, const char *page, size_t count) | |||
2215 | } | 2292 | } |
2216 | 2293 | ||
2217 | #define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ | 2294 | #define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ |
2218 | static ssize_t __FUNC(struct cfq_data *cfqd, char *page) \ | 2295 | static ssize_t __FUNC(elevator_t *e, char *page) \ |
2219 | { \ | 2296 | { \ |
2297 | struct cfq_data *cfqd = e->elevator_data; \ | ||
2220 | unsigned int __data = __VAR; \ | 2298 | unsigned int __data = __VAR; \ |
2221 | if (__CONV) \ | 2299 | if (__CONV) \ |
2222 | __data = jiffies_to_msecs(__data); \ | 2300 | __data = jiffies_to_msecs(__data); \ |
@@ -2226,8 +2304,8 @@ SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0); | |||
2226 | SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0); | 2304 | SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0); |
2227 | SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1); | 2305 | SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1); |
2228 | SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1); | 2306 | SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1); |
2229 | SHOW_FUNCTION(cfq_back_max_show, cfqd->cfq_back_max, 0); | 2307 | SHOW_FUNCTION(cfq_back_seek_max_show, cfqd->cfq_back_max, 0); |
2230 | SHOW_FUNCTION(cfq_back_penalty_show, cfqd->cfq_back_penalty, 0); | 2308 | SHOW_FUNCTION(cfq_back_seek_penalty_show, cfqd->cfq_back_penalty, 0); |
2231 | SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1); | 2309 | SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1); |
2232 | SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1); | 2310 | SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1); |
2233 | SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1); | 2311 | SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1); |
@@ -2236,8 +2314,9 @@ SHOW_FUNCTION(cfq_max_depth_show, cfqd->cfq_max_depth, 0); | |||
2236 | #undef SHOW_FUNCTION | 2314 | #undef SHOW_FUNCTION |
2237 | 2315 | ||
2238 | #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ | 2316 | #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ |
2239 | static ssize_t __FUNC(struct cfq_data *cfqd, const char *page, size_t count) \ | 2317 | static ssize_t __FUNC(elevator_t *e, const char *page, size_t count) \ |
2240 | { \ | 2318 | { \ |
2319 | struct cfq_data *cfqd = e->elevator_data; \ | ||
2241 | unsigned int __data; \ | 2320 | unsigned int __data; \ |
2242 | int ret = cfq_var_store(&__data, (page), count); \ | 2321 | int ret = cfq_var_store(&__data, (page), count); \ |
2243 | if (__data < (MIN)) \ | 2322 | if (__data < (MIN)) \ |
@@ -2254,8 +2333,8 @@ STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0); | |||
2254 | STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0); | 2333 | STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0); |
2255 | STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1); | 2334 | STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1); |
2256 | STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1); | 2335 | STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1); |
2257 | STORE_FUNCTION(cfq_back_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0); | 2336 | STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0); |
2258 | STORE_FUNCTION(cfq_back_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0); | 2337 | STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0); |
2259 | STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1); | 2338 | STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1); |
2260 | STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1); | 2339 | STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1); |
2261 | STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1); | 2340 | STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1); |
@@ -2263,112 +2342,22 @@ STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, | |||
2263 | STORE_FUNCTION(cfq_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0); | 2342 | STORE_FUNCTION(cfq_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0); |
2264 | #undef STORE_FUNCTION | 2343 | #undef STORE_FUNCTION |
2265 | 2344 | ||
2266 | static struct cfq_fs_entry cfq_quantum_entry = { | 2345 | #define CFQ_ATTR(name) \ |
2267 | .attr = {.name = "quantum", .mode = S_IRUGO | S_IWUSR }, | 2346 | __ATTR(name, S_IRUGO|S_IWUSR, cfq_##name##_show, cfq_##name##_store) |
2268 | .show = cfq_quantum_show, | 2347 | |
2269 | .store = cfq_quantum_store, | 2348 | static struct elv_fs_entry cfq_attrs[] = { |
2270 | }; | 2349 | CFQ_ATTR(quantum), |
2271 | static struct cfq_fs_entry cfq_queued_entry = { | 2350 | CFQ_ATTR(queued), |
2272 | .attr = {.name = "queued", .mode = S_IRUGO | S_IWUSR }, | 2351 | CFQ_ATTR(fifo_expire_sync), |
2273 | .show = cfq_queued_show, | 2352 | CFQ_ATTR(fifo_expire_async), |
2274 | .store = cfq_queued_store, | 2353 | CFQ_ATTR(back_seek_max), |
2275 | }; | 2354 | CFQ_ATTR(back_seek_penalty), |
2276 | static struct cfq_fs_entry cfq_fifo_expire_sync_entry = { | 2355 | CFQ_ATTR(slice_sync), |
2277 | .attr = {.name = "fifo_expire_sync", .mode = S_IRUGO | S_IWUSR }, | 2356 | CFQ_ATTR(slice_async), |
2278 | .show = cfq_fifo_expire_sync_show, | 2357 | CFQ_ATTR(slice_async_rq), |
2279 | .store = cfq_fifo_expire_sync_store, | 2358 | CFQ_ATTR(slice_idle), |
2280 | }; | 2359 | CFQ_ATTR(max_depth), |
2281 | static struct cfq_fs_entry cfq_fifo_expire_async_entry = { | 2360 | __ATTR_NULL |
2282 | .attr = {.name = "fifo_expire_async", .mode = S_IRUGO | S_IWUSR }, | ||
2283 | .show = cfq_fifo_expire_async_show, | ||
2284 | .store = cfq_fifo_expire_async_store, | ||
2285 | }; | ||
2286 | static struct cfq_fs_entry cfq_back_max_entry = { | ||
2287 | .attr = {.name = "back_seek_max", .mode = S_IRUGO | S_IWUSR }, | ||
2288 | .show = cfq_back_max_show, | ||
2289 | .store = cfq_back_max_store, | ||
2290 | }; | ||
2291 | static struct cfq_fs_entry cfq_back_penalty_entry = { | ||
2292 | .attr = {.name = "back_seek_penalty", .mode = S_IRUGO | S_IWUSR }, | ||
2293 | .show = cfq_back_penalty_show, | ||
2294 | .store = cfq_back_penalty_store, | ||
2295 | }; | ||
2296 | static struct cfq_fs_entry cfq_slice_sync_entry = { | ||
2297 | .attr = {.name = "slice_sync", .mode = S_IRUGO | S_IWUSR }, | ||
2298 | .show = cfq_slice_sync_show, | ||
2299 | .store = cfq_slice_sync_store, | ||
2300 | }; | ||
2301 | static struct cfq_fs_entry cfq_slice_async_entry = { | ||
2302 | .attr = {.name = "slice_async", .mode = S_IRUGO | S_IWUSR }, | ||
2303 | .show = cfq_slice_async_show, | ||
2304 | .store = cfq_slice_async_store, | ||
2305 | }; | ||
2306 | static struct cfq_fs_entry cfq_slice_async_rq_entry = { | ||
2307 | .attr = {.name = "slice_async_rq", .mode = S_IRUGO | S_IWUSR }, | ||
2308 | .show = cfq_slice_async_rq_show, | ||
2309 | .store = cfq_slice_async_rq_store, | ||
2310 | }; | ||
2311 | static struct cfq_fs_entry cfq_slice_idle_entry = { | ||
2312 | .attr = {.name = "slice_idle", .mode = S_IRUGO | S_IWUSR }, | ||
2313 | .show = cfq_slice_idle_show, | ||
2314 | .store = cfq_slice_idle_store, | ||
2315 | }; | ||
2316 | static struct cfq_fs_entry cfq_max_depth_entry = { | ||
2317 | .attr = {.name = "max_depth", .mode = S_IRUGO | S_IWUSR }, | ||
2318 | .show = cfq_max_depth_show, | ||
2319 | .store = cfq_max_depth_store, | ||
2320 | }; | ||
2321 | |||
2322 | static struct attribute *default_attrs[] = { | ||
2323 | &cfq_quantum_entry.attr, | ||
2324 | &cfq_queued_entry.attr, | ||
2325 | &cfq_fifo_expire_sync_entry.attr, | ||
2326 | &cfq_fifo_expire_async_entry.attr, | ||
2327 | &cfq_back_max_entry.attr, | ||
2328 | &cfq_back_penalty_entry.attr, | ||
2329 | &cfq_slice_sync_entry.attr, | ||
2330 | &cfq_slice_async_entry.attr, | ||
2331 | &cfq_slice_async_rq_entry.attr, | ||
2332 | &cfq_slice_idle_entry.attr, | ||
2333 | &cfq_max_depth_entry.attr, | ||
2334 | NULL, | ||
2335 | }; | ||
2336 | |||
2337 | #define to_cfq(atr) container_of((atr), struct cfq_fs_entry, attr) | ||
2338 | |||
2339 | static ssize_t | ||
2340 | cfq_attr_show(struct kobject *kobj, struct attribute *attr, char *page) | ||
2341 | { | ||
2342 | elevator_t *e = container_of(kobj, elevator_t, kobj); | ||
2343 | struct cfq_fs_entry *entry = to_cfq(attr); | ||
2344 | |||
2345 | if (!entry->show) | ||
2346 | return -EIO; | ||
2347 | |||
2348 | return entry->show(e->elevator_data, page); | ||
2349 | } | ||
2350 | |||
2351 | static ssize_t | ||
2352 | cfq_attr_store(struct kobject *kobj, struct attribute *attr, | ||
2353 | const char *page, size_t length) | ||
2354 | { | ||
2355 | elevator_t *e = container_of(kobj, elevator_t, kobj); | ||
2356 | struct cfq_fs_entry *entry = to_cfq(attr); | ||
2357 | |||
2358 | if (!entry->store) | ||
2359 | return -EIO; | ||
2360 | |||
2361 | return entry->store(e->elevator_data, page, length); | ||
2362 | } | ||
2363 | |||
2364 | static struct sysfs_ops cfq_sysfs_ops = { | ||
2365 | .show = cfq_attr_show, | ||
2366 | .store = cfq_attr_store, | ||
2367 | }; | ||
2368 | |||
2369 | static struct kobj_type cfq_ktype = { | ||
2370 | .sysfs_ops = &cfq_sysfs_ops, | ||
2371 | .default_attrs = default_attrs, | ||
2372 | }; | 2361 | }; |
2373 | 2362 | ||
2374 | static struct elevator_type iosched_cfq = { | 2363 | static struct elevator_type iosched_cfq = { |
@@ -2389,8 +2378,9 @@ static struct elevator_type iosched_cfq = { | |||
2389 | .elevator_may_queue_fn = cfq_may_queue, | 2378 | .elevator_may_queue_fn = cfq_may_queue, |
2390 | .elevator_init_fn = cfq_init_queue, | 2379 | .elevator_init_fn = cfq_init_queue, |
2391 | .elevator_exit_fn = cfq_exit_queue, | 2380 | .elevator_exit_fn = cfq_exit_queue, |
2381 | .trim = cfq_trim, | ||
2392 | }, | 2382 | }, |
2393 | .elevator_ktype = &cfq_ktype, | 2383 | .elevator_attrs = cfq_attrs, |
2394 | .elevator_name = "cfq", | 2384 | .elevator_name = "cfq", |
2395 | .elevator_owner = THIS_MODULE, | 2385 | .elevator_owner = THIS_MODULE, |
2396 | }; | 2386 | }; |
@@ -2419,7 +2409,13 @@ static int __init cfq_init(void) | |||
2419 | 2409 | ||
2420 | static void __exit cfq_exit(void) | 2410 | static void __exit cfq_exit(void) |
2421 | { | 2411 | { |
2412 | DECLARE_COMPLETION(all_gone); | ||
2422 | elv_unregister(&iosched_cfq); | 2413 | elv_unregister(&iosched_cfq); |
2414 | ioc_gone = &all_gone; | ||
2415 | barrier(); | ||
2416 | if (atomic_read(&ioc_count)) | ||
2417 | complete(ioc_gone); | ||
2418 | synchronize_rcu(); | ||
2423 | cfq_slab_kill(); | 2419 | cfq_slab_kill(); |
2424 | } | 2420 | } |
2425 | 2421 | ||