subr_bufq.c revision 1.26.4.1 1 1.26.4.1 christos /* $NetBSD: subr_bufq.c,v 1.26.4.1 2019/06/10 22:09:03 christos 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.26.4.1 christos __KERNEL_RCSID(0, "$NetBSD: subr_bufq.c,v 1.26.4.1 2019/06/10 22:09:03 christos 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.26.4.1 christos char strategy_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.26 pgoyette /* Try to autoload the bufq strategy module */
182 1.26.4.1 christos strlcpy(strategy_module_name, "bufq_",
183 1.26.4.1 christos sizeof(strategy_module_name));
184 1.26.4.1 christos strlcat(strategy_module_name, strategy,
185 1.26.4.1 christos sizeof(strategy_module_name));
186 1.22 pgoyette mutex_exit(&bufq_mutex);
187 1.26.4.1 christos (void) module_autoload(strategy_module_name, MODULE_CLASS_BUFQ);
188 1.22 pgoyette mutex_enter(&bufq_mutex);
189 1.22 pgoyette } while (gen != module_gen);
190 1.1 yamt
191 1.1 yamt if (bsp == NULL) {
192 1.1 yamt panic("bufq_alloc: no strategy");
193 1.1 yamt }
194 1.22 pgoyette if (strategy != BUFQ_STRAT_ANY && !found_exact) {
195 1.1 yamt if ((flags & BUFQ_EXACT)) {
196 1.1 yamt error = ENOENT;
197 1.22 pgoyette mutex_exit(&bufq_mutex);
198 1.1 yamt goto out;
199 1.1 yamt }
200 1.1 yamt #if defined(DEBUG)
201 1.1 yamt printf("bufq_alloc: '%s' is not available. using '%s'.\n",
202 1.1 yamt strategy, bsp->bs_name);
203 1.1 yamt #endif
204 1.1 yamt }
205 1.1 yamt #if defined(BUFQ_DEBUG)
206 1.1 yamt /* XXX aprint? */
207 1.1 yamt printf("bufq_alloc: using '%s'\n", bsp->bs_name);
208 1.1 yamt #endif
209 1.1 yamt
210 1.22 pgoyette bsp->bs_refcnt++;
211 1.22 pgoyette mutex_exit(&bufq_mutex);
212 1.18 yamt *bufqp = bufq = kmem_zalloc(sizeof(*bufq), KM_SLEEP);
213 1.1 yamt bufq->bq_flags = flags;
214 1.5 yamt bufq->bq_strat = bsp;
215 1.1 yamt (*bsp->bs_initfn)(bufq);
216 1.1 yamt
217 1.1 yamt out:
218 1.11 yamt return error;
219 1.1 yamt }
220 1.1 yamt
221 1.1 yamt void
222 1.1 yamt bufq_put(struct bufq_state *bufq, struct buf *bp)
223 1.1 yamt {
224 1.1 yamt
225 1.1 yamt (*bufq->bq_put)(bufq, bp);
226 1.1 yamt }
227 1.1 yamt
228 1.1 yamt struct buf *
229 1.1 yamt bufq_get(struct bufq_state *bufq)
230 1.1 yamt {
231 1.1 yamt
232 1.1 yamt return (*bufq->bq_get)(bufq, 1);
233 1.1 yamt }
234 1.1 yamt
235 1.1 yamt struct buf *
236 1.1 yamt bufq_peek(struct bufq_state *bufq)
237 1.1 yamt {
238 1.1 yamt
239 1.1 yamt return (*bufq->bq_get)(bufq, 0);
240 1.1 yamt }
241 1.1 yamt
242 1.15 reinoud struct buf *
243 1.15 reinoud bufq_cancel(struct bufq_state *bufq, struct buf *bp)
244 1.15 reinoud {
245 1.17 yamt
246 1.15 reinoud return (*bufq->bq_cancel)(bufq, bp);
247 1.15 reinoud }
248 1.15 reinoud
249 1.1 yamt /*
250 1.1 yamt * Drain a device buffer queue.
251 1.1 yamt */
252 1.1 yamt void
253 1.1 yamt bufq_drain(struct bufq_state *bufq)
254 1.1 yamt {
255 1.1 yamt struct buf *bp;
256 1.1 yamt
257 1.16 yamt while ((bp = bufq_get(bufq)) != NULL) {
258 1.1 yamt bp->b_error = EIO;
259 1.1 yamt bp->b_resid = bp->b_bcount;
260 1.1 yamt biodone(bp);
261 1.1 yamt }
262 1.1 yamt }
263 1.1 yamt
264 1.1 yamt /*
265 1.1 yamt * Destroy a device buffer queue.
266 1.1 yamt */
267 1.1 yamt void
268 1.1 yamt bufq_free(struct bufq_state *bufq)
269 1.1 yamt {
270 1.1 yamt
271 1.16 yamt KASSERT(bufq_peek(bufq) == NULL);
272 1.1 yamt
273 1.18 yamt bufq->bq_fini(bufq);
274 1.22 pgoyette
275 1.22 pgoyette mutex_enter(&bufq_mutex);
276 1.22 pgoyette bufq->bq_strat->bs_refcnt--;
277 1.22 pgoyette mutex_exit(&bufq_mutex);
278 1.22 pgoyette
279 1.18 yamt kmem_free(bufq, sizeof(*bufq));
280 1.1 yamt }
281 1.2 xtraeme
282 1.5 yamt /*
283 1.5 yamt * get a strategy identifier of a buffer queue.
284 1.5 yamt */
285 1.5 yamt const char *
286 1.5 yamt bufq_getstrategyname(struct bufq_state *bufq)
287 1.5 yamt {
288 1.5 yamt
289 1.5 yamt return bufq->bq_strat->bs_name;
290 1.5 yamt }
291 1.5 yamt
292 1.5 yamt /*
293 1.5 yamt * move all requests on a buffer queue to another.
294 1.5 yamt */
295 1.5 yamt void
296 1.5 yamt bufq_move(struct bufq_state *dst, struct bufq_state *src)
297 1.5 yamt {
298 1.5 yamt struct buf *bp;
299 1.5 yamt
300 1.16 yamt while ((bp = bufq_get(src)) != NULL) {
301 1.16 yamt bufq_put(dst, bp);
302 1.5 yamt }
303 1.5 yamt }
304 1.5 yamt
305 1.8 yamt static int
306 1.8 yamt docopy(char *buf, size_t *bufoffp, size_t buflen,
307 1.8 yamt const char *datap, size_t datalen)
308 1.8 yamt {
309 1.8 yamt int error = 0;
310 1.8 yamt
311 1.8 yamt if (buf != NULL && datalen > 0) {
312 1.8 yamt
313 1.8 yamt if (*bufoffp + datalen > buflen) {
314 1.8 yamt goto out;
315 1.8 yamt }
316 1.8 yamt error = copyout(datap, buf + *bufoffp, datalen);
317 1.8 yamt if (error) {
318 1.8 yamt goto out;
319 1.8 yamt }
320 1.8 yamt }
321 1.8 yamt out:
322 1.8 yamt if (error == 0) {
323 1.8 yamt *bufoffp += datalen;
324 1.8 yamt }
325 1.8 yamt
326 1.8 yamt return error;
327 1.8 yamt }
328 1.8 yamt
329 1.8 yamt static int
330 1.8 yamt docopystr(char *buf, size_t *bufoffp, size_t buflen, const char *datap)
331 1.8 yamt {
332 1.8 yamt
333 1.8 yamt return docopy(buf, bufoffp, buflen, datap, strlen(datap));
334 1.8 yamt }
335 1.8 yamt
336 1.8 yamt static int
337 1.8 yamt docopynul(char *buf, size_t *bufoffp, size_t buflen)
338 1.8 yamt {
339 1.8 yamt
340 1.8 yamt return docopy(buf, bufoffp, buflen, "", 1);
341 1.8 yamt }
342 1.8 yamt
343 1.2 xtraeme /*
344 1.2 xtraeme * sysctl function that will print all bufq strategies
345 1.22 pgoyette * currently available to the kernel.
346 1.2 xtraeme */
347 1.2 xtraeme static int
348 1.2 xtraeme sysctl_kern_bufq_strategies(SYSCTLFN_ARGS)
349 1.2 xtraeme {
350 1.22 pgoyette const struct bufq_strat *bq_strat;
351 1.8 yamt const char *delim = "";
352 1.8 yamt size_t off = 0;
353 1.8 yamt size_t buflen = *oldlenp;
354 1.8 yamt int error;
355 1.2 xtraeme
356 1.22 pgoyette SLIST_FOREACH(bq_strat, &bufq_strat_list, bs_next) {
357 1.8 yamt error = docopystr(oldp, &off, buflen, delim);
358 1.8 yamt if (error) {
359 1.8 yamt goto out;
360 1.8 yamt }
361 1.22 pgoyette error = docopystr(oldp, &off, buflen, (bq_strat)->bs_name);
362 1.8 yamt if (error) {
363 1.8 yamt goto out;
364 1.8 yamt }
365 1.8 yamt delim = " ";
366 1.2 xtraeme }
367 1.8 yamt
368 1.22 pgoyette /* In case there are no registered strategies ... */
369 1.22 pgoyette if (off == 0) {
370 1.22 pgoyette error = docopystr(oldp, &off, buflen, "NULL");
371 1.22 pgoyette if (error) {
372 1.22 pgoyette goto out;
373 1.22 pgoyette }
374 1.22 pgoyette }
375 1.22 pgoyette
376 1.8 yamt /* NUL terminate */
377 1.8 yamt error = docopynul(oldp, &off, buflen);
378 1.8 yamt out:
379 1.8 yamt *oldlenp = off;
380 1.2 xtraeme return error;
381 1.2 xtraeme }
382 1.2 xtraeme
383 1.19 pooka static void
384 1.19 pooka sysctl_kern_bufq_strategies_setup(struct sysctllog **clog)
385 1.2 xtraeme {
386 1.2 xtraeme const struct sysctlnode *node;
387 1.2 xtraeme
388 1.2 xtraeme node = NULL;
389 1.2 xtraeme sysctl_createv(clog, 0, NULL, &node,
390 1.2 xtraeme CTLFLAG_PERMANENT,
391 1.2 xtraeme CTLTYPE_NODE, "bufq",
392 1.2 xtraeme SYSCTL_DESCR("buffer queue subtree"),
393 1.2 xtraeme NULL, 0, NULL, 0,
394 1.2 xtraeme CTL_KERN, CTL_CREATE, CTL_EOL);
395 1.2 xtraeme if (node != NULL) {
396 1.2 xtraeme sysctl_createv(clog, 0, NULL, NULL,
397 1.2 xtraeme CTLFLAG_PERMANENT,
398 1.2 xtraeme CTLTYPE_STRING, "strategies",
399 1.2 xtraeme SYSCTL_DESCR("List of bufq strategies present"),
400 1.2 xtraeme sysctl_kern_bufq_strategies, 0, NULL, 0,
401 1.2 xtraeme CTL_KERN, node->sysctl_num, CTL_CREATE, CTL_EOL);
402 1.2 xtraeme }
403 1.2 xtraeme }
404