1 /* $NetBSD: subr_bufq.c,v 1.13 2007/07/29 12:15:45 ad 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.13 2007/07/29 12:15:45 ad 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_resid = bp->b_bcount; 198 biodone(bp); 199 } 200 } 201 202 /* 203 * Destroy a device buffer queue. 204 */ 205 void 206 bufq_free(struct bufq_state *bufq) 207 { 208 209 KASSERT(bufq->bq_private != NULL); 210 KASSERT(BUFQ_PEEK(bufq) == NULL); 211 212 free(bufq->bq_private, M_DEVBUF); 213 free(bufq, M_DEVBUF); 214 } 215 216 /* 217 * get a strategy identifier of a buffer queue. 218 */ 219 const char * 220 bufq_getstrategyname(struct bufq_state *bufq) 221 { 222 223 return bufq->bq_strat->bs_name; 224 } 225 226 /* 227 * move all requests on a buffer queue to another. 228 */ 229 void 230 bufq_move(struct bufq_state *dst, struct bufq_state *src) 231 { 232 struct buf *bp; 233 234 while ((bp = BUFQ_GET(src)) != NULL) { 235 BUFQ_PUT(dst, bp); 236 } 237 } 238 239 static int 240 docopy(char *buf, size_t *bufoffp, size_t buflen, 241 const char *datap, size_t datalen) 242 { 243 int error = 0; 244 245 if (buf != NULL && datalen > 0) { 246 247 if (*bufoffp + datalen > buflen) { 248 goto out; 249 } 250 error = copyout(datap, buf + *bufoffp, datalen); 251 if (error) { 252 goto out; 253 } 254 } 255 out: 256 if (error == 0) { 257 *bufoffp += datalen; 258 } 259 260 return error; 261 } 262 263 static int 264 docopystr(char *buf, size_t *bufoffp, size_t buflen, const char *datap) 265 { 266 267 return docopy(buf, bufoffp, buflen, datap, strlen(datap)); 268 } 269 270 static int 271 docopynul(char *buf, size_t *bufoffp, size_t buflen) 272 { 273 274 return docopy(buf, bufoffp, buflen, "", 1); 275 } 276 277 /* 278 * sysctl function that will print all bufq strategies 279 * built in the kernel. 280 */ 281 static int 282 sysctl_kern_bufq_strategies(SYSCTLFN_ARGS) 283 { 284 __link_set_decl(bufq_strats, const struct bufq_strat); 285 const struct bufq_strat * const *bq_strat; 286 const char *delim = ""; 287 size_t off = 0; 288 size_t buflen = *oldlenp; 289 int error; 290 291 __link_set_foreach(bq_strat, bufq_strats) { 292 if ((*bq_strat) == &bufq_strat_dummy) { 293 continue; 294 } 295 error = docopystr(oldp, &off, buflen, delim); 296 if (error) { 297 goto out; 298 } 299 error = docopystr(oldp, &off, buflen, (*bq_strat)->bs_name); 300 if (error) { 301 goto out; 302 } 303 delim = " "; 304 } 305 306 /* NUL terminate */ 307 error = docopynul(oldp, &off, buflen); 308 out: 309 *oldlenp = off; 310 return error; 311 } 312 313 SYSCTL_SETUP(sysctl_kern_bufq_strategies_setup, "sysctl kern.bufq tree setup") 314 { 315 const struct sysctlnode *node; 316 317 sysctl_createv(clog, 0, NULL, NULL, 318 CTLFLAG_PERMANENT, 319 CTLTYPE_NODE, "kern", NULL, 320 NULL, 0, NULL, 0, 321 CTL_KERN, CTL_EOL); 322 node = NULL; 323 sysctl_createv(clog, 0, NULL, &node, 324 CTLFLAG_PERMANENT, 325 CTLTYPE_NODE, "bufq", 326 SYSCTL_DESCR("buffer queue subtree"), 327 NULL, 0, NULL, 0, 328 CTL_KERN, CTL_CREATE, CTL_EOL); 329 if (node != NULL) { 330 sysctl_createv(clog, 0, NULL, NULL, 331 CTLFLAG_PERMANENT, 332 CTLTYPE_STRING, "strategies", 333 SYSCTL_DESCR("List of bufq strategies present"), 334 sysctl_kern_bufq_strategies, 0, NULL, 0, 335 CTL_KERN, node->sysctl_num, CTL_CREATE, CTL_EOL); 336 } 337 } 338