blob: bdb6abdc9826edad4ebbf3f9b8a109cb9dd16000 [file] [log] [blame]
Tatyana Brokhman16349062012-09-20 10:46:10 +03001/*
2 * ROW (Read Over Write) I/O scheduler.
3 *
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +02004 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Tatyana Brokhman16349062012-09-20 10:46:10 +03005 *
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>
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +020028#include <linux/hrtimer.h>
Tatyana Brokhman16349062012-09-20 10:46:10 +030029
30/*
31 * enum row_queue_prio - Priorities of the ROW queues
32 *
33 * This enum defines the priorities (and the number of queues)
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +020034 * the requests will be distributed to. The higher priority -
35 * the bigger is the "bus time" (or the dispatch quantum) given
36 * to that queue.
Tatyana Brokhman16349062012-09-20 10:46:10 +030037 * ROWQ_PRIO_HIGH_READ - is the higher priority queue.
38 *
39 */
40enum row_queue_prio {
41 ROWQ_PRIO_HIGH_READ = 0,
Tatyana Brokhman16349062012-09-20 10:46:10 +030042 ROWQ_PRIO_HIGH_SWRITE,
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +020043 ROWQ_PRIO_REG_READ,
Tatyana Brokhman16349062012-09-20 10:46:10 +030044 ROWQ_PRIO_REG_SWRITE,
45 ROWQ_PRIO_REG_WRITE,
46 ROWQ_PRIO_LOW_READ,
47 ROWQ_PRIO_LOW_SWRITE,
48 ROWQ_MAX_PRIO,
49};
50
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +020051/*
52 * The following indexes define the distribution of ROW queues according to
53 * priorities. Each index defines the first queue in that priority group.
54 */
55#define ROWQ_HIGH_PRIO_IDX ROWQ_PRIO_HIGH_READ
56#define ROWQ_REG_PRIO_IDX ROWQ_PRIO_REG_READ
57#define ROWQ_LOW_PRIO_IDX ROWQ_PRIO_LOW_READ
58
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +020059/**
60 * struct row_queue_params - ROW queue parameters
61 * @idling_enabled: Flag indicating whether idling is enable on
62 * the queue
63 * @quantum: Number of requests to be dispatched from this queue
64 * in a dispatch cycle
65 * @is_urgent: Flags indicating whether the queue can notify on
66 * urgent requests
67 *
68 */
69struct row_queue_params {
70 bool idling_enabled;
71 int quantum;
72 bool is_urgent;
Tatyana Brokhman16349062012-09-20 10:46:10 +030073};
74
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +020075/*
76 * This array holds the default values of the different configurables
77 * for each ROW queue. Each row of the array holds the following values:
78 * {idling_enabled, quantum, is_urgent}
79 * Each row corresponds to a queue with the same index (according to
80 * enum row_queue_prio)
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +020081 * Note: The quantums are valid inside their priority type. For example:
82 * For every 10 high priority read requests, 1 high priority sync
83 * write will be dispatched.
84 * For every 100 regular read requests 1 regular write request will
85 * be dispatched.
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +020086 */
87static const struct row_queue_params row_queues_def[] = {
88/* idling_enabled, quantum, is_urgent */
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +020089 {true, 10, true}, /* ROWQ_PRIO_HIGH_READ */
90 {false, 1, true}, /* ROWQ_PRIO_HIGH_SWRITE */
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +020091 {true, 100, true}, /* ROWQ_PRIO_REG_READ */
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +020092 {false, 1, false}, /* ROWQ_PRIO_REG_SWRITE */
93 {false, 1, false}, /* ROWQ_PRIO_REG_WRITE */
94 {false, 1, false}, /* ROWQ_PRIO_LOW_READ */
95 {false, 1, false} /* ROWQ_PRIO_LOW_SWRITE */
Tatyana Brokhman16349062012-09-20 10:46:10 +030096};
97
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +020098/* Default values for idling on read queues (in msec) */
99#define ROW_IDLE_TIME_MSEC 5
100#define ROW_READ_FREQ_MSEC 20
Tatyana Brokhman16349062012-09-20 10:46:10 +0300101
102/**
103 * struct rowq_idling_data - parameters for idling on the queue
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200104 * @last_insert_time: time the last request was inserted
105 * to the queue
Tatyana Brokhman16349062012-09-20 10:46:10 +0300106 * @begin_idling: flag indicating wether we should idle
107 *
108 */
109struct rowq_idling_data {
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200110 ktime_t last_insert_time;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300111 bool begin_idling;
112};
113
114/**
115 * struct row_queue - requests grouping structure
116 * @rdata: parent row_data structure
117 * @fifo: fifo of requests
118 * @prio: queue priority (enum row_queue_prio)
119 * @nr_dispatched: number of requests already dispatched in
120 * the current dispatch cycle
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200121 * @nr_req: number of requests in queue
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200122 * @dispatch quantum: number of requests this queue may
123 * dispatch in a dispatch cycle
Tatyana Brokhman16349062012-09-20 10:46:10 +0300124 * @idle_data: data for idling on queues
125 *
126 */
127struct row_queue {
128 struct row_data *rdata;
129 struct list_head fifo;
130 enum row_queue_prio prio;
131
132 unsigned int nr_dispatched;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300133
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200134 unsigned int nr_req;
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200135 int disp_quantum;
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200136
Tatyana Brokhman16349062012-09-20 10:46:10 +0300137 /* used only for READ queues */
138 struct rowq_idling_data idle_data;
139};
140
141/**
142 * struct idling_data - data for idling on empty rqueue
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200143 * @idle_time_ms: idling duration (msec)
144 * @freq_ms: min time between two requests that
Tatyana Brokhman16349062012-09-20 10:46:10 +0300145 * triger idling (msec)
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200146 * @hr_timer: idling timer
147 * @idle_work: the work to be scheduled when idling timer expires
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200148 * @idling_queue_idx: index of the queues we're idling on
Tatyana Brokhman16349062012-09-20 10:46:10 +0300149 *
150 */
151struct idling_data {
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200152 s64 idle_time_ms;
153 s64 freq_ms;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300154
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200155 struct hrtimer hr_timer;
156 struct work_struct idle_work;
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200157 enum row_queue_prio idling_queue_idx;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300158};
159
160/**
161 * struct row_queue - Per block device rqueue structure
162 * @dispatch_queue: dispatch rqueue
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200163 * @row_queues: array of priority request queues
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200164 * @rd_idle_data: data for idling after READ request
Tatyana Brokhman16349062012-09-20 10:46:10 +0300165 * @nr_reqs: nr_reqs[0] holds the number of all READ requests in
166 * scheduler, nr_reqs[1] holds the number of all WRITE
167 * requests in scheduler
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200168 * @nr_urgent_in_flight: number of uncompleted urgent requests
169 * (both reads and writes)
Tatyana Brokhman16349062012-09-20 10:46:10 +0300170 * @cycle_flags: used for marking unserved queueus
171 *
172 */
173struct row_data {
174 struct request_queue *dispatch_queue;
175
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200176 struct row_queue row_queues[ROWQ_MAX_PRIO];
Tatyana Brokhman16349062012-09-20 10:46:10 +0300177
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200178 struct idling_data rd_idle_data;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300179 unsigned int nr_reqs[2];
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200180 unsigned int nr_urgent_in_flight;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300181
182 unsigned int cycle_flags;
183};
184
185#define RQ_ROWQ(rq) ((struct row_queue *) ((rq)->elv.priv[0]))
186
187#define row_log(q, fmt, args...) \
188 blk_add_trace_msg(q, "%s():" fmt , __func__, ##args)
189#define row_log_rowq(rdata, rowq_id, fmt, args...) \
190 blk_add_trace_msg(rdata->dispatch_queue, "rowq%d " fmt, \
191 rowq_id, ##args)
192
193static inline void row_mark_rowq_unserved(struct row_data *rd,
194 enum row_queue_prio qnum)
195{
196 rd->cycle_flags |= (1 << qnum);
197}
198
199static inline void row_clear_rowq_unserved(struct row_data *rd,
200 enum row_queue_prio qnum)
201{
202 rd->cycle_flags &= ~(1 << qnum);
203}
204
205static inline int row_rowq_unserved(struct row_data *rd,
206 enum row_queue_prio qnum)
207{
208 return rd->cycle_flags & (1 << qnum);
209}
210
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200211static inline void __maybe_unused row_dump_queues_stat(struct row_data *rd)
212{
213 int i;
214
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200215 row_log(rd->dispatch_queue, " Queues status:");
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200216 for (i = 0; i < ROWQ_MAX_PRIO; i++)
217 row_log(rd->dispatch_queue,
218 "queue%d: dispatched= %d, nr_req=%d", i,
219 rd->row_queues[i].nr_dispatched,
220 rd->row_queues[i].nr_req);
221}
222
Tatyana Brokhman16349062012-09-20 10:46:10 +0300223/******************** Static helper functions ***********************/
Tatyana Brokhman16349062012-09-20 10:46:10 +0300224static void kick_queue(struct work_struct *work)
225{
Tatyana Brokhman16349062012-09-20 10:46:10 +0300226 struct idling_data *read_data =
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200227 container_of(work, struct idling_data, idle_work);
228 struct row_data *rd =
229 container_of(read_data, struct row_data, rd_idle_data);
230
231 blk_run_queue(rd->dispatch_queue);
232}
233
234
235static enum hrtimer_restart row_idle_hrtimer_fn(struct hrtimer *hr_timer)
236{
237 struct idling_data *read_data =
238 container_of(hr_timer, struct idling_data, hr_timer);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300239 struct row_data *rd =
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200240 container_of(read_data, struct row_data, rd_idle_data);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300241
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200242 row_log_rowq(rd, rd->rd_idle_data.idling_queue_idx,
243 "Performing delayed work");
Tatyana Brokhman16349062012-09-20 10:46:10 +0300244 /* Mark idling process as done */
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200245 rd->row_queues[rd->rd_idle_data.idling_queue_idx].
246 idle_data.begin_idling = false;
247 rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300248
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200249 if (!rd->nr_reqs[READ] && !rd->nr_reqs[WRITE])
Tatyana Brokhman16349062012-09-20 10:46:10 +0300250 row_log(rd->dispatch_queue, "No requests in scheduler");
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200251 else
252 kblockd_schedule_work(rd->dispatch_queue,
253 &read_data->idle_work);
254 return HRTIMER_NORESTART;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300255}
256
Tatyana Brokhman16349062012-09-20 10:46:10 +0300257/******************* Elevator callback functions *********************/
258
259/*
260 * row_add_request() - Add request to the scheduler
261 * @q: requests queue
262 * @rq: request to add
263 *
264 */
265static void row_add_request(struct request_queue *q,
266 struct request *rq)
267{
268 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
269 struct row_queue *rqueue = RQ_ROWQ(rq);
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200270 s64 diff_ms;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300271
272 list_add_tail(&rq->queuelist, &rqueue->fifo);
273 rd->nr_reqs[rq_data_dir(rq)]++;
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200274 rqueue->nr_req++;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300275 rq_set_fifo_time(rq, jiffies); /* for statistics*/
276
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +0200277 if (row_queues_def[rqueue->prio].idling_enabled) {
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200278 if (rd->rd_idle_data.idling_queue_idx == rqueue->prio &&
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200279 hrtimer_active(&rd->rd_idle_data.hr_timer)) {
280 (void)hrtimer_cancel(&rd->rd_idle_data.hr_timer);
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200281 row_log_rowq(rd, rqueue->prio,
282 "Canceled delayed work on %d",
283 rd->rd_idle_data.idling_queue_idx);
284 rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
285 }
286 diff_ms = ktime_to_ms(ktime_sub(ktime_get(),
287 rqueue->idle_data.last_insert_time));
288 if (unlikely(diff_ms < 0)) {
289 pr_err("ROW BUG: %s diff_ms < 0", __func__);
290 rqueue->idle_data.begin_idling = false;
291 return;
292 }
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200293 if (diff_ms < rd->rd_idle_data.freq_ms) {
Tatyana Brokhman16349062012-09-20 10:46:10 +0300294 rqueue->idle_data.begin_idling = true;
295 row_log_rowq(rd, rqueue->prio, "Enable idling");
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200296 } else {
Tatyana Brokhman16349062012-09-20 10:46:10 +0300297 rqueue->idle_data.begin_idling = false;
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200298 row_log_rowq(rd, rqueue->prio, "Disable idling (%ldms)",
299 (long)diff_ms);
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200300 }
Tatyana Brokhman16349062012-09-20 10:46:10 +0300301
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200302 rqueue->idle_data.last_insert_time = ktime_get();
Tatyana Brokhman16349062012-09-20 10:46:10 +0300303 }
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +0200304 if (row_queues_def[rqueue->prio].is_urgent &&
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200305 row_rowq_unserved(rd, rqueue->prio)) {
306 row_log_rowq(rd, rqueue->prio,
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200307 "added urgent request (total on queue=%d)",
308 rqueue->nr_req);
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200309 rq->cmd_flags |= REQ_URGENT;
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200310 } else
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200311 row_log_rowq(rd, rqueue->prio,
312 "added request (total on queue=%d)", rqueue->nr_req);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300313}
314
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200315/**
316 * row_reinsert_req() - Reinsert request back to the scheduler
317 * @q: requests queue
318 * @rq: request to add
319 *
320 * Reinsert the given request back to the queue it was
321 * dispatched from as if it was never dispatched.
322 *
323 * Returns 0 on success, error code otherwise
324 */
325static int row_reinsert_req(struct request_queue *q,
326 struct request *rq)
327{
328 struct row_data *rd = q->elevator->elevator_data;
329 struct row_queue *rqueue = RQ_ROWQ(rq);
330
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200331 if (rqueue->prio >= ROWQ_MAX_PRIO) {
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200332 pr_err("\n\n%s:ROW BUG: row_reinsert_req() rqueue->prio = %d\n",
333 rq->rq_disk->disk_name, rqueue->prio);
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200334 blk_dump_rq_flags(rq, "");
335 return -EIO;
336 }
337
338 list_add(&rq->queuelist, &rqueue->fifo);
339 rd->nr_reqs[rq_data_dir(rq)]++;
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200340 rqueue->nr_req++;
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200341
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200342 row_log_rowq(rd, rqueue->prio,
343 "request reinserted (total on queue=%d)", rqueue->nr_req);
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200344
345 return 0;
346}
347
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200348static void row_completed_req(struct request_queue *q, struct request *rq)
349{
350 struct row_data *rd = q->elevator->elevator_data;
351
352 if (rq->cmd_flags & REQ_URGENT) {
353 if (!rd->nr_urgent_in_flight) {
354 pr_err("ROW BUG: %s() nr_urgent_in_flight = 0",
355 __func__);
356 return;
357 }
358 rd->nr_urgent_in_flight--;
359 }
360}
361
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200362/**
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200363 * row_urgent_pending() - Return TRUE if there is an urgent
364 * request on scheduler
365 * @q: requests queue
366 */
367static bool row_urgent_pending(struct request_queue *q)
368{
369 struct row_data *rd = q->elevator->elevator_data;
370 int i;
371
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200372 if (rd->nr_urgent_in_flight) {
373 row_log(rd->dispatch_queue, "%d urgent requests in flight",
374 rd->nr_urgent_in_flight);
375 return false;
376 }
377
378 for (i = ROWQ_HIGH_PRIO_IDX; i < ROWQ_REG_PRIO_IDX; i++)
379 if (!list_empty(&rd->row_queues[i].fifo)) {
380 row_log_rowq(rd, i,
381 "Urgent (high prio) request pending");
382 return true;
383 }
384
385 for (i = ROWQ_REG_PRIO_IDX; i < ROWQ_MAX_PRIO; i++)
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +0200386 if (row_queues_def[i].is_urgent && row_rowq_unserved(rd, i) &&
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200387 !list_empty(&rd->row_queues[i].fifo)) {
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200388 row_log_rowq(rd, i, "Urgent request pending");
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200389 return true;
390 }
391
392 return false;
393}
394
395/**
Tatyana Brokhman16349062012-09-20 10:46:10 +0300396 * row_remove_request() - Remove given request from scheduler
397 * @q: requests queue
398 * @rq: request to remove
399 *
400 */
401static void row_remove_request(struct request_queue *q,
402 struct request *rq)
403{
404 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200405 struct row_queue *rqueue = RQ_ROWQ(rq);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300406
407 rq_fifo_clear(rq);
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200408 rqueue->nr_req--;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300409 rd->nr_reqs[rq_data_dir(rq)]--;
410}
411
412/*
413 * row_dispatch_insert() - move request to dispatch queue
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200414 * @rd: pointer to struct row_data
415 * @queue_idx: index of the row_queue to dispatch from
Tatyana Brokhman16349062012-09-20 10:46:10 +0300416 *
417 * This function moves the next request to dispatch from
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200418 * the given queue (row_queues[queue_idx]) to the dispatch queue
Tatyana Brokhman16349062012-09-20 10:46:10 +0300419 *
420 */
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200421static void row_dispatch_insert(struct row_data *rd, int queue_idx)
Tatyana Brokhman16349062012-09-20 10:46:10 +0300422{
423 struct request *rq;
424
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200425 rq = rq_entry_fifo(rd->row_queues[queue_idx].fifo.next);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300426 row_remove_request(rd->dispatch_queue, rq);
427 elv_dispatch_add_tail(rd->dispatch_queue, rq);
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200428 rd->row_queues[queue_idx].nr_dispatched++;
429 row_clear_rowq_unserved(rd, queue_idx);
430 row_log_rowq(rd, queue_idx, " Dispatched request nr_disp = %d",
431 rd->row_queues[queue_idx].nr_dispatched);
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200432 if (rq->cmd_flags & REQ_URGENT)
433 rd->nr_urgent_in_flight++;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300434}
435
436/*
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200437 * row_get_ioprio_class_to_serve() - Return the next I/O priority
438 * class to dispatch requests from
Tatyana Brokhman16349062012-09-20 10:46:10 +0300439 * @rd: pointer to struct row_data
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200440 * @force: flag indicating if forced dispatch
Tatyana Brokhman16349062012-09-20 10:46:10 +0300441 *
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200442 * This function returns the next I/O priority class to serve
443 * {IOPRIO_CLASS_NONE, IOPRIO_CLASS_RT, IOPRIO_CLASS_BE, IOPRIO_CLASS_IDLE}.
444 * If there are no more requests in scheduler or if we're idling on some queue
445 * IOPRIO_CLASS_NONE will be returned.
446 * If idling is scheduled on a lower priority queue than the one that needs
447 * to be served, it will be canceled.
Tatyana Brokhman16349062012-09-20 10:46:10 +0300448 *
449 */
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200450static int row_get_ioprio_class_to_serve(struct row_data *rd, int force)
Tatyana Brokhman16349062012-09-20 10:46:10 +0300451{
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200452 int i;
453 int ret = IOPRIO_CLASS_NONE;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300454
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200455 if (!rd->nr_reqs[READ] && !rd->nr_reqs[WRITE]) {
Tatyana Brokhman16349062012-09-20 10:46:10 +0300456 row_log(rd->dispatch_queue, "No more requests in scheduler");
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200457 goto check_idling;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300458 }
459
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200460 /* First, go over the high priority queues */
461 for (i = 0; i < ROWQ_REG_PRIO_IDX; i++) {
462 if (!list_empty(&rd->row_queues[i].fifo)) {
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200463 if (hrtimer_active(&rd->rd_idle_data.hr_timer)) {
464 (void)hrtimer_cancel(
465 &rd->rd_idle_data.hr_timer);
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200466 row_log_rowq(rd,
467 rd->rd_idle_data.idling_queue_idx,
468 "Canceling delayed work on %d. RT pending",
469 rd->rd_idle_data.idling_queue_idx);
470 rd->rd_idle_data.idling_queue_idx =
471 ROWQ_MAX_PRIO;
472 }
473 ret = IOPRIO_CLASS_RT;
474 goto done;
475 }
476 }
Tatyana Brokhman16349062012-09-20 10:46:10 +0300477
478 /*
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200479 * At the moment idling is implemented only for READ queues.
480 * If enabled on WRITE, this needs updating
Tatyana Brokhman16349062012-09-20 10:46:10 +0300481 */
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200482 if (hrtimer_active(&rd->rd_idle_data.hr_timer)) {
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200483 row_log(rd->dispatch_queue, "Delayed work pending. Exiting");
484 goto done;
485 }
486check_idling:
487 /* Check for (high priority) idling and enable if needed */
488 for (i = 0; i < ROWQ_REG_PRIO_IDX && !force; i++) {
489 if (rd->row_queues[i].idle_data.begin_idling &&
490 row_queues_def[i].idling_enabled)
491 goto initiate_idling;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300492 }
493
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200494 /* Regular priority queues */
495 for (i = ROWQ_REG_PRIO_IDX; i < ROWQ_LOW_PRIO_IDX; i++) {
496 if (list_empty(&rd->row_queues[i].fifo)) {
497 /* We can idle only if this is not a forced dispatch */
498 if (rd->row_queues[i].idle_data.begin_idling &&
499 !force && row_queues_def[i].idling_enabled)
500 goto initiate_idling;
501 } else {
502 ret = IOPRIO_CLASS_BE;
503 goto done;
504 }
505 }
506
507 if (rd->nr_reqs[READ] || rd->nr_reqs[WRITE])
508 ret = IOPRIO_CLASS_IDLE;
509 goto done;
510
511initiate_idling:
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200512 hrtimer_start(&rd->rd_idle_data.hr_timer,
513 ktime_set(0, rd->rd_idle_data.idle_time_ms * NSEC_PER_MSEC),
514 HRTIMER_MODE_REL);
515
516 rd->rd_idle_data.idling_queue_idx = i;
517 row_log_rowq(rd, i, "Scheduled delayed work on %d. exiting", i);
518
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200519done:
520 return ret;
521}
522
523static void row_restart_cycle(struct row_data *rd,
524 int start_idx, int end_idx)
525{
526 int i;
527
528 row_dump_queues_stat(rd);
529 for (i = start_idx; i < end_idx; i++) {
530 if (rd->row_queues[i].nr_dispatched <
531 rd->row_queues[i].disp_quantum)
532 row_mark_rowq_unserved(rd, i);
533 rd->row_queues[i].nr_dispatched = 0;
534 }
535 row_log(rd->dispatch_queue, "Restarting cycle for class @ %d-%d",
536 start_idx, end_idx);
537}
538
539/*
540 * row_get_next_queue() - selects the next queue to dispatch from
541 * @q: requests queue
542 * @rd: pointer to struct row_data
543 * @start_idx/end_idx: indexes in the row_queues array to select a queue
544 * from.
545 *
546 * Return index of the queues to dispatch from. Error code if fails.
547 *
548 */
549static int row_get_next_queue(struct request_queue *q, struct row_data *rd,
550 int start_idx, int end_idx)
551{
552 int i = start_idx;
553 bool restart = true;
554 int ret = -EIO;
555
556 do {
557 if (list_empty(&rd->row_queues[i].fifo) ||
558 rd->row_queues[i].nr_dispatched >=
559 rd->row_queues[i].disp_quantum) {
560 i++;
561 if (i == end_idx && restart) {
562 /* Restart cycle for this priority class */
563 row_restart_cycle(rd, start_idx, end_idx);
564 i = start_idx;
565 restart = false;
566 }
567 } else {
568 ret = i;
569 break;
570 }
571 } while (i < end_idx);
572
573 return ret;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300574}
575
576/*
577 * row_dispatch_requests() - selects the next request to dispatch
578 * @q: requests queue
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200579 * @force: flag indicating if forced dispatch
Tatyana Brokhman16349062012-09-20 10:46:10 +0300580 *
581 * Return 0 if no requests were moved to the dispatch queue.
582 * 1 otherwise
583 *
584 */
585static int row_dispatch_requests(struct request_queue *q, int force)
586{
587 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200588 int ret = 0, currq, ioprio_class_to_serve, start_idx, end_idx;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300589
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200590 if (force && hrtimer_active(&rd->rd_idle_data.hr_timer)) {
591 (void)hrtimer_cancel(&rd->rd_idle_data.hr_timer);
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200592 row_log_rowq(rd, rd->rd_idle_data.idling_queue_idx,
593 "Canceled delayed work on %d - forced dispatch",
594 rd->rd_idle_data.idling_queue_idx);
595 rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300596 }
597
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200598 ioprio_class_to_serve = row_get_ioprio_class_to_serve(rd, force);
599 row_log(rd->dispatch_queue, "Dispatching from %d priority class",
600 ioprio_class_to_serve);
601
602 switch (ioprio_class_to_serve) {
603 case IOPRIO_CLASS_NONE:
604 goto done;
605 case IOPRIO_CLASS_RT:
606 start_idx = ROWQ_HIGH_PRIO_IDX;
607 end_idx = ROWQ_REG_PRIO_IDX;
608 break;
609 case IOPRIO_CLASS_BE:
610 start_idx = ROWQ_REG_PRIO_IDX;
611 end_idx = ROWQ_LOW_PRIO_IDX;
612 break;
613 case IOPRIO_CLASS_IDLE:
614 start_idx = ROWQ_LOW_PRIO_IDX;
615 end_idx = ROWQ_MAX_PRIO;
616 break;
617 default:
618 pr_err("%s(): Invalid I/O priority class", __func__);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300619 goto done;
620 }
621
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200622 currq = row_get_next_queue(q, rd, start_idx, end_idx);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300623
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200624 /* Dispatch */
625 if (currq >= 0) {
626 row_dispatch_insert(rd, currq);
627 ret = 1;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300628 }
Tatyana Brokhman16349062012-09-20 10:46:10 +0300629done:
630 return ret;
631}
632
633/*
634 * row_init_queue() - Init scheduler data structures
635 * @q: requests queue
636 *
637 * Return pointer to struct row_data to be saved in elevator for
638 * this dispatch queue
639 *
640 */
641static void *row_init_queue(struct request_queue *q)
642{
643
644 struct row_data *rdata;
645 int i;
646
647 rdata = kmalloc_node(sizeof(*rdata),
648 GFP_KERNEL | __GFP_ZERO, q->node);
649 if (!rdata)
650 return NULL;
651
Tatyana Brokhman522778f2013-01-24 16:17:27 +0200652 memset(rdata, 0, sizeof(*rdata));
Tatyana Brokhman16349062012-09-20 10:46:10 +0300653 for (i = 0; i < ROWQ_MAX_PRIO; i++) {
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200654 INIT_LIST_HEAD(&rdata->row_queues[i].fifo);
Tatyana Brokhman9375bcc2013-01-12 16:23:18 +0200655 rdata->row_queues[i].disp_quantum = row_queues_def[i].quantum;
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200656 rdata->row_queues[i].rdata = rdata;
657 rdata->row_queues[i].prio = i;
658 rdata->row_queues[i].idle_data.begin_idling = false;
659 rdata->row_queues[i].idle_data.last_insert_time =
Tatyana Brokhmanbfb04f62012-12-06 13:17:19 +0200660 ktime_set(0, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300661 }
662
663 /*
664 * Currently idling is enabled only for READ queues. If we want to
665 * enable it for write queues also, note that idling frequency will
666 * be the same in both cases
667 */
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200668 rdata->rd_idle_data.idle_time_ms = ROW_IDLE_TIME_MSEC;
669 rdata->rd_idle_data.freq_ms = ROW_READ_FREQ_MSEC;
670 hrtimer_init(&rdata->rd_idle_data.hr_timer,
671 CLOCK_MONOTONIC, HRTIMER_MODE_REL);
672 rdata->rd_idle_data.hr_timer.function = &row_idle_hrtimer_fn;
673
674 INIT_WORK(&rdata->rd_idle_data.idle_work, kick_queue);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300675
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200676 rdata->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300677 rdata->dispatch_queue = q;
678
Tatyana Brokhman16349062012-09-20 10:46:10 +0300679 return rdata;
680}
681
682/*
683 * row_exit_queue() - called on unloading the RAW scheduler
684 * @e: poiner to struct elevator_queue
685 *
686 */
687static void row_exit_queue(struct elevator_queue *e)
688{
689 struct row_data *rd = (struct row_data *)e->elevator_data;
690 int i;
691
692 for (i = 0; i < ROWQ_MAX_PRIO; i++)
Tatyana Brokhman8a970bc2013-01-12 16:21:12 +0200693 BUG_ON(!list_empty(&rd->row_queues[i].fifo));
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200694 if (hrtimer_cancel(&rd->rd_idle_data.hr_timer))
695 pr_err("ROW BUG: idle timer was active!");
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200696 rd->rd_idle_data.idling_queue_idx = ROWQ_MAX_PRIO;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300697 kfree(rd);
698}
699
700/*
701 * row_merged_requests() - Called when 2 requests are merged
702 * @q: requests queue
703 * @rq: request the two requests were merged into
704 * @next: request that was merged
705 */
706static void row_merged_requests(struct request_queue *q, struct request *rq,
707 struct request *next)
708{
709 struct row_queue *rqueue = RQ_ROWQ(next);
710
711 list_del_init(&next->queuelist);
Tatyana Brokhmanbd56be32013-01-13 22:04:59 +0200712 rqueue->nr_req--;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300713
714 rqueue->rdata->nr_reqs[rq_data_dir(rq)]--;
715}
716
717/*
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200718 * row_get_queue_prio() - Get queue priority for a given request
Tatyana Brokhman16349062012-09-20 10:46:10 +0300719 *
720 * This is a helping function which purpose is to determine what
721 * ROW queue the given request should be added to (and
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200722 * dispatched from later on)
Tatyana Brokhman16349062012-09-20 10:46:10 +0300723 *
Tatyana Brokhman16349062012-09-20 10:46:10 +0300724 */
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200725static enum row_queue_prio row_get_queue_prio(struct request *rq)
Tatyana Brokhman16349062012-09-20 10:46:10 +0300726{
727 const int data_dir = rq_data_dir(rq);
728 const bool is_sync = rq_is_sync(rq);
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200729 enum row_queue_prio q_type = ROWQ_MAX_PRIO;
730 int ioprio_class = IOPRIO_PRIO_CLASS(rq->elv.icq->ioc->ioprio);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300731
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200732 switch (ioprio_class) {
733 case IOPRIO_CLASS_RT:
734 if (data_dir == READ)
735 q_type = ROWQ_PRIO_HIGH_READ;
736 else if (is_sync)
737 q_type = ROWQ_PRIO_HIGH_SWRITE;
738 else {
739 pr_err("%s:%s(): got a simple write from RT_CLASS. How???",
740 rq->rq_disk->disk_name, __func__);
741 q_type = ROWQ_PRIO_REG_WRITE;
742 }
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200743 rq->cmd_flags |= REQ_URGENT;
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200744 break;
745 case IOPRIO_CLASS_IDLE:
746 if (data_dir == READ)
747 q_type = ROWQ_PRIO_LOW_READ;
748 else if (is_sync)
749 q_type = ROWQ_PRIO_LOW_SWRITE;
750 else {
751 pr_err("%s:%s(): got a simple write from IDLE_CLASS. How???",
752 rq->rq_disk->disk_name, __func__);
753 q_type = ROWQ_PRIO_REG_WRITE;
754 }
755 break;
756 case IOPRIO_CLASS_NONE:
757 case IOPRIO_CLASS_BE:
758 default:
759 if (data_dir == READ)
760 q_type = ROWQ_PRIO_REG_READ;
761 else if (is_sync)
762 q_type = ROWQ_PRIO_REG_SWRITE;
763 else
764 q_type = ROWQ_PRIO_REG_WRITE;
765 break;
766 }
767
768 return q_type;
Tatyana Brokhman16349062012-09-20 10:46:10 +0300769}
770
771/*
772 * row_set_request() - Set ROW data structures associated with this request.
773 * @q: requests queue
774 * @rq: pointer to the request
775 * @gfp_mask: ignored
776 *
777 */
778static int
779row_set_request(struct request_queue *q, struct request *rq, gfp_t gfp_mask)
780{
781 struct row_data *rd = (struct row_data *)q->elevator->elevator_data;
782 unsigned long flags;
783
784 spin_lock_irqsave(q->queue_lock, flags);
785 rq->elv.priv[0] =
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200786 (void *)(&rd->row_queues[row_get_queue_prio(rq)]);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300787 spin_unlock_irqrestore(q->queue_lock, flags);
788
789 return 0;
790}
791
792/********** Helping sysfs functions/defenitions for ROW attributes ******/
793static ssize_t row_var_show(int var, char *page)
794{
795 return snprintf(page, 100, "%d\n", var);
796}
797
798static ssize_t row_var_store(int *var, const char *page, size_t count)
799{
800 int err;
801 err = kstrtoul(page, 10, (unsigned long *)var);
802
803 return count;
804}
805
806#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
807static ssize_t __FUNC(struct elevator_queue *e, char *page) \
808{ \
809 struct row_data *rowd = e->elevator_data; \
810 int __data = __VAR; \
811 if (__CONV) \
812 __data = jiffies_to_msecs(__data); \
813 return row_var_show(__data, (page)); \
814}
815SHOW_FUNCTION(row_hp_read_quantum_show,
816 rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 0);
817SHOW_FUNCTION(row_rp_read_quantum_show,
818 rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum, 0);
819SHOW_FUNCTION(row_hp_swrite_quantum_show,
820 rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum, 0);
821SHOW_FUNCTION(row_rp_swrite_quantum_show,
822 rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum, 0);
823SHOW_FUNCTION(row_rp_write_quantum_show,
824 rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum, 0);
825SHOW_FUNCTION(row_lp_read_quantum_show,
826 rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum, 0);
827SHOW_FUNCTION(row_lp_swrite_quantum_show,
828 rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum, 0);
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200829SHOW_FUNCTION(row_rd_idle_data_show, rowd->rd_idle_data.idle_time_ms, 0);
830SHOW_FUNCTION(row_rd_idle_data_freq_show, rowd->rd_idle_data.freq_ms, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300831#undef SHOW_FUNCTION
832
833#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
834static ssize_t __FUNC(struct elevator_queue *e, \
835 const char *page, size_t count) \
836{ \
837 struct row_data *rowd = e->elevator_data; \
838 int __data; \
839 int ret = row_var_store(&__data, (page), count); \
840 if (__CONV) \
841 __data = (int)msecs_to_jiffies(__data); \
842 if (__data < (MIN)) \
843 __data = (MIN); \
844 else if (__data > (MAX)) \
845 __data = (MAX); \
846 *(__PTR) = __data; \
847 return ret; \
848}
849STORE_FUNCTION(row_hp_read_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200850&rowd->row_queues[ROWQ_PRIO_HIGH_READ].disp_quantum, 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300851STORE_FUNCTION(row_rp_read_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200852 &rowd->row_queues[ROWQ_PRIO_REG_READ].disp_quantum,
853 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300854STORE_FUNCTION(row_hp_swrite_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200855 &rowd->row_queues[ROWQ_PRIO_HIGH_SWRITE].disp_quantum,
856 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300857STORE_FUNCTION(row_rp_swrite_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200858 &rowd->row_queues[ROWQ_PRIO_REG_SWRITE].disp_quantum,
859 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300860STORE_FUNCTION(row_rp_write_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200861 &rowd->row_queues[ROWQ_PRIO_REG_WRITE].disp_quantum,
862 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300863STORE_FUNCTION(row_lp_read_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200864 &rowd->row_queues[ROWQ_PRIO_LOW_READ].disp_quantum,
865 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300866STORE_FUNCTION(row_lp_swrite_quantum_store,
Tatyana Brokhman0a0345a2012-10-15 20:50:54 +0200867 &rowd->row_queues[ROWQ_PRIO_LOW_SWRITE].disp_quantum,
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200868 1, INT_MAX, 0);
Tatyana Brokhmance1a8ed2013-01-17 20:56:07 +0200869STORE_FUNCTION(row_rd_idle_data_store, &rowd->rd_idle_data.idle_time_ms,
870 1, INT_MAX, 0);
871STORE_FUNCTION(row_rd_idle_data_freq_store, &rowd->rd_idle_data.freq_ms,
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200872 1, INT_MAX, 0);
Tatyana Brokhman16349062012-09-20 10:46:10 +0300873
874#undef STORE_FUNCTION
875
876#define ROW_ATTR(name) \
877 __ATTR(name, S_IRUGO|S_IWUSR, row_##name##_show, \
878 row_##name##_store)
879
880static struct elv_fs_entry row_attrs[] = {
881 ROW_ATTR(hp_read_quantum),
882 ROW_ATTR(rp_read_quantum),
883 ROW_ATTR(hp_swrite_quantum),
884 ROW_ATTR(rp_swrite_quantum),
885 ROW_ATTR(rp_write_quantum),
886 ROW_ATTR(lp_read_quantum),
887 ROW_ATTR(lp_swrite_quantum),
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200888 ROW_ATTR(rd_idle_data),
889 ROW_ATTR(rd_idle_data_freq),
Tatyana Brokhman16349062012-09-20 10:46:10 +0300890 __ATTR_NULL
891};
892
893static struct elevator_type iosched_row = {
894 .ops = {
895 .elevator_merge_req_fn = row_merged_requests,
896 .elevator_dispatch_fn = row_dispatch_requests,
897 .elevator_add_req_fn = row_add_request,
Tatyana Brokhmanb7bf9ac2012-10-30 08:33:06 +0200898 .elevator_reinsert_req_fn = row_reinsert_req,
Tatyana Brokhman0ef81432012-12-20 19:23:58 +0200899 .elevator_is_urgent_fn = row_urgent_pending,
Tatyana Brokhman4c3c3cc2013-01-24 15:08:40 +0200900 .elevator_completed_req_fn = row_completed_req,
Tatyana Brokhman16349062012-09-20 10:46:10 +0300901 .elevator_former_req_fn = elv_rb_former_request,
902 .elevator_latter_req_fn = elv_rb_latter_request,
903 .elevator_set_req_fn = row_set_request,
904 .elevator_init_fn = row_init_queue,
905 .elevator_exit_fn = row_exit_queue,
906 },
Tatyana Brokhmandb7c1532013-01-23 17:15:49 +0200907 .icq_size = sizeof(struct io_cq),
908 .icq_align = __alignof__(struct io_cq),
Tatyana Brokhman16349062012-09-20 10:46:10 +0300909 .elevator_attrs = row_attrs,
910 .elevator_name = "row",
911 .elevator_owner = THIS_MODULE,
912};
913
914static int __init row_init(void)
915{
916 elv_register(&iosched_row);
917 return 0;
918}
919
920static void __exit row_exit(void)
921{
922 elv_unregister(&iosched_row);
923}
924
925module_init(row_init);
926module_exit(row_exit);
927
928MODULE_LICENSE("GPLv2");
929MODULE_DESCRIPTION("Read Over Write IO scheduler");