1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <linux/fs.h>
24#include <linux/blkdev.h>
25#include <linux/elevator.h>
26#include <linux/blk.h>
27#include <linux/module.h>
28#include <asm/uaccess.h>
29
30
31
32
33
34
35
36inline int bh_rq_in_between(struct buffer_head *bh, struct request *rq,
37 struct list_head *head)
38{
39 struct list_head *next;
40 struct request *next_rq;
41
42 next = rq->queue.next;
43 if (next == head)
44 return 0;
45
46
47
48
49
50 next_rq = blkdev_entry_to_request(next);
51 if (next_rq->rq_dev != rq->rq_dev)
52 return bh->b_rsector > rq->sector;
53
54
55
56
57
58 if (bh->b_rsector < next_rq->sector && bh->b_rsector > rq->sector)
59 return 1;
60
61
62
63
64 if (next_rq->sector > rq->sector)
65 return 0;
66
67
68
69
70
71 if (bh->b_rsector > rq->sector || bh->b_rsector < next_rq->sector)
72 return 1;
73
74 return 0;
75}
76
77
78int elevator_linus_merge(request_queue_t *q, struct request **req,
79 struct list_head * head,
80 struct buffer_head *bh, int rw,
81 int max_sectors)
82{
83 struct list_head *entry = &q->queue_head;
84 unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
85 struct request *__rq;
86 int backmerge_only = 0;
87
88 while (!backmerge_only && (entry = entry->prev) != head) {
89 __rq = blkdev_entry_to_request(entry);
90
91
92
93
94 if (__rq->elevator_sequence <= 0)
95 backmerge_only = 1;
96
97 if (__rq->waiting)
98 continue;
99 if (__rq->rq_dev != bh->b_rdev)
100 continue;
101 if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head) && !backmerge_only)
102 *req = __rq;
103 if (__rq->cmd != rw)
104 continue;
105 if (__rq->nr_sectors + count > max_sectors)
106 continue;
107 if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
108 ret = ELEVATOR_BACK_MERGE;
109 *req = __rq;
110 break;
111 } else if (__rq->sector - count == bh->b_rsector && !backmerge_only) {
112 ret = ELEVATOR_FRONT_MERGE;
113 __rq->elevator_sequence--;
114 *req = __rq;
115 break;
116 }
117 }
118
119
120
121
122
123 if (*req) {
124 int scan_cost = ret ? 1 : ELV_LINUS_SEEK_COST;
125 struct list_head *entry = &(*req)->queue;
126
127 while ((entry = entry->next) != &q->queue_head) {
128 __rq = blkdev_entry_to_request(entry);
129 __rq->elevator_sequence -= scan_cost;
130 }
131 }
132
133 return ret;
134}
135
136void elevator_linus_merge_req(struct request *req, struct request *next)
137{
138 if (next->elevator_sequence < req->elevator_sequence)
139 req->elevator_sequence = next->elevator_sequence;
140}
141
142
143
144
145int elevator_noop_merge(request_queue_t *q, struct request **req,
146 struct list_head * head,
147 struct buffer_head *bh, int rw,
148 int max_sectors)
149{
150 struct list_head *entry;
151 unsigned int count = bh->b_size >> 9;
152
153 if (list_empty(&q->queue_head))
154 return ELEVATOR_NO_MERGE;
155
156 entry = &q->queue_head;
157 while ((entry = entry->prev) != head) {
158 struct request *__rq = blkdev_entry_to_request(entry);
159
160 if (__rq->cmd != rw)
161 continue;
162 if (__rq->rq_dev != bh->b_rdev)
163 continue;
164 if (__rq->nr_sectors + count > max_sectors)
165 continue;
166 if (__rq->waiting)
167 continue;
168 if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
169 *req = __rq;
170 return ELEVATOR_BACK_MERGE;
171 } else if (__rq->sector - count == bh->b_rsector) {
172 *req = __rq;
173 return ELEVATOR_FRONT_MERGE;
174 }
175 }
176
177 *req = blkdev_entry_to_request(q->queue_head.prev);
178 return ELEVATOR_NO_MERGE;
179}
180
181void elevator_noop_merge_req(struct request *req, struct request *next) {}
182
183int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
184{
185 blkelv_ioctl_arg_t output;
186
187 output.queue_ID = elevator->queue_ID;
188 output.read_latency = elevator->read_latency;
189 output.write_latency = elevator->write_latency;
190 output.max_bomb_segments = 0;
191
192 if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t)))
193 return -EFAULT;
194
195 return 0;
196}
197
198int blkelvset_ioctl(elevator_t * elevator, const blkelv_ioctl_arg_t * arg)
199{
200 blkelv_ioctl_arg_t input;
201
202 if (copy_from_user(&input, arg, sizeof(blkelv_ioctl_arg_t)))
203 return -EFAULT;
204
205 if (input.read_latency < 0)
206 return -EINVAL;
207 if (input.write_latency < 0)
208 return -EINVAL;
209
210 elevator->read_latency = input.read_latency;
211 elevator->write_latency = input.write_latency;
212 return 0;
213}
214
215void elevator_init(elevator_t * elevator, elevator_t type)
216{
217 static unsigned int queue_ID;
218
219 *elevator = type;
220 elevator->queue_ID = queue_ID++;
221}
222