|
|
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,
1.1.1.2 ! root 80: int, long, daddr_t *, int));
1.1 root 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:
1.1.1.2 ! root 533: cbp = cluster_create(vp, bp, lbn, blkno, size, num_io, secsize, &ioblkno, B_AGE);
1.1 root 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:
1.1.1.2 ! root 609: cbp = cluster_create(vp, NULL, lblkno, blkno, size, num_io, secsize, &ioblkno, 0);
1.1 root 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 *
1.1.1.2 ! root 767: cluster_create(vp, bp, lbn, blkno, size, run, secsize, ioblkno, flags)
1.1 root 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;
1.1.1.2 ! root 776: int flags;
1.1 root 777: {
778: struct cluster_save *b_save;
779: struct buf *tbp, *cbp;
780: caddr_t cp;
781: daddr_t bn;
782: int i, inc;
783:
784: inc = btodb(size, secsize);
785:
786: if (bp == NULL) {
787: while (run && (tbp = incore(vp, lbn))) {
788: /*
789: * if a block is already in core
790: * and is not busy
791: * then get and release to freshen it in the LRU
792: */
793: if ( !(tbp->b_flags & B_BUSY)) {
794: tbp = getblk(vp, lbn, size, 0, 0);
795: brelse(tbp);
796: }
797: lbn++;
798: run--;
799: blkno += inc;
800: }
801: if (run == 0) {
802: *ioblkno = lbn;
803: return (NULL);
804: }
805: }
806: b_save = _MALLOC((sizeof(struct buf *) * run) + sizeof(struct cluster_save), M_SEGMENT, M_NOWAIT);
807:
808: if (b_save)
809: cbp = alloc_io_buf(vp);
810: else
811: cbp = NULL;
812:
813: if (b_save == NULL || cbp == NULL) {
814: if (b_save)
815: _FREE(b_save, M_SEGMENT);
816: if (cbp)
817: free_io_buf(cbp);
818: *ioblkno = lbn;
819:
820: return (NULL);
821: }
822: b_save->bs_bufsize = size;
823: b_save->bs_nchildren = 0;
824: b_save->bs_children = (struct buf **)(b_save + 1);
825:
826: cbp->b_saveaddr = (caddr_t)b_save;
827: cbp->b_iodone = cluster_callback;
828: cbp->b_blkno = blkno;
829: cbp->b_lblkno = lbn;
830: cbp->b_flags |= (B_READ | B_ASYNC | B_CALL);
831:
832: cp = (char *)cbp->b_data;
833:
834: for (bn = blkno, i = 0; i < run; ++i, bn += inc, ++lbn) {
835: if (bp && bp->b_lblkno == lbn)
836: tbp = bp;
837: else {
838: if (tbp = incore(vp, lbn)) {
839: /*
840: * A component of the cluster is already in core,
841: * terminate the cluster early.
842: * if its not busy then also
843: * get and release to freshen it in the LRU
844: */
845: if ( !(tbp->b_flags & B_BUSY)) {
846: tbp = getblk(vp, lbn, size, 0, 0);
847: brelse(tbp);
848: }
849: break;
850: }
851: tbp = getblk(vp, lbn, size, 0, 0);
852: }
853: pagemove(tbp->b_data, cp, size);
854:
855: tbp->b_bufsize -= size;
856: tbp->b_blkno = bn;
857: cbp->b_bcount += size;
858: cbp->b_bufsize += size;
859: cp += size;
860:
861: if (tbp != bp)
1.1.1.2 ! root 862: tbp->b_flags |= (B_READ | B_ASYNC | flags);
1.1 root 863: b_save->bs_children[i] = tbp;
864: b_save->bs_nchildren++;
865: }
866: *ioblkno = lbn;
867: /*
868: * The cluster may have been terminated early
869: * If no cluster could be formed, deallocate the cluster save info.
870: */
871: if (cbp->b_bcount == 0) {
872: _FREE(b_save, M_SEGMENT);
873: free_io_buf(cbp);
874: return(NULL);
875: }
876: return(cbp);
877: }
878:
879:
880: /*
881: * Cleanup after a clustered read or write.
882: * This is complicated by the fact that any of the buffers might have
883: * extra memory (if there were no empty buffer headers at allocbuf time)
884: * that we will need to shift around.
885: */
886: void
887: cluster_callback(bp)
888: struct buf *bp;
889: {
890: struct cluster_save *b_save;
891: struct buf **bpp, *tbp;
892: long bsize;
893: int xsize;
894: int n;
895: caddr_t cp;
896: int error = 0;
897:
898: /*
899: * Must propogate errors to all the components.
900: */
901: if (bp->b_flags & B_ERROR)
902: error = bp->b_error;
903: b_save = (struct cluster_save *)(bp->b_saveaddr);
904:
905: bsize = b_save->bs_bufsize;
906: xsize = bp->b_bcount - bp->b_resid;
907: cp = (char *)bp->b_data;
908: /*
909: * Move memory from the large cluster buffer into the component
910: * buffers and mark IO as done on these.
911: */
912: for (bpp = b_save->bs_children; b_save->bs_nchildren--; ++bpp) {
913: tbp = *bpp;
914: pagemove(cp, tbp->b_data, bsize);
915: tbp->b_bufsize += bsize;
916:
917: n = min(bsize, xsize);
918: xsize -= n;
919:
920: if ((tbp->b_bcount = n) == 0)
921: tbp->b_flags |= B_INVAL;
922: tbp->b_resid = bsize - n;
923:
924: if (error) {
925: tbp->b_flags |= B_ERROR;
926: tbp->b_error = error;
927: }
928: biodone(tbp);
929: bp->b_bufsize -= bsize;
930: cp += bsize;
931: }
932: _FREE(b_save, M_SEGMENT);
933:
934: free_io_buf(bp);
935: }
936:
937:
938: /*
939: * on close, flush out any remaining cluster
940: *
941: */
942: cluster_close(vp, bsize, secsize)
943: struct vnode *vp;
944: int bsize;
945: long secsize;
946: {
947: int cursize;
948:
949: if (vp->v_clen) {
950: cursize = vp->v_lastw - vp->v_cstart + 1;
951:
952: cluster_wbuild(vp, NULL, bsize, vp->v_cstart, cursize, -1, secsize, 0);
953:
954: vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
955: }
956: }
957:
958:
959: /*
960: * Do clustered write for FFS.
961: *
962: * Three cases:
963: * 1. Write is not sequential (write asynchronously)
964: * Write is sequential:
965: * 2. beginning of cluster - begin cluster
966: * 3. middle of a cluster - add to cluster
967: * 4. end of a cluster - asynchronously write cluster
968: */
969:
970: cluster_write(bp, filesize, secsize)
971: struct buf *bp;
972: u_quad_t filesize;
973: long secsize;
974: {
975: struct vnode *vp;
976: daddr_t lbn;
977: daddr_t bn;
978: int maxclen, cursize;
979: int need_commit;
980: int need_sync;
981: int bsize;
982: int error = 0;
983:
984: need_commit = (bp->b_flags & B_CLUST_COMMIT);
985: need_sync = (bp->b_flags & B_CLUST_SYNC);
986: bp->b_flags &= ~(B_CLUST_COMMIT | B_CLUST_SYNC);
987:
988: vp = bp->b_vp;
989: bn = bp->b_blkno;
990: lbn = bp->b_lblkno;
991: bsize = bp->b_bcount;
992:
993: if ((bsize & (PAGE_SIZE - 1)) || bsize > MAXBSIZE) {
994: bp->b_flags |= B_AGE;
995: bawrite(bp);
996:
997: return (error);
998: }
999: /* Initialize vnode to beginning of file. */
1000: if (lbn == 0)
1001: vp->v_lasta = vp->v_clen = vp->v_cstart = vp->v_lastw = 0;
1002:
1003:
1004: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_START,
1005: bp->b_lblkno,
1006: bp->b_bcount,
1007: vp->v_lasta,
1008: vp->v_clen,
1009: 0);
1010:
1011: if (vp->v_clen == 0 || lbn != vp->v_lastw + 1 ||
1012: (bn != vp->v_lasta + btodb(bsize, secsize)))
1013: {
1014: maxclen = (MAXPHYSIO / bsize) - 1;
1015:
1016: if (vp->v_clen != 0) {
1017: /*
1018: * Next block is not sequential.
1019: *
1020: * If we are not writing at end of file, the process
1021: * seeked to another point in the file since its
1022: * last write, or we have reached our maximum
1023: * cluster size, then push the previous cluster.
1024: * Otherwise try reallocating to make it sequential.
1025: */
1026: cursize = vp->v_lastw - vp->v_cstart + 1;
1027: if (((u_quad_t)(lbn + 1)) * (u_quad_t)bsize != filesize ||
1028: lbn != vp->v_lastw + 1 || vp->v_clen <= cursize) {
1029: cluster_wbuild(vp, NULL, bsize,
1030: vp->v_cstart, cursize, lbn, secsize, need_sync);
1031: } else {
1032: struct buf **bpp, **endbp;
1033: struct cluster_save *buflist;
1034:
1035: buflist = cluster_collectbufs(vp, bp);
1036:
1037: if (buflist == NULL) {
1038: cluster_wbuild(vp, NULL, bp->b_bcount,
1039: vp->v_cstart, cursize, lbn, secsize, need_sync);
1040: } else {
1041:
1042: endbp = &buflist->bs_children
1043: [buflist->bs_nchildren - 1];
1044: if (VOP_REALLOCBLKS(vp, buflist)) {
1045: /*
1046: * Failed, push the previous cluster.
1047: */
1048: for (bpp = buflist->bs_children;
1049: bpp < endbp; bpp++)
1050: brelse(*bpp);
1051: _FREE(buflist, M_SEGMENT);
1052:
1053: cluster_wbuild(vp, NULL, bsize,
1054: vp->v_cstart, cursize, lbn, secsize, need_sync);
1055: } else {
1056: /*
1057: * Succeeded, keep building cluster.
1058: * don't bdwrite the last bp, we'll
1059: * first check to see if we now have a full
1060: * cluster, or the caller has requested a SYNC write
1061: */
1062: for (bpp = buflist->bs_children;
1063: bpp < endbp; bpp++)
1064: bdwrite(*bpp);
1065: _FREE(buflist, M_SEGMENT);
1066: /*
1067: * update the physical block number because,
1068: * VOP_REALLOCBLKS will have changed it
1069: */
1070: bn = bp->b_blkno;
1071: goto chk_cluster_full;
1072: }
1073: }
1074: }
1075: }
1076: /*
1077: * Consider beginning a cluster.
1078: * If at end of file, make cluster as large as possible,
1079: * otherwise find size of existing cluster.
1080: */
1081: if (((u_quad_t)(lbn + 1)) * (u_quad_t)bsize != filesize &&
1082: (VOP_BMAP(vp, lbn, NULL, &bp->b_blkno, &maxclen) ||
1083: bp->b_blkno == -1)) {
1084: bn = bp->b_blkno;
1085: vp->v_clen = 0;
1086: vp->v_cstart = lbn + 1;
1087:
1088: if (need_sync)
1089: bwrite(bp);
1090: else
1091: bawrite(bp);
1092:
1093: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1094: bp->b_lblkno,
1095: bp->b_blkno,
1096: bp->b_bcount,
1097: vp->v_cstart,
1098: 1 );
1099: goto check_for_commit;
1100: }
1101: bn = bp->b_blkno;
1102:
1103: 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 */
1104: vp->v_cstart = lbn + 1; /* chunk of the I/O request */
1105:
1106: if (need_sync)
1107: bwrite(bp);
1108: else
1109: bawrite(bp);
1110:
1111: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1112: bp->b_lblkno,
1113: bp->b_blkno,
1114: bp->b_bcount,
1115: vp->v_cstart,
1116: 2 );
1117: } else { /* Wait for rest of cluster */
1118: vp->v_cstart = lbn;
1119:
1120: bdwrite(bp);
1121:
1122: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1123: bp->b_lblkno,
1124: bp->b_blkno,
1125: bp->b_bcount,
1126: vp->v_cstart,
1127: 3 );
1128: }
1129: goto check_for_commit;
1130: }
1131: chk_cluster_full:
1132: if ((lbn == vp->v_cstart + vp->v_clen) || need_commit) {
1133: /*
1134: * At end of cluster, write it out.
1135: */
1136: cluster_wbuild(vp, bp, bsize, vp->v_cstart,
1137: (lbn - vp->v_cstart) + 1, lbn, secsize, need_sync);
1138:
1139: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1140: vp->v_cstart,
1141: vp->v_clen + 1,
1142: lbn,
1143: 0,
1144: 4 );
1145: vp->v_clen = 0;
1146: vp->v_cstart = lbn + 1;
1147: } else {
1148: /*
1149: * In the middle of a cluster, so just delay the
1150: * I/O for now.
1151: */
1152: bdwrite(bp);
1153:
1154: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_END,
1155: bp->b_lblkno,
1156: bp->b_blkno,
1157: bp->b_bcount,
1158: vp->v_cstart,
1159: 5 );
1160: }
1161: check_for_commit:
1162: vp->v_lastw = lbn;
1163: vp->v_lasta = bn;
1164:
1165: if (need_commit) {
1166: bp = getblk(vp, lbn, bsize, 0, 0);
1167:
1168: if (bp->b_flags & B_ERROR)
1169: error = (bp->b_error ? bp->b_error : EIO);
1170: brelse(bp);
1171: }
1172: return (error);
1173: }
1174:
1175:
1176: /*
1177: * This is an awful lot like cluster_rbuild...wish they could be combined.
1178: * The last lbn argument is the current block on which I/O is being
1179: * performed. Check to see that it doesn't fall in the middle of
1180: * the current block (if last_bp == NULL).
1181: */
1182: void
1183: cluster_wbuild(vp, last_bp, size, start_lbn, len, lbn, secsize, need_sync)
1184: struct vnode *vp;
1185: struct buf *last_bp;
1186: long size;
1187: daddr_t start_lbn;
1188: int len;
1189: daddr_t lbn;
1190: long secsize;
1191: int need_sync;
1192: {
1193: struct cluster_save *b_save;
1194: struct buf *bp, *tbp;
1195: caddr_t cp;
1196: int i, s;
1197:
1198: #if DIAGNOSTIC
1199: if (size != vp->v_mount->mnt_stat.f_iosize)
1200: panic("cluster_wbuild: size %d != filesize %d\n",
1201: size, vp->v_mount->mnt_stat.f_iosize);
1202: #endif
1203: redo:
1204: while ((!incore(vp, start_lbn) || start_lbn == lbn) && len) {
1205: ++start_lbn;
1206: --len;
1207: }
1208: /* Get more memory for current buffer */
1209: if (len <= 1) {
1210: if (last_bp) {
1211: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1212: last_bp->b_lblkno,
1213: last_bp->b_blkno,
1214: last_bp->b_bcount,
1215: 1,
1216: 0 );
1217: if (need_sync)
1218: bwrite(last_bp);
1219: else
1220: bawrite(last_bp);
1221: } else if (len) {
1222: bp = getblk(vp, start_lbn, size, 0, 0);
1223:
1224: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1225: bp->b_lblkno,
1226: bp->b_blkno,
1227: bp->b_bcount,
1228: 2,
1229: 0 );
1230: if (bp->b_flags & B_DELWRI) {
1231: if (need_sync)
1232: bwrite(bp);
1233: else
1234: bawrite(bp);
1235: } else
1236: brelse(bp);
1237: }
1238: return;
1239: }
1240: b_save = _MALLOC(sizeof(struct buf *) * len + sizeof(struct cluster_save),
1241: M_SEGMENT, M_NOWAIT);
1242: if (b_save)
1243: bp = alloc_io_buf(vp);
1244: else
1245: bp = NULL;
1246:
1247: if (b_save == NULL || bp == NULL) {
1248: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1249: bp,
1250: b_save,
1251: 0,
1252: 4,
1253: 0 );
1254: if (bp)
1255: free_io_buf(bp);
1256: if (b_save)
1257: _FREE(b_save, M_SEGMENT);
1258:
1259: for (i = 0; i < len; ++i, ++start_lbn) {
1260: if (!incore(vp, start_lbn))
1261: continue;
1262: if (last_bp == NULL || start_lbn != lbn) {
1263: tbp = getblk(vp, start_lbn, size, 0, 0);
1264:
1265: if (tbp->b_flags & B_DELWRI) {
1266: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1267: tbp->b_lblkno,
1268: tbp->b_blkno,
1269: tbp->b_bcount,
1270: 5,
1271: 0 );
1272:
1273: if (need_sync)
1274: bwrite(tbp);
1275: else
1276: bawrite(tbp);
1277: } else
1278: brelse(tbp);
1279: }
1280: }
1281: if (last_bp) {
1282: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1283: last_bp->b_lblkno,
1284: last_bp->b_blkno,
1285: last_bp->b_bcount,
1286: 6,
1287: 0 );
1288: if (need_sync)
1289: bwrite(last_bp);
1290: else
1291: bawrite(last_bp);
1292: }
1293: return;
1294: }
1295: b_save->bs_bufsize = size;
1296: b_save->bs_nchildren = 0;
1297: b_save->bs_children = (struct buf **)(b_save + 1);
1298:
1299: bp->b_saveaddr = (caddr_t)b_save;
1300: bp->b_iodone = cluster_callback;
1301: bp->b_flags |= (B_WRITEINPROG | B_CALL | B_ASYNC);
1302:
1303: cp = (char *)bp->b_data;
1304:
1305: for (start_lbn, i = 0; i < len; ++i, ++start_lbn) {
1306: /*
1307: * Block is not in core or the non-sequential block
1308: * ending our cluster was part of the cluster (in which
1309: * case we don't want to write it twice).
1310: */
1311: if (!incore(vp, start_lbn) ||
1312: (last_bp == NULL && start_lbn == lbn))
1313: break;
1314:
1315: /*
1316: * Get the desired block buffer (unless it is the final
1317: * sequential block whose buffer was passed in explictly
1318: * as last_bp).
1319: */
1320: if (last_bp == NULL || start_lbn != lbn) {
1321: tbp = getblk(vp, start_lbn, size, 0, 0);
1322: if (!(tbp->b_flags & B_DELWRI)) {
1323: brelse(tbp);
1324: break;
1325: }
1326: } else
1327: tbp = last_bp;
1328:
1329: if (i == 0) {
1330: bp->b_blkno = tbp->b_blkno;
1331: bp->b_lblkno= tbp->b_lblkno;
1332: } else {
1333: if (tbp->b_blkno != (bp->b_blkno + btodb(bp->b_bufsize, secsize))) {
1334: brelse(tbp);
1335: break;
1336: }
1337: }
1338: /* Move memory from children to parent */
1339: pagemove(tbp->b_data, cp, size);
1340: bp->b_bcount += size;
1341: bp->b_bufsize += size;
1342: cp += size;
1343:
1344: tbp->b_bufsize -= size;
1345: tbp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
1346: tbp->b_flags |= (B_ASYNC | B_AGE);
1347:
1348: s = splbio();
1349: reassignbuf(tbp, tbp->b_vp); /* put on clean list */
1350: ++tbp->b_vp->v_numoutput;
1351: splx(s);
1352:
1353: b_save->bs_children[i] = tbp;
1354: b_save->bs_nchildren++;
1355: }
1356:
1357: KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 12)) | DBG_FUNC_NONE,
1358: bp->b_lblkno,
1359: bp->b_blkno,
1360: bp->b_bcount,
1361: 7,
1362: 0 );
1363: if (i == 0) {
1364: /* None to cluster */
1365: free_io_buf(bp);
1366: _FREE(b_save, M_SEGMENT);
1367: } else {
1368: if (bp->b_bcount > MAXPHYSIO)
1369: panic("cluster_wbuild: bp->b_bcount = %x\n", bp->b_bcount);
1370:
1371: VOP_STRATEGY(bp);
1372: }
1373: if (i < len) {
1374: len -= i + 1;
1375: start_lbn += 1;
1376: goto redo;
1377: }
1378: }
1379:
1380: /*
1381: * Collect together all the buffers in a cluster.
1382: * Plus add one additional buffer.
1383: */
1384: struct cluster_save *
1385: cluster_collectbufs(vp, last_bp)
1386: struct vnode *vp;
1387: struct buf *last_bp;
1388: {
1389: struct cluster_save *buflist;
1390: daddr_t lbn;
1391: int i, j, len;
1392:
1393: len = vp->v_lastw - vp->v_cstart + 1;
1394: buflist = _MALLOC(sizeof(struct buf *) * (len + 1) + sizeof(*buflist),
1395: M_SEGMENT, M_NOWAIT);
1396:
1397: if (buflist == NULL)
1398: return (NULL);
1399:
1400: buflist->bs_nchildren = 0;
1401: buflist->bs_children = (struct buf **)(buflist + 1);
1402: for (lbn = vp->v_cstart, i = 0; i < len; lbn++, i++) {
1403: (void)bread(vp, lbn, last_bp->b_bcount, NOCRED,
1404: &buflist->bs_children[i]);
1405: if(!(buflist->bs_children[i]->b_flags & B_DELWRI)) {
1406: for (j=0; j<=i; j++)
1407: brelse(buflist->bs_children[j]);
1408: _FREE(buflist, M_SEGMENT);
1409: return(NULL);
1410: }
1411: }
1412: buflist->bs_children[i] = last_bp;
1413: buflist->bs_nchildren = i + 1;
1414: return (buflist);
1415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.