subr_bufq.c revision 1.13.32.2 1 1.13.32.2 ad /* $NetBSD: subr_bufq.c,v 1.13.32.2 2007/07/29 12:15:46 ad Exp $ */
2 1.13.32.2 ad /* NetBSD: subr_disk.c,v 1.70 2005/08/20 12:00:01 yamt Exp $ */
3 1.13.32.2 ad
4 1.13.32.2 ad /*-
5 1.13.32.2 ad * Copyright (c) 1996, 1997, 1999, 2000 The NetBSD Foundation, Inc.
6 1.13.32.2 ad * All rights reserved.
7 1.13.32.2 ad *
8 1.13.32.2 ad * This code is derived from software contributed to The NetBSD Foundation
9 1.13.32.2 ad * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 1.13.32.2 ad * NASA Ames Research Center.
11 1.13.32.2 ad *
12 1.13.32.2 ad * Redistribution and use in source and binary forms, with or without
13 1.13.32.2 ad * modification, are permitted provided that the following conditions
14 1.13.32.2 ad * are met:
15 1.13.32.2 ad * 1. Redistributions of source code must retain the above copyright
16 1.13.32.2 ad * notice, this list of conditions and the following disclaimer.
17 1.13.32.2 ad * 2. Redistributions in binary form must reproduce the above copyright
18 1.13.32.2 ad * notice, this list of conditions and the following disclaimer in the
19 1.13.32.2 ad * documentation and/or other materials provided with the distribution.
20 1.13.32.2 ad * 3. All advertising materials mentioning features or use of this software
21 1.13.32.2 ad * must display the following acknowledgement:
22 1.13.32.2 ad * This product includes software developed by the NetBSD
23 1.13.32.2 ad * Foundation, Inc. and its contributors.
24 1.13.32.2 ad * 4. Neither the name of The NetBSD Foundation nor the names of its
25 1.13.32.2 ad * contributors may be used to endorse or promote products derived
26 1.13.32.2 ad * from this software without specific prior written permission.
27 1.13.32.2 ad *
28 1.13.32.2 ad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 1.13.32.2 ad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 1.13.32.2 ad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 1.13.32.2 ad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 1.13.32.2 ad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 1.13.32.2 ad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 1.13.32.2 ad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 1.13.32.2 ad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 1.13.32.2 ad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 1.13.32.2 ad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 1.13.32.2 ad * POSSIBILITY OF SUCH DAMAGE.
39 1.13.32.2 ad */
40 1.13.32.2 ad
41 1.13.32.2 ad /*
42 1.13.32.2 ad * Copyright (c) 1982, 1986, 1988, 1993
43 1.13.32.2 ad * The Regents of the University of California. All rights reserved.
44 1.13.32.2 ad * (c) UNIX System Laboratories, Inc.
45 1.13.32.2 ad * All or some portions of this file are derived from material licensed
46 1.13.32.2 ad * to the University of California by American Telephone and Telegraph
47 1.13.32.2 ad * Co. or Unix System Laboratories, Inc. and are reproduced herein with
48 1.13.32.2 ad * the permission of UNIX System Laboratories, Inc.
49 1.13.32.2 ad *
50 1.13.32.2 ad * Redistribution and use in source and binary forms, with or without
51 1.13.32.2 ad * modification, are permitted provided that the following conditions
52 1.13.32.2 ad * are met:
53 1.13.32.2 ad * 1. Redistributions of source code must retain the above copyright
54 1.13.32.2 ad * notice, this list of conditions and the following disclaimer.
55 1.13.32.2 ad * 2. Redistributions in binary form must reproduce the above copyright
56 1.13.32.2 ad * notice, this list of conditions and the following disclaimer in the
57 1.13.32.2 ad * documentation and/or other materials provided with the distribution.
58 1.13.32.2 ad * 3. Neither the name of the University nor the names of its contributors
59 1.13.32.2 ad * may be used to endorse or promote products derived from this software
60 1.13.32.2 ad * without specific prior written permission.
61 1.13.32.2 ad *
62 1.13.32.2 ad * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
63 1.13.32.2 ad * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
64 1.13.32.2 ad * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
65 1.13.32.2 ad * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
66 1.13.32.2 ad * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
67 1.13.32.2 ad * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
68 1.13.32.2 ad * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
69 1.13.32.2 ad * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
70 1.13.32.2 ad * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
71 1.13.32.2 ad * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
72 1.13.32.2 ad * SUCH DAMAGE.
73 1.13.32.2 ad *
74 1.13.32.2 ad * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
75 1.13.32.2 ad */
76 1.13.32.2 ad
77 1.13.32.2 ad #include <sys/cdefs.h>
78 1.13.32.2 ad __KERNEL_RCSID(0, "$NetBSD: subr_bufq.c,v 1.13.32.2 2007/07/29 12:15:46 ad Exp $");
79 1.13.32.2 ad
80 1.13.32.2 ad #include <sys/param.h>
81 1.13.32.2 ad #include <sys/systm.h>
82 1.13.32.2 ad #include <sys/buf.h>
83 1.13.32.2 ad #include <sys/bufq.h>
84 1.13.32.2 ad #include <sys/bufq_impl.h>
85 1.13.32.2 ad #include <sys/malloc.h>
86 1.13.32.2 ad #include <sys/sysctl.h>
87 1.13.32.2 ad
88 1.13.32.2 ad BUFQ_DEFINE(dummy, 0, NULL); /* so that bufq_strats won't be empty */
89 1.13.32.2 ad
90 1.13.32.2 ad #define STRAT_MATCH(id, bs) (strcmp((id), (bs)->bs_name) == 0)
91 1.13.32.2 ad
92 1.13.32.2 ad /*
93 1.13.32.2 ad * Create a device buffer queue.
94 1.13.32.2 ad */
95 1.13.32.2 ad int
96 1.13.32.2 ad bufq_alloc(struct bufq_state **bufqp, const char *strategy, int flags)
97 1.13.32.2 ad {
98 1.13.32.2 ad __link_set_decl(bufq_strats, const struct bufq_strat);
99 1.13.32.2 ad const struct bufq_strat *bsp;
100 1.13.32.2 ad const struct bufq_strat * const *it;
101 1.13.32.2 ad struct bufq_state *bufq;
102 1.13.32.2 ad int error = 0;
103 1.13.32.2 ad
104 1.13.32.2 ad KASSERT((flags & BUFQ_EXACT) == 0 || strategy != BUFQ_STRAT_ANY);
105 1.13.32.2 ad
106 1.13.32.2 ad switch (flags & BUFQ_SORT_MASK) {
107 1.13.32.2 ad case BUFQ_SORT_RAWBLOCK:
108 1.13.32.2 ad case BUFQ_SORT_CYLINDER:
109 1.13.32.2 ad break;
110 1.13.32.2 ad case 0:
111 1.13.32.2 ad /*
112 1.13.32.2 ad * for strategies which don't care about block numbers.
113 1.13.32.2 ad * eg. fcfs
114 1.13.32.2 ad */
115 1.13.32.2 ad flags |= BUFQ_SORT_RAWBLOCK;
116 1.13.32.2 ad break;
117 1.13.32.2 ad default:
118 1.13.32.2 ad panic("bufq_alloc: sort out of range");
119 1.13.32.2 ad }
120 1.13.32.2 ad
121 1.13.32.2 ad /*
122 1.13.32.2 ad * select strategy.
123 1.13.32.2 ad * if a strategy specified by flags is found, use it.
124 1.13.32.2 ad * otherwise, select one with the largest bs_prio.
125 1.13.32.2 ad */
126 1.13.32.2 ad bsp = NULL;
127 1.13.32.2 ad __link_set_foreach(it, bufq_strats) {
128 1.13.32.2 ad if ((*it) == &bufq_strat_dummy)
129 1.13.32.2 ad continue;
130 1.13.32.2 ad if (strategy != BUFQ_STRAT_ANY &&
131 1.13.32.2 ad STRAT_MATCH(strategy, (*it))) {
132 1.13.32.2 ad bsp = *it;
133 1.13.32.2 ad break;
134 1.13.32.2 ad }
135 1.13.32.2 ad if (bsp == NULL || (*it)->bs_prio > bsp->bs_prio)
136 1.13.32.2 ad bsp = *it;
137 1.13.32.2 ad }
138 1.13.32.2 ad
139 1.13.32.2 ad if (bsp == NULL) {
140 1.13.32.2 ad panic("bufq_alloc: no strategy");
141 1.13.32.2 ad }
142 1.13.32.2 ad if (strategy != BUFQ_STRAT_ANY && !STRAT_MATCH(strategy, bsp)) {
143 1.13.32.2 ad if ((flags & BUFQ_EXACT)) {
144 1.13.32.2 ad error = ENOENT;
145 1.13.32.2 ad goto out;
146 1.13.32.2 ad }
147 1.13.32.2 ad #if defined(DEBUG)
148 1.13.32.2 ad printf("bufq_alloc: '%s' is not available. using '%s'.\n",
149 1.13.32.2 ad strategy, bsp->bs_name);
150 1.13.32.2 ad #endif
151 1.13.32.2 ad }
152 1.13.32.2 ad #if defined(BUFQ_DEBUG)
153 1.13.32.2 ad /* XXX aprint? */
154 1.13.32.2 ad printf("bufq_alloc: using '%s'\n", bsp->bs_name);
155 1.13.32.2 ad #endif
156 1.13.32.2 ad
157 1.13.32.2 ad *bufqp = bufq = malloc(sizeof(*bufq), M_DEVBUF, M_WAITOK | M_ZERO);
158 1.13.32.2 ad bufq->bq_flags = flags;
159 1.13.32.2 ad bufq->bq_strat = bsp;
160 1.13.32.2 ad (*bsp->bs_initfn)(bufq);
161 1.13.32.2 ad
162 1.13.32.2 ad out:
163 1.13.32.2 ad return error;
164 1.13.32.2 ad }
165 1.13.32.2 ad
166 1.13.32.2 ad void
167 1.13.32.2 ad bufq_put(struct bufq_state *bufq, struct buf *bp)
168 1.13.32.2 ad {
169 1.13.32.2 ad
170 1.13.32.2 ad (*bufq->bq_put)(bufq, bp);
171 1.13.32.2 ad }
172 1.13.32.2 ad
173 1.13.32.2 ad struct buf *
174 1.13.32.2 ad bufq_get(struct bufq_state *bufq)
175 1.13.32.2 ad {
176 1.13.32.2 ad
177 1.13.32.2 ad return (*bufq->bq_get)(bufq, 1);
178 1.13.32.2 ad }
179 1.13.32.2 ad
180 1.13.32.2 ad struct buf *
181 1.13.32.2 ad bufq_peek(struct bufq_state *bufq)
182 1.13.32.2 ad {
183 1.13.32.2 ad
184 1.13.32.2 ad return (*bufq->bq_get)(bufq, 0);
185 1.13.32.2 ad }
186 1.13.32.2 ad
187 1.13.32.2 ad /*
188 1.13.32.2 ad * Drain a device buffer queue.
189 1.13.32.2 ad */
190 1.13.32.2 ad void
191 1.13.32.2 ad bufq_drain(struct bufq_state *bufq)
192 1.13.32.2 ad {
193 1.13.32.2 ad struct buf *bp;
194 1.13.32.2 ad
195 1.13.32.2 ad while ((bp = BUFQ_GET(bufq)) != NULL) {
196 1.13.32.2 ad bp->b_error = EIO;
197 1.13.32.2 ad bp->b_resid = bp->b_bcount;
198 1.13.32.2 ad biodone(bp);
199 1.13.32.2 ad }
200 1.13.32.2 ad }
201 1.13.32.2 ad
202 1.13.32.2 ad /*
203 1.13.32.2 ad * Destroy a device buffer queue.
204 1.13.32.2 ad */
205 1.13.32.2 ad void
206 1.13.32.2 ad bufq_free(struct bufq_state *bufq)
207 1.13.32.2 ad {
208 1.13.32.2 ad
209 1.13.32.2 ad KASSERT(bufq->bq_private != NULL);
210 1.13.32.2 ad KASSERT(BUFQ_PEEK(bufq) == NULL);
211 1.13.32.2 ad
212 1.13.32.2 ad free(bufq->bq_private, M_DEVBUF);
213 1.13.32.2 ad free(bufq, M_DEVBUF);
214 1.13.32.2 ad }
215 1.13.32.2 ad
216 1.13.32.2 ad /*
217 1.13.32.2 ad * get a strategy identifier of a buffer queue.
218 1.13.32.2 ad */
219 1.13.32.2 ad const char *
220 1.13.32.2 ad bufq_getstrategyname(struct bufq_state *bufq)
221 1.13.32.2 ad {
222 1.13.32.2 ad
223 1.13.32.2 ad return bufq->bq_strat->bs_name;
224 1.13.32.2 ad }
225 1.13.32.2 ad
226 1.13.32.2 ad /*
227 1.13.32.2 ad * move all requests on a buffer queue to another.
228 1.13.32.2 ad */
229 1.13.32.2 ad void
230 1.13.32.2 ad bufq_move(struct bufq_state *dst, struct bufq_state *src)
231 1.13.32.2 ad {
232 1.13.32.2 ad struct buf *bp;
233 1.13.32.2 ad
234 1.13.32.2 ad while ((bp = BUFQ_GET(src)) != NULL) {
235 1.13.32.2 ad BUFQ_PUT(dst, bp);
236 1.13.32.2 ad }
237 1.13.32.2 ad }
238 1.13.32.2 ad
239 1.13.32.2 ad static int
240 1.13.32.2 ad docopy(char *buf, size_t *bufoffp, size_t buflen,
241 1.13.32.2 ad const char *datap, size_t datalen)
242 1.13.32.2 ad {
243 1.13.32.2 ad int error = 0;
244 1.13.32.2 ad
245 1.13.32.2 ad if (buf != NULL && datalen > 0) {
246 1.13.32.2 ad
247 1.13.32.2 ad if (*bufoffp + datalen > buflen) {
248 1.13.32.2 ad goto out;
249 1.13.32.2 ad }
250 1.13.32.2 ad error = copyout(datap, buf + *bufoffp, datalen);
251 1.13.32.2 ad if (error) {
252 1.13.32.2 ad goto out;
253 1.13.32.2 ad }
254 1.13.32.2 ad }
255 1.13.32.2 ad out:
256 1.13.32.2 ad if (error == 0) {
257 1.13.32.2 ad *bufoffp += datalen;
258 1.13.32.2 ad }
259 1.13.32.2 ad
260 1.13.32.2 ad return error;
261 1.13.32.2 ad }
262 1.13.32.2 ad
263 1.13.32.2 ad static int
264 1.13.32.2 ad docopystr(char *buf, size_t *bufoffp, size_t buflen, const char *datap)
265 1.13.32.2 ad {
266 1.13.32.2 ad
267 1.13.32.2 ad return docopy(buf, bufoffp, buflen, datap, strlen(datap));
268 1.13.32.2 ad }
269 1.13.32.2 ad
270 1.13.32.2 ad static int
271 1.13.32.2 ad docopynul(char *buf, size_t *bufoffp, size_t buflen)
272 1.13.32.2 ad {
273 1.13.32.2 ad
274 1.13.32.2 ad return docopy(buf, bufoffp, buflen, "", 1);
275 1.13.32.2 ad }
276 1.13.32.2 ad
277 1.13.32.2 ad /*
278 1.13.32.2 ad * sysctl function that will print all bufq strategies
279 1.13.32.2 ad * built in the kernel.
280 1.13.32.2 ad */
281 1.13.32.2 ad static int
282 1.13.32.2 ad sysctl_kern_bufq_strategies(SYSCTLFN_ARGS)
283 1.13.32.2 ad {
284 1.13.32.2 ad __link_set_decl(bufq_strats, const struct bufq_strat);
285 1.13.32.2 ad const struct bufq_strat * const *bq_strat;
286 1.13.32.2 ad const char *delim = "";
287 1.13.32.2 ad size_t off = 0;
288 1.13.32.2 ad size_t buflen = *oldlenp;
289 1.13.32.2 ad int error;
290 1.13.32.2 ad
291 1.13.32.2 ad __link_set_foreach(bq_strat, bufq_strats) {
292 1.13.32.2 ad if ((*bq_strat) == &bufq_strat_dummy) {
293 1.13.32.2 ad continue;
294 1.13.32.2 ad }
295 1.13.32.2 ad error = docopystr(oldp, &off, buflen, delim);
296 1.13.32.2 ad if (error) {
297 1.13.32.2 ad goto out;
298 1.13.32.2 ad }
299 1.13.32.2 ad error = docopystr(oldp, &off, buflen, (*bq_strat)->bs_name);
300 1.13.32.2 ad if (error) {
301 1.13.32.2 ad goto out;
302 1.13.32.2 ad }
303 1.13.32.2 ad delim = " ";
304 1.13.32.2 ad }
305 1.13.32.2 ad
306 1.13.32.2 ad /* NUL terminate */
307 1.13.32.2 ad error = docopynul(oldp, &off, buflen);
308 1.13.32.2 ad out:
309 1.13.32.2 ad *oldlenp = off;
310 1.13.32.2 ad return error;
311 1.13.32.2 ad }
312 1.13.32.2 ad
313 1.13.32.2 ad SYSCTL_SETUP(sysctl_kern_bufq_strategies_setup, "sysctl kern.bufq tree setup")
314 1.13.32.2 ad {
315 1.13.32.2 ad const struct sysctlnode *node;
316 1.13.32.2 ad
317 1.13.32.2 ad sysctl_createv(clog, 0, NULL, NULL,
318 1.13.32.2 ad CTLFLAG_PERMANENT,
319 1.13.32.2 ad CTLTYPE_NODE, "kern", NULL,
320 1.13.32.2 ad NULL, 0, NULL, 0,
321 1.13.32.2 ad CTL_KERN, CTL_EOL);
322 1.13.32.2 ad node = NULL;
323 1.13.32.2 ad sysctl_createv(clog, 0, NULL, &node,
324 1.13.32.2 ad CTLFLAG_PERMANENT,
325 1.13.32.2 ad CTLTYPE_NODE, "bufq",
326 1.13.32.2 ad SYSCTL_DESCR("buffer queue subtree"),
327 1.13.32.2 ad NULL, 0, NULL, 0,
328 1.13.32.2 ad CTL_KERN, CTL_CREATE, CTL_EOL);
329 1.13.32.2 ad if (node != NULL) {
330 1.13.32.2 ad sysctl_createv(clog, 0, NULL, NULL,
331 1.13.32.2 ad CTLFLAG_PERMANENT,
332 1.13.32.2 ad CTLTYPE_STRING, "strategies",
333 1.13.32.2 ad SYSCTL_DESCR("List of bufq strategies present"),
334 1.13.32.2 ad sysctl_kern_bufq_strategies, 0, NULL, 0,
335 1.13.32.2 ad CTL_KERN, node->sysctl_num, CTL_CREATE, CTL_EOL);
336 1.13.32.2 ad }
337 1.13.32.2 ad }
338