diff options
Diffstat (limited to 'sys/ufs/ffs/ffs_alloc.c')
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 244 |
1 files changed, 185 insertions, 59 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index e1272ab..4787c1c 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -30,7 +30,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)ffs_alloc.c 8.8 (Berkeley) 2/21/94 + * @(#)ffs_alloc.c 8.18 (Berkeley) 5/26/95 * $FreeBSD$ */ @@ -57,23 +57,23 @@ extern u_long nextgennumber; -typedef daddr_t allocfcn_t __P((struct inode *ip, int cg, daddr_t bpref, - int size)); +typedef ufs_daddr_t allocfcn_t __P((struct inode *ip, int cg, ufs_daddr_t bpref, + int size)); -static daddr_t ffs_alloccg __P((struct inode *, int, daddr_t, int)); -static daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, daddr_t)); -#ifdef notyet -static daddr_t ffs_clusteralloc __P((struct inode *, int, daddr_t, int)); -#endif +static ufs_daddr_t ffs_alloccg __P((struct inode *, int, ufs_daddr_t, int)); +static ufs_daddr_t ffs_alloccgblk __P((struct fs *, struct cg *, ufs_daddr_t)); +static void ffs_clusteracct __P((struct fs *, struct cg *, ufs_daddr_t, + int)); +static ufs_daddr_t ffs_clusteralloc __P((struct inode *, int, ufs_daddr_t, + int)); static ino_t ffs_dirpref __P((struct fs *)); -static daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); +static ufs_daddr_t ffs_fragextend __P((struct inode *, int, long, int, int)); static void ffs_fserr __P((struct fs *, u_int, char *)); static u_long ffs_hashalloc __P((struct inode *, int, long, int, allocfcn_t *)); -static ino_t ffs_nodealloccg __P((struct inode *, int, daddr_t, int)); -static daddr_t ffs_mapsearch __P((struct fs *, struct cg *, daddr_t, int)); - -static void ffs_clusteracct __P((struct fs *, struct cg *, daddr_t, int)); +static ino_t ffs_nodealloccg __P((struct inode *, int, ufs_daddr_t, int)); +static ufs_daddr_t ffs_mapsearch __P((struct fs *, struct cg *, ufs_daddr_t, + int)); /* * Allocate a block in the file system. @@ -97,19 +97,18 @@ static void ffs_clusteracct __P((struct fs *, struct cg *, daddr_t, int)); int ffs_alloc(ip, lbn, bpref, size, cred, bnp) register struct inode *ip; - daddr_t lbn, bpref; + ufs_daddr_t lbn, bpref; int size; struct ucred *cred; - daddr_t *bnp; + ufs_daddr_t *bnp; { register struct fs *fs; - daddr_t bno; + ufs_daddr_t bno; int cg; #ifdef QUOTA int error; #endif - *bnp = 0; fs = ip->i_fs; #ifdef DIAGNOSTIC @@ -136,7 +135,8 @@ ffs_alloc(ip, lbn, bpref, size, cred, bnp) cg = ino_to_cg(fs, ip->i_number); else cg = dtog(fs, bpref); - bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, ffs_alloccg); + bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, size, + ffs_alloccg); if (bno > 0) { ip->i_blocks += btodb(size); ip->i_flag |= IN_CHANGE | IN_UPDATE; @@ -166,8 +166,8 @@ nospace: int ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) register struct inode *ip; - daddr_t lbprev; - daddr_t bpref; + ufs_daddr_t lbprev; + ufs_daddr_t bpref; int osize, nsize; struct ucred *cred; struct buf **bpp; @@ -175,7 +175,7 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) register struct fs *fs; struct buf *bp; int cg, request, error; - daddr_t bprev, bno; + ufs_daddr_t bprev, bno; *bpp = 0; fs = ip->i_fs; @@ -285,7 +285,8 @@ ffs_realloccg(ip, lbprev, bpref, osize, nsize, cred, bpp) panic("ffs_realloccg: bad optim"); /* NOTREACHED */ } - bno = (daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, ffs_alloccg); + bno = (ufs_daddr_t)ffs_hashalloc(ip, cg, (long)bpref, request, + ffs_alloccg); if (bno > 0) { bp->b_blkno = fsbtodb(fs, bno); ffs_blkfree(ip, bprev, (long)osize); @@ -331,7 +332,13 @@ nospace: * the previous block allocation will be used. */ static int doasyncfree = 1; -SYSCTL_INT(_debug, OID_AUTO, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); +SYSCTL_INT(_vfs_ffs, FFS_ASYNCFREE, doasyncfree, CTLFLAG_RW, &doasyncfree, 0, ""); + +int doreallocblks = 1; +SYSCTL_INT(_vfs_ffs, FFS_REALLOCBLKS, doreallocblks, CTLFLAG_RW, &doreallocblks, 0, ""); + +static int prtrealloc = 0; + int ffs_reallocblks(ap) struct vop_reallocblks_args /* { @@ -346,13 +353,15 @@ ffs_reallocblks(ap) struct inode *ip; struct vnode *vp; struct buf *sbp, *ebp; - daddr_t *bap, *sbap, *ebap = 0; + ufs_daddr_t *bap, *sbap, *ebap = 0; struct cluster_save *buflist; - daddr_t start_lbn, end_lbn, soff, newblk, blkno; + ufs_daddr_t start_lbn, end_lbn, soff, newblk, blkno; struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; int i, len, start_lvl, end_lvl, pref, ssize; struct timeval tv; + if (doreallocblks == 0) + return (ENOSPC); vp = ap->a_vp; ip = VTOI(vp); fs = ip->i_fs; @@ -363,9 +372,18 @@ ffs_reallocblks(ap) start_lbn = buflist->bs_children[0]->b_lblkno; end_lbn = start_lbn + len - 1; #ifdef DIAGNOSTIC + for (i = 0; i < len; i++) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 1"); for (i = 1; i < len; i++) if (buflist->bs_children[i]->b_lblkno != start_lbn + i) - panic("ffs_reallocblks: non-cluster"); + panic("ffs_reallocblks: non-logical cluster"); + blkno = buflist->bs_children[0]->b_blkno; + ssize = fsbtodb(fs, fs->fs_frag); + for (i = 1; i < len - 1; i++) + if (buflist->bs_children[i]->b_blkno != blkno + (i * ssize)) + panic("ffs_reallocblks: non-physical cluster %d", i); #endif /* * If the latest allocation is in a new cylinder group, assume that @@ -390,7 +408,7 @@ ffs_reallocblks(ap) brelse(sbp); return (ENOSPC); } - sbap = (daddr_t *)sbp->b_data; + sbap = (ufs_daddr_t *)sbp->b_data; soff = idp->in_off; } /* @@ -410,12 +428,12 @@ ffs_reallocblks(ap) ssize = len - (idp->in_off + 1); if (bread(vp, idp->in_lbn, (int)fs->fs_bsize, NOCRED, &ebp)) goto fail; - ebap = (daddr_t *)ebp->b_data; + ebap = (ufs_daddr_t *)ebp->b_data; } /* * Search the block map looking for an allocation of the desired size. */ - if ((newblk = (daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, + if ((newblk = (ufs_daddr_t)ffs_hashalloc(ip, dtog(fs, pref), (long)pref, len, ffs_clusteralloc)) == 0) goto fail; /* @@ -425,14 +443,26 @@ ffs_reallocblks(ap) * block pointers in the inode and indirect blocks associated * with the file. */ +#ifdef DEBUG + if (prtrealloc) + printf("realloc: ino %d, lbns %d-%d\n\told:", ip->i_number, + start_lbn, end_lbn); +#endif blkno = newblk; for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->fs_frag) { if (i == ssize) bap = ebap; #ifdef DIAGNOSTIC - if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 2"); + if (dbtofsb(fs, buflist->bs_children[i]->b_blkno) != *bap) panic("ffs_reallocblks: alloc mismatch"); #endif +#ifdef DEBUG + if (prtrealloc) + printf(" %d,", *bap); +#endif *bap++ = blkno; } /* @@ -469,11 +499,28 @@ ffs_reallocblks(ap) /* * Last, free the old blocks and assign the new blocks to the buffers. */ +#ifdef DEBUG + if (prtrealloc) + printf("\n\tnew:"); +#endif for (blkno = newblk, i = 0; i < len; i++, blkno += fs->fs_frag) { ffs_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize); buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); +#ifdef DEBUG + if (!ffs_checkblk(ip, + dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->fs_bsize)) + panic("ffs_reallocblks: unallocated block 3"); + if (prtrealloc) + printf(" %d,", blkno); +#endif + } +#ifdef DEBUG + if (prtrealloc) { + prtrealloc--; + printf("\n"); } +#endif return (0); fail: @@ -615,17 +662,17 @@ ffs_dirpref(fs) * fs_rotdelay milliseconds. This is to allow time for the processor to * schedule another I/O transfer. */ -daddr_t +ufs_daddr_t ffs_blkpref(ip, lbn, indx, bap) struct inode *ip; - daddr_t lbn; + ufs_daddr_t lbn; int indx; - daddr_t *bap; + ufs_daddr_t *bap; { register struct fs *fs; register int cg; int avgbfree, startcg; - daddr_t nextblk; + ufs_daddr_t nextblk; fs = ip->i_fs; if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { @@ -740,7 +787,7 @@ ffs_hashalloc(ip, cg, pref, size, allocator) * Check to see if the necessary fragments are available, and * if they are, allocate them. */ -static daddr_t +static ufs_daddr_t ffs_fragextend(ip, cg, bprev, osize, nsize) struct inode *ip; int cg; @@ -810,11 +857,11 @@ ffs_fragextend(ip, cg, bprev, osize, nsize) * Check to see if a block of the appropriate size is available, * and if it is, allocate it. */ -static daddr_t +static ufs_daddr_t ffs_alloccg(ip, cg, bpref, size) struct inode *ip; int cg; - daddr_t bpref; + ufs_daddr_t bpref; int size; { register struct fs *fs; @@ -904,13 +951,13 @@ ffs_alloccg(ip, cg, bpref, size) * Note that this routine only allocates fs_bsize blocks; these * blocks may be fragmented by the routine that allocates them. */ -static daddr_t +static ufs_daddr_t ffs_alloccgblk(fs, cgp, bpref) register struct fs *fs; register struct cg *cgp; - daddr_t bpref; + ufs_daddr_t bpref; { - daddr_t bno, blkno; + ufs_daddr_t bno, blkno; int cylno, pos, delta; short *cylbp; register int i; @@ -1016,21 +1063,22 @@ gotit: * are multiple choices in the same cylinder group. Instead we just * take the first one that we find following bpref. */ -static daddr_t +static ufs_daddr_t ffs_clusteralloc(ip, cg, bpref, len) struct inode *ip; int cg; - daddr_t bpref; + ufs_daddr_t bpref; int len; { register struct fs *fs; register struct cg *cgp; struct buf *bp; - int i, run, bno, bit, map; + int i, got, run, bno, bit, map; u_char *mapp; + int32_t *lp; fs = ip->i_fs; - if (fs->fs_cs(fs, cg).cs_nbfree < len) + if (fs->fs_maxcluster[cg] < len) return (NULL); if (bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize, NOCRED, &bp)) @@ -1042,11 +1090,25 @@ ffs_clusteralloc(ip, cg, bpref, len) * Check to see if a cluster of the needed size (or bigger) is * available in this cylinder group. */ + lp = &cg_clustersum(cgp)[len]; for (i = len; i <= fs->fs_contigsumsize; i++) - if (cg_clustersum(cgp)[i] > 0) + if (*lp++ > 0) break; - if (i > fs->fs_contigsumsize) + if (i > fs->fs_contigsumsize) { + /* + * This is the first time looking for a cluster in this + * cylinder group. Update the cluster summary information + * to reflect the true maximum sized cluster so that + * future cluster allocation requests can avoid reading + * the cylinder group map only to find no clusters. + */ + lp = &cg_clustersum(cgp)[len - 1]; + for (i = len - 1; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cg] = i; goto fail; + } /* * Search the cluster map to find a big enough cluster. * We take the first one that we find, even if it is larger @@ -1065,7 +1127,7 @@ ffs_clusteralloc(ip, cg, bpref, len) mapp = &cg_clustersfree(cgp)[bpref / NBBY]; map = *mapp++; bit = 1 << (bpref % NBBY); - for (run = 0, i = bpref; i < cgp->cg_nclusterblks; i++) { + for (run = 0, got = bpref; got < cgp->cg_nclusterblks; got++) { if ((map & bit) == 0) { run = 0; } else { @@ -1073,22 +1135,27 @@ ffs_clusteralloc(ip, cg, bpref, len) if (run == len) break; } - if ((i & (NBBY - 1)) != (NBBY - 1)) { + if ((got & (NBBY - 1)) != (NBBY - 1)) { bit <<= 1; } else { map = *mapp++; bit = 1; } } - if (i == cgp->cg_nclusterblks) + if (got == cgp->cg_nclusterblks) goto fail; /* * Allocate the cluster that we have found. */ - bno = cg * fs->fs_fpg + blkstofrags(fs, i - run + 1); + for (i = 1; i <= len; i++) + if (!ffs_isblock(fs, cg_blksfree(cgp), got - run + i)) + panic("ffs_clusteralloc: map mismatch"); + bno = cg * fs->fs_fpg + blkstofrags(fs, got - run + 1); + if (dtog(fs, bno) != cg) + panic("ffs_clusteralloc: allocated out of group"); len = blkstofrags(fs, len); for (i = 0; i < len; i += fs->fs_frag) - if (ffs_alloccgblk(fs, cgp, bno + i) != bno + i) + if ((got = ffs_alloccgblk(fs, cgp, bno + i)) != bno + i) panic("ffs_clusteralloc: lost block"); bdwrite(bp); return (bno); @@ -1112,7 +1179,7 @@ static ino_t ffs_nodealloccg(ip, cg, ipref, mode) struct inode *ip; int cg; - daddr_t ipref; + ufs_daddr_t ipref; int mode; { register struct fs *fs; @@ -1191,13 +1258,13 @@ gotit: void ffs_blkfree(ip, bno, size) register struct inode *ip; - daddr_t bno; + ufs_daddr_t bno; long size; { register struct fs *fs; register struct cg *cgp; struct buf *bp; - daddr_t blkno; + ufs_daddr_t blkno; int i, error, cg, blk, frags, bbase; fs = ip->i_fs; @@ -1288,6 +1355,56 @@ ffs_blkfree(ip, bno, size) bdwrite(bp); } +#ifdef DIAGNOSTIC +/* + * Verify allocation of a block or fragment. Returns true if block or + * fragment is allocated, false if it is free. + */ +ffs_checkblk(ip, bno, size) + struct inode *ip; + ufs_daddr_t bno; + long size; +{ + struct fs *fs; + struct cg *cgp; + struct buf *bp; + int i, error, frags, free; + + fs = ip->i_fs; + if ((u_int)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("bsize = %d, size = %d, fs = %s\n", + fs->fs_bsize, size, fs->fs_fsmnt); + panic("checkblk: bad size"); + } + if ((u_int)bno >= fs->fs_size) + panic("checkblk: bad block %d", bno); + error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, dtog(fs, bno))), + (int)fs->fs_cgsize, NOCRED, &bp); + if (error) { + brelse(bp); + return; + } + cgp = (struct cg *)bp->b_data; + if (!cg_chkmagic(cgp)) { + brelse(bp); + return; + } + bno = dtogd(fs, bno); + if (size == fs->fs_bsize) { + free = ffs_isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno)); + } else { + frags = numfrags(fs, size); + for (free = 0, i = 0; i < frags; i++) + if (isset(cg_blksfree(cgp), bno + i)) + free++; + if (free != 0 && free != frags) + panic("checkblk: partially free fragment"); + } + brelse(bp); + return (!free); +} +#endif /* DIAGNOSTIC */ + /* * Free an inode. * @@ -1355,14 +1472,14 @@ ffs_vfree(ap) * It is a panic if a request is made to find a block if none are * available. */ -static daddr_t +static ufs_daddr_t ffs_mapsearch(fs, cgp, bpref, allocsiz) register struct fs *fs; register struct cg *cgp; - daddr_t bpref; + ufs_daddr_t bpref; int allocsiz; { - daddr_t bno; + ufs_daddr_t bno; int start, len, loc, i; int blk, field, subfield, pos; @@ -1423,10 +1540,11 @@ static void ffs_clusteracct(fs, cgp, blkno, cnt) struct fs *fs; struct cg *cgp; - daddr_t blkno; + ufs_daddr_t blkno; int cnt; { - long *sump; + int32_t *sump; + int32_t *lp; u_char *freemapp, *mapp; int i, start, end, forw, back, map, bit; @@ -1495,6 +1613,14 @@ ffs_clusteracct(fs, cgp, blkno, cnt) sump[back] -= cnt; if (forw > 0) sump[forw] -= cnt; + /* + * Update cluster summary information. + */ + lp = &sump[fs->fs_contigsumsize]; + for (i = fs->fs_contigsumsize; i > 0; i--) + if (*lp-- > 0) + break; + fs->fs_maxcluster[cgp->cg_cgx] = i; } /* |