1 /*
2 * linux/drivers/block/elevator.c
3 *
4 * Block device elevator/IO-scheduler.
5 *
6 * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
7 *
8 * 30042000 Jens Axboe <axboe@suse.de> :
9 *
10 * Split the elevator a bit so that it is possible to choose a different
11 * one or even write a new "plug in". There are three pieces:
12 * - elevator_fn, inserts a new request in the queue list
13 * - elevator_merge_fn, decides whether a new buffer can be merged with
14 * an existing request
15 * - elevator_dequeue_fn, called when a request is taken off the active list
16 *
17 * 20082000 Dave Jones <davej@suse.de> :
18 * Removed tests for max-bomb-segments, which was breaking elvtune
19 * when run without -bN
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 int elevator_linus_merge(request_queue_t *q, struct request **req,
31 struct list_head * head,
32 struct buffer_head *bh, int rw,
33 int max_sectors, int max_segments)
34 {
35 struct list_head *entry = &q->queue_head;
36 unsigned int count = bh->b_size >> 9, ret = ELEVATOR_NO_MERGE;
37
38 while ((entry = entry->prev) != head) {
39 struct request *__rq = blkdev_entry_to_request(entry);
40
41 /*
42 * simply "aging" of requests in queue
43 */
44 if (__rq->elevator_sequence-- <= 0) {
45 *req = __rq;
46 break;
47 }
48
49 if (__rq->sem)
50 continue;
51 if (__rq->cmd != rw)
52 continue;
53 if (__rq->rq_dev != bh->b_rdev)
54 continue;
55 if (__rq->nr_sectors + count > max_sectors)
56 continue;
57 if (__rq->elevator_sequence < count)
58 break;
59 if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
60 ret = ELEVATOR_BACK_MERGE;
61 *req = __rq;
62 break;
63 } else if (__rq->sector - count == bh->b_rsector) {
64 ret = ELEVATOR_FRONT_MERGE;
65 __rq->elevator_sequence -= count;
66 *req = __rq;
67 break;
68 } else if (!*req && BHRQ_IN_ORDER(bh, __rq))
69 *req = __rq;
70 }
71
72 return ret;
73 }
74
75 void elevator_linus_merge_cleanup(request_queue_t *q, struct request *req, int count)
76 {
77 struct list_head *entry = &req->queue, *head = &q->queue_head;
78
79 /*
80 * second pass scan of requests that got passed over, if any
81 */
82 while ((entry = entry->next) != head) {
83 struct request *tmp = blkdev_entry_to_request(entry);
84 tmp->elevator_sequence -= count;
85 }
86 }
87
88 void elevator_linus_merge_req(struct request *req, struct request *next)
89 {
90 if (next->elevator_sequence < req->elevator_sequence)
91 req->elevator_sequence = next->elevator_sequence;
92 }
93
94 /*
95 * See if we can find a request that this buffer can be coalesced with.
96 */
97 int elevator_noop_merge(request_queue_t *q, struct request **req,
98 struct list_head * head,
99 struct buffer_head *bh, int rw,
100 int max_sectors, int max_segments)
101 {
102 struct list_head *entry;
103 unsigned int count = bh->b_size >> 9;
104
105 if (list_empty(&q->queue_head))
106 return ELEVATOR_NO_MERGE;
107
108 entry = &q->queue_head;
109 while ((entry = entry->prev) != head) {
110 struct request *__rq = blkdev_entry_to_request(entry);
111
112 if (__rq->cmd != rw)
113 continue;
114 if (__rq->rq_dev != bh->b_rdev)
115 continue;
116 if (__rq->nr_sectors + count > max_sectors)
117 continue;
118 if (__rq->sem)
119 continue;
120 if (__rq->sector + __rq->nr_sectors == bh->b_rsector) {
121 *req = __rq;
122 return ELEVATOR_BACK_MERGE;
123 } else if (__rq->sector - count == bh->b_rsector) {
124 *req = __rq;
125 return ELEVATOR_FRONT_MERGE;
126 }
127 }
128
129 *req = blkdev_entry_to_request(q->queue_head.prev);
130 return ELEVATOR_NO_MERGE;
131 }
132
133 void elevator_noop_merge_cleanup(request_queue_t *q, struct request *req, int count) {}
134
135 void elevator_noop_merge_req(struct request *req, struct request *next) {}
136
137 int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
138 {
139 blkelv_ioctl_arg_t output;
140
141 output.queue_ID = elevator->queue_ID;
142 output.read_latency = elevator->read_latency;
143 output.write_latency = elevator->write_latency;
144 output.max_bomb_segments = 0;
145
146 if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t)))
147 return -EFAULT;
148
149 return 0;
150 }
151
152 int blkelvset_ioctl(elevator_t * elevator, const blkelv_ioctl_arg_t * arg)
153 {
154 blkelv_ioctl_arg_t input;
155
156 if (copy_from_user(&input, arg, sizeof(blkelv_ioctl_arg_t)))
157 return -EFAULT;
158
159 if (input.read_latency < 0)
160 return -EINVAL;
161 if (input.write_latency < 0)
162 return -EINVAL;
163
164 elevator->read_latency = input.read_latency;
165 elevator->write_latency = input.write_latency;
166 return 0;
167 }
168
169 void elevator_init(elevator_t * elevator, elevator_t type)
170 {
171 static unsigned int queue_ID;
172
173 *elevator = type;
174 elevator->queue_ID = queue_ID++;
175 }
176
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.