1/*- 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * (c) UNIX System Laboratories, Inc. 5 * All or some portions of this file are derived from material licensed 6 * to the University of California by American Telephone and Telegraph 7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with 8 * the permission of UNIX System Laboratories, Inc.
| 1/* 2 * Copyright (c) 1994 John S. Dyson 3 * All rights reserved.
|
9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright
| 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright
|
14 * notice, this list of conditions and the following disclaimer.
| 9 * notice immediately at the beginning of the file, without modification, 10 * this list of conditions, and the following disclaimer.
|
15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution.
| 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution.
|
18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * from: @(#)vfs_bio.c 8.6 (Berkeley) 1/11/94
| 14 * 3. Absolutely no warranty of function or purpose is made by the author 15 * John S. Dyson. 16 * 4. Modifications may be freely made to this file if the above conditions 17 * are met.
|
39 */ 40 41#include <sys/param.h> 42#include <sys/systm.h>
| 18 */ 19 20#include <sys/param.h> 21#include <sys/systm.h>
|
| 22#include <sys/kernel.h>
|
43#include <sys/proc.h>
| 23#include <sys/proc.h>
|
44#include <sys/buf.h>
| |
45#include <sys/vnode.h>
| 24#include <sys/vnode.h>
|
| 25#include <sys/buf.h>
|
46#include <sys/mount.h>
| 26#include <sys/mount.h>
|
47#include <sys/trace.h>
| |
48#include <sys/malloc.h> 49#include <sys/resourcevar.h>
| 27#include <sys/malloc.h> 28#include <sys/resourcevar.h>
|
| 29#include <vm/vm.h> 30#include <vm/vm_pageout.h>
|
50
| 31
|
| 32#include <miscfs/specfs/specdev.h> 33 34struct buf *buf; /* the buffer pool itself */ 35int nbuf; /* number of buffer headers */ 36int bufpages; /* number of memory pages in the buffer pool */ 37struct buf *swbuf; /* swap I/O headers */ 38int nswbuf; 39#define BUFHSZ 512 40int bufhash = BUFHSZ - 1; 41 42struct buf *getnewbuf(int,int); 43extern vm_map_t buffer_map, io_map; 44void vm_hold_free_pages(vm_offset_t from, vm_offset_t to); 45void vm_hold_load_pages(vm_offset_t from, vm_offset_t to);
|
51/* 52 * Definitions for the buffer hash lists. 53 */ 54#define BUFHASH(dvp, lbn) \ 55 (&bufhashtbl[((int)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash])
| 46/* 47 * Definitions for the buffer hash lists. 48 */ 49#define BUFHASH(dvp, lbn) \ 50 (&bufhashtbl[((int)(dvp) / sizeof(*(dvp)) + (int)(lbn)) & bufhash])
|
56LIST_HEAD(bufhashhdr, buf) *bufhashtbl, invalhash; 57u_long bufhash;
| |
58 59/*
| 51 52/*
|
60 * Insq/Remq for the buffer hash lists. 61 */ 62#define binshash(bp, dp) LIST_INSERT_HEAD(dp, bp, b_hash) 63#define bremhash(bp) LIST_REMOVE(bp, b_hash) 64 65/*
| |
66 * Definitions for the buffer free lists. 67 */
| 53 * Definitions for the buffer free lists. 54 */
|
68#define BQUEUES 4 /* number of free buffer queues */
| 55#define BQUEUES 5 /* number of free buffer queues */
|
69
| 56
|
70#define BQ_LOCKED 0 /* super-blocks &c */ 71#define BQ_LRU 1 /* lru, useful buffers */ 72#define BQ_AGE 2 /* rubbish */ 73#define BQ_EMPTY 3 /* buffer headers with no memory */ 74
| 57LIST_HEAD(bufhashhdr, buf) bufhashtbl[BUFHSZ], invalhash;
|
75TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
| 58TAILQ_HEAD(bqueues, buf) bufqueues[BQUEUES];
|
76int needbuffer;
| |
77
| 59
|
| 60#define BQ_NONE 0 /* on no queue */ 61#define BQ_LOCKED 1 /* locked buffers */ 62#define BQ_LRU 2 /* useful buffers */ 63#define BQ_AGE 3 /* less useful buffers */ 64#define BQ_EMPTY 4 /* empty buffer headers*/ 65 66int needsbuffer; 67
|
78/*
| 68/*
|
79 * Insq/Remq for the buffer free lists.
| 69 * Internal update daemon, process 3 70 * The variable vfs_update_wakeup allows for internal syncs.
|
80 */
| 71 */
|
81#define binsheadfree(bp, dp) TAILQ_INSERT_HEAD(dp, bp, b_freelist) 82#define binstailfree(bp, dp) TAILQ_INSERT_TAIL(dp, bp, b_freelist)
| 72int vfs_update_wakeup;
|
83
| 73
|
84void 85bremfree(bp) 86 struct buf *bp; 87{ 88 struct bqueues *dp = NULL; 89 90 /* 91 * We only calculate the head of the freelist when removing 92 * the last element of the list as that is the only time that 93 * it is needed (e.g. to reset the tail pointer). 94 * 95 * NB: This makes an assumption about how tailq's are implemented. 96 */ 97 if (bp->b_freelist.tqe_next == NULL) { 98 for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++) 99 if (dp->tqh_last == &bp->b_freelist.tqe_next) 100 break; 101 if (dp == &bufqueues[BQUEUES]) 102 panic("bremfree: lost tail"); 103 } 104 TAILQ_REMOVE(dp, bp, b_freelist); 105} 106
| |
107/*
| 74/*
|
108 * Initialize buffers and hash links for buffers.
| 75 * Initialize buffer headers and related structures.
|
109 */
| 76 */
|
110void 111bufinit()
| 77void bufinit()
|
112{
| 78{
|
113 register struct buf *bp; 114 struct bqueues *dp; 115 register int i; 116 int base, residual;
| 79 struct buf *bp; 80 int i;
|
117
| 81
|
118 for (dp = bufqueues; dp < &bufqueues[BQUEUES]; dp++) 119 TAILQ_INIT(dp); 120 bufhashtbl = hashinit(nbuf, M_CACHE, &bufhash); 121 base = bufpages / nbuf; 122 residual = bufpages % nbuf; 123 for (i = 0; i < nbuf; i++) {
| 82 TAILQ_INIT(&bswlist); 83 LIST_INIT(&invalhash); 84 85 /* first, make a null hash table */ 86 for(i=0;i<BUFHSZ;i++) 87 LIST_INIT(&bufhashtbl[i]); 88 89 /* next, make a null set of free lists */ 90 for(i=0;i<BQUEUES;i++) 91 TAILQ_INIT(&bufqueues[i]); 92 93 /* finally, initialize each buffer header and stick on empty q */ 94 for(i=0;i<nbuf;i++) {
|
124 bp = &buf[i];
| 95 bp = &buf[i];
|
125 bzero((char *)bp, sizeof *bp);
| 96 bzero(bp, sizeof *bp); 97 bp->b_flags = B_INVAL; /* we're just an empty header */
|
126 bp->b_dev = NODEV;
| 98 bp->b_dev = NODEV;
|
| 99 bp->b_vp = NULL;
|
127 bp->b_rcred = NOCRED; 128 bp->b_wcred = NOCRED;
| 100 bp->b_rcred = NOCRED; 101 bp->b_wcred = NOCRED;
|
| 102 bp->b_qindex = BQ_EMPTY;
|
129 bp->b_vnbufs.le_next = NOLIST;
| 103 bp->b_vnbufs.le_next = NOLIST;
|
130 bp->b_data = buffers + i * MAXBSIZE; 131 if (i < residual) 132 bp->b_bufsize = (base + 1) * CLBYTES; 133 else 134 bp->b_bufsize = base * CLBYTES; 135 bp->b_flags = B_INVAL; 136 dp = bp->b_bufsize ? &bufqueues[BQ_AGE] : &bufqueues[BQ_EMPTY]; 137 binsheadfree(bp, dp); 138 binshash(bp, &invalhash);
| 104 bp->b_data = (caddr_t)kmem_alloc_pageable(buffer_map, MAXBSIZE); 105 TAILQ_INSERT_TAIL(&bufqueues[BQ_EMPTY], bp, b_freelist); 106 LIST_INSERT_HEAD(&invalhash, bp, b_hash);
|
139 } 140} 141
| 107 } 108} 109
|
142bread(a1, a2, a3, a4, a5) 143 struct vnode *a1; 144 daddr_t a2; 145 int a3; 146 struct ucred *a4; 147 struct buf **a5;
| 110/* 111 * remove the buffer from the appropriate free list 112 */ 113void 114bremfree(struct buf *bp)
|
148{
| 115{
|
| 116 int s = splbio(); 117 if( bp->b_qindex != BQ_NONE) { 118 TAILQ_REMOVE(&bufqueues[bp->b_qindex], bp, b_freelist); 119 bp->b_qindex = BQ_NONE; 120 } else { 121 panic("bremfree: removing a buffer when not on a queue"); 122 } 123 splx(s); 124}
|
149
| 125
|
150 /* 151 * Body deleted. 152 */ 153 return (EIO);
| 126/* 127 * Get a buffer with the specified data. Look in the cache first. 128 */ 129int 130bread(struct vnode *vp, daddr_t blkno, int size, struct ucred *cred, 131 struct buf **bpp) 132{ 133 struct buf *bp; 134 135 bp = getblk (vp, blkno, size, 0, 0); 136 *bpp = bp; 137 138 /* if not found in cache, do some I/O */ 139 if ((bp->b_flags & B_CACHE) == 0) { 140 if (curproc && curproc->p_stats) /* count block I/O */ 141 curproc->p_stats->p_ru.ru_inblock++; 142 bp->b_flags |= B_READ; 143 bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); 144 if( bp->b_rcred == NOCRED) { 145 if (cred != NOCRED) 146 crhold(cred); 147 bp->b_rcred = cred; 148 } 149 VOP_STRATEGY(bp); 150 return( biowait (bp)); 151 } 152 153 return (0);
|
154} 155
| 154} 155
|
156breadn(a1, a2, a3, a4, a5, a6, a7, a8) 157 struct vnode *a1; 158 daddr_t a2; int a3; 159 daddr_t a4[]; int a5[]; 160 int a6; 161 struct ucred *a7; 162 struct buf **a8;
| 156/* 157 * Operates like bread, but also starts asynchronous I/O on 158 * read-ahead blocks. 159 */ 160int 161breadn(struct vnode *vp, daddr_t blkno, int size, 162 daddr_t *rablkno, int *rabsize, 163 int cnt, struct ucred *cred, struct buf **bpp)
|
163{
| 164{
|
| 165 struct buf *bp, *rabp; 166 int i; 167 int rv = 0, readwait = 0;
|
164
| 168
|
165 /* 166 * Body deleted. 167 */ 168 return (EIO);
| 169 *bpp = bp = getblk (vp, blkno, size, 0, 0); 170 171 /* if not found in cache, do some I/O */ 172 if ((bp->b_flags & B_CACHE) == 0) { 173 if (curproc && curproc->p_stats) /* count block I/O */ 174 curproc->p_stats->p_ru.ru_inblock++; 175 bp->b_flags |= B_READ; 176 bp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); 177 if( bp->b_rcred == NOCRED) { 178 if (cred != NOCRED) 179 crhold(cred); 180 bp->b_rcred = cred; 181 } 182 VOP_STRATEGY(bp); 183 ++readwait; 184 } 185 186 for(i=0;i<cnt;i++, rablkno++, rabsize++) { 187 if( incore(vp, *rablkno)) { 188 continue; 189 } 190 rabp = getblk (vp, *rablkno, *rabsize, 0, 0); 191 192 if ((rabp->b_flags & B_CACHE) == 0) { 193 if (curproc && curproc->p_stats) 194 curproc->p_stats->p_ru.ru_inblock++; 195 rabp->b_flags |= B_READ | B_ASYNC; 196 rabp->b_flags &= ~(B_DONE|B_ERROR|B_INVAL); 197 if( rabp->b_rcred == NOCRED) { 198 if (cred != NOCRED) 199 crhold(cred); 200 rabp->b_rcred = cred; 201 } 202 VOP_STRATEGY(rabp); 203 } else { 204 brelse(rabp); 205 } 206 } 207 208 if( readwait) { 209 rv = biowait (bp); 210 } 211 212 return (rv);
|
169} 170
| 213} 214
|
171bwrite(a1) 172 struct buf *a1;
| 215/* 216 * Write, release buffer on completion. (Done by iodone 217 * if async.) 218 */ 219int 220bwrite(struct buf *bp)
|
173{
| 221{
|
| 222 int oldflags = bp->b_flags;
|
174
| 223
|
175 /* 176 * Body deleted. 177 */ 178 return (EIO);
| 224 if(bp->b_flags & B_INVAL) { 225 brelse(bp); 226 return (0); 227 } 228 229 if(!(bp->b_flags & B_BUSY)) 230 panic("bwrite: buffer is not busy???"); 231 232 bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI); 233 bp->b_flags |= B_WRITEINPROG; 234 235 if (oldflags & B_ASYNC) { 236 if (oldflags & B_DELWRI) { 237 reassignbuf(bp, bp->b_vp); 238 } else if( curproc) { 239 ++curproc->p_stats->p_ru.ru_oublock; 240 } 241 } 242 243 bp->b_vp->v_numoutput++; 244 VOP_STRATEGY(bp); 245 246 if( (oldflags & B_ASYNC) == 0) { 247 int rtval = biowait(bp); 248 if (oldflags & B_DELWRI) { 249 reassignbuf(bp, bp->b_vp); 250 } else if( curproc) { 251 ++curproc->p_stats->p_ru.ru_oublock; 252 } 253 brelse(bp); 254 return (rtval); 255 } 256 257 return(0);
|
179} 180 181int 182vn_bwrite(ap) 183 struct vop_bwrite_args *ap; 184{ 185 return (bwrite(ap->a_bp)); 186} 187
| 258} 259 260int 261vn_bwrite(ap) 262 struct vop_bwrite_args *ap; 263{ 264 return (bwrite(ap->a_bp)); 265} 266
|
188bdwrite(a1) 189 struct buf *a1;
| 267/* 268 * Delayed write. (Buffer is marked dirty). 269 */ 270void 271bdwrite(struct buf *bp)
|
190{ 191
| 272{ 273
|
192 /* 193 * Body deleted. 194 */
| 274 if((bp->b_flags & B_BUSY) == 0) { 275 panic("bdwrite: buffer is not busy"); 276 } 277 278 if(bp->b_flags & B_INVAL) { 279 brelse(bp); 280 return; 281 } 282 283 if(bp->b_flags & B_TAPE) { 284 bawrite(bp); 285 return; 286 } 287 288 bp->b_flags &= ~B_READ; 289 if( (bp->b_flags & B_DELWRI) == 0) { 290 if( curproc) 291 ++curproc->p_stats->p_ru.ru_oublock; 292 bp->b_flags |= B_DONE|B_DELWRI; 293 reassignbuf(bp, bp->b_vp); 294 } 295 brelse(bp);
|
195 return; 196} 197
| 296 return; 297} 298
|
198bawrite(a1) 199 struct buf *a1;
| 299/* 300 * Asynchronous write. 301 * Start output on a buffer, but do not wait for it to complete. 302 * The buffer is released when the output completes. 303 */ 304void 305bawrite(struct buf *bp)
|
200{
| 306{
|
201 202 /* 203 * Body deleted. 204 */ 205 return;
| 307 bp->b_flags |= B_ASYNC; 308 (void) bwrite(bp);
|
206} 207
| 309} 310
|
208brelse(a1) 209 struct buf *a1;
| 311/* 312 * Release a buffer. 313 */ 314void 315brelse(struct buf *bp)
|
210{
| 316{
|
| 317 int x;
|
211
| 318
|
212 /* 213 * Body deleted. 214 */ 215 return;
| 319 /* anyone need a "free" block? */ 320 x=splbio(); 321 if (needsbuffer) { 322 needsbuffer = 0; 323 wakeup((caddr_t)&needsbuffer); 324 } 325 /* anyone need this very block? */ 326 if (bp->b_flags & B_WANTED) { 327 bp->b_flags &= ~(B_WANTED|B_AGE); 328 wakeup((caddr_t)bp); 329 } 330 331 if (bp->b_flags & B_LOCKED) 332 bp->b_flags &= ~B_ERROR; 333 334 if ((bp->b_flags & (B_NOCACHE|B_INVAL|B_ERROR)) || 335 (bp->b_bufsize <= 0)) { 336 bp->b_flags |= B_INVAL; 337 bp->b_flags &= ~(B_DELWRI|B_CACHE); 338 if(bp->b_vp) 339 brelvp(bp); 340 } 341 342 if( bp->b_qindex != BQ_NONE) 343 panic("brelse: free buffer onto another queue???"); 344 345 /* enqueue */ 346 /* buffers with junk contents */ 347 if(bp->b_bufsize == 0) { 348 bp->b_qindex = BQ_EMPTY; 349 TAILQ_INSERT_HEAD(&bufqueues[BQ_EMPTY], bp, b_freelist); 350 LIST_REMOVE(bp, b_hash); 351 LIST_INSERT_HEAD(&invalhash, bp, b_hash); 352 bp->b_dev = NODEV; 353 } else if(bp->b_flags & (B_ERROR|B_INVAL|B_NOCACHE)) { 354 bp->b_qindex = BQ_AGE; 355 TAILQ_INSERT_HEAD(&bufqueues[BQ_AGE], bp, b_freelist); 356 LIST_REMOVE(bp, b_hash); 357 LIST_INSERT_HEAD(&invalhash, bp, b_hash); 358 bp->b_dev = NODEV; 359 /* buffers that are locked */ 360 } else if(bp->b_flags & B_LOCKED) { 361 bp->b_qindex = BQ_LOCKED; 362 TAILQ_INSERT_TAIL(&bufqueues[BQ_LOCKED], bp, b_freelist); 363 /* buffers with stale but valid contents */ 364 } else if(bp->b_flags & B_AGE) { 365 bp->b_qindex = BQ_AGE; 366 TAILQ_INSERT_TAIL(&bufqueues[BQ_AGE], bp, b_freelist); 367 /* buffers with valid and quite potentially reuseable contents */ 368 } else { 369 bp->b_qindex = BQ_LRU; 370 TAILQ_INSERT_TAIL(&bufqueues[BQ_LRU], bp, b_freelist); 371 } 372 373 /* unlock */ 374 bp->b_flags &= ~(B_WANTED|B_BUSY|B_ASYNC|B_NOCACHE|B_AGE); 375 splx(x);
|
216} 217
| 376} 377
|
| 378int freebufspace; 379int allocbufspace; 380 381/* 382 * Find a buffer header which is available for use. 383 */
|
218struct buf *
| 384struct buf *
|
219incore(a1, a2) 220 struct vnode *a1; 221 daddr_t a2;
| 385getnewbuf(int slpflag, int slptimeo)
|
222{
| 386{
|
| 387 struct buf *bp; 388 int x; 389 x = splbio(); 390start: 391 /* can we constitute a new buffer? */ 392 if (bp = bufqueues[BQ_EMPTY].tqh_first) { 393 if( bp->b_qindex != BQ_EMPTY) 394 panic("getnewbuf: inconsistent EMPTY queue"); 395 bremfree(bp); 396 goto fillbuf; 397 }
|
223
| 398
|
224 /* 225 * Body deleted. 226 */ 227 return (0);
| 399tryfree: 400 if (bp = bufqueues[BQ_AGE].tqh_first) { 401 if( bp->b_qindex != BQ_AGE) 402 panic("getnewbuf: inconsistent AGE queue"); 403 bremfree(bp); 404 } else if (bp = bufqueues[BQ_LRU].tqh_first) { 405 if( bp->b_qindex != BQ_LRU) 406 panic("getnewbuf: inconsistent LRU queue"); 407 bremfree(bp); 408 } else { 409 /* wait for a free buffer of any kind */ 410 needsbuffer = 1; 411 tsleep((caddr_t)&needsbuffer, PRIBIO, "newbuf", 0); 412 splx(x); 413 return (0); 414 } 415 416 417 /* if we are a delayed write, convert to an async write */ 418 if (bp->b_flags & B_DELWRI) { 419 bp->b_flags |= B_BUSY; 420 bawrite (bp); 421 goto start; 422 } 423 424 if(bp->b_vp) 425 brelvp(bp); 426 427 /* we are not free, nor do we contain interesting data */ 428 if (bp->b_rcred != NOCRED) 429 crfree(bp->b_rcred); 430 if (bp->b_wcred != NOCRED) 431 crfree(bp->b_wcred); 432fillbuf: 433 bp->b_flags = B_BUSY; 434 LIST_REMOVE(bp, b_hash); 435 LIST_INSERT_HEAD(&invalhash, bp, b_hash); 436 splx(x); 437 bp->b_dev = NODEV; 438 bp->b_vp = NULL; 439 bp->b_blkno = bp->b_lblkno = 0; 440 bp->b_iodone = 0; 441 bp->b_error = 0; 442 bp->b_resid = 0; 443 bp->b_bcount = 0; 444 bp->b_wcred = bp->b_rcred = NOCRED; 445 bp->b_dirtyoff = bp->b_dirtyend = 0; 446 bp->b_validoff = bp->b_validend = 0; 447 return (bp);
|
228} 229
| 448} 449
|
| 450/* 451 * Check to see if a block is currently memory resident. 452 */
|
230struct buf *
| 453struct buf *
|
231getblk(a1, a2, a3, a4, a5) 232 struct vnode *a1; 233 daddr_t a2; 234 int a3, a4, a5;
| 454incore(struct vnode *vp, daddr_t blkno)
|
235{
| 455{
|
| 456 struct buf *bp; 457 struct bufhashhdr *bh;
|
236
| 458
|
237 /* 238 * Body deleted. 239 */ 240 return ((struct buf *)0);
| 459 int s = splbio(); 460 461 bh = BUFHASH(vp, blkno); 462 bp = bh->lh_first; 463 464 /* Search hash chain */ 465 while (bp) { 466 if( (bp < buf) || (bp >= buf + nbuf)) { 467 printf("incore: buf out of range: %lx, hash: %d\n", 468 bp, bh - bufhashtbl); 469 panic("incore: buf fault"); 470 } 471 /* hit */ 472 if (bp->b_lblkno == blkno && bp->b_vp == vp 473 && (bp->b_flags & B_INVAL) == 0) 474 return (bp); 475 bp = bp->b_hash.le_next; 476 } 477 splx(s); 478 479 return(0);
|
241} 242
| 480} 481
|
| 482/* 483 * Get a block given a specified block and offset into a file/device. 484 */
|
243struct buf *
| 485struct buf *
|
244geteblk(a1) 245 int a1;
| 486getblk(struct vnode *vp, daddr_t blkno, int size, int slpflag, int slptimeo)
|
246{
| 487{
|
| 488 struct buf *bp; 489 int x; 490 struct bufhashhdr *bh;
|
247
| 491
|
248 /* 249 * Body deleted. 250 */ 251 return ((struct buf *)0);
| 492 x = splbio(); 493loop: 494 if (bp = incore(vp, blkno)) { 495 if (bp->b_flags & B_BUSY) { 496 bp->b_flags |= B_WANTED; 497 tsleep ((caddr_t)bp, PRIBIO, "getblk", 0); 498 goto loop; 499 } 500 bp->b_flags |= B_BUSY | B_CACHE; 501 bremfree(bp); 502 /* 503 * check for size inconsistancies 504 */ 505 if (bp->b_bcount != size) { 506 printf("getblk: invalid buffer size: %d\n", bp->b_bcount); 507 bp->b_flags |= B_INVAL; 508 bwrite(bp); 509 goto loop; 510 } 511 } else { 512 513 if ((bp = getnewbuf(0, 0)) == 0) 514 goto loop; 515 allocbuf(bp, size); 516 /* 517 * have to check again, because of a possible 518 * race condition. 519 */ 520 if (incore( vp, blkno)) { 521 allocbuf(bp, 0); 522 bp->b_flags |= B_INVAL; 523 brelse(bp); 524 goto loop; 525 } 526 bp->b_blkno = bp->b_lblkno = blkno; 527 bgetvp(vp, bp); 528 LIST_REMOVE(bp, b_hash); 529 bh = BUFHASH(vp, blkno); 530 LIST_INSERT_HEAD(bh, bp, b_hash); 531 } 532 splx(x); 533 return (bp);
|
252} 253
| 534} 535
|
254allocbuf(a1, a2) 255 struct buf *a1; 256 int a2;
| 536/* 537 * Get an empty, disassociated buffer of given size. 538 */ 539struct buf * 540geteblk(int size)
|
257{
| 541{
|
258 259 /* 260 * Body deleted. 261 */ 262 return (0);
| 542 struct buf *bp; 543 while ((bp = getnewbuf(0, 0)) == 0) 544 ; 545 allocbuf(bp, size); 546 bp->b_flags |= B_INVAL; 547 return (bp);
|
263} 264
| 548} 549
|
265struct buf * 266getnewbuf(a1, a2) 267 int a1, a2;
| 550/* 551 * Modify the length of a buffer's underlying buffer storage without 552 * destroying information (unless, of course the buffer is shrinking). 553 */ 554void 555allocbuf(struct buf *bp, int size)
|
268{ 269
| 556{ 557
|
270 /* 271 * Body deleted. 272 */ 273 return ((struct buf *)0);
| 558 int newbsize = round_page(size); 559 560 if( newbsize == bp->b_bufsize) { 561 bp->b_bcount = size; 562 return; 563 } else if( newbsize < bp->b_bufsize) { 564 vm_hold_free_pages( 565 (vm_offset_t) bp->b_data + newbsize, 566 (vm_offset_t) bp->b_data + bp->b_bufsize); 567 } else if( newbsize > bp->b_bufsize) { 568 vm_hold_load_pages( 569 (vm_offset_t) bp->b_data + bp->b_bufsize, 570 (vm_offset_t) bp->b_data + newbsize); 571 } 572 573 /* adjust buffer cache's idea of memory allocated to buffer contents */ 574 freebufspace -= newbsize - bp->b_bufsize; 575 allocbufspace += newbsize - bp->b_bufsize; 576 577 bp->b_bufsize = newbsize; 578 bp->b_bcount = size;
|
274} 275
| 579} 580
|
276biowait(a1) 277 struct buf *a1;
| 581/* 582 * Wait for buffer I/O completion, returning error status. 583 */ 584int 585biowait(register struct buf *bp)
|
278{
| 586{
|
| 587 int x;
|
279
| 588
|
280 /* 281 * Body deleted. 282 */ 283 return (EIO);
| 589 x = splbio(); 590 while ((bp->b_flags & B_DONE) == 0) 591 tsleep((caddr_t)bp, PRIBIO, "biowait", 0); 592 if((bp->b_flags & B_ERROR) || bp->b_error) { 593 if ((bp->b_flags & B_INVAL) == 0) { 594 bp->b_flags |= B_INVAL; 595 bp->b_dev = NODEV; 596 LIST_REMOVE(bp, b_hash); 597 LIST_INSERT_HEAD(&invalhash, bp, b_hash); 598 } 599 if (!bp->b_error) 600 bp->b_error = EIO; 601 else 602 bp->b_flags |= B_ERROR; 603 splx(x); 604 return (bp->b_error); 605 } else { 606 splx(x); 607 return (0); 608 }
|
284} 285
| 609} 610
|
| 611/* 612 * Finish I/O on a buffer, calling an optional function. 613 * This is usually called from interrupt level, so process blocking 614 * is not *a good idea*. 615 */
|
286void
| 616void
|
287biodone(a1) 288 struct buf *a1;
| 617biodone(register struct buf *bp)
|
289{
| 618{
|
| 619 int s; 620 s = splbio(); 621 bp->b_flags |= B_DONE;
|
290
| 622
|
291 /* 292 * Body deleted. 293 */ 294 return;
| 623 if ((bp->b_flags & B_READ) == 0) { 624 vwakeup(bp); 625 } 626 627 /* call optional completion function if requested */ 628 if (bp->b_flags & B_CALL) { 629 bp->b_flags &= ~B_CALL; 630 (*bp->b_iodone)(bp); 631 splx(s); 632 return; 633 } 634 635/* 636 * For asynchronous completions, release the buffer now. The brelse 637 * checks for B_WANTED and will do the wakeup there if necessary - 638 * so no need to do a wakeup here in the async case. 639 */ 640 641 if (bp->b_flags & B_ASYNC) { 642 brelse(bp); 643 } else { 644 bp->b_flags &= ~B_WANTED; 645 wakeup((caddr_t) bp); 646 } 647 splx(s);
|
295} 296 297int 298count_lock_queue() 299{
| 648} 649 650int 651count_lock_queue() 652{
|
| 653 int count; 654 struct buf *bp; 655 656 count = 0; 657 for(bp = bufqueues[BQ_LOCKED].tqh_first; 658 bp != NULL; 659 bp = bp->b_freelist.tqe_next) 660 count++; 661 return(count); 662}
|
300
| 663
|
301 /* 302 * Body deleted. 303 */ 304 return (0);
| 664#ifndef UPDATE_INTERVAL 665int vfs_update_interval = 30; 666#else 667int vfs_update_interval = UPDATE_INTERVAL; 668#endif 669 670void 671vfs_update() { 672 (void) spl0(); 673 while(1) { 674 tsleep((caddr_t)&vfs_update_wakeup, PRIBIO, "update", 675 hz * vfs_update_interval); 676 vfs_update_wakeup = 0; 677 sync(curproc, NULL, NULL); 678 }
|
305} 306
| 679} 680
|
307#ifdef DIAGNOSTIC
| |
308/*
| 681/*
|
309 * Print out statistics on the current allocation of the buffer pool. 310 * Can be enabled to print out on every ``sync'' by setting "syncprt" 311 * in vfs_syscalls.c using sysctl.
| 682 * these routines are not in the correct place (yet) 683 * also they work *ONLY* for kernel_pmap!!!
|
312 */ 313void
| 684 */ 685void
|
314vfs_bufstats() 315{ 316 int s, i, j, count; 317 register struct buf *bp; 318 register struct bqueues *dp; 319 int counts[MAXBSIZE/CLBYTES+1]; 320 static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" };
| 686vm_hold_load_pages(vm_offset_t froma, vm_offset_t toa) { 687 vm_offset_t pg; 688 vm_page_t p; 689 vm_offset_t from = round_page(froma); 690 vm_offset_t to = round_page(toa);
|
321
| 691
|
322 for (dp = bufqueues, i = 0; dp < &bufqueues[BQUEUES]; dp++, i++) { 323 count = 0; 324 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 325 counts[j] = 0; 326 s = splbio(); 327 for (bp = dp->tqh_first; bp; bp = bp->b_freelist.tqe_next) { 328 counts[bp->b_bufsize/CLBYTES]++; 329 count++;
| 692 for(pg = from ; pg < to ; pg += PAGE_SIZE) { 693 vm_offset_t pa; 694 695 tryagain: 696 p = vm_page_alloc(kernel_object, pg - VM_MIN_KERNEL_ADDRESS); 697 if( !p) { 698 VM_WAIT; 699 goto tryagain;
|
330 }
| 700 }
|
331 splx(s); 332 printf("%s: total-%d", bname[i], count); 333 for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 334 if (counts[j] != 0) 335 printf(", %d-%d", j * CLBYTES, counts[j]); 336 printf("\n");
| 701 702 vm_page_wire(p); 703 pmap_enter(kernel_pmap, pg, VM_PAGE_TO_PHYS(p), 704 VM_PROT_READ|VM_PROT_WRITE, 1);
|
337 } 338}
| 705 } 706}
|
339#endif /* DIAGNOSTIC */
| 707 708void 709vm_hold_free_pages(vm_offset_t froma, vm_offset_t toa) { 710 vm_offset_t pg; 711 vm_page_t p; 712 vm_offset_t from = round_page(froma); 713 vm_offset_t to = round_page(toa); 714 715 for(pg = from ; pg < to ; pg += PAGE_SIZE) { 716 vm_offset_t pa; 717 pa = pmap_kextract(pg); 718 if( !pa) { 719 printf("No pa for va: %x\n", pg); 720 } else { 721 p = PHYS_TO_VM_PAGE( pa); 722 pmap_remove(kernel_pmap, pg, pg + PAGE_SIZE); 723 vm_page_free(p); 724 } 725 } 726} 727 728void 729bufstats() 730{ 731} 732
|
| |