diff options
Diffstat (limited to 'block/cfq-iosched.c')
| -rw-r--r-- | block/cfq-iosched.c | 59 |
1 files changed, 58 insertions, 1 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 3bacf4bb7dd2..3fc6e505e9c8 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
| @@ -177,6 +177,8 @@ struct cfq_data { | |||
| 177 | unsigned int cfq_slice_async_rq; | 177 | unsigned int cfq_slice_async_rq; |
| 178 | unsigned int cfq_slice_idle; | 178 | unsigned int cfq_slice_idle; |
| 179 | unsigned int cfq_max_depth; | 179 | unsigned int cfq_max_depth; |
| 180 | |||
| 181 | struct list_head cic_list; | ||
| 180 | }; | 182 | }; |
| 181 | 183 | ||
| 182 | /* | 184 | /* |
| @@ -1215,7 +1217,12 @@ static void cfq_free_io_context(struct cfq_io_context *cic) | |||
| 1215 | static void cfq_exit_single_io_context(struct cfq_io_context *cic) | 1217 | static void cfq_exit_single_io_context(struct cfq_io_context *cic) |
| 1216 | { | 1218 | { |
| 1217 | struct cfq_data *cfqd = cic->key; | 1219 | struct cfq_data *cfqd = cic->key; |
| 1218 | request_queue_t *q = cfqd->queue; | 1220 | request_queue_t *q; |
| 1221 | |||
| 1222 | if (!cfqd) | ||
| 1223 | return; | ||
| 1224 | |||
| 1225 | q = cfqd->queue; | ||
| 1219 | 1226 | ||
| 1220 | WARN_ON(!irqs_disabled()); | 1227 | WARN_ON(!irqs_disabled()); |
| 1221 | 1228 | ||
| @@ -1236,6 +1243,7 @@ static void cfq_exit_single_io_context(struct cfq_io_context *cic) | |||
| 1236 | } | 1243 | } |
| 1237 | 1244 | ||
| 1238 | cic->key = NULL; | 1245 | cic->key = NULL; |
| 1246 | list_del_init(&cic->queue_list); | ||
| 1239 | spin_unlock(q->queue_lock); | 1247 | spin_unlock(q->queue_lock); |
| 1240 | } | 1248 | } |
| 1241 | 1249 | ||
| @@ -1254,12 +1262,14 @@ static void cfq_exit_io_context(struct cfq_io_context *cic) | |||
| 1254 | /* | 1262 | /* |
| 1255 | * put the reference this task is holding to the various queues | 1263 | * put the reference this task is holding to the various queues |
| 1256 | */ | 1264 | */ |
| 1265 | read_lock(&cfq_exit_lock); | ||
| 1257 | list_for_each(entry, &cic->list) { | 1266 | list_for_each(entry, &cic->list) { |
| 1258 | __cic = list_entry(entry, struct cfq_io_context, list); | 1267 | __cic = list_entry(entry, struct cfq_io_context, list); |
| 1259 | cfq_exit_single_io_context(__cic); | 1268 | cfq_exit_single_io_context(__cic); |
| 1260 | } | 1269 | } |
| 1261 | 1270 | ||
| 1262 | cfq_exit_single_io_context(cic); | 1271 | cfq_exit_single_io_context(cic); |
| 1272 | read_unlock(&cfq_exit_lock); | ||
| 1263 | local_irq_restore(flags); | 1273 | local_irq_restore(flags); |
| 1264 | } | 1274 | } |
| 1265 | 1275 | ||
| @@ -1279,6 +1289,7 @@ cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask) | |||
| 1279 | cic->ttime_mean = 0; | 1289 | cic->ttime_mean = 0; |
| 1280 | cic->dtor = cfq_free_io_context; | 1290 | cic->dtor = cfq_free_io_context; |
| 1281 | cic->exit = cfq_exit_io_context; | 1291 | cic->exit = cfq_exit_io_context; |
| 1292 | INIT_LIST_HEAD(&cic->queue_list); | ||
| 1282 | } | 1293 | } |
| 1283 | 1294 | ||
| 1284 | return cic; | 1295 | return cic; |
| @@ -1446,6 +1457,7 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
| 1446 | if (!ioc) | 1457 | if (!ioc) |
| 1447 | return NULL; | 1458 | return NULL; |
| 1448 | 1459 | ||
| 1460 | restart: | ||
| 1449 | if ((cic = ioc->cic) == NULL) { | 1461 | if ((cic = ioc->cic) == NULL) { |
| 1450 | cic = cfq_alloc_io_context(cfqd, gfp_mask); | 1462 | cic = cfq_alloc_io_context(cfqd, gfp_mask); |
| 1451 | 1463 | ||
| @@ -1461,6 +1473,7 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
| 1461 | read_lock(&cfq_exit_lock); | 1473 | read_lock(&cfq_exit_lock); |
| 1462 | ioc->set_ioprio = cfq_ioc_set_ioprio; | 1474 | ioc->set_ioprio = cfq_ioc_set_ioprio; |
| 1463 | ioc->cic = cic; | 1475 | ioc->cic = cic; |
| 1476 | list_add(&cic->queue_list, &cfqd->cic_list); | ||
| 1464 | read_unlock(&cfq_exit_lock); | 1477 | read_unlock(&cfq_exit_lock); |
| 1465 | } else { | 1478 | } else { |
| 1466 | struct cfq_io_context *__cic; | 1479 | struct cfq_io_context *__cic; |
| @@ -1471,6 +1484,19 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
| 1471 | if (cic->key == cfqd) | 1484 | if (cic->key == cfqd) |
| 1472 | goto out; | 1485 | goto out; |
| 1473 | 1486 | ||
| 1487 | if (unlikely(!cic->key)) { | ||
| 1488 | read_lock(&cfq_exit_lock); | ||
| 1489 | if (list_empty(&cic->list)) | ||
| 1490 | ioc->cic = NULL; | ||
| 1491 | else | ||
| 1492 | ioc->cic = list_entry(cic->list.next, | ||
| 1493 | struct cfq_io_context, | ||
| 1494 | list); | ||
| 1495 | read_unlock(&cfq_exit_lock); | ||
| 1496 | kmem_cache_free(cfq_ioc_pool, cic); | ||
| 1497 | goto restart; | ||
| 1498 | } | ||
| 1499 | |||
| 1474 | /* | 1500 | /* |
| 1475 | * cic exists, check if we already are there. linear search | 1501 | * cic exists, check if we already are there. linear search |
| 1476 | * should be ok here, the list will usually not be more than | 1502 | * should be ok here, the list will usually not be more than |
| @@ -1485,6 +1511,13 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
| 1485 | cic = __cic; | 1511 | cic = __cic; |
| 1486 | goto out; | 1512 | goto out; |
| 1487 | } | 1513 | } |
| 1514 | if (unlikely(!__cic->key)) { | ||
| 1515 | read_lock(&cfq_exit_lock); | ||
| 1516 | list_del(&__cic->list); | ||
| 1517 | read_unlock(&cfq_exit_lock); | ||
| 1518 | kmem_cache_free(cfq_ioc_pool, __cic); | ||
| 1519 | goto restart; | ||
| 1520 | } | ||
| 1488 | } | 1521 | } |
| 1489 | 1522 | ||
| 1490 | /* | 1523 | /* |
| @@ -1499,6 +1532,7 @@ cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, gfp_t gfp_mask) | |||
| 1499 | __cic->key = cfqd; | 1532 | __cic->key = cfqd; |
| 1500 | read_lock(&cfq_exit_lock); | 1533 | read_lock(&cfq_exit_lock); |
| 1501 | list_add(&__cic->list, &cic->list); | 1534 | list_add(&__cic->list, &cic->list); |
| 1535 | list_add(&__cic->queue_list, &cfqd->cic_list); | ||
| 1502 | read_unlock(&cfq_exit_lock); | 1536 | read_unlock(&cfq_exit_lock); |
| 1503 | cic = __cic; | 1537 | cic = __cic; |
| 1504 | } | 1538 | } |
| @@ -2104,8 +2138,30 @@ static void cfq_put_cfqd(struct cfq_data *cfqd) | |||
| 2104 | static void cfq_exit_queue(elevator_t *e) | 2138 | static void cfq_exit_queue(elevator_t *e) |
| 2105 | { | 2139 | { |
| 2106 | struct cfq_data *cfqd = e->elevator_data; | 2140 | struct cfq_data *cfqd = e->elevator_data; |
| 2141 | request_queue_t *q = cfqd->queue; | ||
| 2107 | 2142 | ||
| 2108 | cfq_shutdown_timer_wq(cfqd); | 2143 | cfq_shutdown_timer_wq(cfqd); |
| 2144 | write_lock(&cfq_exit_lock); | ||
| 2145 | spin_lock_irq(q->queue_lock); | ||
| 2146 | if (cfqd->active_queue) | ||
| 2147 | __cfq_slice_expired(cfqd, cfqd->active_queue, 0); | ||
| 2148 | while(!list_empty(&cfqd->cic_list)) { | ||
| 2149 | struct cfq_io_context *cic = list_entry(cfqd->cic_list.next, | ||
| 2150 | struct cfq_io_context, | ||
| 2151 | queue_list); | ||
| 2152 | if (cic->cfqq[ASYNC]) { | ||
| 2153 | cfq_put_queue(cic->cfqq[ASYNC]); | ||
| 2154 | cic->cfqq[ASYNC] = NULL; | ||
| 2155 | } | ||
| 2156 | if (cic->cfqq[SYNC]) { | ||
| 2157 | cfq_put_queue(cic->cfqq[SYNC]); | ||
| 2158 | cic->cfqq[SYNC] = NULL; | ||
| 2159 | } | ||
| 2160 | cic->key = NULL; | ||
| 2161 | list_del_init(&cic->queue_list); | ||
| 2162 | } | ||
| 2163 | spin_unlock_irq(q->queue_lock); | ||
| 2164 | write_unlock(&cfq_exit_lock); | ||
| 2109 | cfq_put_cfqd(cfqd); | 2165 | cfq_put_cfqd(cfqd); |
| 2110 | } | 2166 | } |
| 2111 | 2167 | ||
| @@ -2127,6 +2183,7 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e) | |||
| 2127 | INIT_LIST_HEAD(&cfqd->cur_rr); | 2183 | INIT_LIST_HEAD(&cfqd->cur_rr); |
| 2128 | INIT_LIST_HEAD(&cfqd->idle_rr); | 2184 | INIT_LIST_HEAD(&cfqd->idle_rr); |
| 2129 | INIT_LIST_HEAD(&cfqd->empty_list); | 2185 | INIT_LIST_HEAD(&cfqd->empty_list); |
| 2186 | INIT_LIST_HEAD(&cfqd->cic_list); | ||
| 2130 | 2187 | ||
| 2131 | cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); | 2188 | cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL); |
| 2132 | if (!cfqd->crq_hash) | 2189 | if (!cfqd->crq_hash) |
