summaryrefslogtreecommitdiffstats
path: root/sys/ufs/ffs/ffs_alloc.c
diff options
context:
space:
mode:
authordyson <dyson@FreeBSD.org>1997-02-10 02:22:35 +0000
committerdyson <dyson@FreeBSD.org>1997-02-10 02:22:35 +0000
commit10f666af84d48e89e4e2960415c9b616fce4077f (patch)
tree88a944de263165091f0a18abeedbaaccec532407 /sys/ufs/ffs/ffs_alloc.c
parent0960d7e91af3428ffba89b42228d82d8afaa0389 (diff)
downloadFreeBSD-src-10f666af84d48e89e4e2960415c9b616fce4077f.zip
FreeBSD-src-10f666af84d48e89e4e2960415c9b616fce4077f.tar.gz
This is the kernel Lite/2 commit. There are some requisite userland
changes, so don't expect to be able to run the kernel as-is (very well) without the appropriate Lite/2 userland changes. The system boots and can mount UFS filesystems. Untested: ext2fs, msdosfs, NFS Known problems: Incorrect Berkeley ID strings in some files. Mount_std mounts will not work until the getfsent library routine is changed. Reviewed by: various people Submitted by: Jeffery Hsu <hsu@freebsd.org>
Diffstat (limited to 'sys/ufs/ffs/ffs_alloc.c')
-rw-r--r--sys/ufs/ffs/ffs_alloc.c244
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;
}
/*
OpenPOWER on IntegriCloud