blob: a4184da84a2564ddbe6b0fe372fdd3af7bd7ea51 [file] [log] [blame]
Tatyana Brokhman16349062012-09-20 10:46:10 +03001/*
2 * ROW (Read Over Write) I/O scheduler.
3 *
4 * Copyright (c) 2012, The Linux Foundation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 and
8 * only version 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16/* See Documentation/block/row-iosched.txt */
17
18#include <linux/kernel.h>
19#include <linux/fs.h>
20#include <linux/blkdev.h>
21#include <linux/elevator.h>
22#include <linux/bio.h>
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/init.h>
26#include <linux/compiler.h>
27#include <linux/blktrace_api.h>
28#include <linux/jiffies.h>
29
30/*
31 * enum row_queue_prio - Priorities of the ROW queues
32 *
33 * This enum defines the priorities (and the number of queues)
34 * the requests will be disptributed to. The higher priority -
35 * the bigger is the dispatch quantum given to that queue.
36 * ROWQ_PRIO_HIGH_READ - is the higher priority queue.
37 *
38 */
39enum row_queue_prio {
40 ROWQ_PRIO_HIGH_READ = 0,
41 ROWQ_PRIO_REG_READ,
42 ROWQ_PRIO_HIGH_SWRITE,
43 ROWQ_PRIO_REG_SWRITE,
44 ROWQ_PRIO_REG_WRITE,
45 ROWQ_PRIO_LOW_READ,
46 ROWQ_PRIO_LOW_SWRITE,
47 ROWQ_MAX_PRIO,
48};
49
50/* Flags indicating whether idling is enabled on the queue */
51static const bool queue_idling_enabled[] = {
52 true, /* ROWQ_PRIO_HIGH_READ */
53 true, /* ROWQ_PRIO_REG_READ */
54 false, /* ROWQ_PRIO_HIGH_SWRITE */
55 false, /* ROWQ_PRIO_REG_SWRITE */
56 false, /* ROWQ_PRIO_REG_WRITE */
57 false, /* ROWQ_PRIO_LOW_READ */
58 false, /* ROWQ_PRIO_LOW_SWRITE */
59};
60
Tatyana Brokhman0ef81432012-12-20 19:23:58 +020061/* Flags indicating whether the queue can notify on urgent requests */
62static const bool urgent_queues[] = {
63 true, /* ROWQ_PRIO_HIGH_READ */
64 true, /* ROWQ_PRIO_REG_READ */
65 false, /* ROWQ_PRIO_HIGH_SWRITE */
66 false, /* ROWQ_PRIO_REG_SWRITE */
67 false, /* ROWQ_PRIO_REG_WRITE */
68 false, /* ROWQ_PRIO_LOW_READ */
69 false, /* ROWQ_PRIO_LOW_SWRITE */
70};
71
Tatyana Brokhman16349062012-09-20 10:46:10 +030072/* Default values for row queues quantums in each dispatch cycle */
73static const int queue_quantum[] = {
74 100, /* ROWQ_PRIO_HIGH_READ */
75 100, /* ROWQ_PRIO_REG_READ */
76 2, /* ROWQ_PRIO_HIGH_SWRITE */
77 1, /* ROWQ_PRIO_REG_SWRITE */
78 1, /* ROWQ_PRIO_REG_WRITE */
79 1, /* ROWQ_PRIO_LOW_READ */
80 1 /* ROWQ_PRIO_LOW_SWRITE */
81};
82
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +020083/* Default values for idling on read queues (in msec) */
84#define ROW_IDLE_TIME_MSEC 5
85#define ROW_READ_FREQ_MSEC 20
Tatyana Brokhman16349062012-09-20 10:46:10 +030086
87/**
88 * struct rowq_idling_data - parameters for idling on the queue
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +020089 * @last_insert_time: time the last request was inserted
90 * to the queue
Tatyana Brokhman16349062012-09-20 10:46:10 +030091 * @begin_idling: flag indicating wether we should idle
92 *
93 */
94struct rowq_idling_data {
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +020095 ktime_t last_insert_time;
Tatyana Brokhman16349062012-09-20 10:46:10 +030096 bool begin_idling;
97};
98
99/**
100 * struct row_queue - requests grouping structure
101 * @rdata: parent row_data structure
102 * @fifo: fifo of requests
103 * @prio: queue priority (enum row_queue_prio)
104 * @nr_dispatched: number of requests already dispatched in
105 * the current dispatch cycle
106 * @slice: number of requests to dispatch in a cycle
107 * @idle_data: data for idling on queues
108 *
109 */
110struct row_queue {
111 struct row_data *rdata;
112 struct list_head fifo;
113 enum row_queue_prio prio;
114
115 unsigned int nr_dispatched;
116 unsigned int slice;
117
118 /* used only for READ queues */
119 struct rowq_idling_data idle_data;
120};
121
122/**
123 * struct idling_data - data for idling on empty rqueue
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200124 * @idle_time: idling duration (jiffies)
Tatyana Brokhman16349062012-09-20 10:46:10 +0300125 * @freq: min time between two requests that
126 * triger idling (msec)
127 * @idle_work: pointer to struct delayed_work
128 *
129 */
130struct idling_data {
131 unsigned long idle_time;
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200132 u32 freq;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300133
134 struct workqueue_struct *idle_workqueue;
135 struct delayed_work idle_work;
136};
137
138/**
139 * struct row_queue - Per block device rqueue structure
140 * @dispatch_queue: dispatch rqueue
141 * @row_queues: array of priority request queues with
142 * dispatch quantum per rqueue
143 * @curr_queue: index in the row_queues array of the
144 * currently serviced rqueue
145 * @read_idle: data for idling after READ request
146 * @nr_reqs: nr_reqs[0] holds the number of all READ requests in
147 * scheduler, nr_reqs[1] holds the number of all WRITE
148 * requests in scheduler
149 * @cycle_flags: used for marking unserved queueus
150 *
151 */
152struct row_data {
153 struct request_queue *dispatch_queue;
154
155 struct {
156 struct row_queue rqueue;
157 int disp_quantum;
158 } row_queues[ROWQ_MAX_PRIO];
159
160 enum row_queue_prio curr_queue;
161
162 struct idling_data read_idle;
163 unsigned int nr_reqs[2];
164
165 unsigned int cycle_flags;
166};
167
168#define RQ_ROWQ(rq) ((struct row_queue *) ((rq)->elv.priv[0]))
169
170#define row_log(q, fmt, args...) \
171 blk_add_trace_msg(q, "%s():" fmt , __func__, ##args)
172#define row_log_rowq(rdata, rowq_id, fmt, args...) \
173 blk_add_trace_msg(rdata->dispatch_queue, "rowq%d " fmt, \
174 rowq_id, ##args)
175
176static inline void row_mark_rowq_unserved(struct row_data *rd,
177 enum row_queue_prio qnum)
178{
179 rd->cycle_flags |= (1 << qnum);
180}
181
182static inline void row_clear_rowq_unserved(struct row_data *rd,
183 enum row_queue_prio qnum)
184{
185 rd->cycle_flags &= ~(1 << qnum);
186}
187
188static inline int row_rowq_unserved(struct row_data *rd,
189 enum row_queue_prio qnum)
190{
191 return rd->cycle_flags & (1 << qnum);
192}
193
194/******************** Static helper functions ***********************/
195/*
196 * kick_queue() - Wake up device driver queue thread
197 * @work: pointer to struct work_struct
198 *
199 * This is a idling delayed work function. It's purpose is to wake up the
200 * device driver in order for it to start fetching requests.
201 *
202 */
203static void kick_queue(struct work_struct *work)
204{
205 struct delayed_work *idle_work = to_delayed_work(work);
206 struct idling_data *read_data =
207 container_of(idle_work, struct idling_data, idle_work);
208 struct row_data *rd =
209 container_of(read_data, struct row_data, read_idle);
210
211 row_log_rowq(rd, rd->curr_queue, "Performing delayed work");
212 /* Mark idling process as done */
213 rd->row_queues[rd->curr_queue].rqueue.idle_data.begin_idling = false;
214
215 if (!(rd->nr_reqs[0] + rd->nr_reqs[1]))
216 row_log(rd->dispatch_queue, "No requests in scheduler");
217 else {
218 spin_lock_irq(rd->dispatch_queue->queue_lock);
219 __blk_run_queue(rd->dispatch_queue);
220 spin_unlock_irq(rd->dispatch_queue->queue_lock);
221 }
222}
223
224/*
225 * row_restart_disp_cycle() - Restart the dispatch cycle
226 * @rd: pointer to struct row_data
227 *
228 * This function restarts the dispatch cycle by:
229 * - Setting current queue to ROWQ_PRIO_HIGH_READ
230 * - For each queue: reset the number of requests dispatched in
231 * the cycle
232 */
233static inline void row_restart_disp_cycle(struct row_data *rd)
234{
235 int i;
236
237 for (i = 0; i < ROWQ_MAX_PRIO; i++)
238 rd->row_queues[i].rqueue.nr_dispatched = 0;
239
240 rd->curr_queue = ROWQ_PRIO_HIGH_READ;
241 row_log(rd->dispatch_queue, "Restarting cycle");
242}
243
244static inline void row_get_next_queue(struct row_data *rd)
245{
246 rd->curr_queue++;
247 if (rd->curr_queue == ROWQ_MAX_PRIO)
248 row_restart_disp_cycle(rd);
249}
250
251/******************* Elevator callback functions *********************/
252
253/*
254 * row_add_request() - Add request to the scheduler
255 * @q: requests queue
256 * @rq: request to add
257 *
258 */
259static void row_add_request(struct request_queue *q,
260 struct request *rq)
261{
262 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
263 struct row_queue *rqueue = RQ_ROWQ(rq);
264
265 list_add_tail(&rq->queuelist, &rqueue->fifo);
266 rd->nr_reqs[rq_data_dir(rq)]++;
267 rq_set_fifo_time(rq, jiffies); /* for statistics*/
268
269 if (queue_idling_enabled[rqueue->prio]) {
270 if (delayed_work_pending(&rd->read_idle.idle_work))
271 (void)cancel_delayed_work(
272 &rd->read_idle.idle_work);
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200273 if (ktime_to_ms(ktime_sub(ktime_get(),
274 rqueue->idle_data.last_insert_time)) <
275 rd->read_idle.freq) {
Tatyana Brokhman16349062012-09-20 10:46:10 +0300276 rqueue->idle_data.begin_idling = true;
277 row_log_rowq(rd, rqueue->prio, "Enable idling");
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200278 } else {
Tatyana Brokhman16349062012-09-20 10:46:10 +0300279 rqueue->idle_data.begin_idling = false;
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200280 row_log_rowq(rd, rqueue->prio, "Disable idling");
281 }
Tatyana Brokhman16349062012-09-20 10:46:10 +0300282
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200283 rqueue->idle_data.last_insert_time = ktime_get();
Tatyana Brokhman16349062012-09-20 10:46:10 +0300284 }
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200285 if (urgent_queues[rqueue->prio] &&
286 row_rowq_unserved(rd, rqueue->prio)) {
287 row_log_rowq(rd, rqueue->prio,
288 "added urgent req curr_queue = %d",
289 rd->curr_queue);
290 } else
291 row_log_rowq(rd, rqueue->prio, "added request");
Tatyana Brokhman16349062012-09-20 10:46:10 +0300292}
293
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200294/**
295 * row_reinsert_req() - Reinsert request back to the scheduler
296 * @q: requests queue
297 * @rq: request to add
298 *
299 * Reinsert the given request back to the queue it was
300 * dispatched from as if it was never dispatched.
301 *
302 * Returns 0 on success, error code otherwise
303 */
304static int row_reinsert_req(struct request_queue *q,
305 struct request *rq)
306{
307 struct row_data *rd = q->elevator->elevator_data;
308 struct row_queue *rqueue = RQ_ROWQ(rq);
309
310 /* Verify rqueue is legitimate */
311 if (rqueue->prio >= ROWQ_MAX_PRIO) {
312 pr_err("\n\nROW BUG: row_reinsert_req() rqueue->prio = %d\n",
313 rqueue->prio);
314 blk_dump_rq_flags(rq, "");
315 return -EIO;
316 }
317
318 list_add(&rq->queuelist, &rqueue->fifo);
319 rd->nr_reqs[rq_data_dir(rq)]++;
320
321 row_log_rowq(rd, rqueue->prio, "request reinserted");
322
323 return 0;
324}
325
326/**
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200327 * row_urgent_pending() - Return TRUE if there is an urgent
328 * request on scheduler
329 * @q: requests queue
330 */
331static bool row_urgent_pending(struct request_queue *q)
332{
333 struct row_data *rd = q->elevator->elevator_data;
334 int i;
335
336 for (i = 0; i < ROWQ_MAX_PRIO; i++)
337 if (urgent_queues[i] && row_rowq_unserved(rd, i) &&
338 !list_empty(&rd->row_queues[i].rqueue.fifo)) {
339 row_log_rowq(rd, i,
340 "Urgent request pending (curr=%i)",
341 rd->curr_queue);
342 return true;
343 }
344
345 return false;
346}
347
348/**
Tatyana Brokhman16349062012-09-20 10:46:10 +0300349 * row_remove_request() - Remove given request from scheduler
350 * @q: requests queue
351 * @rq: request to remove
352 *
353 */
354static void row_remove_request(struct request_queue *q,
355 struct request *rq)
356{
357 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
358
359 rq_fifo_clear(rq);
360 rd->nr_reqs[rq_data_dir(rq)]--;
361}
362
363/*
364 * row_dispatch_insert() - move request to dispatch queue
365 * @rd: pointer to struct row_data
366 *
367 * This function moves the next request to dispatch from
368 * rd->curr_queue to the dispatch queue
369 *
370 */
371static void row_dispatch_insert(struct row_data *rd)
372{
373 struct request *rq;
374
375 rq = rq_entry_fifo(rd->row_queues[rd->curr_queue].rqueue.fifo.next);
376 row_remove_request(rd->dispatch_queue, rq);
377 elv_dispatch_add_tail(rd->dispatch_queue, rq);
378 rd->row_queues[rd->curr_queue].rqueue.nr_dispatched++;
379 row_clear_rowq_unserved(rd, rd->curr_queue);
380 row_log_rowq(rd, rd->curr_queue, " Dispatched request nr_disp = %d",
381 rd->row_queues[rd->curr_queue].rqueue.nr_dispatched);
382}
383
384/*
385 * row_choose_queue() - choose the next queue to dispatch from
386 * @rd: pointer to struct row_data
387 *
388 * Updates rd->curr_queue. Returns 1 if there are requests to
389 * dispatch, 0 if there are no requests in scheduler
390 *
391 */
392static int row_choose_queue(struct row_data *rd)
393{
394 int prev_curr_queue = rd->curr_queue;
395
396 if (!(rd->nr_reqs[0] + rd->nr_reqs[1])) {
397 row_log(rd->dispatch_queue, "No more requests in scheduler");
398 return 0;
399 }
400
401 row_get_next_queue(rd);
402
403 /*
404 * Loop over all queues to find the next queue that is not empty.
405 * Stop when you get back to curr_queue
406 */
407 while (list_empty(&rd->row_queues[rd->curr_queue].rqueue.fifo)
408 && rd->curr_queue != prev_curr_queue) {
409 /* Mark rqueue as unserved */
410 row_mark_rowq_unserved(rd, rd->curr_queue);
411 row_get_next_queue(rd);
412 }
413
414 return 1;
415}
416
417/*
418 * row_dispatch_requests() - selects the next request to dispatch
419 * @q: requests queue
420 * @force: ignored
421 *
422 * Return 0 if no requests were moved to the dispatch queue.
423 * 1 otherwise
424 *
425 */
426static int row_dispatch_requests(struct request_queue *q, int force)
427{
428 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
429 int ret = 0, currq, i;
430
431 currq = rd->curr_queue;
432
433 /*
434 * Find the first unserved queue (with higher priority then currq)
435 * that is not empty
436 */
437 for (i = 0; i < currq; i++) {
438 if (row_rowq_unserved(rd, i) &&
439 !list_empty(&rd->row_queues[i].rqueue.fifo)) {
440 row_log_rowq(rd, currq,
441 " Preemting for unserved rowq%d", i);
442 rd->curr_queue = i;
443 row_dispatch_insert(rd);
444 ret = 1;
445 goto done;
446 }
447 }
448
449 if (rd->row_queues[currq].rqueue.nr_dispatched >=
450 rd->row_queues[currq].disp_quantum) {
451 rd->row_queues[currq].rqueue.nr_dispatched = 0;
452 row_log_rowq(rd, currq, "Expiring rqueue");
453 ret = row_choose_queue(rd);
454 if (ret)
455 row_dispatch_insert(rd);
456 goto done;
457 }
458
459 /* Dispatch from curr_queue */
460 if (list_empty(&rd->row_queues[currq].rqueue.fifo)) {
461 /* check idling */
462 if (delayed_work_pending(&rd->read_idle.idle_work)) {
Tatyana Brokhman25f39882012-10-15 20:56:02 +0200463 if (force) {
464 (void)cancel_delayed_work(
465 &rd->read_idle.idle_work);
466 row_log_rowq(rd, currq,
467 "Canceled delayed work - forced dispatch");
468 } else {
469 row_log_rowq(rd, currq,
470 "Delayed work pending. Exiting");
471 goto done;
472 }
Tatyana Brokhman16349062012-09-20 10:46:10 +0300473 }
474
Tatyana Brokhman25f39882012-10-15 20:56:02 +0200475 if (!force && queue_idling_enabled[currq] &&
Tatyana Brokhman16349062012-09-20 10:46:10 +0300476 rd->row_queues[currq].rqueue.idle_data.begin_idling) {
477 if (!queue_delayed_work(rd->read_idle.idle_workqueue,
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200478 &rd->read_idle.idle_work,
479 rd->read_idle.idle_time)) {
Tatyana Brokhman16349062012-09-20 10:46:10 +0300480 row_log_rowq(rd, currq,
481 "Work already on queue!");
482 pr_err("ROW_BUG: Work already on queue!");
483 } else
484 row_log_rowq(rd, currq,
485 "Scheduled delayed work. exiting");
486 goto done;
487 } else {
488 row_log_rowq(rd, currq,
489 "Currq empty. Choose next queue");
490 ret = row_choose_queue(rd);
491 if (!ret)
492 goto done;
493 }
494 }
495
496 ret = 1;
497 row_dispatch_insert(rd);
498
499done:
500 return ret;
501}
502
503/*
504 * row_init_queue() - Init scheduler data structures
505 * @q: requests queue
506 *
507 * Return pointer to struct row_data to be saved in elevator for
508 * this dispatch queue
509 *
510 */
511static void *row_init_queue(struct request_queue *q)
512{
513
514 struct row_data *rdata;
515 int i;
516
517 rdata = kmalloc_node(sizeof(*rdata),
518 GFP_KERNEL | __GFP_ZERO, q->node);
519 if (!rdata)
520 return NULL;
521
522 for (i = 0; i < ROWQ_MAX_PRIO; i++) {
523 INIT_LIST_HEAD(&rdata->row_queues[i].rqueue.fifo);
524 rdata->row_queues[i].disp_quantum = queue_quantum[i];
525 rdata->row_queues[i].rqueue.rdata = rdata;
526 rdata->row_queues[i].rqueue.prio = i;
527 rdata->row_queues[i].rqueue.idle_data.begin_idling = false;
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200528 rdata->row_queues[i].rqueue.idle_data.last_insert_time =
529 ktime_set(0, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300530 }
531
532 /*
533 * Currently idling is enabled only for READ queues. If we want to
534 * enable it for write queues also, note that idling frequency will
535 * be the same in both cases
536 */
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200537 rdata->read_idle.idle_time = msecs_to_jiffies(ROW_IDLE_TIME_MSEC);
538 /* Maybe 0 on some platforms */
539 if (!rdata->read_idle.idle_time)
540 rdata->read_idle.idle_time = 1;
541 rdata->read_idle.freq = ROW_READ_FREQ_MSEC;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300542 rdata->read_idle.idle_workqueue = alloc_workqueue("row_idle_work",
543 WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
544 if (!rdata->read_idle.idle_workqueue)
545 panic("Failed to create idle workqueue\n");
546 INIT_DELAYED_WORK(&rdata->read_idle.idle_work, kick_queue);
547
548 rdata->curr_queue = ROWQ_PRIO_HIGH_READ;
549 rdata->dispatch_queue = q;
550
551 rdata->nr_reqs[READ] = rdata->nr_reqs[WRITE] = 0;
552
553 return rdata;
554}
555
556/*
557 * row_exit_queue() - called on unloading the RAW scheduler
558 * @e: poiner to struct elevator_queue
559 *
560 */
561static void row_exit_queue(struct elevator_queue *e)
562{
563 struct row_data *rd = (struct row_data *)e->elevator_data;
564 int i;
565
566 for (i = 0; i < ROWQ_MAX_PRIO; i++)
567 BUG_ON(!list_empty(&rd->row_queues[i].rqueue.fifo));
568 (void)cancel_delayed_work_sync(&rd->read_idle.idle_work);
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200569 BUG_ON(delayed_work_pending(&rd->read_idle.idle_work));
570 destroy_workqueue(rd->read_idle.idle_workqueue);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300571 kfree(rd);
572}
573
574/*
575 * row_merged_requests() - Called when 2 requests are merged
576 * @q: requests queue
577 * @rq: request the two requests were merged into
578 * @next: request that was merged
579 */
580static void row_merged_requests(struct request_queue *q, struct request *rq,
581 struct request *next)
582{
583 struct row_queue *rqueue = RQ_ROWQ(next);
584
585 list_del_init(&next->queuelist);
586
587 rqueue->rdata->nr_reqs[rq_data_dir(rq)]--;
588}
589
590/*
591 * get_queue_type() - Get queue type for a given request
592 *
593 * This is a helping function which purpose is to determine what
594 * ROW queue the given request should be added to (and
595 * dispatched from leter on)
596 *
597 * TODO: Right now only 3 queues are used REG_READ, REG_WRITE
598 * and REG_SWRITE
599 */
600static enum row_queue_prio get_queue_type(struct request *rq)
601{
602 const int data_dir = rq_data_dir(rq);
603 const bool is_sync = rq_is_sync(rq);
604
605 if (data_dir == READ)
606 return ROWQ_PRIO_REG_READ;
607 else if (is_sync)
608 return ROWQ_PRIO_REG_SWRITE;
609 else
610 return ROWQ_PRIO_REG_WRITE;
611}
612
613/*
614 * row_set_request() - Set ROW data structures associated with this request.
615 * @q: requests queue
616 * @rq: pointer to the request
617 * @gfp_mask: ignored
618 *
619 */
620static int
621row_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
622{
623 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
624 unsigned long flags;
625
626 spin_lock_irqsave(q->queue_lock, flags);
627 rq->elv.priv[0] =
628 (void *)(&rd->row_queues[get_queue_type(rq)]);
629 spin_unlock_irqrestore(q->queue_lock, flags);
630
631 return 0;
632}
633
634/********** Helping sysfs functions/defenitions for ROW attributes ******/
635static ssize_t row_var_show(int var, char *page)
636{
637 return snprintf(page, 100, "%d\n", var);
638}
639
640static ssize_t row_var_store(int *var, const char *page, size_t count)
641{
642 int err;
643 err = kstrtoul(page, 10, (unsigned long *)var);
644
645 return count;
646}
647
648#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
649static ssize_t __FUNC(struct elevator_queue *e, char *page) \
650{ \
651 struct row_data *rowd = e->elevator_data; \
652 int __data = __VAR; \
653 if (__CONV) \
654 __data = jiffies_to_msecs(__data); \
655 return row_var_show(__data, (page)); \
656}
657SHOW_FUNCTION(row_hp_read_quantum_show,
658 rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0);
659SHOW_FUNCTION(row_rp_read_quantum_show,
660 rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0);
661SHOW_FUNCTION(row_hp_swrite_quantum_show,
662 rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0);
663SHOW_FUNCTION(row_rp_swrite_quantum_show,
664 rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0);
665SHOW_FUNCTION(row_rp_write_quantum_show,
666 rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0);
667SHOW_FUNCTION(row_lp_read_quantum_show,
668 rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0);
669SHOW_FUNCTION(row_lp_swrite_quantum_show,
670 rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
671SHOW_FUNCTION(row_read_idle_show, rowd->read_idle.idle_time, 1);
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200672SHOW_FUNCTION(row_read_idle_freq_show, rowd->read_idle.freq, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300673#undef SHOW_FUNCTION
674
675#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
676static ssize_t __FUNC(struct elevator_queue *e, \
677 const char *page, size_t count) \
678{ \
679 struct row_data *rowd = e->elevator_data; \
680 int __data; \
681 int ret = row_var_store(&__data, (page), count); \
682 if (__CONV) \
683 __data = (int)msecs_to_jiffies(__data); \
684 if (__data < (MIN)) \
685 __data = (MIN); \
686 else if (__data > (MAX)) \
687 __data = (MAX); \
688 *(__PTR) = __data; \
689 return ret; \
690}
691STORE_FUNCTION(row_hp_read_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200692&rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300693STORE_FUNCTION(row_rp_read_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200694 &rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum,
695 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300696STORE_FUNCTION(row_hp_swrite_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200697 &rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum,
698 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300699STORE_FUNCTION(row_rp_swrite_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200700 &rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum,
701 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300702STORE_FUNCTION(row_rp_write_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200703 &rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum,
704 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300705STORE_FUNCTION(row_lp_read_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200706 &rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum,
707 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300708STORE_FUNCTION(row_lp_swrite_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200709 &rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum,
710 1, INT_MAX, 1);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300711STORE_FUNCTION(row_read_idle_store, &rowd->read_idle.idle_time, 1, INT_MAX, 1);
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200712STORE_FUNCTION(row_read_idle_freq_store, &rowd->read_idle.freq, 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300713
714#undef STORE_FUNCTION
715
716#define ROW_ATTR(name) \
717 __ATTR(name, S_IRUGO|S_IWUSR, row_##name##_show, \
718 row_##name##_store)
719
720static struct elv_fs_entry row_attrs[] = {
721 ROW_ATTR(hp_read_quantum),
722 ROW_ATTR(rp_read_quantum),
723 ROW_ATTR(hp_swrite_quantum),
724 ROW_ATTR(rp_swrite_quantum),
725 ROW_ATTR(rp_write_quantum),
726 ROW_ATTR(lp_read_quantum),
727 ROW_ATTR(lp_swrite_quantum),
728 ROW_ATTR(read_idle),
729 ROW_ATTR(read_idle_freq),
730 __ATTR_NULL
731};
732
733static struct elevator_type iosched_row = {
734 .ops = {
735 .elevator_merge_req_fn = row_merged_requests,
736 .elevator_dispatch_fn = row_dispatch_requests,
737 .elevator_add_req_fn = row_add_request,
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200738 .elevator_reinsert_req_fn = row_reinsert_req,
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200739 .elevator_is_urgent_fn = row_urgent_pending,
Tatyana Brokhman16349062012-09-20 10:46:10 +0300740 .elevator_former_req_fn = elv_rb_former_request,
741 .elevator_latter_req_fn = elv_rb_latter_request,
742 .elevator_set_req_fn = row_set_request,
743 .elevator_init_fn = row_init_queue,
744 .elevator_exit_fn = row_exit_queue,
745 },
746
747 .elevator_attrs = row_attrs,
748 .elevator_name = "row",
749 .elevator_owner = THIS_MODULE,
750};
751
752static int __init row_init(void)
753{
754 elv_register(&iosched_row);
755 return 0;
756}
757
758static void __exit row_exit(void)
759{
760 elv_unregister(&iosched_row);
761}
762
763module_init(row_init);
764module_exit(row_exit);
765
766MODULE_LICENSE("GPLv2");
767MODULE_DESCRIPTION("Read Over Write IO scheduler");