/* * Read a disk block. * This algorithm described in Bach (p.54). */ int bread(struct vnode *vp, daddr_t blkno, int size, struct buf **bpp) { struct buf *bp; /* Get buffer for block. */ bp = *bpp = bio_doread(vp, blkno, size, 0); /* Wait for the read to complete, and return result. */ return (biowait(bp)); }
/* * Read-ahead multiple disk blocks. The first is sync, the rest async. * Trivial modification to the breada algorithm presented in Bach (p.55). */ int breadn(struct vnode *vp, daddr_t blkno, int size, daddr_t rablks[], int rasizes[], int nrablks, struct ucred *cred, struct buf **bpp) { struct buf *bp; int i; bp = *bpp = bio_doread(vp, blkno, size, 0); /* * For each of the read-ahead blocks, start a read, if necessary. */ for (i = 0; i < nrablks; i++) { /* If it's in the cache, just go on to next one. */ if (incore(vp, rablks[i])) continue; /* Get a buffer for the read-ahead block */ (void) bio_doread(vp, rablks[i], rasizes[i], B_ASYNC); } /* Otherwise, we had to start a read for it; wait until it's valid. */ return (biowait(bp)); }
int bread_cluster(struct vnode *vp, daddr_t blkno, int size, struct buf **rbpp) { struct buf *bp, **xbpp; int howmany, maxra, i, inc; daddr_t sblkno; *rbpp = bio_doread(vp, blkno, size, 0); if (size != round_page(size)) goto out; if (VOP_BMAP(vp, blkno + 1, NULL, &sblkno, &maxra)) goto out; maxra++; if (sblkno == -1 || maxra < 2) goto out; howmany = MAXPHYS / size; if (howmany > maxra) howmany = maxra; xbpp = malloc((howmany + 1) * sizeof(struct buf *), M_TEMP, M_NOWAIT); if (xbpp == NULL) goto out; for (i = howmany - 1; i >= 0; i--) { size_t sz; /* * First buffer allocates big enough size to cover what * all the other buffers need. */ sz = i == 0 ? howmany * size : 0; xbpp[i] = buf_get(vp, blkno + i + 1, sz); if (xbpp[i] == NULL) { for (++i; i < howmany; i++) { SET(xbpp[i]->b_flags, B_INVAL); brelse(xbpp[i]); } free(xbpp, M_TEMP); goto out; } } bp = xbpp[0]; xbpp[howmany] = 0; inc = btodb(size); for (i = 1; i < howmany; i++) { bcstats.pendingreads++; bcstats.numreads++; SET(xbpp[i]->b_flags, B_READ | B_ASYNC); xbpp[i]->b_blkno = sblkno + (i * inc); xbpp[i]->b_bufsize = xbpp[i]->b_bcount = size; xbpp[i]->b_data = NULL; xbpp[i]->b_pobj = bp->b_pobj; xbpp[i]->b_poffs = bp->b_poffs + (i * size); } KASSERT(bp->b_lblkno == blkno + 1); KASSERT(bp->b_vp == vp); bp->b_blkno = sblkno; SET(bp->b_flags, B_READ | B_ASYNC | B_CALL); bp->b_saveaddr = (void *)xbpp; bp->b_iodone = bread_cluster_callback; bcstats.pendingreads++; bcstats.numreads++; VOP_STRATEGY(bp); curproc->p_ru.ru_inblock++; out: return (biowait(*rbpp)); }