|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
26: /*
27: * Copyright (c) 1993
28: * The Regents of the University of California. All rights reserved.
29: *
30: * Redistribution and use in source and binary forms, with or without
31: * modification, are permitted provided that the following conditions
32: * are met:
33: * 1. Redistributions of source code must retain the above copyright
34: * notice, this list of conditions and the following disclaimer.
35: * 2. Redistributions in binary form must reproduce the above copyright
36: * notice, this list of conditions and the following disclaimer in the
37: * documentation and/or other materials provided with the distribution.
38: * 3. All advertising materials mentioning features or use of this software
39: * must display the following acknowledgement:
40: * This product includes software developed by the University of
41: * California, Berkeley and its contributors.
42: * 4. Neither the name of the University nor the names of its contributors
43: * may be used to endorse or promote products derived from this software
44: * without specific prior written permission.
45: *
46: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56: * SUCH DAMAGE.
57: *
58: * @(#)vfs_cluster.c 8.10 (Berkeley) 3/28/95
59: */
60:
61: #include <sys/param.h>
62: #include <sys/proc.h>
63: #include <sys/buf.h>
64: #include <sys/vnode.h>
65: #include <sys/mount.h>
66: #include <sys/trace.h>
67: #include <sys/malloc.h>
68: #include <sys/resourcevar.h>
69: #include <libkern/libkern.h>
70: #include <kern/mapfs.h>
71:
72: #include <kern/kdebug.h>
73:
74: /*
75: * Local declarations
76: */
77: struct buf *cluster_rbuild __P((struct vnode *, u_quad_t, struct buf *,
78: daddr_t, daddr_t, long, int, long, long));
79: struct buf *cluster_create __P((struct vnode *, struct buf *, daddr_t, daddr_t, long,
80: int, long, daddr_t *));
81: int cluster_block __P((struct vnode *, u_quad_t, struct buf *, long, long));
82: void cluster_wbuild __P((struct vnode *, struct buf *, long,
83: daddr_t, int, daddr_t, long, int));
84: struct cluster_save *cluster_collectbufs __P((struct vnode *, struct buf *));
85:
86: #if DIAGNOSTIC
87: /*
88: * Set to 1 if reads of block zero should cause readahead to be done.
89: * Set to 0 treats a read of block zero as a non-sequential read.
90: *
91: * Setting to one assumes that most reads of block zero of files are due to
92: * sequential passes over the files (e.g. cat, sum) where additional blocks
93: * will soon be needed. Setting to zero assumes that the majority are
94: * surgical strikes to get particular info (e.g. size, file) where readahead
95: * blocks will not be used and, in fact, push out other potentially useful
96: * blocks from the cache. The former seems intuitive, but some quick tests
97: * showed that the latter performed better from a system-wide point of view.
98: */
99: int doclusterraz = 0;
100: #define ISSEQREAD(vp, blk) \
101: (((blk) != 0 || doclusterraz) && \
102: ((blk) == (vp)->v_lastr + 1 || (blk) == (vp)->v_lastr))
103: #else
104: #define ISSEQREAD(vp, blk) \
105: ((blk) != 0 && ((blk) == (vp)->v_lastr + 1 || (blk) == (vp)->v_lastr))
106: #endif
107:
108: /*
109: * This replaces bread. If this is a bread at the beginning of a file and
110: * lastr is 0, we assume this is the first read and we'll read up to two
111: * blocks if they are sequential. After that, we'll do regular read ahead
112: * in clustered chunks.
113: *
114: * There are 4 or 5 cases depending on how you count:
115: * Desired block is in the cache:
116: * 1 Not sequential access (0 I/Os).
117: * 2 Access is sequential, do read-ahead (1 ASYNC).
118: * Desired block is not in cache:
119: * 3 Not sequential access (1 SYNC).
120: * 4 Sequential access, next block is contiguous (1 SYNC).
121: * 5 Sequential access, next block is not contiguous (1 SYNC, 1 ASYNC)
122: *
123: * There are potentially two buffers that require I/O.
124: * bp is the block requested.
125: * rbp is the read-ahead block.
126: * If either is NULL, then you don't have to do the I/O.
127: */
128:
129: cluster_read(vp, filesize, lblkno, size, cred, bpp, secsize,
130: firstpass, resid, fp_sequential)
131: struct vnode *vp;
132: u_quad_t filesize;
133: daddr_t lblkno;
134: long size;
135: struct ucred *cred;
136: struct buf **bpp;
137: long secsize;
138: int firstpass;
139: long resid;
140: int *fp_sequential;
141: {
142: struct buf *bp, *rbp, *cbp;
143: daddr_t blkno, ioblkno;
144: long flags;
145: int error, num_ra, alreadyincore;
146: long num;
147: int sequential, case4;
148:
149: #if DIAGNOSTIC
150: if (size == 0)
151: panic("cluster_read: size = 0");
152: #endif
153:
154: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_START,
155: lblkno,
156: resid,
157: firstpass,
158: vp,
159: 0);
160: error = 0;
161: flags = B_READ;
162: *bpp = bp = getblk(vp, lblkno, size, 0, 0);
163:
164: if (resid == PAGE_SIZE && lblkno && !ISSEQREAD(vp, lblkno) &&
165: (vp->v_mount->mnt_stat.f_iosize & (PAGE_SIZE - 1)) == 0) {
166: if (bp->b_flags & B_CACHE) {
167:
168: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_END,
169: lblkno,
170: size,
171: -1,
172: 0,
173: 0);
174:
175: vp->v_consumed += (bp->b_bcount/size);
176: return (0);
177: }
178: bp->b_flags |= B_READ;
179:
180: if (cluster_block(vp, filesize, bp, size, secsize)) {
181:
182: error = biowait(bp);
183:
184: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_END,
185: bp,
186: 0,
187: 0,
188: 0,
189: 0);
190:
191: return(error);
192: }
193: }
194: /* round up resid count to nearest block size */
195: if ( resid > size )
196: resid += size - 1;
197:
198: if (bp->b_flags & B_CACHE) {
199: /*
200: * Desired block is in cache; do any readahead ASYNC.
201: * Case 1, 2.
202: */
203: trace(TR_BREADHIT, pack(vp, size), lblkno);
204: flags |= B_ASYNC;
205: if (resid > size)
206: resid -= size;
207:
208: if (!fp_sequential)
209: {
210: ioblkno = lblkno + 1;
211: alreadyincore = incore(vp, ioblkno) != NULL;
212: }
213: else
214: {
215: ioblkno = lblkno + (vp->v_ralen ? vp->v_ralen : 1);
216: alreadyincore = incore(vp, ioblkno) != NULL;
217: }
218: /*
219: * treat this as a hit for purposes of speculative I/O around paging activity
220: */
221: vp->v_consumed += (bp->b_bcount/size);
222:
223: bp = NULL;
224: } else {
225: /* Block wasn't in cache, case 3, 4, 5. */
226: trace(TR_BREADMISS, pack(vp, size), lblkno);
227: bp->b_flags |= B_READ;
228: ioblkno = lblkno;
229: alreadyincore = 0;
230: current_proc()->p_stats->p_ru.ru_inblock++; /* XXX */
231: }
232: /*
233: * XXX
234: * Replace 1 with a window size based on some permutation of
235: * maxcontig and rot_delay. This will let you figure out how
236: * many blocks you should read-ahead (case 2, 4, 5).
237: *
238: * If the access isn't sequential, reset the window to 1.
239: * Note that a read to the same block is considered sequential.
240: * This catches the case where the file is being read sequentially,
241: * but at smaller than the filesystem block size.
242: */
243: rbp = NULL;
244: cbp = NULL;
245: case4 = 0;
246:
247: if (!ISSEQREAD(vp, lblkno)) {
248: vp->v_ralen = 0;
249: vp->v_maxra = lblkno;
250: sequential = 0;
251: }
252: else
253: sequential = 1;
254:
255: /* On first pass set the sequential state.
256: * Otherwise, just use the value passed in.
257: */
258: if (firstpass)
259: *fp_sequential = sequential;
260:
261: if (resid > size || *fp_sequential) {
262: if (((u_quad_t)(ioblkno + 1)) * (u_quad_t)size <= filesize && !alreadyincore &&
263: !(error = VOP_BMAP(vp, ioblkno, NULL, &blkno, &num_ra)) &&
264: blkno != -1) {
265: /*
266: * Reading sequentially, and the next block is not in the
267: * cache. We are going to try reading ahead.
268: */
269: if (num_ra) {
270: /*
271: * If our desired readahead block had been read
272: * in a previous readahead but is no longer in
273: * core, then we may be reading ahead too far
274: * or are not using our readahead very rapidly.
275: * In this case we scale back the window.
276: */
277: if (*fp_sequential) {
278: if (!alreadyincore && ioblkno <= vp->v_maxra)
279: vp->v_ralen = max(vp->v_ralen >> 1, 1);
280: /*
281: * There are more sequential blocks than our current
282: * window allows, scale up. Ideally we want to get
283: * in sync with the filesystem maxcontig value.
284: */
285: else if (num_ra > vp->v_ralen && lblkno != vp->v_lastr)
286: vp->v_ralen = vp->v_ralen ?
287: min(num_ra, vp->v_ralen << 1) : 1;
288: }
289: num = max((resid/size)-1, vp->v_ralen);
290: num_ra = min(num, num_ra);
291: }
292:
293: if (num_ra) { /* case 2, 4 */
294: cbp = cluster_rbuild(vp, filesize,
295: bp, ioblkno, blkno, size, num_ra, flags, secsize);
296:
297: if ( !(cbp->b_flags & B_CALL)) {
298: if ((rbp = cbp) == bp)
299: rbp = NULL;
300: cbp = NULL;
301: } else
302: case4 = 1;
303: } else if (ioblkno == lblkno) {
304: bp->b_blkno = blkno;
305: /* Case 5: check how many blocks to read ahead */
306: ++ioblkno;
307: if (((u_quad_t)(ioblkno + 1)) * (u_quad_t)size > filesize ||
308: incore(vp, ioblkno) || (error = VOP_BMAP(vp,
309: ioblkno, NULL, &blkno, &num_ra)) || blkno == -1)
310: goto skip_readahead;
311: /*
312: * Adjust readahead as above.
313: * Don't check alreadyincore, we know it is 0 from
314: * the previous conditional.
315: */
316: if (num_ra) {
317: if (*fp_sequential) {
318: if (ioblkno <= vp->v_maxra)
319: vp->v_ralen = max(vp->v_ralen >> 1, 1);
320: else if (num_ra > vp->v_ralen &&
321: lblkno != vp->v_lastr)
322: vp->v_ralen = vp->v_ralen ?
323: min(num_ra,vp->v_ralen<<1) : 1;
324: }
325: num = max((resid/size)-1, vp->v_ralen);
326: num_ra = min(num, num_ra);
327: }
328: flags |= B_ASYNC;
329:
330: if (num_ra) {
331: cbp = cluster_rbuild(vp, filesize,
332: NULL, ioblkno, blkno, size, num_ra, flags,
333: secsize);
334: if ( !(cbp->b_flags & B_CALL)) {
335: rbp = cbp;
336: cbp = NULL;
337: }
338: } else {
339: rbp = getblk(vp, ioblkno, size, 0, 0);
340: rbp->b_flags |= flags;
341: rbp->b_blkno = blkno;
342: }
343: } else {
344: /* case 2; read ahead single block */
345: rbp = getblk(vp, ioblkno, size, 0, 0);
346: rbp->b_flags |= flags;
347: rbp->b_blkno = blkno;
348: }
349: if (cbp || rbp) { /* case 2, 5 */
350: trace(TR_BREADMISSRA,
351: pack(vp, (num_ra + 1) * size), ioblkno);
352: current_proc()->p_stats->p_ru.ru_inblock++; /* XXX */
353: }
354: }
355: }
356:
357: skip_readahead:
358: if (bp && !case4) {
359: if (bp->b_flags & (B_DONE | B_DELWRI))
360: panic("cluster_read: DONE bp");
361: else {
362: /*
363: * issue the BMAP here if needed due to the block device's
364: * lack of a BMAP call in the strategy routine.... when being
365: * used by the filesystem/mount code, the blockno's being worked
366: * with are always physical so the strategy routine doesn't bother.
367: * Now that we are calling cluster read/write from spec_read/spec_write
368: * we have to use real logical blockno's in order to properly trigger
369: * the read-ahead and write-coalescing.
370: */
371: if (bp->b_lblkno == bp->b_blkno) {
372: VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
373:
374: if ((long)bp->b_blkno == -1)
375: clrbuf(bp);
376: }
377: error = VOP_STRATEGY(bp);
378:
379: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_NONE,
380: bp->b_lblkno,
381: bp->b_bufsize,
382: bp->b_bcount,
383: 1, 0 );
384: }
385: }
386: if (rbp) {
387: if (error || rbp->b_flags & (B_DONE | B_DELWRI)) {
388: rbp->b_flags &= ~(B_ASYNC | B_READ);
389: brelse(rbp);
390: } else {
391: /*
392: * issue the BMAP here if needed due to the block device's
393: * lack of a BMAP call in the strategy routine.... when being
394: * used by the filesystem/mount code, the blockno's being worked
395: * with are always physical so the strategy routine doesn't bother.
396: * Now that we are calling cluster read/write from spec_read/spec_write
397: * we have to use real logical blockno's in order to properly trigger
398: * the read-ahead and write-coalescing.
399: */
400: if (rbp->b_lblkno == rbp->b_blkno) {
401: VOP_BMAP(vp, rbp->b_lblkno, NULL, &rbp->b_blkno, NULL);
402:
403: if ((long)rbp->b_blkno == -1)
404: clrbuf(rbp);
405: }
406: (void) VOP_STRATEGY(rbp);
407:
408: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_NONE,
409: rbp->b_lblkno,
410: rbp->b_bufsize,
411: rbp->b_bcount,
412: 2, 0 );
413: }
414: }
415: if (cbp) {
416: (void) VOP_STRATEGY(cbp);
417:
418: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_NONE,
419: cbp->b_lblkno,
420: cbp->b_bufsize,
421: cbp->b_bcount,
422: 3, 0 );
423: }
424: /*
425: * Recalculate our maximum readahead
426: */
427: if (rbp == NULL) {
428: if (cbp)
429: rbp = cbp;
430: else
431: rbp = bp;
432: }
433: if (rbp)
434: vp->v_maxra = rbp->b_lblkno + (rbp->b_bcount / size) - 1;
435:
436: if (bp)
437: error = biowait(bp);
438:
439: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 11)) | DBG_FUNC_END,
440: bp,
441: rbp,
442: cbp,
443: vp->v_maxra,
444: 0);
445: return(error);
446: }
447:
448: struct pent {
449: int mask;
450: int num;
451: } pent[7] = {
452: {0,0},
453: {0,0},
454: {~0,1},
455: {~1,2},
456: {~3,4},
457: {~7,8},
458: {~15,16}};
459:
460:
461: int cluster_block(vp, filesize, bp, size, secsize)
462: struct vnode *vp;
463: u_quad_t filesize;
464: struct buf *bp;
465: long size;
466: long secsize;
467: {
468: struct buf *cbp;
469: daddr_t lblkno, blkno, ioblkno, lbn;
470: int num_io, num;
471: unsigned ratio;
472:
473: #if 0 /* FIXED READS */
474: /* calculate maximum number of blocks to read in */
475:
476: lblkno = bp->b_lblkno & ~0x07; /* put us on a 32k (8 page boundary) boundary */
477: num = 8;
478: num_io = 0;
479: #else /* ADAPTIVE READS */
480: if (vp->v_bread > vp->v_trigger) {
481: ratio = (vp->v_consumed*100) / vp->v_bread;
482:
483: if (ratio < 50 && vp->v_power > 2) {
484: vp->v_power--;
485: vp->v_trigger = vp->v_bread + (16 * pent[vp->v_power].num);
486: } else if (ratio > 75 && vp->v_power < 6) {
487: vp->v_power++;
488: vp->v_trigger = vp->v_bread + (16 * pent[vp->v_power].num);
489: }
490: }
491: if ((num = pent[vp->v_power].num) == 1)
492: return (0);
493: lblkno = bp->b_lblkno & pent[vp->v_power].mask;
494: num_io = 0;
495: #endif
496:
497: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_START,
498: lblkno,
499: num,
500: vp->v_flag,
501: vp,
502: 0 );
503:
504: for (lbn = bp->b_lblkno; lbn > lblkno; lbn--) {
505: if (incore(vp, lbn - 1))
506: break;
507: }
508: num -= (lbn - lblkno);
509:
510: for (;;) {
511: if (VOP_BMAP(vp, lbn, NULL, &blkno, &num_io) || blkno == -1 || num_io == 0) {
512: if (lbn == bp->b_lblkno) {
513: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_END,
514: -1,
515: lbn,
516: blkno,
517: num_io,
518: 0);
519: return (0);
520: }
521: }
522: if ((lbn + num_io) >= bp->b_lblkno)
523: break;
524: lbn++;
525: num--;
526: }
527: if ((num_io = min(num, num_io + 1)) == 1)
528: return (0);
529:
530: if ((u_quad_t)size * ((u_quad_t)(lbn + num_io)) > filesize)
531: num_io = (filesize - ((u_quad_t)size * (u_quad_t)lbn)) / size;
532:
533: cbp = cluster_create(vp, bp, lbn, blkno, size, num_io, secsize, &ioblkno);
534:
535: if (cbp) {
536: (void) VOP_STRATEGY(cbp);
537: vp->v_bread += (cbp->b_bcount / size);
538: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_END,
539: cbp->b_lblkno,
540: cbp->b_blkno,
541: cbp->b_bcount,
542: 0,
543: 0 );
544:
545: return (1);
546: }
547: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 14)) | DBG_FUNC_END,
548: 0,
549: 0,
550: 0,
551: 0,
552: 0);
553: return (0);
554: }
555:
556:
557: /*
558: * generate advisory I/O in as big of chunks as possible
559: * and then parcel them up into logical blocks in the buffer hash table.
560: */
561: advisory_read(vp, filesize, lblkno, size, runt_size, io_size, secsize)
562: struct vnode *vp;
563: u_quad_t filesize;
564: daddr_t lblkno;
565: long size;
566: long runt_size;
567: long io_size;
568: long secsize;
569: {
570: struct buf *bp, *cbp;
571: daddr_t blkno, ioblkno;
572: int error, num_io;
573: long num;
574:
575: error = 0;
576:
577: /* calculate maximum number of blocks to read in */
578:
579: num = (io_size + (size - 1)) / size;
580:
581: if ((u_quad_t)size * ((u_quad_t)(lblkno + num)) > filesize) {
582: if (((u_quad_t)size * (u_quad_t)lblkno) >= filesize)
583: return(EFBIG);
584: io_size = filesize - ((u_quad_t)size * (u_quad_t)lblkno);
585:
586: num = io_size / size;
587: } else
588: io_size = num * size;
589:
590: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_START,
591: lblkno,
592: io_size,
593: num,
594: vp,
595: 0 );
596:
597: while (num) {
598: if (error = VOP_BMAP(vp, lblkno, NULL, &blkno, &num_io))
599: break;
600:
601: if (blkno == -1) {
602: lblkno++;
603: num--;
604: io_size -= size;
605: continue;
606: }
607: num_io = min(num, num_io + 1);
608:
609: cbp = cluster_create(vp, NULL, lblkno, blkno, size, num_io, secsize, &ioblkno);
610:
611: if (cbp) {
612: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_NONE,
613: cbp->b_lblkno,
614: cbp->b_blkno,
615: cbp->b_bcount,
616: 3,
617: 0 );
618:
619: (void) VOP_STRATEGY(cbp);
620: } else {
621: if (ioblkno == lblkno) {
622: error = ENOMEM;
623: break;
624: }
625: }
626: io_size -= ((ioblkno - lblkno) * size);
627: num -= ioblkno - lblkno;
628: lblkno = ioblkno;
629: }
630: if (io_size && !error) {
631: bp = getblk(vp, lblkno, runt_size, 0, 0);
632:
633: if (bp->b_flags & (B_DONE | B_DELWRI))
634: brelse(bp);
635: else {
636: bp->b_flags |= (B_READ | B_ASYNC);
637:
638: (void) VOP_STRATEGY(bp);
639:
640: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_NONE,
641: bp->b_lblkno,
642: bp->b_blkno,
643: bp->b_bcount,
644: 4,
645: 0 );
646: }
647: io_size -= runt_size;
648: }
649:
650: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 13)) | DBG_FUNC_END,
651: lblkno,
652: io_size,
653: num,
654: error,
655: 0);
656: return(error);
657: }
658:
659:
660: /*
661: * If blocks are contiguous on disk, use this to provide clustered
662: * read ahead. We will read as many blocks as possible sequentially
663: * and then parcel them up into logical blocks in the buffer hash table.
664: */
665: struct buf *
666: cluster_rbuild(vp, filesize, bp, lbn, blkno, size, run, flags, secsize)
667: struct vnode *vp;
668: u_quad_t filesize;
669: struct buf *bp;
670: daddr_t lbn;
671: daddr_t blkno;
672: long size;
673: int run;
674: long flags;
675: long secsize;
676: {
677: struct cluster_save *b_save;
678: struct buf *tbp, *cbp;
679: caddr_t cp;
680: daddr_t bn;
681: int i, inc;
682:
683: #if DIAGNOSTIC
684: if (size != vp->v_mount->mnt_stat.f_iosize)
685: panic("cluster_rbuild: size %d != filesize %d\n",
686: size, vp->v_mount->mnt_stat.f_iosize);
687: #endif
688: if ((u_quad_t)size * ((u_quad_t)(lbn + run + 1)) > filesize)
689: --run;
690: if (run == 0) {
691: if (!bp) {
692: bp = getblk(vp, lbn, size, 0, 0);
693: bp->b_blkno = blkno;
694: bp->b_flags |= flags;
695: }
696: return(bp);
697: }
698: b_save = _MALLOC(sizeof(struct buf *) * (run + 1) + sizeof(struct cluster_save),
699: M_SEGMENT, M_NOWAIT);
700:
701: if (b_save)
702: cbp = alloc_io_buf(vp);
703: else
704: cbp = NULL;
705:
706: if (b_save == NULL || cbp == NULL) {
707: if (b_save)
708: _FREE(b_save, M_SEGMENT);
709: if (cbp)
710: free_io_buf(cbp);
711: return (bp);
712: }
713: b_save->bs_bufsize = size;
714: b_save->bs_nchildren = 0;
715: b_save->bs_children = (struct buf **)(b_save + 1);
716:
717: cbp->b_saveaddr = (caddr_t)b_save;
718: cbp->b_iodone = cluster_callback;
719: cbp->b_blkno = blkno;
720: cbp->b_lblkno = lbn;
721: cbp->b_flags |= flags | B_CALL;
722:
723: inc = btodb(size, secsize);
724: cp = (char *)cbp->b_data;
725: tbp = bp;
726:
727: for (bn = blkno, i = 0; i <= run; ++i, bn += inc) {
728: if (tbp == NULL) {
729: if (incore(vp, lbn + i))
730: /*
731: * A component of the cluster is already in core,
732: * terminate the cluster early.
733: */
734: break;
735: tbp = getblk(vp, lbn + i, size, 0, 0);
736: }
737: pagemove(tbp->b_data, cp, size);
738: cbp->b_bcount += size;
739: cbp->b_bufsize += size;
740: cp += size;
741:
742: if (bp != tbp)
743: tbp->b_flags |= flags | B_READ | B_ASYNC;
744: tbp->b_bufsize -= size;
745: tbp->b_blkno = bn;
746:
747: b_save->bs_children[i] = tbp;
748: b_save->bs_nchildren++;
749:
750: tbp = NULL;
751: }
752: /*
753: * The cluster may have been terminated early
754: * If no cluster could be formed, deallocate the cluster save info.
755: */
756: if (i == 0) {
757: _FREE(b_save, M_SEGMENT);
758: free_io_buf(cbp);
759: return(bp);
760: }
761: return(cbp);
762: }
763:
764:
765:
766: struct buf *
767: cluster_create(vp, bp, lbn, blkno, size, run, secsize, ioblkno)
768: struct vnode *vp;
769: struct buf *bp;
770: daddr_t lbn;
771: daddr_t blkno;
772: long size;
773: int run;
774: long secsize;
775: daddr_t *ioblkno;
776: {
777: struct cluster_save *b_save;
778: struct buf *tbp, *cbp;
779: caddr_t cp;
780: daddr_t bn;
781: int i, inc;
782:
783: inc = btodb(size, secsize);
784:
785: if (bp == NULL) {
786: while (run && (tbp = incore(vp, lbn))) {
787: /*
788: * if a block is already in core
789: * and is not busy
790: * then get and release to freshen it in the LRU
791: */
792: if ( !(tbp->b_flags & B_BUSY)) {
793: tbp = getblk(vp, lbn, size, 0, 0);
794: brelse(tbp);
795: }
796: lbn++;
797: run--;
798: blkno += inc;
799: }
800: if (run == 0) {
801: *ioblkno = lbn;
802: return (NULL);
803: }
804: }
805: b_save = _MALLOC((sizeof(struct buf *) * run) + sizeof(struct cluster_save), M_SEGMENT, M_NOWAIT);
806:
807: if (b_save)
808: cbp = alloc_io_buf(vp);
809: else
810: cbp = NULL;
811:
812: if (b_save == NULL || cbp == NULL) {
813: if (b_save)
814: _FREE(b_save, M_SEGMENT);
815: if (cbp)
816: free_io_buf(cbp);
817: *ioblkno = lbn;
818:
819: return (NULL);
820: }
821: b_save->bs_bufsize = size;
822: b_save->bs_nchildren = 0;
823: b_save->bs_children = (struct buf **)(b_save + 1);
824:
825: cbp->b_saveaddr = (caddr_t)b_save;
826: cbp->b_iodone = cluster_callback;
827: cbp->b_blkno = blkno;
828: cbp->b_lblkno = lbn;
829: cbp->b_flags |= (B_READ | B_ASYNC | B_CALL);
830:
831: cp = (char *)cbp->b_data;
832:
833: for (bn = blkno, i = 0; i < run; ++i, bn += inc, ++lbn) {
834: if (bp && bp->b_lblkno == lbn)
835: tbp = bp;
836: else {
837: if (tbp = incore(vp, lbn)) {
838: /*
839: * A component of the cluster is already in core,
840: * terminate the cluster early.
841: * if its not busy then also
842: * get and release to freshen it in the LRU
843: */
844: if ( !(tbp->b_flags & B_BUSY)) {
845: tbp = getblk(vp, lbn, size, 0, 0);
846: brelse(tbp);
847: }
848: break;
849: }
850: tbp = getblk(vp, lbn, size, 0, 0);
851: }
852: pagemove(tbp->b_data, cp, size);
853:
854: tbp->b_bufsize -= size;
855: tbp->b_blkno = bn;
856: cbp->b_bcount += size;
857: cbp->b_bufsize += size;
858: cp += size;
859:
860: if (tbp != bp)
861: tbp->b_flags |= (B_READ | B_ASYNC);
862: b_save->bs_children[i] = tbp;
863: b_save->bs_nchildren++;
864: }
865: *ioblkno = lbn;
866: /*
867: * The cluster may have been terminated early
868: * If no cluster could be formed, deallocate the cluster save info.
869: */
870: if (cbp->b_bcount == 0) {
871: _FREE(b_save, M_SEGMENT);
872: free_io_buf(cbp);
873: return(NULL);
874: }
875: return(cbp);
876: }
877:
878:
879: /*
880: * Cleanup after a clustered read or write.
881: * This is complicated by the fact that any of the buffers might have
882: * extra memory (if there were no empty buffer headers at allocbuf time)
883: * that we will need to shift around.
884: */
885: void
886: cluster_callback(bp)
887: struct buf *bp;
888: {
889: struct cluster_save *b_save;
890: struct buf **bpp, *tbp;
891: long bsize;
892: int xsize;
893: int n;
894: caddr_t cp;
895: int error = 0;
896:
897: /*
898: * Must propogate errors to all the components.
899: */
900: if (bp->b_flags & B_ERROR)
901: error = bp->b_error;
902: b_save = (struct cluster_save *)(bp->b_saveaddr);
903:
904: bsize = b_save->bs_bufsize;
905: xsize = bp->b_bcount - bp->b_resid;
906: cp = (char *)bp->b_data;
907: /*
908: * Move memory from the large cluster buffer into the component
909: * buffers and mark IO as done on these.
910: */
911: for (bpp = b_save->bs_children; b_save->bs_nchildren--; ++bpp) {
912: tbp = *bpp;
913: pagemove(cp, tbp->b_data, bsize);
914: tbp->b_bufsize += bsize;
915:
916: n = min(bsize, xsize);
917: xsize -= n;
918:
919: if ((tbp->b_bcount = n) == 0)
920: tbp->b_flags |= B_INVAL;
921: tbp->b_resid = bsize - n;
922:
923: if (error) {
924: tbp->b_flags |= B_ERROR;
925: tbp->b_error = error;
926: }
927: biodone(tbp);
928: bp->b_bufsize -= bsize;
929: cp += bsize;
930: }
931: _FREE(b_save, M_SEGMENT);
932:
933: free_io_buf(bp);
934: }
935:
936:
937: /*
938: * on close, flush out any remaining cluster
939: *
940: */
941: cluster_close(vp, bsize, secsize)
942: struct vnode *vp;
943: int bsize;
944: long secsize;
945: {
946: int cursize;
947:
948: if (vp->v_clen) {
949: cursize = vp->v_lastw - vp->v_cstart + 1;
950:
951: cluster_wbuild(vp, NULL, bsize, vp->v_cstart, cursize, -1, secsize, 0);
952:
953: vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
954: }
955: }
956:
957:
958: /*
959: * Do clustered write for FFS.
960: *
961: * Three cases:
962: * 1. Write is not sequential (write asynchronously)
963: * Write is sequential:
964: * 2. beginning of cluster - begin cluster
965: * 3. middle of a cluster - add to cluster
966: * 4. end of a cluster - asynchronously write cluster
967: */
968:
969: cluster_write(bp, filesize, secsize)
970: struct buf *bp;
971: u_quad_t filesize;
972: long secsize;
973: {
974: struct vnode *vp;
975: daddr_t lbn;
976: daddr_t bn;
977: int maxclen, cursize;
978: int need_commit;
979: int need_sync;
980: int bsize;
981: int error = 0;
982:
983: need_commit = (bp->b_flags & B_CLUST_COMMIT);
984: need_sync = (bp->b_flags & B_CLUST_SYNC);
985: bp->b_flags &= ~(B_CLUST_COMMIT | B_CLUST_SYNC);
986:
987: vp = bp->b_vp;
988: bn = bp->b_blkno;
989: lbn = bp->b_lblkno;
990: bsize = bp->b_bcount;
991:
992: if ((bsize & (PAGE_SIZE - 1)) || bsize > MAXBSIZE) {
993: bp->b_flags |= B_AGE;
994: bawrite(bp);
995:
996: return (error);
997: }
998: /* Initialize vnode to beginning of file. */
999: if (lbn == 0)
1000: vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
1001:
1002:
1003: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START,
1004: bp->b_lblkno,
1005: bp->b_bcount,
1006: vp->v_lasta,
1007: vp->v_clen,
1008: 0);
1009:
1010: if (vp->v_clen == 0 || lbn != vp->v_lastw + 1 ||
1011: (bn != vp->v_lasta + btodb(bsize, secsize)))
1012: {
1013: maxclen = (MAXPHYSIO / bsize) - 1;
1014:
1015: if (vp->v_clen != 0) {
1016: /*
1017: * Next block is not sequential.
1018: *
1019: * If we are not writing at end of file, the process
1020: * seeked to another point in the file since its
1021: * last write, or we have reached our maximum
1022: * cluster size, then push the previous cluster.
1023: * Otherwise try reallocating to make it sequential.
1024: */
1025: cursize = vp->v_lastw - vp->v_cstart + 1;
1026: if (((u_quad_t)(lbn + 1)) * (u_quad_t)bsize != filesize ||
1027: lbn != vp->v_lastw + 1 || vp->v_clen <= cursize) {
1028: cluster_wbuild(vp, NULL, bsize,
1029: vp->v_cstart, cursize, lbn, secsize, need_sync);
1030: } else {
1031: struct buf **bpp, **endbp;
1032: struct cluster_save *buflist;
1033:
1034: buflist = cluster_collectbufs(vp, bp);
1035:
1036: if (buflist == NULL) {
1037: cluster_wbuild(vp, NULL, bp->b_bcount,
1038: vp->v_cstart, cursize, lbn, secsize, need_sync);
1039: } else {
1040:
1041: endbp = &buflist->bs_children
1042: [buflist->bs_nchildren - 1];
1043: if (VOP_REALLOCBLKS(vp, buflist)) {
1044: /*
1045: * Failed, push the previous cluster.
1046: */
1047: for (bpp = buflist->bs_children;
1048: bpp < endbp; bpp++)
1049: brelse(*bpp);
1050: _FREE(buflist, M_SEGMENT);
1051:
1052: cluster_wbuild(vp, NULL, bsize,
1053: vp->v_cstart, cursize, lbn, secsize, need_sync);
1054: } else {
1055: /*
1056: * Succeeded, keep building cluster.
1057: * don't bdwrite the last bp, we'll
1058: * first check to see if we now have a full
1059: * cluster, or the caller has requested a SYNC write
1060: */
1061: for (bpp = buflist->bs_children;
1062: bpp < endbp; bpp++)
1063: bdwrite(*bpp);
1064: _FREE(buflist, M_SEGMENT);
1065: /*
1066: * update the physical block number because,
1067: * VOP_REALLOCBLKS will have changed it
1068: */
1069: bn = bp->b_blkno;
1070: goto chk_cluster_full;
1071: }
1072: }
1073: }
1074: }
1075: /*
1076: * Consider beginning a cluster.
1077: * If at end of file, make cluster as large as possible,
1078: * otherwise find size of existing cluster.
1079: */
1080: if (((u_quad_t)(lbn + 1)) * (u_quad_t)bsize != filesize &&
1081: (VOP_BMAP(vp, lbn, NULL, &bp->b_blkno, &maxclen) ||
1082: bp->b_blkno == -1)) {
1083: bn = bp->b_blkno;
1084: vp->v_clen = 0;
1085: vp->v_cstart = lbn + 1;
1086:
1087: if (need_sync)
1088: bwrite(bp);
1089: else
1090: bawrite(bp);
1091:
1092: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1093: bp->b_lblkno,
1094: bp->b_blkno,
1095: bp->b_bcount,
1096: vp->v_cstart,
1097: 1 );
1098: goto check_for_commit;
1099: }
1100: bn = bp->b_blkno;
1101:
1102: if ((vp->v_clen = maxclen) == 0 || need_commit) { /* I/O not contiguous or we're being asked to do IO_SYNC and this is the last */
1103: vp->v_cstart = lbn + 1; /* chunk of the I/O request */
1104:
1105: if (need_sync)
1106: bwrite(bp);
1107: else
1108: bawrite(bp);
1109:
1110: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1111: bp->b_lblkno,
1112: bp->b_blkno,
1113: bp->b_bcount,
1114: vp->v_cstart,
1115: 2 );
1116: } else { /* Wait for rest of cluster */
1117: vp->v_cstart = lbn;
1118:
1119: bdwrite(bp);
1120:
1121: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1122: bp->b_lblkno,
1123: bp->b_blkno,
1124: bp->b_bcount,
1125: vp->v_cstart,
1126: 3 );
1127: }
1128: goto check_for_commit;
1129: }
1130: chk_cluster_full:
1131: if ((lbn == vp->v_cstart + vp->v_clen) || need_commit) {
1132: /*
1133: * At end of cluster, write it out.
1134: */
1135: cluster_wbuild(vp, bp, bsize, vp->v_cstart,
1136: (lbn - vp->v_cstart) + 1, lbn, secsize, need_sync);
1137:
1138: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1139: vp->v_cstart,
1140: vp->v_clen + 1,
1141: lbn,
1142: 0,
1143: 4 );
1144: vp->v_clen = 0;
1145: vp->v_cstart = lbn + 1;
1146: } else {
1147: /*
1148: * In the middle of a cluster, so just delay the
1149: * I/O for now.
1150: */
1151: bdwrite(bp);
1152:
1153: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1154: bp->b_lblkno,
1155: bp->b_blkno,
1156: bp->b_bcount,
1157: vp->v_cstart,
1158: 5 );
1159: }
1160: check_for_commit:
1161: vp->v_lastw = lbn;
1162: vp->v_lasta = bn;
1163:
1164: if (need_commit) {
1165: bp = getblk(vp, lbn, bsize, 0, 0);
1166:
1167: if (bp->b_flags & B_ERROR)
1168: error = (bp->b_error ? bp->b_error : EIO);
1169: brelse(bp);
1170: }
1171: return (error);
1172: }
1173:
1174:
1175: /*
1176: * This is an awful lot like cluster_rbuild...wish they could be combined.
1177: * The last lbn argument is the current block on which I/O is being
1178: * performed. Check to see that it doesn't fall in the middle of
1179: * the current block (if last_bp == NULL).
1180: */
1181: void
1182: cluster_wbuild(vp, last_bp, size, start_lbn, len, lbn, secsize, need_sync)
1183: struct vnode *vp;
1184: struct buf *last_bp;
1185: long size;
1186: daddr_t start_lbn;
1187: int len;
1188: daddr_t lbn;
1189: long secsize;
1190: int need_sync;
1191: {
1192: struct cluster_save *b_save;
1193: struct buf *bp, *tbp;
1194: caddr_t cp;
1195: int i, s;
1196:
1197: #if DIAGNOSTIC
1198: if (size != vp->v_mount->mnt_stat.f_iosize)
1199: panic("cluster_wbuild: size %d != filesize %d\n",
1200: size, vp->v_mount->mnt_stat.f_iosize);
1201: #endif
1202: redo:
1203: while ((!incore(vp, start_lbn) || start_lbn == lbn) && len) {
1204: ++start_lbn;
1205: --len;
1206: }
1207: /* Get more memory for current buffer */
1208: if (len <= 1) {
1209: if (last_bp) {
1210: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1211: last_bp->b_lblkno,
1212: last_bp->b_blkno,
1213: last_bp->b_bcount,
1214: 1,
1215: 0 );
1216: if (need_sync)
1217: bwrite(last_bp);
1218: else
1219: bawrite(last_bp);
1220: } else if (len) {
1221: bp = getblk(vp, start_lbn, size, 0, 0);
1222:
1223: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1224: bp->b_lblkno,
1225: bp->b_blkno,
1226: bp->b_bcount,
1227: 2,
1228: 0 );
1229: if (bp->b_flags & B_DELWRI) {
1230: if (need_sync)
1231: bwrite(bp);
1232: else
1233: bawrite(bp);
1234: } else
1235: brelse(bp);
1236: }
1237: return;
1238: }
1239: b_save = _MALLOC(sizeof(struct buf *) * len + sizeof(struct cluster_save),
1240: M_SEGMENT, M_NOWAIT);
1241: if (b_save)
1242: bp = alloc_io_buf(vp);
1243: else
1244: bp = NULL;
1245:
1246: if (b_save == NULL || bp == NULL) {
1247: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1248: bp,
1249: b_save,
1250: 0,
1251: 4,
1252: 0 );
1253: if (bp)
1254: free_io_buf(bp);
1255: if (b_save)
1256: _FREE(b_save, M_SEGMENT);
1257:
1258: for (i = 0; i < len; ++i, ++start_lbn) {
1259: if (!incore(vp, start_lbn))
1260: continue;
1261: if (last_bp == NULL || start_lbn != lbn) {
1262: tbp = getblk(vp, start_lbn, size, 0, 0);
1263:
1264: if (tbp->b_flags & B_DELWRI) {
1265: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1266: tbp->b_lblkno,
1267: tbp->b_blkno,
1268: tbp->b_bcount,
1269: 5,
1270: 0 );
1271:
1272: if (need_sync)
1273: bwrite(tbp);
1274: else
1275: bawrite(tbp);
1276: } else
1277: brelse(tbp);
1278: }
1279: }
1280: if (last_bp) {
1281: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1282: last_bp->b_lblkno,
1283: last_bp->b_blkno,
1284: last_bp->b_bcount,
1285: 6,
1286: 0 );
1287: if (need_sync)
1288: bwrite(last_bp);
1289: else
1290: bawrite(last_bp);
1291: }
1292: return;
1293: }
1294: b_save->bs_bufsize = size;
1295: b_save->bs_nchildren = 0;
1296: b_save->bs_children = (struct buf **)(b_save + 1);
1297:
1298: bp->b_saveaddr = (caddr_t)b_save;
1299: bp->b_iodone = cluster_callback;
1300: bp->b_flags |= (B_WRITEINPROG | B_CALL | B_ASYNC);
1301:
1302: cp = (char *)bp->b_data;
1303:
1304: for (start_lbn, i = 0; i < len; ++i, ++start_lbn) {
1305: /*
1306: * Block is not in core or the non-sequential block
1307: * ending our cluster was part of the cluster (in which
1308: * case we don't want to write it twice).
1309: */
1310: if (!incore(vp, start_lbn) ||
1311: (last_bp == NULL && start_lbn == lbn))
1312: break;
1313:
1314: /*
1315: * Get the desired block buffer (unless it is the final
1316: * sequential block whose buffer was passed in explictly
1317: * as last_bp).
1318: */
1319: if (last_bp == NULL || start_lbn != lbn) {
1320: tbp = getblk(vp, start_lbn, size, 0, 0);
1321: if (!(tbp->b_flags & B_DELWRI)) {
1322: brelse(tbp);
1323: break;
1324: }
1325: } else
1326: tbp = last_bp;
1327:
1328: if (i == 0) {
1329: bp->b_blkno = tbp->b_blkno;
1330: bp->b_lblkno= tbp->b_lblkno;
1331: } else {
1332: if (tbp->b_blkno != (bp->b_blkno + btodb(bp->b_bufsize, secsize))) {
1333: brelse(tbp);
1334: break;
1335: }
1336: }
1337: /* Move memory from children to parent */
1338: pagemove(tbp->b_data, cp, size);
1339: bp->b_bcount += size;
1340: bp->b_bufsize += size;
1341: cp += size;
1342:
1343: tbp->b_bufsize -= size;
1344: tbp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
1345: tbp->b_flags |= (B_ASYNC | B_AGE);
1346:
1347: s = splbio();
1348: reassignbuf(tbp, tbp->b_vp); /* put on clean list */
1349: ++tbp->b_vp->v_numoutput;
1350: splx(s);
1351:
1352: b_save->bs_children[i] = tbp;
1353: b_save->bs_nchildren++;
1354: }
1355:
1356: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1357: bp->b_lblkno,
1358: bp->b_blkno,
1359: bp->b_bcount,
1360: 7,
1361: 0 );
1362: if (i == 0) {
1363: /* None to cluster */
1364: free_io_buf(bp);
1365: _FREE(b_save, M_SEGMENT);
1366: } else {
1367: if (bp->b_bcount > MAXPHYSIO)
1368: panic("cluster_wbuild: bp->b_bcount = %x\n", bp->b_bcount);
1369:
1370: VOP_STRATEGY(bp);
1371: }
1372: if (i < len) {
1373: len -= i + 1;
1374: start_lbn += 1;
1375: goto redo;
1376: }
1377: }
1378:
1379: /*
1380: * Collect together all the buffers in a cluster.
1381: * Plus add one additional buffer.
1382: */
1383: struct cluster_save *
1384: cluster_collectbufs(vp, last_bp)
1385: struct vnode *vp;
1386: struct buf *last_bp;
1387: {
1388: struct cluster_save *buflist;
1389: daddr_t lbn;
1390: int i, j, len;
1391:
1392: len = vp->v_lastw - vp->v_cstart + 1;
1393: buflist = _MALLOC(sizeof(struct buf *) * (len + 1) + sizeof(*buflist),
1394: M_SEGMENT, M_NOWAIT);
1395:
1396: if (buflist == NULL)
1397: return (NULL);
1398:
1399: buflist->bs_nchildren = 0;
1400: buflist->bs_children = (struct buf **)(buflist + 1);
1401: for (lbn = vp->v_cstart, i = 0; i < len; lbn++, i++) {
1402: (void)bread(vp, lbn, last_bp->b_bcount, NOCRED,
1403: &buflist->bs_children[i]);
1404: if(!(buflist->bs_children[i]->b_flags & B_DELWRI)) {
1405: for (j=0; j<=i; j++)
1406: brelse(buflist->bs_children[j]);
1407: _FREE(buflist, M_SEGMENT);
1408: return(NULL);
1409: }
1410: }
1411: buflist->bs_children[i] = last_bp;
1412: buflist->bs_nchildren = i + 1;
1413: return (buflist);
1414: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.