OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [block/] [elevator.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
/*
31
 * This is a bit tricky. It's given that bh and rq are for the same
32
 * device, but the next request might of course not be. Run through
33
 * the tests below to check if we want to insert here if we can't merge
34
 * bh into an existing request
35
 */
36
inline 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
         * if the device is different (usually on a different partition),
48
         * just check if bh is after rq
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
         * ok, rq, next_rq and bh are on the same device. if bh is in between
56
         * the two, this is the sweet spot
57
         */
58
        if (bh->b_rsector < next_rq->sector && bh->b_rsector > rq->sector)
59
                return 1;
60
 
61
        /*
62
         * next_rq is ordered wrt rq, but bh is not in between the two
63
         */
64
        if (next_rq->sector > rq->sector)
65
                return 0;
66
 
67
        /*
68
         * next_rq and rq not ordered, if we happen to be either before
69
         * next_rq or after rq insert here anyway
70
         */
71
        if (bh->b_rsector > rq->sector || bh->b_rsector < next_rq->sector)
72
                return 1;
73
 
74
        return 0;
75
}
76
 
77
 
78
int 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
                 * we can't insert beyond a zero sequence point
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
         * account merge (ret != 0, cost is 1) or seeky insert (*req is set,
121
         * cost is ELV_LINUS_SEEK_COST
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
 
136
void 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
 * See if we can find a request that this buffer can be coalesced with.
144
 */
145
int 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
 
181
void elevator_noop_merge_req(struct request *req, struct request *next) {}
182
 
183
int 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
 
198
int 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
 
215
void 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.