diff options
| -rw-r--r-- | drivers/block/elevator.c | 242 | ||||
| -rw-r--r-- | drivers/block/ll_rw_blk.c | 23 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 17 | ||||
| -rw-r--r-- | include/linux/elevator.h | 16 |
4 files changed, 201 insertions, 97 deletions
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c index 4144f30d82a9..a27555908d35 100644 --- a/drivers/block/elevator.c +++ b/drivers/block/elevator.c | |||
| @@ -40,6 +40,11 @@ | |||
| 40 | static DEFINE_SPINLOCK(elv_list_lock); | 40 | static DEFINE_SPINLOCK(elv_list_lock); |
| 41 | static LIST_HEAD(elv_list); | 41 | static LIST_HEAD(elv_list); |
| 42 | 42 | ||
| 43 | static inline sector_t rq_last_sector(struct request *rq) | ||
| 44 | { | ||
| 45 | return rq->sector + rq->nr_sectors; | ||
| 46 | } | ||
| 47 | |||
| 43 | /* | 48 | /* |
| 44 | * can we safely merge with this request? | 49 | * can we safely merge with this request? |
| 45 | */ | 50 | */ |
| @@ -143,6 +148,9 @@ static int elevator_attach(request_queue_t *q, struct elevator_type *e, | |||
| 143 | INIT_LIST_HEAD(&q->queue_head); | 148 | INIT_LIST_HEAD(&q->queue_head); |
| 144 | q->last_merge = NULL; | 149 | q->last_merge = NULL; |
| 145 | q->elevator = eq; | 150 | q->elevator = eq; |
| 151 | q->last_sector = 0; | ||
| 152 | q->boundary_rq = NULL; | ||
| 153 | q->max_back_kb = 0; | ||
| 146 | 154 | ||
| 147 | if (eq->ops->elevator_init_fn) | 155 | if (eq->ops->elevator_init_fn) |
| 148 | ret = eq->ops->elevator_init_fn(q, eq); | 156 | ret = eq->ops->elevator_init_fn(q, eq); |
| @@ -225,6 +233,48 @@ void elevator_exit(elevator_t *e) | |||
| 225 | kfree(e); | 233 | kfree(e); |
| 226 | } | 234 | } |
| 227 | 235 | ||
| 236 | /* | ||
| 237 | * Insert rq into dispatch queue of q. Queue lock must be held on | ||
| 238 | * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be | ||
| 239 | * appended to the dispatch queue. To be used by specific elevators. | ||
| 240 | */ | ||
| 241 | void elv_dispatch_insert(request_queue_t *q, struct request *rq, int sort) | ||
| 242 | { | ||
| 243 | sector_t boundary; | ||
| 244 | unsigned max_back; | ||
| 245 | struct list_head *entry; | ||
| 246 | |||
| 247 | if (!sort) { | ||
| 248 | /* Specific elevator is performing sort. Step away. */ | ||
| 249 | q->last_sector = rq_last_sector(rq); | ||
| 250 | q->boundary_rq = rq; | ||
| 251 | list_add_tail(&rq->queuelist, &q->queue_head); | ||
| 252 | return; | ||
| 253 | } | ||
| 254 | |||
| 255 | boundary = q->last_sector; | ||
| 256 | max_back = q->max_back_kb * 2; | ||
| 257 | boundary = boundary > max_back ? boundary - max_back : 0; | ||
| 258 | |||
| 259 | list_for_each_prev(entry, &q->queue_head) { | ||
| 260 | struct request *pos = list_entry_rq(entry); | ||
| 261 | |||
| 262 | if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED)) | ||
| 263 | break; | ||
| 264 | if (rq->sector >= boundary) { | ||
| 265 | if (pos->sector < boundary) | ||
| 266 | continue; | ||
| 267 | } else { | ||
| 268 | if (pos->sector >= boundary) | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | if (rq->sector >= pos->sector) | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | |||
| 275 | list_add(&rq->queuelist, entry); | ||
| 276 | } | ||
| 277 | |||
| 228 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) | 278 | int elv_merge(request_queue_t *q, struct request **req, struct bio *bio) |
| 229 | { | 279 | { |
| 230 | elevator_t *e = q->elevator; | 280 | elevator_t *e = q->elevator; |
| @@ -255,13 +305,7 @@ void elv_merge_requests(request_queue_t *q, struct request *rq, | |||
| 255 | e->ops->elevator_merge_req_fn(q, rq, next); | 305 | e->ops->elevator_merge_req_fn(q, rq, next); |
| 256 | } | 306 | } |
| 257 | 307 | ||
| 258 | /* | 308 | void elv_requeue_request(request_queue_t *q, struct request *rq) |
| 259 | * For careful internal use by the block layer. Essentially the same as | ||
| 260 | * a requeue in that it tells the io scheduler that this request is not | ||
| 261 | * active in the driver or hardware anymore, but we don't want the request | ||
| 262 | * added back to the scheduler. Function is not exported. | ||
| 263 | */ | ||
| 264 | void elv_deactivate_request(request_queue_t *q, struct request *rq) | ||
| 265 | { | 309 | { |
| 266 | elevator_t *e = q->elevator; | 310 | elevator_t *e = q->elevator; |
| 267 | 311 | ||
| @@ -269,19 +313,14 @@ void elv_deactivate_request(request_queue_t *q, struct request *rq) | |||
| 269 | * it already went through dequeue, we need to decrement the | 313 | * it already went through dequeue, we need to decrement the |
| 270 | * in_flight count again | 314 | * in_flight count again |
| 271 | */ | 315 | */ |
| 272 | if (blk_account_rq(rq)) | 316 | if (blk_account_rq(rq)) { |
| 273 | q->in_flight--; | 317 | q->in_flight--; |
| 318 | if (blk_sorted_rq(rq) && e->ops->elevator_deactivate_req_fn) | ||
| 319 | e->ops->elevator_deactivate_req_fn(q, rq); | ||
| 320 | } | ||
| 274 | 321 | ||
| 275 | rq->flags &= ~REQ_STARTED; | 322 | rq->flags &= ~REQ_STARTED; |
| 276 | 323 | ||
| 277 | if (e->ops->elevator_deactivate_req_fn) | ||
| 278 | e->ops->elevator_deactivate_req_fn(q, rq); | ||
| 279 | } | ||
| 280 | |||
| 281 | void elv_requeue_request(request_queue_t *q, struct request *rq) | ||
| 282 | { | ||
| 283 | elv_deactivate_request(q, rq); | ||
| 284 | |||
| 285 | /* | 324 | /* |
| 286 | * if this is the flush, requeue the original instead and drop the flush | 325 | * if this is the flush, requeue the original instead and drop the flush |
| 287 | */ | 326 | */ |
| @@ -290,55 +329,89 @@ void elv_requeue_request(request_queue_t *q, struct request *rq) | |||
| 290 | rq = rq->end_io_data; | 329 | rq = rq->end_io_data; |
| 291 | } | 330 | } |
| 292 | 331 | ||
| 293 | /* | 332 | __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); |
| 294 | * the request is prepped and may have some resources allocated. | ||
| 295 | * allowing unprepped requests to pass this one may cause resource | ||
| 296 | * deadlock. turn on softbarrier. | ||
| 297 | */ | ||
| 298 | rq->flags |= REQ_SOFTBARRIER; | ||
| 299 | |||
| 300 | /* | ||
| 301 | * if iosched has an explicit requeue hook, then use that. otherwise | ||
| 302 | * just put the request at the front of the queue | ||
| 303 | */ | ||
| 304 | if (q->elevator->ops->elevator_requeue_req_fn) | ||
| 305 | q->elevator->ops->elevator_requeue_req_fn(q, rq); | ||
| 306 | else | ||
| 307 | __elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0); | ||
| 308 | } | 333 | } |
| 309 | 334 | ||
| 310 | void __elv_add_request(request_queue_t *q, struct request *rq, int where, | 335 | void __elv_add_request(request_queue_t *q, struct request *rq, int where, |
| 311 | int plug) | 336 | int plug) |
| 312 | { | 337 | { |
| 313 | /* | 338 | if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) { |
| 314 | * barriers implicitly indicate back insertion | 339 | /* |
| 315 | */ | 340 | * barriers implicitly indicate back insertion |
| 316 | if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER) && | 341 | */ |
| 317 | where == ELEVATOR_INSERT_SORT) | 342 | if (where == ELEVATOR_INSERT_SORT) |
| 318 | where = ELEVATOR_INSERT_BACK; | 343 | where = ELEVATOR_INSERT_BACK; |
| 344 | |||
| 345 | /* | ||
| 346 | * this request is scheduling boundary, update last_sector | ||
| 347 | */ | ||
| 348 | if (blk_fs_request(rq)) { | ||
| 349 | q->last_sector = rq_last_sector(rq); | ||
| 350 | q->boundary_rq = rq; | ||
| 351 | } | ||
| 352 | } | ||
| 319 | 353 | ||
| 320 | if (plug) | 354 | if (plug) |
| 321 | blk_plug_device(q); | 355 | blk_plug_device(q); |
| 322 | 356 | ||
| 323 | rq->q = q; | 357 | rq->q = q; |
| 324 | 358 | ||
| 325 | if (!test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)) { | 359 | if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags))) { |
| 326 | q->elevator->ops->elevator_add_req_fn(q, rq, where); | ||
| 327 | |||
| 328 | if (blk_queue_plugged(q)) { | ||
| 329 | int nrq = q->rq.count[READ] + q->rq.count[WRITE] | ||
| 330 | - q->in_flight; | ||
| 331 | |||
| 332 | if (nrq >= q->unplug_thresh) | ||
| 333 | __generic_unplug_device(q); | ||
| 334 | } | ||
| 335 | } else | ||
| 336 | /* | 360 | /* |
| 337 | * if drain is set, store the request "locally". when the drain | 361 | * if drain is set, store the request "locally". when the drain |
| 338 | * is finished, the requests will be handed ordered to the io | 362 | * is finished, the requests will be handed ordered to the io |
| 339< | |||
