4 * Copyright (C) 2007 Aaron Carroll <aaronc@gelato.unsw.edu.au>
9 * The next request is decided based on its distance from the last
10 * request, with a multiplicative penalty of `rev_penalty' applied
11 * for reversing the head direction. A rev_penalty of 1 means SSTF
12 * behaviour. As this variable is increased, the algorithm approaches
13 * pure SCAN. Setting rev_penalty to 0 forces SCAN.
15 * Async and synch requests are not treated seperately. Instead we
16 * rely on deadlines to ensure fairness.
19 #include <linux/kernel.h>
21 #include <linux/blkdev.h>
22 #include <linux/elevator.h>
23 #include <linux/bio.h>
24 #include <linux/module.h>
25 #include <linux/slab.h>
26 #include <linux/init.h>
27 #include <linux/compiler.h>
28 #include <linux/rbtree.h>
40 static const int sync_expire
= HZ
/ 2; /* max time before a sync is submitted. */
41 static const int async_expire
= 5 * HZ
; /* ditto for async, these limits are SOFT! */
42 static const int fifo_batch
= 16;
43 static const int rev_penalty
= 10; /* penalty for reversing head direction */
46 struct rb_root sort_list
;
47 struct list_head fifo_list
[2];
49 struct request
*next_rq
;
50 struct request
*prev_rq
;
52 unsigned int nbatched
;
53 sector_t last_sector
; /* head position */
62 static void vr_move_request(struct vr_data
*, struct request
*);
64 static inline struct vr_data
*
65 vr_get_data(struct request_queue
*q
)
67 return q
->elevator
->elevator_data
;
71 vr_add_rq_rb(struct vr_data
*vd
, struct request
*rq
)
73 struct request
*alias
= elv_rb_add(&vd
->sort_list
, rq
);
75 if (unlikely(alias
)) {
76 vr_move_request(vd
, alias
);
77 alias
= elv_rb_add(&vd
->sort_list
, rq
);
81 if (rq
->sector
>= vd
->last_sector
) {
82 if (!vd
->next_rq
|| vd
->next_rq
->sector
> rq
->sector
)
86 if (!vd
->prev_rq
|| vd
->prev_rq
->sector
< rq
->sector
)
90 BUG_ON(vd
->next_rq
&& vd
->next_rq
== vd
->prev_rq
);
91 BUG_ON(vd
->next_rq
&& vd
->prev_rq
&& vd
->next_rq
->sector
< vd
->prev_rq
->sector
);
95 vr_del_rq_rb(struct vr_data
*vd
, struct request
*rq
)
98 * We might be deleting our cached next request.
99 * If so, find its sucessor.
102 if (vd
->next_rq
== rq
)
103 vd
->next_rq
= elv_rb_latter_request(NULL
, rq
);
104 else if (vd
->prev_rq
== rq
)
105 vd
->prev_rq
= elv_rb_former_request(NULL
, rq
);
107 BUG_ON(vd
->next_rq
&& vd
->next_rq
== vd
->prev_rq
);
108 BUG_ON(vd
->next_rq
&& vd
->prev_rq
&& vd
->next_rq
->sector
< vd
->prev_rq
->sector
);
110 elv_rb_del(&vd
->sort_list
, rq
);
114 * add rq to rbtree and fifo
117 vr_add_request(struct request_queue
*q
, struct request
*rq
)
119 struct vr_data
*vd
= vr_get_data(q
);
120 const int dir
= rq_is_sync(rq
);
122 vr_add_rq_rb(vd
, rq
);
124 if (vd
->fifo_expire
[dir
]) {
125 rq_set_fifo_time(rq
, jiffies
+ vd
->fifo_expire
[dir
]);
126 list_add_tail(&rq
->queuelist
, &vd
->fifo_list
[dir
]);
131 * remove rq from rbtree and fifo.
134 vr_remove_request(struct request_queue
*q
, struct request
*rq
)
136 struct vr_data
*vd
= vr_get_data(q
);
139 vr_del_rq_rb(vd
, rq
);
143 vr_merge(struct request_queue
*q
, struct request
**rqp
, struct bio
*bio
)
145 sector_t sector
= bio
->bi_sector
+ bio_sectors(bio
);
146 struct vr_data
*vd
= vr_get_data(q
);
147 struct request
*rq
= elv_rb_find(&vd
->sort_list
, sector
);
149 if (rq
&& elv_rq_merge_ok(rq
, bio
)) {
151 return ELEVATOR_FRONT_MERGE
;
153 return ELEVATOR_NO_MERGE
;
157 vr_merged_request(struct request_queue
*q
, struct request
*req
, int type
)
159 struct vr_data
*vd
= vr_get_data(q
);
162 * if the merge was a front merge, we need to reposition request
164 if (type
== ELEVATOR_FRONT_MERGE
) {
165 vr_del_rq_rb(vd
, req
);
166 vr_add_rq_rb(vd
, req
);
171 vr_merged_requests(struct request_queue
*q
, struct request
*rq
,
172 struct request
*next
)
175 * if next expires before rq, assign its expire time to rq
176 * and move into next position (next will be deleted) in fifo
178 if (!list_empty(&rq
->queuelist
) && !list_empty(&next
->queuelist
)) {
179 if (time_before(rq_fifo_time(next
), rq_fifo_time(rq
))) {
180 list_move(&rq
->queuelist
, &next
->queuelist
);
181 rq_set_fifo_time(rq
, rq_fifo_time(next
));
185 vr_remove_request(q
, next
);
189 * move an entry to dispatch queue
192 vr_move_request(struct vr_data
*vd
, struct request
*rq
)
194 struct request_queue
*q
= rq
->q
;
196 if (rq
->sector
> vd
->last_sector
)
197 vd
->head_dir
= FORWARD
;
199 vd
->head_dir
= BACKWARD
;
201 vd
->last_sector
= rq
->sector
;
202 vd
->next_rq
= elv_rb_latter_request(NULL
, rq
);
203 vd
->prev_rq
= elv_rb_former_request(NULL
, rq
);
205 BUG_ON(vd
->next_rq
&& vd
->next_rq
== vd
->prev_rq
);
207 vr_remove_request(q
, rq
);
208 elv_dispatch_add_tail(q
, rq
);
213 * get the first expired request in direction ddir
215 static struct request
*
216 vr_expired_request(struct vr_data
*vd
, int ddir
)
220 if (list_empty(&vd
->fifo_list
[ddir
]))
223 rq
= rq_entry_fifo(vd
->fifo_list
[ddir
].next
);
224 if (time_after(jiffies
, rq_fifo_time(rq
)))
231 * Returns the oldest expired request
233 static struct request
*
234 vr_check_fifo(struct vr_data
*vd
)
236 struct request
*rq_sync
= vr_expired_request(vd
, SYNC
);
237 struct request
*rq_async
= vr_expired_request(vd
, ASYNC
);
239 if (rq_async
&& rq_sync
) {
240 if (time_after(rq_fifo_time(rq_async
), rq_fifo_time(rq_sync
)))
250 * Return the request with the lowest penalty
252 static struct request
*
253 vr_choose_request(struct vr_data
*vd
)
255 int penalty
= (vd
->rev_penalty
) ? : INT_MAX
;
256 struct request
*next
= vd
->next_rq
;
257 struct request
*prev
= vd
->prev_rq
;
258 sector_t next_pen
, prev_pen
;
260 BUG_ON(prev
&& prev
== next
);
267 /* At this point both prev and next are defined and distinct */
269 next_pen
= next
->sector
- vd
->last_sector
;
270 prev_pen
= vd
->last_sector
- prev
->sector
;
272 if (vd
->head_dir
== FORWARD
)
277 if (next_pen
<= prev_pen
)
284 vr_dispatch_requests(struct request_queue
*q
, int force
)
286 struct vr_data
*vd
= vr_get_data(q
);
287 struct request
*rq
= NULL
;
289 /* Check for and issue expired requests */
290 if (vd
->nbatched
> vd
->fifo_batch
) {
292 rq
= vr_check_fifo(vd
);
296 rq
= vr_choose_request(vd
);
301 vr_move_request(vd
, rq
);
307 vr_queue_empty(struct request_queue
*q
)
309 struct vr_data
*vd
= vr_get_data(q
);
310 return RB_EMPTY_ROOT(&vd
->sort_list
);
314 vr_exit_queue(elevator_t
*e
)
316 struct vr_data
*vd
= e
->elevator_data
;
317 BUG_ON(!RB_EMPTY_ROOT(&vd
->sort_list
));
322 * initialize elevator private data (vr_data).
324 static void *vr_init_queue(struct request_queue
*q
)
328 vd
= kmalloc_node(sizeof(*vd
), GFP_KERNEL
| __GFP_ZERO
, q
->node
);
332 INIT_LIST_HEAD(&vd
->fifo_list
[SYNC
]);
333 INIT_LIST_HEAD(&vd
->fifo_list
[ASYNC
]);
334 vd
->sort_list
= RB_ROOT
;
335 vd
->fifo_expire
[SYNC
] = sync_expire
;
336 vd
->fifo_expire
[ASYNC
] = async_expire
;
337 vd
->fifo_batch
= fifo_batch
;
338 vd
->rev_penalty
= rev_penalty
;
347 vr_var_show(int var
, char *page
)
349 return sprintf(page
, "%d\n", var
);
353 vr_var_store(int *var
, const char *page
, size_t count
)
355 *var
= simple_strtol(page
, NULL
, 10);
359 #define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
360 static ssize_t __FUNC(elevator_t *e, char *page) \
362 struct vr_data *vd = e->elevator_data; \
363 int __data = __VAR; \
365 __data = jiffies_to_msecs(__data); \
366 return vr_var_show(__data, (page)); \
368 SHOW_FUNCTION(vr_sync_expire_show
, vd
->fifo_expire
[SYNC
], 1);
369 SHOW_FUNCTION(vr_async_expire_show
, vd
->fifo_expire
[ASYNC
], 1);
370 SHOW_FUNCTION(vr_fifo_batch_show
, vd
->fifo_batch
, 0);
371 SHOW_FUNCTION(vr_rev_penalty_show
, vd
->rev_penalty
, 0);
374 #define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
375 static ssize_t __FUNC(elevator_t *e, const char *page, size_t count) \
377 struct vr_data *vd = e->elevator_data; \
379 int ret = vr_var_store(&__data, (page), count); \
380 if (__data < (MIN)) \
382 else if (__data > (MAX)) \
385 *(__PTR) = msecs_to_jiffies(__data); \
390 STORE_FUNCTION(vr_sync_expire_store
, &vd
->fifo_expire
[SYNC
], 0, INT_MAX
, 1);
391 STORE_FUNCTION(vr_async_expire_store
, &vd
->fifo_expire
[ASYNC
], 0, INT_MAX
, 1);
392 STORE_FUNCTION(vr_fifo_batch_store
, &vd
->fifo_batch
, 0, INT_MAX
, 0);
393 STORE_FUNCTION(vr_rev_penalty_store
, &vd
->rev_penalty
, 0, INT_MAX
, 0);
394 #undef STORE_FUNCTION
396 #define DD_ATTR(name) \
397 __ATTR(name, S_IRUGO|S_IWUSR, vr_##name##_show, \
400 static struct elv_fs_entry vr_attrs
[] = {
401 DD_ATTR(sync_expire
),
402 DD_ATTR(async_expire
),
404 DD_ATTR(rev_penalty
),
408 static struct elevator_type iosched_vr
= {
410 .elevator_merge_fn
= vr_merge
,
411 .elevator_merged_fn
= vr_merged_request
,
412 .elevator_merge_req_fn
= vr_merged_requests
,
413 .elevator_dispatch_fn
= vr_dispatch_requests
,
414 .elevator_add_req_fn
= vr_add_request
,
415 .elevator_queue_empty_fn
= vr_queue_empty
,
416 .elevator_former_req_fn
= elv_rb_former_request
,
417 .elevator_latter_req_fn
= elv_rb_latter_request
,
418 .elevator_init_fn
= vr_init_queue
,
419 .elevator_exit_fn
= vr_exit_queue
,
422 .elevator_attrs
= vr_attrs
,
423 .elevator_name
= "vr",
424 .elevator_owner
= THIS_MODULE
,
427 static int __init
vr_init(void)
429 elv_register(&iosched_vr
);
434 static void __exit
vr_exit(void)
436 elv_unregister(&iosched_vr
);
439 module_init(vr_init
);
440 module_exit(vr_exit
);
442 MODULE_AUTHOR("Aaron Carroll");
443 MODULE_LICENSE("GPL");
444 MODULE_DESCRIPTION("V(R) IO scheduler");