From: CSRG Date: Wed, 28 Sep 1983 10:55:25 +0000 (-0800) Subject: BSD 4_2 development X-Git-Tag: BSD-4_3^2~35 X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/commitdiff_plain/a1183b775d29c753730e2bb5414401d5a851fff5 BSD 4_2 development Work on file usr/src/sys/sys/ufs_alloc.c Synthesized-from: CSRG/cd1/4.2 --- diff --git a/usr/src/sys/sys/ufs_alloc.c b/usr/src/sys/sys/ufs_alloc.c new file mode 100644 index 0000000000..f9527b7d47 --- /dev/null +++ b/usr/src/sys/sys/ufs_alloc.c @@ -0,0 +1,937 @@ +/* ufs_alloc.c 6.2 83/09/28 */ + +#include "../h/param.h" +#include "../h/systm.h" +#include "../h/mount.h" +#include "../h/fs.h" +#include "../h/conf.h" +#include "../h/buf.h" +#include "../h/inode.h" +#include "../h/dir.h" +#include "../h/user.h" +#include "../h/quota.h" +#include "../h/kernel.h" + +extern u_long hashalloc(); +extern ino_t ialloccg(); +extern daddr_t alloccg(); +extern daddr_t alloccgblk(); +extern daddr_t fragextend(); +extern daddr_t blkpref(); +extern daddr_t mapsearch(); +extern int inside[], around[]; +extern unsigned char *fragtbl[]; + +/* + * Allocate a block in the file system. + * + * The size of the requested block is given, which must be some + * multiple of fs_fsize and <= fs_bsize. + * A preference may be optionally specified. If a preference is given + * the following hierarchy is used to allocate a block: + * 1) allocate the requested block. + * 2) allocate a rotationally optimal block in the same cylinder. + * 3) allocate a block in the same cylinder group. + * 4) quadradically rehash into other cylinder groups, until an + * available block is located. + * If no block preference is given the following heirarchy is used + * to allocate a block: + * 1) allocate a block in the cylinder group that contains the + * inode for the file. + * 2) quadradically rehash into other cylinder groups, until an + * available block is located. + */ +struct buf * +alloc(ip, bpref, size) + register struct inode *ip; + daddr_t bpref; + int size; +{ + daddr_t bno; + register struct fs *fs; + register struct buf *bp; + int cg; + + fs = ip->i_fs; + if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", + ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); + panic("alloc: bad size"); + } + if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) + goto nospace; + if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0) + goto nospace; +#ifdef QUOTA + u.u_error = chkdq(ip, (long)btodb(size), 0); + if (u.u_error) + return (NULL); +#endif + if (bpref >= fs->fs_size) + bpref = 0; + if (bpref == 0) + cg = itog(fs, ip->i_number); + else + cg = dtog(fs, bpref); + bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size, + (u_long (*)())alloccg); + if (bno <= 0) + goto nospace; + ip->i_blocks += btodb(size); + ip->i_flag |= IUPD|ICHG; + bp = getblk(ip->i_dev, fsbtodb(fs, bno), size); + clrbuf(bp); + return (bp); +nospace: + fserr(fs, "file system full"); + uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); + u.u_error = ENOSPC; + return (NULL); +} + +/* + * Reallocate a fragment to a bigger size + * + * The number and size of the old block is given, and a preference + * and new size is also specified. The allocator attempts to extend + * the original block. Failing that, the regular block allocator is + * invoked to get an appropriate block. + */ +struct buf * +realloccg(ip, bprev, bpref, osize, nsize) + register struct inode *ip; + daddr_t bprev, bpref; + int osize, nsize; +{ + daddr_t bno; + register struct fs *fs; + register struct buf *bp, *obp; + int cg; + + fs = ip->i_fs; + if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || + (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) { + printf("dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n", + ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt); + panic("realloccg: bad size"); + } + if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0) + goto nospace; + if (bprev == 0) { + printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n", + ip->i_dev, fs->fs_bsize, bprev, fs->fs_fsmnt); + panic("realloccg: bad bprev"); + } +#ifdef QUOTA + u.u_error = chkdq(ip, (long)btodb(nsize - osize), 0); + if (u.u_error) + return (NULL); +#endif + cg = dtog(fs, bprev); + bno = fragextend(ip, cg, (long)bprev, osize, nsize); + if (bno != 0) { + do { + bp = bread(ip->i_dev, fsbtodb(fs, bno), osize); + if (bp->b_flags & B_ERROR) { + brelse(bp); + return (NULL); + } + } while (brealloc(bp, nsize) == 0); + bp->b_flags |= B_DONE; + bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize); + ip->i_blocks += btodb(nsize - osize); + ip->i_flag |= IUPD|ICHG; + return (bp); + } + if (bpref >= fs->fs_size) + bpref = 0; + bno = (daddr_t)hashalloc(ip, cg, (long)bpref, nsize, + (u_long (*)())alloccg); + if (bno > 0) { + obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize); + if (obp->b_flags & B_ERROR) { + brelse(obp); + return (NULL); + } + bp = getblk(ip->i_dev, fsbtodb(fs, bno), nsize); + bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize); + bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize); + brelse(obp); + free(ip, bprev, (off_t)osize); + ip->i_blocks += btodb(nsize - osize); + ip->i_flag |= IUPD|ICHG; + return (bp); + } +nospace: + /* + * no space available + */ + fserr(fs, "file system full"); + uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); + u.u_error = ENOSPC; + return (NULL); +} + +/* + * Allocate an inode in the file system. + * + * A preference may be optionally specified. If a preference is given + * the following hierarchy is used to allocate an inode: + * 1) allocate the requested inode. + * 2) allocate an inode in the same cylinder group. + * 3) quadradically rehash into other cylinder groups, until an + * available inode is located. + * If no inode preference is given the following heirarchy is used + * to allocate an inode: + * 1) allocate an inode in cylinder group 0. + * 2) quadradically rehash into other cylinder groups, until an + * available inode is located. + */ +struct inode * +ialloc(pip, ipref, mode) + register struct inode *pip; + ino_t ipref; + int mode; +{ + ino_t ino; + register struct fs *fs; + register struct inode *ip; + int cg; + + fs = pip->i_fs; + if (fs->fs_cstotal.cs_nifree == 0) + goto noinodes; +#ifdef QUOTA + u.u_error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0); + if (u.u_error) + return (NULL); +#endif + if (ipref >= fs->fs_ncg * fs->fs_ipg) + ipref = 0; + cg = itog(fs, ipref); + ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg); + if (ino == 0) + goto noinodes; + ip = iget(pip->i_dev, pip->i_fs, ino); + if (ip == NULL) { + ifree(pip, ino, 0); + return (NULL); + } + if (ip->i_mode) { + printf("mode = 0%o, inum = %d, fs = %s\n", + ip->i_mode, ip->i_number, fs->fs_fsmnt); + panic("ialloc: dup alloc"); + } + if (ip->i_blocks) { /* XXX */ + printf("free inode %s/%d had %d blocks\n", + fs->fs_fsmnt, ino, ip->i_blocks); + ip->i_blocks = 0; + } + return (ip); +noinodes: + fserr(fs, "out of inodes"); + uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); + u.u_error = ENOSPC; + return (NULL); +} + +/* + * Find a cylinder to place a directory. + * + * The policy implemented by this algorithm is to select from + * among those cylinder groups with above the average number of + * free inodes, the one with the smallest number of directories. + */ +ino_t +dirpref(fs) + register struct fs *fs; +{ + int cg, minndir, mincg, avgifree; + + avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; + minndir = fs->fs_ipg; + mincg = 0; + for (cg = 0; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_ndir < minndir && + fs->fs_cs(fs, cg).cs_nifree >= avgifree) { + mincg = cg; + minndir = fs->fs_cs(fs, cg).cs_ndir; + } + return ((ino_t)(fs->fs_ipg * mincg)); +} + +/* + * Select the desired position for the next block in a file. The file is + * logically divided into sections. The first section is composed of the + * direct blocks. Each additional section contains fs_maxbpg blocks. + * + * If no blocks have been allocated in the first section, the policy is to + * request a block in the same cylinder group as the inode that describes + * the file. If no blocks have been allocated in any other section, the + * policy is to place the section in a cylinder group with a greater than + * average number of free blocks. An appropriate cylinder group is found + * by maintaining a rotor that sweeps the cylinder groups. When a new + * group of blocks is needed, the rotor is advanced until a cylinder group + * with greater than the average number of free blocks is found. + * + * If a section is already partially allocated, the policy is to + * contiguously allocate fs_maxcontig blocks. The end of one of these + * contiguous blocks and the beginning of the next is physically separated + * so that the disk head will be in transit between them for at least + * fs_rotdelay milliseconds. This is to allow time for the processor to + * schedule another I/O transfer. + */ +daddr_t +blkpref(ip, lbn, indx, bap) + struct inode *ip; + daddr_t lbn; + int indx; + daddr_t *bap; +{ + register struct fs *fs; + int cg, avgbfree; + daddr_t nextblk; + + fs = ip->i_fs; + if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { + if (lbn < NDADDR) { + cg = itog(fs, ip->i_number); + return (fs->fs_fpg * cg + fs->fs_frag); + } + /* + * Find a cylinder with greater than average number of + * unused data blocks. + */ + avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; + for (cg = fs->fs_cgrotor + 1; cg < fs->fs_ncg; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (fs->fs_fpg * cg + fs->fs_frag); + } + for (cg = 0; cg <= fs->fs_cgrotor; cg++) + if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { + fs->fs_cgrotor = cg; + return (fs->fs_fpg * cg + fs->fs_frag); + } + return (NULL); + } + /* + * One or more previous blocks have been laid out. If less + * than fs_maxcontig previous blocks are contiguous, the + * next block is requested contiguously, otherwise it is + * requested rotationally delayed by fs_rotdelay milliseconds. + */ + nextblk = bap[indx - 1] + fs->fs_frag; + if (indx > fs->fs_maxcontig && + bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig) + != nextblk) + return (nextblk); + if (fs->fs_rotdelay != 0) + /* + * Here we convert ms of delay to frags as: + * (frags) = (ms) * (rev/sec) * (sect/rev) / + * ((sect/frag) * (ms/sec)) + * then round up to the next block. + */ + nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / + (NSPF(fs) * 1000), fs->fs_frag); + return (nextblk); +} + +/* + * Implement the cylinder overflow algorithm. + * + * The policy implemented by this algorithm is: + * 1) allocate the block in its requested cylinder group. + * 2) quadradically rehash on the cylinder group number. + * 3) brute force search for a free block. + */ +/*VARARGS5*/ +u_long +hashalloc(ip, cg, pref, size, allocator) + struct inode *ip; + int cg; + long pref; + int size; /* size for data blocks, mode for inodes */ + u_long (*allocator)(); +{ + register struct fs *fs; + long result; + int i, icg = cg; + + fs = ip->i_fs; + /* + * 1: preferred cylinder group + */ + result = (*allocator)(ip, cg, pref, size); + if (result) + return (result); + /* + * 2: quadratic rehash + */ + for (i = 1; i < fs->fs_ncg; i *= 2) { + cg += i; + if (cg >= fs->fs_ncg) + cg -= fs->fs_ncg; + result = (*allocator)(ip, cg, 0, size); + if (result) + return (result); + } + /* + * 3: brute force search + * Note that we start at i == 2, since 0 was checked initially, + * and 1 is always checked in the quadratic rehash. + */ + cg = (icg + 2) % fs->fs_ncg; + for (i = 2; i < fs->fs_ncg; i++) { + result = (*allocator)(ip, cg, 0, size); + if (result) + return (result); + cg++; + if (cg == fs->fs_ncg) + cg = 0; + } + return (NULL); +} + +/* + * Determine whether a fragment can be extended. + * + * Check to see if the necessary fragments are available, and + * if they are, allocate them. + */ +daddr_t +fragextend(ip, cg, bprev, osize, nsize) + struct inode *ip; + int cg; + long bprev; + int osize, nsize; +{ + register struct fs *fs; + register struct buf *bp; + register struct cg *cgp; + long bno; + int frags, bbase; + int i; + + fs = ip->i_fs; + if (fs->fs_cs(fs, cg).cs_nffree < nsize - osize) + return (NULL); + frags = numfrags(fs, nsize); + bbase = fragoff(fs, bprev); + if (bbase > (bprev + frags - 1) % fs->fs_frag) { + /* cannot extend across a block boundry */ + return (NULL); + } + bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); + cgp = bp->b_un.b_cg; + if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { + brelse(bp); + return (NULL); + } + cgp->cg_time = time.tv_sec; + bno = dtogd(fs, bprev); + for (i = numfrags(fs, osize); i < frags; i++) + if (isclr(cgp->cg_free, bno + i)) { + brelse(bp); + return (NULL); + } + /* + * the current fragment can be extended + * deduct the count on fragment being extended into + * increase the count on the remaining fragment (if any) + * allocate the extended piece + */ + for (i = frags; i < fs->fs_frag - bbase; i++) + if (isclr(cgp->cg_free, bno + i)) + break; + cgp->cg_frsum[i - numfrags(fs, osize)]--; + if (i != frags) + cgp->cg_frsum[i - frags]++; + for (i = numfrags(fs, osize); i < frags; i++) { + clrbit(cgp->cg_free, bno + i); + cgp->cg_cs.cs_nffree--; + fs->fs_cstotal.cs_nffree--; + fs->fs_cs(fs, cg).cs_nffree--; + } + fs->fs_fmod++; + bdwrite(bp); + return (bprev); +} + +/* + * Determine whether a block can be allocated. + * + * Check to see if a block of the apprpriate size is available, + * and if it is, allocate it. + */ +daddr_t +alloccg(ip, cg, bpref, size) + struct inode *ip; + int cg; + daddr_t bpref; + int size; +{ + register struct fs *fs; + register struct buf *bp; + register struct cg *cgp; + int bno, frags; + int allocsiz; + register int i; + + fs = ip->i_fs; + if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) + return (NULL); + bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); + cgp = bp->b_un.b_cg; + if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { + brelse(bp); + return (NULL); + } + if (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize) + return (NULL); + cgp->cg_time = time.tv_sec; + if (size == fs->fs_bsize) { + bno = alloccgblk(fs, cgp, bpref); + bdwrite(bp); + return (bno); + } + /* + * check to see if any fragments are already available + * allocsiz is the size which will be allocated, hacking + * it down to a smaller size if necessary + */ + frags = numfrags(fs, size); + for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) + if (cgp->cg_frsum[allocsiz] != 0) + break; + if (allocsiz == fs->fs_frag) { + /* + * no fragments were available, so a block will be + * allocated, and hacked up + */ + if (cgp->cg_cs.cs_nbfree == 0) { + brelse(bp); + return (NULL); + } + bno = alloccgblk(fs, cgp, bpref); + bpref = dtogd(fs, bno); + for (i = frags; i < fs->fs_frag; i++) + setbit(cgp->cg_free, bpref + i); + i = fs->fs_frag - frags; + cgp->cg_cs.cs_nffree += i; + fs->fs_cstotal.cs_nffree += i; + fs->fs_cs(fs, cg).cs_nffree += i; + fs->fs_fmod++; + cgp->cg_frsum[i]++; + bdwrite(bp); + return (bno); + } + bno = mapsearch(fs, cgp, bpref, allocsiz); + if (bno < 0) + return (NULL); + for (i = 0; i < frags; i++) + clrbit(cgp->cg_free, bno + i); + cgp->cg_cs.cs_nffree -= frags; + fs->fs_cstotal.cs_nffree -= frags; + fs->fs_cs(fs, cg).cs_nffree -= frags; + fs->fs_fmod++; + cgp->cg_frsum[allocsiz]--; + if (frags != allocsiz) + cgp->cg_frsum[allocsiz - frags]++; + bdwrite(bp); + return (cg * fs->fs_fpg + bno); +} + +/* + * Allocate a block in a cylinder group. + * + * This algorithm implements the following policy: + * 1) allocate the requested block. + * 2) allocate a rotationally optimal block in the same cylinder. + * 3) allocate the next available block on the block rotor for the + * specified cylinder group. + * Note that this routine only allocates fs_bsize blocks; these + * blocks may be fragmented by the routine that allocates them. + */ +daddr_t +alloccgblk(fs, cgp, bpref) + register struct fs *fs; + register struct cg *cgp; + daddr_t bpref; +{ + daddr_t bno; + int cylno, pos, delta; + short *cylbp; + register int i; + + if (bpref == 0) { + bpref = cgp->cg_rotor; + goto norot; + } + bpref &= ~(fs->fs_frag - 1); + bpref = dtogd(fs, bpref); + /* + * if the requested block is available, use it + */ + if (isblock(fs, cgp->cg_free, fragstoblks(fs, bpref))) { + bno = bpref; + goto gotit; + } + /* + * check for a block available on the same cylinder + */ + cylno = cbtocylno(fs, bpref); + if (cgp->cg_btot[cylno] == 0) + goto norot; + if (fs->fs_cpc == 0) { + /* + * block layout info is not available, so just have + * to take any block in this cylinder. + */ + bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); + goto norot; + } + /* + * check the summary information to see if a block is + * available in the requested cylinder starting at the + * requested rotational position and proceeding around. + */ + cylbp = cgp->cg_b[cylno]; + pos = cbtorpos(fs, bpref); + for (i = pos; i < NRPOS; i++) + if (cylbp[i] > 0) + break; + if (i == NRPOS) + for (i = 0; i < pos; i++) + if (cylbp[i] > 0) + break; + if (cylbp[i] > 0) { + /* + * found a rotational position, now find the actual + * block. A panic if none is actually there. + */ + pos = cylno % fs->fs_cpc; + bno = (cylno - pos) * fs->fs_spc / NSPB(fs); + if (fs->fs_postbl[pos][i] == -1) { + printf("pos = %d, i = %d, fs = %s\n", + pos, i, fs->fs_fsmnt); + panic("alloccgblk: cyl groups corrupted"); + } + for (i = fs->fs_postbl[pos][i];; ) { + if (isblock(fs, cgp->cg_free, bno + i)) { + bno = blkstofrags(fs, (bno + i)); + goto gotit; + } + delta = fs->fs_rotbl[i]; + if (delta <= 0 || delta > MAXBPC - i) + break; + i += delta; + } + printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt); + panic("alloccgblk: can't find blk in cyl"); + } +norot: + /* + * no blocks in the requested cylinder, so take next + * available one in this cylinder group. + */ + bno = mapsearch(fs, cgp, bpref, (int)fs->fs_frag); + if (bno < 0) + return (NULL); + cgp->cg_rotor = bno; +gotit: + clrblock(fs, cgp->cg_free, (long)fragstoblks(fs, bno)); + cgp->cg_cs.cs_nbfree--; + fs->fs_cstotal.cs_nbfree--; + fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; + cylno = cbtocylno(fs, bno); + cgp->cg_b[cylno][cbtorpos(fs, bno)]--; + cgp->cg_btot[cylno]--; + fs->fs_fmod++; + return (cgp->cg_cgx * fs->fs_fpg + bno); +} + +/* + * Determine whether an inode can be allocated. + * + * Check to see if an inode is available, and if it is, + * allocate it using the following policy: + * 1) allocate the requested inode. + * 2) allocate the next available inode after the requested + * inode in the specified cylinder group. + */ +ino_t +ialloccg(ip, cg, ipref, mode) + struct inode *ip; + int cg; + daddr_t ipref; + int mode; +{ + register struct fs *fs; + register struct buf *bp; + register struct cg *cgp; + int i; + + fs = ip->i_fs; + if (fs->fs_cs(fs, cg).cs_nifree == 0) + return (NULL); + bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); + cgp = bp->b_un.b_cg; + if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { + brelse(bp); + return (NULL); + } + if (cgp->cg_cs.cs_nifree == 0) + return (NULL); + cgp->cg_time = time.tv_sec; + if (ipref) { + ipref %= fs->fs_ipg; + if (isclr(cgp->cg_iused, ipref)) + goto gotit; + } else + ipref = cgp->cg_irotor; + for (i = 0; i < fs->fs_ipg; i++) { + ipref++; + if (ipref >= fs->fs_ipg) + ipref = 0; + if (isclr(cgp->cg_iused, ipref)) { + cgp->cg_irotor = ipref; + goto gotit; + } + } + brelse(bp); + return (NULL); +gotit: + setbit(cgp->cg_iused, ipref); + cgp->cg_cs.cs_nifree--; + fs->fs_cstotal.cs_nifree--; + fs->fs_cs(fs, cg).cs_nifree--; + fs->fs_fmod++; + if ((mode & IFMT) == IFDIR) { + cgp->cg_cs.cs_ndir++; + fs->fs_cstotal.cs_ndir++; + fs->fs_cs(fs, cg).cs_ndir++; + } + bdwrite(bp); + return (cg * fs->fs_ipg + ipref); +} + +/* + * Free a block or fragment. + * + * The specified block or fragment is placed back in the + * free map. If a fragment is deallocated, a possible + * block reassembly is checked. + */ +free(ip, bno, size) + register struct inode *ip; + daddr_t bno; + off_t size; +{ + register struct fs *fs; + register struct cg *cgp; + register struct buf *bp; + int cg, blk, frags, bbase; + register int i; + + fs = ip->i_fs; + if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { + printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", + ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); + panic("free: bad size"); + } + cg = dtog(fs, bno); + if (badblock(fs, bno)) { + printf("bad block %d, ino %d\n", bno, ip->i_number); + return; + } + bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); + cgp = bp->b_un.b_cg; + if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { + brelse(bp); + return; + } + cgp->cg_time = time.tv_sec; + bno = dtogd(fs, bno); + if (size == fs->fs_bsize) { + if (isblock(fs, cgp->cg_free, fragstoblks(fs, bno))) { + printf("dev = 0x%x, block = %d, fs = %s\n", + ip->i_dev, bno, fs->fs_fsmnt); + panic("free: freeing free block"); + } + setblock(fs, cgp->cg_free, fragstoblks(fs, bno)); + cgp->cg_cs.cs_nbfree++; + fs->fs_cstotal.cs_nbfree++; + fs->fs_cs(fs, cg).cs_nbfree++; + i = cbtocylno(fs, bno); + cgp->cg_b[i][cbtorpos(fs, bno)]++; + cgp->cg_btot[i]++; + } else { + bbase = bno - (bno % fs->fs_frag); + /* + * decrement the counts associated with the old frags + */ + blk = blkmap(fs, cgp->cg_free, bbase); + fragacct(fs, blk, cgp->cg_frsum, -1); + /* + * deallocate the fragment + */ + frags = numfrags(fs, size); + for (i = 0; i < frags; i++) { + if (isset(cgp->cg_free, bno + i)) { + printf("dev = 0x%x, block = %d, fs = %s\n", + ip->i_dev, bno + i, fs->fs_fsmnt); + panic("free: freeing free frag"); + } + setbit(cgp->cg_free, bno + i); + } + cgp->cg_cs.cs_nffree += i; + fs->fs_cstotal.cs_nffree += i; + fs->fs_cs(fs, cg).cs_nffree += i; + /* + * add back in counts associated with the new frags + */ + blk = blkmap(fs, cgp->cg_free, bbase); + fragacct(fs, blk, cgp->cg_frsum, 1); + /* + * if a complete block has been reassembled, account for it + */ + if (isblock(fs, cgp->cg_free, fragstoblks(fs, bbase))) { + cgp->cg_cs.cs_nffree -= fs->fs_frag; + fs->fs_cstotal.cs_nffree -= fs->fs_frag; + fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; + cgp->cg_cs.cs_nbfree++; + fs->fs_cstotal.cs_nbfree++; + fs->fs_cs(fs, cg).cs_nbfree++; + i = cbtocylno(fs, bbase); + cgp->cg_b[i][cbtorpos(fs, bbase)]++; + cgp->cg_btot[i]++; + } + } + fs->fs_fmod++; + bdwrite(bp); +} + +/* + * Free an inode. + * + * The specified inode is placed back in the free map. + */ +ifree(ip, ino, mode) + struct inode *ip; + ino_t ino; + int mode; +{ + register struct fs *fs; + register struct cg *cgp; + register struct buf *bp; + int cg; + + fs = ip->i_fs; + if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) { + printf("dev = 0x%x, ino = %d, fs = %s\n", + ip->i_dev, ino, fs->fs_fsmnt); + panic("ifree: range"); + } + cg = itog(fs, ino); + bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); + cgp = bp->b_un.b_cg; + if (bp->b_flags & B_ERROR || cgp->cg_magic != CG_MAGIC) { + brelse(bp); + return; + } + cgp->cg_time = time.tv_sec; + ino %= fs->fs_ipg; + if (isclr(cgp->cg_iused, ino)) { + printf("dev = 0x%x, ino = %d, fs = %s\n", + ip->i_dev, ino, fs->fs_fsmnt); + panic("ifree: freeing free inode"); + } + clrbit(cgp->cg_iused, ino); + cgp->cg_cs.cs_nifree++; + fs->fs_cstotal.cs_nifree++; + fs->fs_cs(fs, cg).cs_nifree++; + if ((mode & IFMT) == IFDIR) { + cgp->cg_cs.cs_ndir--; + fs->fs_cstotal.cs_ndir--; + fs->fs_cs(fs, cg).cs_ndir--; + } + fs->fs_fmod++; + bdwrite(bp); +} + +/* + * Find a block of the specified size in the specified cylinder group. + * + * It is a panic if a request is made to find a block if none are + * available. + */ +daddr_t +mapsearch(fs, cgp, bpref, allocsiz) + register struct fs *fs; + register struct cg *cgp; + daddr_t bpref; + int allocsiz; +{ + daddr_t bno; + int start, len, loc, i; + int blk, field, subfield, pos; + + /* + * find the fragment by searching through the free block + * map for an appropriate bit pattern + */ + if (bpref) + start = dtogd(fs, bpref) / NBBY; + else + start = cgp->cg_frotor / NBBY; + len = howmany(fs->fs_fpg, NBBY) - start; + loc = scanc((unsigned)len, (caddr_t)&cgp->cg_free[start], + (caddr_t)fragtbl[fs->fs_frag], + (int)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); + if (loc == 0) { + len = start + 1; + start = 0; + loc = scanc((unsigned)len, (caddr_t)&cgp->cg_free[start], + (caddr_t)fragtbl[fs->fs_frag], + (int)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); + if (loc == 0) + return (-1); + } + bno = (start + len - loc) * NBBY; + cgp->cg_frotor = bno; + /* + * found the byte in the map + * sift through the bits to find the selected frag + */ + for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { + blk = blkmap(fs, cgp->cg_free, bno); + blk <<= 1; + field = around[allocsiz]; + subfield = inside[allocsiz]; + for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { + if ((blk & field) == subfield) + return (bno + pos); + field <<= 1; + subfield <<= 1; + } + } + printf("bno = %d, fs = %s\n", bno, fs->fs_fsmnt); + panic("alloccg: block not in map"); + return (-1); +} + +/* + * Fserr prints the name of a file system with an error diagnostic. + * + * The form of the error message is: + * fs: error message + */ +fserr(fs, cp) + struct fs *fs; + char *cp; +{ + + printf("%s: %s\n", fs->fs_fsmnt, cp); +}