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