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