/
greedy-disk-scheduler.c
182 lines (149 loc) · 4.71 KB
/
greedy-disk-scheduler.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
* elevator greedy
*/
#include <linux/blkdev.h>
#include <linux/elevator.h>
#include <linux/bio.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
struct greedy_data {
struct list_head lower_queue;
struct list_head upper_queue;
sector_t head_sector;
};
/*
struct list_head* queue_select(struct sector entry_sector, struct greedy_data* greedy_data) {
if(entry_sector < greedy_data->disk_head)
return greedy_data->lower_queue;
else
return greedy_data->upper_queue;
}
*/
static void greedy_merged_requests(struct request_queue *q, struct request *rq,
struct request *next)
{
list_del_init(&next->queuelist);
}
// dispatch upper
static struct request* greedy_next_lower(struct greedy_data* greedy_data) {
return list_entry_rq(greedy_data->lower->next);
}
// dispatch lower
static struct request* greedy_next_upper(struct greedy_data* greedy_data) {
return list_entry_rq(greedy_data->upper->prev);
}
static int greedy_dispatch(struct request_queue *q, int force) {
struct request* rq, next_upper, next_lower;
struct greedy_data *nd = q->elevator->elevator_data;
struct sector lower_sector, upper_sector;
if(list_empty(nd->lower_queue) && list_empty(nd->upper_queue)) return NULL;
if(list_empty(nd->lower_queue)) {
rq = greedy_next_upper(q, nd);
goto end;
}
if(list_empty(nd->upper_queue)) {
rq = greedy_next_lower(q, nd);
goto end;
}
next_lower = greedy_next_lower(nd);
next_upper = greedy_next_upper(nd);
lower_sector = blk_rq_pos(next_lower);
upper_sector = blk_rq_pos(next_upper);
if((upper_sector - nd->head_sector) < (nd->head_sector - lower_sector)) {
rq = next_upper;
goto end;
}
rq = next_lower;
end:
nd->head_sector = rq_end_sector(rq);
list_del_init(&rq->queuelist);
elv_dispatch_sort(q, rq);
return 1;
}
static void greedy_sorted_add(struct list_head* entry, struct list_head* head) {
struct request* entry_request = list_entry_rq(entry);
struct sector entry_sector = blk_rq_pos(entry_request);
struct request* comparison;
// to-do
list_for_each_entry(comparison, head, queuelist) {
if(entry_sector > blk_rq_pos(comparison)) {
list_add_tail(entry, comparision->queuelist);
return;
}
}
list_add_tail(entry, head);
}
static void greedy_add_request(struct request_queue *q, struct request *rq) {
struct greedy_data *nd = q->elevator->elevator_data;
struct sector entry_sector = blk_rq_pos(rq);
if(entry_sector < nd->head_sector)
greedy_sorted_add(&rq->queuelist, &nd->lower_queue);
else
greedy_sorted_add(&rq->queuelist, &nd->upper_queue);
}
static struct request * greedy_former_request(struct request_queue *q, struct request *rq) {
struct greedy_data *nd = q->elevator->elevator_data;
if (rq->queuelist.prev == &nd->lower_queue || rq->queuelist.prev == &nd->upper_queue)
return NULL;
return list_entry(rq->queuelist.prev, struct request, queuelist);
}
static struct request *
greedy_latter_request(struct request_queue *q, struct request *rq)
{
struct greedy_data *nd = q->elevator->elevator_data;
if (rq->queuelist.next == &nd->lower_queue || rq->queuelist.next == &nd->upper_queue)
return NULL;
return list_entry(rq->queuelist.next, struct request, queuelist);
}
static int greedy_init_queue(struct request_queue *q, struct elevator_type *e) {
struct greedy_data *nd;
struct elevator_queue *eq;
eq = elevator_alloc(q, e);
if (!eq) return -ENOMEM;
nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node);
if (!nd) {
kobject_put(&eq->kobj);
return -ENOMEM;
}
eq->elevator_data = nd;
INIT_LIST_HEAD(&nd->lower_queue);
INIT_LIST_HEAD(&nd->upper_queue);
nd->disk_head = 0ul;
spin_lock_irq(q->queue_lock);
q->elevator = eq;
spin_unlock_irq(q->queue_lock);
return 0;
}
static void greedy_exit_queue(struct elevator_queue *e)
{
struct greedy_data *nd = e->elevator_data;
BUG_ON(!list_empty(&nd->queue));
kfree(nd);
}
static struct elevator_type elevator_greedy = {
.ops = {
.elevator_merge_req_fn = greedy_merged_requests,
.elevator_dispatch_fn = greedy_dispatch,
.elevator_add_req_fn = greedy_add_request,
.elevator_former_req_fn = greedy_former_request,
.elevator_latter_req_fn = greedy_latter_request,
.elevator_init_fn = greedy_init_queue,
.elevator_exit_fn = greedy_exit_queue,
},
.elevator_name = "greedy",
.elevator_owner = THIS_MODULE,
};
static int __init greedy_init(void)
{
return elv_register(&elevator_greedy);
}
static void __exit greedy_exit(void)
{
elv_unregister(&elevator_greedy);
}
module_init(greedy_init);
module_exit(greedy_exit);
MODULE_AUTHOR("Team eXtreme");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Greedy IO scheduler");