123394Smckusick /* 229113Smckusick * Copyright (c) 1982, 1986 Regents of the University of California. 3*34432Sbostic * All rights reserved. 423394Smckusick * 5*34432Sbostic * Redistribution and use in source and binary forms are permitted 6*34432Sbostic * provided that this notice is preserved and that due credit is given 7*34432Sbostic * to the University of California at Berkeley. The name of the University 8*34432Sbostic * may not be used to endorse or promote products derived from this 9*34432Sbostic * software without specific prior written permission. This software 10*34432Sbostic * is provided ``as is'' without express or implied warranty. 11*34432Sbostic * 12*34432Sbostic * @(#)lfs_alloc.c 7.6 (Berkeley) 05/23/88 1323394Smckusick */ 144359Smckusick 1517097Sbloom #include "param.h" 1617097Sbloom #include "systm.h" 1717097Sbloom #include "mount.h" 1817097Sbloom #include "fs.h" 1917097Sbloom #include "buf.h" 2017097Sbloom #include "inode.h" 2117097Sbloom #include "dir.h" 2217097Sbloom #include "user.h" 2317097Sbloom #include "quota.h" 2417097Sbloom #include "kernel.h" 2518307Sralph #include "syslog.h" 2626253Skarels #include "cmap.h" 274359Smckusick 285212Smckusic extern u_long hashalloc(); 299163Ssam extern ino_t ialloccg(); 309163Ssam extern daddr_t alloccg(); 314651Smckusic extern daddr_t alloccgblk(); 324651Smckusic extern daddr_t fragextend(); 334651Smckusic extern daddr_t blkpref(); 344651Smckusic extern daddr_t mapsearch(); 354607Smckusic extern int inside[], around[]; 365322Smckusic extern unsigned char *fragtbl[]; 374359Smckusick 385375Smckusic /* 395375Smckusic * Allocate a block in the file system. 405375Smckusic * 415375Smckusic * The size of the requested block is given, which must be some 425375Smckusic * multiple of fs_fsize and <= fs_bsize. 435375Smckusic * A preference may be optionally specified. If a preference is given 445375Smckusic * the following hierarchy is used to allocate a block: 455375Smckusic * 1) allocate the requested block. 465375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 475375Smckusic * 3) allocate a block in the same cylinder group. 485375Smckusic * 4) quadradically rehash into other cylinder groups, until an 495375Smckusic * available block is located. 505375Smckusic * If no block preference is given the following heirarchy is used 515375Smckusic * to allocate a block: 525375Smckusic * 1) allocate a block in the cylinder group that contains the 535375Smckusic * inode for the file. 545375Smckusic * 2) quadradically rehash into other cylinder groups, until an 555375Smckusic * available block is located. 565375Smckusic */ 574359Smckusick struct buf * 585965Smckusic alloc(ip, bpref, size) 594463Smckusic register struct inode *ip; 604359Smckusick daddr_t bpref; 614359Smckusick int size; 624359Smckusick { 634359Smckusick daddr_t bno; 644359Smckusick register struct fs *fs; 654463Smckusic register struct buf *bp; 664359Smckusick int cg; 674359Smckusick 685965Smckusic fs = ip->i_fs; 696716Smckusick if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { 706716Smckusick printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", 716716Smckusick ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); 724463Smckusic panic("alloc: bad size"); 736716Smckusick } 745322Smckusic if (size == fs->fs_bsize && fs->fs_cstotal.cs_nbfree == 0) 754359Smckusick goto nospace; 7611638Ssam if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0) 774792Smckusic goto nospace; 787650Ssam #ifdef QUOTA 7912643Ssam u.u_error = chkdq(ip, (long)btodb(size), 0); 8012643Ssam if (u.u_error) 8112643Ssam return (NULL); 827483Skre #endif 834948Smckusic if (bpref >= fs->fs_size) 844948Smckusic bpref = 0; 854359Smckusick if (bpref == 0) 865377Smckusic cg = itog(fs, ip->i_number); 874359Smckusick else 885377Smckusic cg = dtog(fs, bpref); 899163Ssam bno = (daddr_t)hashalloc(ip, cg, (long)bpref, size, 909163Ssam (u_long (*)())alloccg); 916567Smckusic if (bno <= 0) 924359Smckusick goto nospace; 9312643Ssam ip->i_blocks += btodb(size); 9412643Ssam ip->i_flag |= IUPD|ICHG; 955965Smckusic bp = getblk(ip->i_dev, fsbtodb(fs, bno), size); 964359Smckusick clrbuf(bp); 974359Smckusick return (bp); 984359Smckusick nospace: 994359Smckusick fserr(fs, "file system full"); 1004359Smckusick uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 1014359Smckusick u.u_error = ENOSPC; 1024359Smckusick return (NULL); 1034359Smckusick } 1044359Smckusick 1055375Smckusic /* 1065375Smckusic * Reallocate a fragment to a bigger size 1075375Smckusic * 1085375Smckusic * The number and size of the old block is given, and a preference 1095375Smckusic * and new size is also specified. The allocator attempts to extend 1105375Smckusic * the original block. Failing that, the regular block allocator is 1115375Smckusic * invoked to get an appropriate block. 1125375Smckusic */ 1134426Smckusic struct buf * 1145965Smckusic realloccg(ip, bprev, bpref, osize, nsize) 1155965Smckusic register struct inode *ip; 1164651Smckusic daddr_t bprev, bpref; 1174426Smckusic int osize, nsize; 1184426Smckusic { 1194426Smckusic register struct fs *fs; 1204463Smckusic register struct buf *bp, *obp; 12124698Smckusick int cg, request; 12225471Smckusick daddr_t bno, bn; 12332664Smckusick int i, count; 1244426Smckusic 1255965Smckusic fs = ip->i_fs; 1265960Smckusic if ((unsigned)osize > fs->fs_bsize || fragoff(fs, osize) != 0 || 1276716Smckusick (unsigned)nsize > fs->fs_bsize || fragoff(fs, nsize) != 0) { 1286716Smckusick printf("dev = 0x%x, bsize = %d, osize = %d, nsize = %d, fs = %s\n", 1296716Smckusick ip->i_dev, fs->fs_bsize, osize, nsize, fs->fs_fsmnt); 1304463Smckusic panic("realloccg: bad size"); 1316716Smckusick } 13211638Ssam if (u.u_uid != 0 && freespace(fs, fs->fs_minfree) <= 0) 1334792Smckusic goto nospace; 1346716Smckusick if (bprev == 0) { 1356716Smckusick printf("dev = 0x%x, bsize = %d, bprev = %d, fs = %s\n", 1366716Smckusick ip->i_dev, fs->fs_bsize, bprev, fs->fs_fsmnt); 1374463Smckusic panic("realloccg: bad bprev"); 1386716Smckusick } 1397650Ssam #ifdef QUOTA 14012643Ssam u.u_error = chkdq(ip, (long)btodb(nsize - osize), 0); 14112643Ssam if (u.u_error) 14212643Ssam return (NULL); 1437483Skre #endif 1446294Smckusick cg = dtog(fs, bprev); 1455965Smckusic bno = fragextend(ip, cg, (long)bprev, osize, nsize); 1464463Smckusic if (bno != 0) { 1477187Sroot do { 1487187Sroot bp = bread(ip->i_dev, fsbtodb(fs, bno), osize); 1497187Sroot if (bp->b_flags & B_ERROR) { 1507187Sroot brelse(bp); 1517187Sroot return (NULL); 1527187Sroot } 1537187Sroot } while (brealloc(bp, nsize) == 0); 1547187Sroot bp->b_flags |= B_DONE; 1559163Ssam bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize); 15612643Ssam ip->i_blocks += btodb(nsize - osize); 15712643Ssam ip->i_flag |= IUPD|ICHG; 1584463Smckusic return (bp); 1594463Smckusic } 1604948Smckusic if (bpref >= fs->fs_size) 1614948Smckusic bpref = 0; 16226253Skarels switch ((int)fs->fs_optim) { 16325256Smckusick case FS_OPTSPACE: 16425256Smckusick /* 16525256Smckusick * Allocate an exact sized fragment. Although this makes 16625256Smckusick * best use of space, we will waste time relocating it if 16725256Smckusick * the file continues to grow. If the fragmentation is 16825256Smckusick * less than half of the minimum free reserve, we choose 16925256Smckusick * to begin optimizing for time. 17025256Smckusick */ 17124698Smckusick request = nsize; 17225256Smckusick if (fs->fs_minfree < 5 || 17325256Smckusick fs->fs_cstotal.cs_nffree > 17425256Smckusick fs->fs_dsize * fs->fs_minfree / (2 * 100)) 17525256Smckusick break; 17625256Smckusick log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n", 17725256Smckusick fs->fs_fsmnt); 17825256Smckusick fs->fs_optim = FS_OPTTIME; 17925256Smckusick break; 18025256Smckusick case FS_OPTTIME: 18125256Smckusick /* 18225256Smckusick * At this point we have discovered a file that is trying 18325256Smckusick * to grow a small fragment to a larger fragment. To save 18425256Smckusick * time, we allocate a full sized block, then free the 18525256Smckusick * unused portion. If the file continues to grow, the 18625256Smckusick * `fragextend' call above will be able to grow it in place 18725256Smckusick * without further copying. If aberrant programs cause 18825256Smckusick * disk fragmentation to grow within 2% of the free reserve, 18925256Smckusick * we choose to begin optimizing for space. 19025256Smckusick */ 19124698Smckusick request = fs->fs_bsize; 19225256Smckusick if (fs->fs_cstotal.cs_nffree < 19325256Smckusick fs->fs_dsize * (fs->fs_minfree - 2) / 100) 19425256Smckusick break; 19525256Smckusick log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n", 19625256Smckusick fs->fs_fsmnt); 19725256Smckusick fs->fs_optim = FS_OPTSPACE; 19825256Smckusick break; 19925256Smckusick default: 20025256Smckusick printf("dev = 0x%x, optim = %d, fs = %s\n", 20125256Smckusick ip->i_dev, fs->fs_optim, fs->fs_fsmnt); 20225256Smckusick panic("realloccg: bad optim"); 20325256Smckusick /* NOTREACHED */ 20425256Smckusick } 20524698Smckusick bno = (daddr_t)hashalloc(ip, cg, (long)bpref, request, 2069163Ssam (u_long (*)())alloccg); 2076567Smckusic if (bno > 0) { 2085965Smckusic obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize); 2095960Smckusic if (obp->b_flags & B_ERROR) { 2105960Smckusic brelse(obp); 2116294Smckusick return (NULL); 2125960Smckusic } 21325471Smckusick bn = fsbtodb(fs, bno); 21425471Smckusick bp = getblk(ip->i_dev, bn, nsize); 21517658Smckusick bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize); 21630749Skarels count = howmany(osize, CLBYTES); 21730749Skarels for (i = 0; i < count; i++) 21830749Skarels munhash(ip->i_dev, bn + i * CLBYTES / DEV_BSIZE); 21917658Smckusick bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize); 22017658Smckusick if (obp->b_flags & B_DELWRI) { 22117658Smckusick obp->b_flags &= ~B_DELWRI; 22217658Smckusick u.u_ru.ru_oublock--; /* delete charge */ 22317658Smckusick } 2244463Smckusic brelse(obp); 22531402Smckusick blkfree(ip, bprev, (off_t)osize); 22624698Smckusick if (nsize < request) 22731402Smckusick blkfree(ip, bno + numfrags(fs, nsize), 22824698Smckusick (off_t)(request - nsize)); 22912643Ssam ip->i_blocks += btodb(nsize - osize); 23012643Ssam ip->i_flag |= IUPD|ICHG; 2316294Smckusick return (bp); 2324463Smckusic } 2334792Smckusic nospace: 2344463Smckusic /* 2354463Smckusic * no space available 2364463Smckusic */ 2374426Smckusic fserr(fs, "file system full"); 2384426Smckusic uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); 2394426Smckusic u.u_error = ENOSPC; 2404426Smckusic return (NULL); 2414426Smckusic } 2424426Smckusic 2435375Smckusic /* 2445375Smckusic * Allocate an inode in the file system. 2455375Smckusic * 2465375Smckusic * A preference may be optionally specified. If a preference is given 2475375Smckusic * the following hierarchy is used to allocate an inode: 2485375Smckusic * 1) allocate the requested inode. 2495375Smckusic * 2) allocate an inode in the same cylinder group. 2505375Smckusic * 3) quadradically rehash into other cylinder groups, until an 2515375Smckusic * available inode is located. 2525375Smckusic * If no inode preference is given the following heirarchy is used 2535375Smckusic * to allocate an inode: 2545375Smckusic * 1) allocate an inode in cylinder group 0. 2555375Smckusic * 2) quadradically rehash into other cylinder groups, until an 2565375Smckusic * available inode is located. 2575375Smckusic */ 2584359Smckusick struct inode * 2595965Smckusic ialloc(pip, ipref, mode) 2605965Smckusic register struct inode *pip; 2614359Smckusick ino_t ipref; 2624359Smckusick int mode; 2634359Smckusick { 2645212Smckusic ino_t ino; 2654359Smckusick register struct fs *fs; 2664359Smckusick register struct inode *ip; 2674359Smckusick int cg; 2684359Smckusick 2695965Smckusic fs = pip->i_fs; 2704792Smckusic if (fs->fs_cstotal.cs_nifree == 0) 2714359Smckusick goto noinodes; 2727650Ssam #ifdef QUOTA 27312643Ssam u.u_error = chkiq(pip->i_dev, (struct inode *)NULL, u.u_uid, 0); 27412643Ssam if (u.u_error) 27512643Ssam return (NULL); 2767483Skre #endif 2774948Smckusic if (ipref >= fs->fs_ncg * fs->fs_ipg) 2784948Smckusic ipref = 0; 2795377Smckusic cg = itog(fs, ipref); 2805965Smckusic ino = (ino_t)hashalloc(pip, cg, (long)ipref, mode, ialloccg); 2814359Smckusick if (ino == 0) 2824359Smckusick goto noinodes; 2835965Smckusic ip = iget(pip->i_dev, pip->i_fs, ino); 2844359Smckusick if (ip == NULL) { 28515120Skarels ifree(pip, ino, 0); 2864359Smckusick return (NULL); 2874359Smckusick } 2886716Smckusick if (ip->i_mode) { 2896716Smckusick printf("mode = 0%o, inum = %d, fs = %s\n", 2906716Smckusick ip->i_mode, ip->i_number, fs->fs_fsmnt); 2914359Smckusick panic("ialloc: dup alloc"); 2926716Smckusick } 29312643Ssam if (ip->i_blocks) { /* XXX */ 29412643Ssam printf("free inode %s/%d had %d blocks\n", 29512643Ssam fs->fs_fsmnt, ino, ip->i_blocks); 29612643Ssam ip->i_blocks = 0; 29712643Ssam } 2984359Smckusick return (ip); 2994359Smckusick noinodes: 3004359Smckusick fserr(fs, "out of inodes"); 3016294Smckusick uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt); 3024359Smckusick u.u_error = ENOSPC; 3034359Smckusick return (NULL); 3044359Smckusick } 3054359Smckusick 3064651Smckusic /* 3075375Smckusic * Find a cylinder to place a directory. 3085375Smckusic * 3095375Smckusic * The policy implemented by this algorithm is to select from 3105375Smckusic * among those cylinder groups with above the average number of 3115375Smckusic * free inodes, the one with the smallest number of directories. 3124651Smckusic */ 3139163Ssam ino_t 3145965Smckusic dirpref(fs) 3155965Smckusic register struct fs *fs; 3164359Smckusick { 3174651Smckusic int cg, minndir, mincg, avgifree; 3184359Smckusick 3194792Smckusic avgifree = fs->fs_cstotal.cs_nifree / fs->fs_ncg; 3204651Smckusic minndir = fs->fs_ipg; 3214359Smckusick mincg = 0; 3224651Smckusic for (cg = 0; cg < fs->fs_ncg; cg++) 3235322Smckusic if (fs->fs_cs(fs, cg).cs_ndir < minndir && 3245322Smckusic fs->fs_cs(fs, cg).cs_nifree >= avgifree) { 3254359Smckusick mincg = cg; 3265322Smckusic minndir = fs->fs_cs(fs, cg).cs_ndir; 3274359Smckusick } 3289163Ssam return ((ino_t)(fs->fs_ipg * mincg)); 3294359Smckusick } 3304359Smckusick 3314651Smckusic /* 3329163Ssam * Select the desired position for the next block in a file. The file is 3339163Ssam * logically divided into sections. The first section is composed of the 3349163Ssam * direct blocks. Each additional section contains fs_maxbpg blocks. 3359163Ssam * 3369163Ssam * If no blocks have been allocated in the first section, the policy is to 3379163Ssam * request a block in the same cylinder group as the inode that describes 3389163Ssam * the file. If no blocks have been allocated in any other section, the 3399163Ssam * policy is to place the section in a cylinder group with a greater than 3409163Ssam * average number of free blocks. An appropriate cylinder group is found 34117696Smckusick * by using a rotor that sweeps the cylinder groups. When a new group of 34217696Smckusick * blocks is needed, the sweep begins in the cylinder group following the 34317696Smckusick * cylinder group from which the previous allocation was made. The sweep 34417696Smckusick * continues until a cylinder group with greater than the average number 34517696Smckusick * of free blocks is found. If the allocation is for the first block in an 34617696Smckusick * indirect block, the information on the previous allocation is unavailable; 34717696Smckusick * here a best guess is made based upon the logical block number being 34817696Smckusick * allocated. 3499163Ssam * 3509163Ssam * If a section is already partially allocated, the policy is to 3519163Ssam * contiguously allocate fs_maxcontig blocks. The end of one of these 3529163Ssam * contiguous blocks and the beginning of the next is physically separated 3539163Ssam * so that the disk head will be in transit between them for at least 3549163Ssam * fs_rotdelay milliseconds. This is to allow time for the processor to 3559163Ssam * schedule another I/O transfer. 3564651Smckusic */ 3575212Smckusic daddr_t 3589163Ssam blkpref(ip, lbn, indx, bap) 3599163Ssam struct inode *ip; 3609163Ssam daddr_t lbn; 3619163Ssam int indx; 3629163Ssam daddr_t *bap; 3639163Ssam { 3645965Smckusic register struct fs *fs; 36517696Smckusick register int cg; 36617696Smckusick int avgbfree, startcg; 3679163Ssam daddr_t nextblk; 3684651Smckusic 3699163Ssam fs = ip->i_fs; 3709163Ssam if (indx % fs->fs_maxbpg == 0 || bap[indx - 1] == 0) { 3719163Ssam if (lbn < NDADDR) { 3729163Ssam cg = itog(fs, ip->i_number); 3735322Smckusic return (fs->fs_fpg * cg + fs->fs_frag); 3744651Smckusic } 3759163Ssam /* 3769163Ssam * Find a cylinder with greater than average number of 3779163Ssam * unused data blocks. 3789163Ssam */ 37917696Smckusick if (indx == 0 || bap[indx - 1] == 0) 38017696Smckusick startcg = itog(fs, ip->i_number) + lbn / fs->fs_maxbpg; 38117696Smckusick else 38217696Smckusick startcg = dtog(fs, bap[indx - 1]) + 1; 38317696Smckusick startcg %= fs->fs_ncg; 3849163Ssam avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg; 38517696Smckusick for (cg = startcg; cg < fs->fs_ncg; cg++) 3869163Ssam if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 3879163Ssam fs->fs_cgrotor = cg; 3889163Ssam return (fs->fs_fpg * cg + fs->fs_frag); 3899163Ssam } 39017696Smckusick for (cg = 0; cg <= startcg; cg++) 3919163Ssam if (fs->fs_cs(fs, cg).cs_nbfree >= avgbfree) { 3929163Ssam fs->fs_cgrotor = cg; 3939163Ssam return (fs->fs_fpg * cg + fs->fs_frag); 3949163Ssam } 3959163Ssam return (NULL); 3969163Ssam } 3979163Ssam /* 3989163Ssam * One or more previous blocks have been laid out. If less 3999163Ssam * than fs_maxcontig previous blocks are contiguous, the 4009163Ssam * next block is requested contiguously, otherwise it is 4019163Ssam * requested rotationally delayed by fs_rotdelay milliseconds. 4029163Ssam */ 4039163Ssam nextblk = bap[indx - 1] + fs->fs_frag; 4049163Ssam if (indx > fs->fs_maxcontig && 40511638Ssam bap[indx - fs->fs_maxcontig] + blkstofrags(fs, fs->fs_maxcontig) 4069163Ssam != nextblk) 4079163Ssam return (nextblk); 4089163Ssam if (fs->fs_rotdelay != 0) 4099163Ssam /* 4109163Ssam * Here we convert ms of delay to frags as: 4119163Ssam * (frags) = (ms) * (rev/sec) * (sect/rev) / 4129163Ssam * ((sect/frag) * (ms/sec)) 4139163Ssam * then round up to the next block. 4149163Ssam */ 4159163Ssam nextblk += roundup(fs->fs_rotdelay * fs->fs_rps * fs->fs_nsect / 4169163Ssam (NSPF(fs) * 1000), fs->fs_frag); 4179163Ssam return (nextblk); 4184651Smckusic } 4194651Smckusic 4205375Smckusic /* 4215375Smckusic * Implement the cylinder overflow algorithm. 4225375Smckusic * 4235375Smckusic * The policy implemented by this algorithm is: 4245375Smckusic * 1) allocate the block in its requested cylinder group. 4255375Smckusic * 2) quadradically rehash on the cylinder group number. 4265375Smckusic * 3) brute force search for a free block. 4275375Smckusic */ 4285212Smckusic /*VARARGS5*/ 4295212Smckusic u_long 4305965Smckusic hashalloc(ip, cg, pref, size, allocator) 4315965Smckusic struct inode *ip; 4324359Smckusick int cg; 4334359Smckusick long pref; 4344359Smckusick int size; /* size for data blocks, mode for inodes */ 4355212Smckusic u_long (*allocator)(); 4364359Smckusick { 4375965Smckusic register struct fs *fs; 4384359Smckusick long result; 4394359Smckusick int i, icg = cg; 4404359Smckusick 4415965Smckusic fs = ip->i_fs; 4424359Smckusick /* 4434359Smckusick * 1: preferred cylinder group 4444359Smckusick */ 4455965Smckusic result = (*allocator)(ip, cg, pref, size); 4464359Smckusick if (result) 4474359Smckusick return (result); 4484359Smckusick /* 4494359Smckusick * 2: quadratic rehash 4504359Smckusick */ 4514359Smckusick for (i = 1; i < fs->fs_ncg; i *= 2) { 4524359Smckusick cg += i; 4534359Smckusick if (cg >= fs->fs_ncg) 4544359Smckusick cg -= fs->fs_ncg; 4555965Smckusic result = (*allocator)(ip, cg, 0, size); 4564359Smckusick if (result) 4574359Smckusick return (result); 4584359Smckusick } 4594359Smckusick /* 4604359Smckusick * 3: brute force search 46110847Ssam * Note that we start at i == 2, since 0 was checked initially, 46210847Ssam * and 1 is always checked in the quadratic rehash. 4634359Smckusick */ 46410848Smckusick cg = (icg + 2) % fs->fs_ncg; 46510847Ssam for (i = 2; i < fs->fs_ncg; i++) { 4665965Smckusic result = (*allocator)(ip, cg, 0, size); 4674359Smckusick if (result) 4684359Smckusick return (result); 4694359Smckusick cg++; 4704359Smckusick if (cg == fs->fs_ncg) 4714359Smckusick cg = 0; 4724359Smckusick } 4736294Smckusick return (NULL); 4744359Smckusick } 4754359Smckusick 4765375Smckusic /* 4775375Smckusic * Determine whether a fragment can be extended. 4785375Smckusic * 4795375Smckusic * Check to see if the necessary fragments are available, and 4805375Smckusic * if they are, allocate them. 4815375Smckusic */ 4824359Smckusick daddr_t 4835965Smckusic fragextend(ip, cg, bprev, osize, nsize) 4845965Smckusic struct inode *ip; 4854426Smckusic int cg; 4864463Smckusic long bprev; 4874426Smckusic int osize, nsize; 4884426Smckusic { 4895965Smckusic register struct fs *fs; 4904463Smckusic register struct buf *bp; 4914463Smckusic register struct cg *cgp; 4924463Smckusic long bno; 4934463Smckusic int frags, bbase; 4944426Smckusic int i; 4954426Smckusic 4965965Smckusic fs = ip->i_fs; 49717224Smckusick if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize)) 4986531Smckusick return (NULL); 4995960Smckusic frags = numfrags(fs, nsize); 50017224Smckusick bbase = fragnum(fs, bprev); 50117224Smckusick if (bbase > fragnum(fs, (bprev + frags - 1))) { 50230749Skarels /* cannot extend across a block boundary */ 5036294Smckusick return (NULL); 5044463Smckusic } 50510278Smckusick bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); 5066531Smckusick cgp = bp->b_un.b_cg; 50734143Smckusick if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) { 5085960Smckusic brelse(bp); 5096294Smckusick return (NULL); 5105960Smckusic } 5118105Sroot cgp->cg_time = time.tv_sec; 5125377Smckusic bno = dtogd(fs, bprev); 5135960Smckusic for (i = numfrags(fs, osize); i < frags; i++) 51434143Smckusick if (isclr(cg_blksfree(cgp), bno + i)) { 5155361Smckusic brelse(bp); 5166294Smckusick return (NULL); 5175361Smckusic } 5185361Smckusic /* 5195361Smckusic * the current fragment can be extended 5205361Smckusic * deduct the count on fragment being extended into 5215361Smckusic * increase the count on the remaining fragment (if any) 5225361Smckusic * allocate the extended piece 5235361Smckusic */ 5245361Smckusic for (i = frags; i < fs->fs_frag - bbase; i++) 52534143Smckusick if (isclr(cg_blksfree(cgp), bno + i)) 5264463Smckusic break; 5275960Smckusic cgp->cg_frsum[i - numfrags(fs, osize)]--; 5285361Smckusic if (i != frags) 5295361Smckusic cgp->cg_frsum[i - frags]++; 5305960Smckusic for (i = numfrags(fs, osize); i < frags; i++) { 53134143Smckusick clrbit(cg_blksfree(cgp), bno + i); 5325361Smckusic cgp->cg_cs.cs_nffree--; 5335361Smckusic fs->fs_cstotal.cs_nffree--; 5345361Smckusic fs->fs_cs(fs, cg).cs_nffree--; 5354463Smckusic } 5365361Smckusic fs->fs_fmod++; 5375361Smckusic bdwrite(bp); 5385361Smckusic return (bprev); 5394426Smckusic } 5404426Smckusic 5415375Smckusic /* 5425375Smckusic * Determine whether a block can be allocated. 5435375Smckusic * 5445375Smckusic * Check to see if a block of the apprpriate size is available, 5455375Smckusic * and if it is, allocate it. 5465375Smckusic */ 5479163Ssam daddr_t 5485965Smckusic alloccg(ip, cg, bpref, size) 5495965Smckusic struct inode *ip; 5504359Smckusick int cg; 5514359Smckusick daddr_t bpref; 5524359Smckusick int size; 5534359Smckusick { 5545965Smckusic register struct fs *fs; 5554463Smckusic register struct buf *bp; 5564463Smckusic register struct cg *cgp; 5574463Smckusic int bno, frags; 5584463Smckusic int allocsiz; 5594463Smckusic register int i; 5604359Smckusick 5615965Smckusic fs = ip->i_fs; 5625322Smckusic if (fs->fs_cs(fs, cg).cs_nbfree == 0 && size == fs->fs_bsize) 5636294Smckusick return (NULL); 56410278Smckusick bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); 5656531Smckusick cgp = bp->b_un.b_cg; 56634143Smckusick if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp) || 56715950Smckusick (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) { 5685960Smckusic brelse(bp); 5696294Smckusick return (NULL); 5705960Smckusic } 5718105Sroot cgp->cg_time = time.tv_sec; 5725322Smckusic if (size == fs->fs_bsize) { 5735212Smckusic bno = alloccgblk(fs, cgp, bpref); 5744463Smckusic bdwrite(bp); 5754463Smckusic return (bno); 5764463Smckusic } 5774463Smckusic /* 5784463Smckusic * check to see if any fragments are already available 5794463Smckusic * allocsiz is the size which will be allocated, hacking 5804463Smckusic * it down to a smaller size if necessary 5814463Smckusic */ 5825960Smckusic frags = numfrags(fs, size); 5835322Smckusic for (allocsiz = frags; allocsiz < fs->fs_frag; allocsiz++) 5844463Smckusic if (cgp->cg_frsum[allocsiz] != 0) 5854463Smckusic break; 5865322Smckusic if (allocsiz == fs->fs_frag) { 5874463Smckusic /* 5884463Smckusic * no fragments were available, so a block will be 5894463Smckusic * allocated, and hacked up 5904463Smckusic */ 5914792Smckusic if (cgp->cg_cs.cs_nbfree == 0) { 5924463Smckusic brelse(bp); 5936294Smckusick return (NULL); 5944463Smckusic } 5955212Smckusic bno = alloccgblk(fs, cgp, bpref); 5965377Smckusic bpref = dtogd(fs, bno); 5975322Smckusic for (i = frags; i < fs->fs_frag; i++) 59834143Smckusick setbit(cg_blksfree(cgp), bpref + i); 5995322Smckusic i = fs->fs_frag - frags; 6004792Smckusic cgp->cg_cs.cs_nffree += i; 6014792Smckusic fs->fs_cstotal.cs_nffree += i; 6025322Smckusic fs->fs_cs(fs, cg).cs_nffree += i; 6039762Ssam fs->fs_fmod++; 6044463Smckusic cgp->cg_frsum[i]++; 6054463Smckusic bdwrite(bp); 6064463Smckusic return (bno); 6074463Smckusic } 6084651Smckusic bno = mapsearch(fs, cgp, bpref, allocsiz); 60915950Smckusick if (bno < 0) { 61015950Smckusick brelse(bp); 6116294Smckusick return (NULL); 61215950Smckusick } 6134463Smckusic for (i = 0; i < frags; i++) 61434143Smckusick clrbit(cg_blksfree(cgp), bno + i); 6154792Smckusic cgp->cg_cs.cs_nffree -= frags; 6164792Smckusic fs->fs_cstotal.cs_nffree -= frags; 6175322Smckusic fs->fs_cs(fs, cg).cs_nffree -= frags; 6189762Ssam fs->fs_fmod++; 6194463Smckusic cgp->cg_frsum[allocsiz]--; 6204463Smckusic if (frags != allocsiz) 6214463Smckusic cgp->cg_frsum[allocsiz - frags]++; 6224463Smckusic bdwrite(bp); 6234463Smckusic return (cg * fs->fs_fpg + bno); 6244463Smckusic } 6254463Smckusic 6265375Smckusic /* 6275375Smckusic * Allocate a block in a cylinder group. 6285375Smckusic * 6295375Smckusic * This algorithm implements the following policy: 6305375Smckusic * 1) allocate the requested block. 6315375Smckusic * 2) allocate a rotationally optimal block in the same cylinder. 6325375Smckusic * 3) allocate the next available block on the block rotor for the 6335375Smckusic * specified cylinder group. 6345375Smckusic * Note that this routine only allocates fs_bsize blocks; these 6355375Smckusic * blocks may be fragmented by the routine that allocates them. 6365375Smckusic */ 6374463Smckusic daddr_t 6385212Smckusic alloccgblk(fs, cgp, bpref) 6395965Smckusic register struct fs *fs; 6404463Smckusic register struct cg *cgp; 6414463Smckusic daddr_t bpref; 6424463Smckusic { 6434651Smckusic daddr_t bno; 6446294Smckusick int cylno, pos, delta; 6454651Smckusic short *cylbp; 6465361Smckusic register int i; 6474463Smckusic 6484651Smckusic if (bpref == 0) { 6494651Smckusic bpref = cgp->cg_rotor; 6505361Smckusic goto norot; 6515361Smckusic } 65217224Smckusick bpref = blknum(fs, bpref); 6535377Smckusic bpref = dtogd(fs, bpref); 6545361Smckusic /* 6555361Smckusic * if the requested block is available, use it 6565361Smckusic */ 65734143Smckusick if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bpref))) { 6585361Smckusic bno = bpref; 6595361Smckusic goto gotit; 6605361Smckusic } 6615361Smckusic /* 6625361Smckusic * check for a block available on the same cylinder 6635361Smckusic */ 6645361Smckusic cylno = cbtocylno(fs, bpref); 66534143Smckusick if (cg_blktot(cgp)[cylno] == 0) 6665375Smckusic goto norot; 6675375Smckusic if (fs->fs_cpc == 0) { 6685375Smckusic /* 6695375Smckusic * block layout info is not available, so just have 6705375Smckusic * to take any block in this cylinder. 6715375Smckusic */ 6725375Smckusic bpref = howmany(fs->fs_spc * cylno, NSPF(fs)); 6735375Smckusic goto norot; 6745375Smckusic } 6755375Smckusic /* 6765361Smckusic * check the summary information to see if a block is 6775361Smckusic * available in the requested cylinder starting at the 6789163Ssam * requested rotational position and proceeding around. 6795361Smckusic */ 68034143Smckusick cylbp = cg_blks(fs, cgp, cylno); 6819163Ssam pos = cbtorpos(fs, bpref); 68234143Smckusick for (i = pos; i < fs->fs_nrpos; i++) 6835361Smckusic if (cylbp[i] > 0) 6845361Smckusic break; 68534143Smckusick if (i == fs->fs_nrpos) 6865361Smckusic for (i = 0; i < pos; i++) 6875361Smckusic if (cylbp[i] > 0) 6885361Smckusic break; 6895361Smckusic if (cylbp[i] > 0) { 6904651Smckusic /* 6915361Smckusic * found a rotational position, now find the actual 6925361Smckusic * block. A panic if none is actually there. 6934651Smckusic */ 6945361Smckusic pos = cylno % fs->fs_cpc; 6955361Smckusic bno = (cylno - pos) * fs->fs_spc / NSPB(fs); 69634143Smckusick if (fs_postbl(fs, pos)[i] == -1) { 6976716Smckusick printf("pos = %d, i = %d, fs = %s\n", 6986716Smckusick pos, i, fs->fs_fsmnt); 6995361Smckusic panic("alloccgblk: cyl groups corrupted"); 7006716Smckusick } 70134143Smckusick for (i = fs_postbl(fs, pos)[i];; ) { 70234143Smckusick if (isblock(fs, cg_blksfree(cgp), bno + i)) { 70311638Ssam bno = blkstofrags(fs, (bno + i)); 7045361Smckusic goto gotit; 7055361Smckusic } 70634143Smckusick delta = fs_rotbl(fs)[i]; 70734143Smckusick if (delta <= 0 || 70834143Smckusick delta + i > fragstoblks(fs, fs->fs_fpg)) 7094651Smckusic break; 7106294Smckusick i += delta; 7114651Smckusic } 7126716Smckusick printf("pos = %d, i = %d, fs = %s\n", pos, i, fs->fs_fsmnt); 7135361Smckusic panic("alloccgblk: can't find blk in cyl"); 7144359Smckusick } 7155361Smckusic norot: 7165361Smckusic /* 7175361Smckusic * no blocks in the requested cylinder, so take next 7185361Smckusic * available one in this cylinder group. 7195361Smckusic */ 7208628Sroot bno = mapsearch(fs, cgp, bpref, (int)fs->fs_frag); 7216567Smckusic if (bno < 0) 7226294Smckusick return (NULL); 7234651Smckusic cgp->cg_rotor = bno; 7244359Smckusick gotit: 72534143Smckusick clrblock(fs, cg_blksfree(cgp), (long)fragstoblks(fs, bno)); 7264792Smckusic cgp->cg_cs.cs_nbfree--; 7274792Smckusic fs->fs_cstotal.cs_nbfree--; 7285322Smckusic fs->fs_cs(fs, cgp->cg_cgx).cs_nbfree--; 7295375Smckusic cylno = cbtocylno(fs, bno); 73034143Smckusick cg_blks(fs, cgp, cylno)[cbtorpos(fs, bno)]--; 73134143Smckusick cg_blktot(cgp)[cylno]--; 7324359Smckusick fs->fs_fmod++; 7334651Smckusic return (cgp->cg_cgx * fs->fs_fpg + bno); 7344359Smckusick } 73534143Smckusick 7365375Smckusic /* 7375375Smckusic * Determine whether an inode can be allocated. 7385375Smckusic * 7395375Smckusic * Check to see if an inode is available, and if it is, 7405375Smckusic * allocate it using the following policy: 7415375Smckusic * 1) allocate the requested inode. 7425375Smckusic * 2) allocate the next available inode after the requested 7435375Smckusic * inode in the specified cylinder group. 7445375Smckusic */ 7459163Ssam ino_t 7465965Smckusic ialloccg(ip, cg, ipref, mode) 7475965Smckusic struct inode *ip; 7484359Smckusick int cg; 7494359Smckusick daddr_t ipref; 7504359Smckusick int mode; 7514359Smckusick { 7525965Smckusic register struct fs *fs; 7534463Smckusic register struct cg *cgp; 75416784Smckusick struct buf *bp; 75516784Smckusick int start, len, loc, map, i; 7564359Smckusick 7575965Smckusic fs = ip->i_fs; 7585322Smckusic if (fs->fs_cs(fs, cg).cs_nifree == 0) 7596294Smckusick return (NULL); 76010278Smckusick bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); 7616531Smckusick cgp = bp->b_un.b_cg; 76234143Smckusick if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp) || 76315950Smckusick cgp->cg_cs.cs_nifree == 0) { 7645960Smckusic brelse(bp); 7656294Smckusick return (NULL); 7665960Smckusic } 7678105Sroot cgp->cg_time = time.tv_sec; 7684359Smckusick if (ipref) { 7694359Smckusick ipref %= fs->fs_ipg; 77034143Smckusick if (isclr(cg_inosused(cgp), ipref)) 7714359Smckusick goto gotit; 77216784Smckusick } 77316784Smckusick start = cgp->cg_irotor / NBBY; 77416784Smckusick len = howmany(fs->fs_ipg - cgp->cg_irotor, NBBY); 77534143Smckusick loc = skpc(0xff, len, &cg_inosused(cgp)[start]); 77616784Smckusick if (loc == 0) { 77717697Smckusick len = start + 1; 77817697Smckusick start = 0; 77934143Smckusick loc = skpc(0xff, len, &cg_inosused(cgp)[0]); 78017697Smckusick if (loc == 0) { 78117697Smckusick printf("cg = %s, irotor = %d, fs = %s\n", 78217697Smckusick cg, cgp->cg_irotor, fs->fs_fsmnt); 78317697Smckusick panic("ialloccg: map corrupted"); 78417697Smckusick /* NOTREACHED */ 78517697Smckusick } 78616784Smckusick } 78716784Smckusick i = start + len - loc; 78834143Smckusick map = cg_inosused(cgp)[i]; 78916784Smckusick ipref = i * NBBY; 79016784Smckusick for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) { 79116784Smckusick if ((map & i) == 0) { 7924359Smckusick cgp->cg_irotor = ipref; 7934359Smckusick goto gotit; 7944359Smckusick } 7954359Smckusick } 79616784Smckusick printf("fs = %s\n", fs->fs_fsmnt); 79716784Smckusick panic("ialloccg: block not in map"); 79816784Smckusick /* NOTREACHED */ 7994359Smckusick gotit: 80034143Smckusick setbit(cg_inosused(cgp), ipref); 8014792Smckusic cgp->cg_cs.cs_nifree--; 8024792Smckusic fs->fs_cstotal.cs_nifree--; 8035322Smckusic fs->fs_cs(fs, cg).cs_nifree--; 8044359Smckusick fs->fs_fmod++; 8054359Smckusick if ((mode & IFMT) == IFDIR) { 8064792Smckusic cgp->cg_cs.cs_ndir++; 8074792Smckusic fs->fs_cstotal.cs_ndir++; 8085322Smckusic fs->fs_cs(fs, cg).cs_ndir++; 8094359Smckusick } 8104359Smckusick bdwrite(bp); 8114359Smckusick return (cg * fs->fs_ipg + ipref); 8124359Smckusick } 8134359Smckusick 8145375Smckusic /* 8155375Smckusic * Free a block or fragment. 8165375Smckusic * 8175375Smckusic * The specified block or fragment is placed back in the 8185375Smckusic * free map. If a fragment is deallocated, a possible 8195375Smckusic * block reassembly is checked. 8205375Smckusic */ 82131402Smckusick blkfree(ip, bno, size) 8225965Smckusic register struct inode *ip; 8234359Smckusick daddr_t bno; 8245212Smckusic off_t size; 8254359Smckusick { 8264359Smckusick register struct fs *fs; 8274359Smckusick register struct cg *cgp; 8284359Smckusick register struct buf *bp; 8294463Smckusic int cg, blk, frags, bbase; 8304463Smckusic register int i; 8314359Smckusick 8325965Smckusic fs = ip->i_fs; 8336716Smckusick if ((unsigned)size > fs->fs_bsize || fragoff(fs, size) != 0) { 8346716Smckusick printf("dev = 0x%x, bsize = %d, size = %d, fs = %s\n", 8356716Smckusick ip->i_dev, fs->fs_bsize, size, fs->fs_fsmnt); 83631402Smckusick panic("blkfree: bad size"); 8376716Smckusick } 8385377Smckusic cg = dtog(fs, bno); 8396567Smckusic if (badblock(fs, bno)) { 8406567Smckusic printf("bad block %d, ino %d\n", bno, ip->i_number); 8414359Smckusick return; 8426567Smckusic } 84310278Smckusick bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); 8446531Smckusick cgp = bp->b_un.b_cg; 84534143Smckusick if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) { 8465960Smckusic brelse(bp); 8474359Smckusick return; 8485960Smckusic } 8498105Sroot cgp->cg_time = time.tv_sec; 8505377Smckusic bno = dtogd(fs, bno); 8515322Smckusic if (size == fs->fs_bsize) { 85234143Smckusick if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno))) { 8536716Smckusick printf("dev = 0x%x, block = %d, fs = %s\n", 8546716Smckusick ip->i_dev, bno, fs->fs_fsmnt); 85531402Smckusick panic("blkfree: freeing free block"); 8566567Smckusic } 85734143Smckusick setblock(fs, cg_blksfree(cgp), fragstoblks(fs, bno)); 8584792Smckusic cgp->cg_cs.cs_nbfree++; 8594792Smckusic fs->fs_cstotal.cs_nbfree++; 8605322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 8615375Smckusic i = cbtocylno(fs, bno); 86234143Smckusick cg_blks(fs, cgp, i)[cbtorpos(fs, bno)]++; 86334143Smckusick cg_blktot(cgp)[i]++; 8644426Smckusic } else { 86517224Smckusick bbase = bno - fragnum(fs, bno); 8664463Smckusic /* 8674463Smckusic * decrement the counts associated with the old frags 8684463Smckusic */ 86934143Smckusick blk = blkmap(fs, cg_blksfree(cgp), bbase); 8705322Smckusic fragacct(fs, blk, cgp->cg_frsum, -1); 8714463Smckusic /* 8724463Smckusic * deallocate the fragment 8734463Smckusic */ 8745960Smckusic frags = numfrags(fs, size); 8754463Smckusic for (i = 0; i < frags; i++) { 87634143Smckusick if (isset(cg_blksfree(cgp), bno + i)) { 8776716Smckusick printf("dev = 0x%x, block = %d, fs = %s\n", 8786716Smckusick ip->i_dev, bno + i, fs->fs_fsmnt); 87931402Smckusick panic("blkfree: freeing free frag"); 8806716Smckusick } 88134143Smckusick setbit(cg_blksfree(cgp), bno + i); 8824426Smckusic } 8836294Smckusick cgp->cg_cs.cs_nffree += i; 8846294Smckusick fs->fs_cstotal.cs_nffree += i; 8856294Smckusick fs->fs_cs(fs, cg).cs_nffree += i; 8864463Smckusic /* 8874463Smckusic * add back in counts associated with the new frags 8884463Smckusic */ 88934143Smckusick blk = blkmap(fs, cg_blksfree(cgp), bbase); 8905322Smckusic fragacct(fs, blk, cgp->cg_frsum, 1); 8914463Smckusic /* 8924463Smckusic * if a complete block has been reassembled, account for it 8934463Smckusic */ 89434143Smckusick if (isblock(fs, cg_blksfree(cgp), fragstoblks(fs, bbase))) { 8955322Smckusic cgp->cg_cs.cs_nffree -= fs->fs_frag; 8965322Smckusic fs->fs_cstotal.cs_nffree -= fs->fs_frag; 8975322Smckusic fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag; 8984792Smckusic cgp->cg_cs.cs_nbfree++; 8994792Smckusic fs->fs_cstotal.cs_nbfree++; 9005322Smckusic fs->fs_cs(fs, cg).cs_nbfree++; 9015375Smckusic i = cbtocylno(fs, bbase); 90234143Smckusick cg_blks(fs, cgp, i)[cbtorpos(fs, bbase)]++; 90334143Smckusick cg_blktot(cgp)[i]++; 9044426Smckusic } 9054426Smckusic } 9064359Smckusick fs->fs_fmod++; 9074359Smckusick bdwrite(bp); 9084359Smckusick } 9094359Smckusick 9105375Smckusic /* 9115375Smckusic * Free an inode. 9125375Smckusic * 9135375Smckusic * The specified inode is placed back in the free map. 9145375Smckusic */ 9155965Smckusic ifree(ip, ino, mode) 9165965Smckusic struct inode *ip; 9174359Smckusick ino_t ino; 9184359Smckusick int mode; 9194359Smckusick { 9204359Smckusick register struct fs *fs; 9214359Smckusick register struct cg *cgp; 9224359Smckusick register struct buf *bp; 9234359Smckusick int cg; 9244359Smckusick 9255965Smckusic fs = ip->i_fs; 9266716Smckusick if ((unsigned)ino >= fs->fs_ipg*fs->fs_ncg) { 9276716Smckusick printf("dev = 0x%x, ino = %d, fs = %s\n", 9286716Smckusick ip->i_dev, ino, fs->fs_fsmnt); 9294359Smckusick panic("ifree: range"); 9306716Smckusick } 9315377Smckusic cg = itog(fs, ino); 93210278Smckusick bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize); 9336531Smckusick cgp = bp->b_un.b_cg; 93434143Smckusick if (bp->b_flags & B_ERROR || !cg_chkmagic(cgp)) { 9355960Smckusic brelse(bp); 9364359Smckusick return; 9375960Smckusic } 9388105Sroot cgp->cg_time = time.tv_sec; 9394359Smckusick ino %= fs->fs_ipg; 94034143Smckusick if (isclr(cg_inosused(cgp), ino)) { 9416716Smckusick printf("dev = 0x%x, ino = %d, fs = %s\n", 9426716Smckusick ip->i_dev, ino, fs->fs_fsmnt); 9434359Smckusick panic("ifree: freeing free inode"); 9446716Smckusick } 94534143Smckusick clrbit(cg_inosused(cgp), ino); 94616784Smckusick if (ino < cgp->cg_irotor) 94716784Smckusick cgp->cg_irotor = ino; 9484792Smckusic cgp->cg_cs.cs_nifree++; 9494792Smckusic fs->fs_cstotal.cs_nifree++; 9505322Smckusic fs->fs_cs(fs, cg).cs_nifree++; 9514359Smckusick if ((mode & IFMT) == IFDIR) { 9524792Smckusic cgp->cg_cs.cs_ndir--; 9534792Smckusic fs->fs_cstotal.cs_ndir--; 9545322Smckusic fs->fs_cs(fs, cg).cs_ndir--; 9554359Smckusick } 9564359Smckusick fs->fs_fmod++; 9574359Smckusick bdwrite(bp); 9584359Smckusick } 9594359Smckusick 9604463Smckusic /* 9615375Smckusic * Find a block of the specified size in the specified cylinder group. 9625375Smckusic * 9634651Smckusic * It is a panic if a request is made to find a block if none are 9644651Smckusic * available. 9654651Smckusic */ 9664651Smckusic daddr_t 9674651Smckusic mapsearch(fs, cgp, bpref, allocsiz) 9684651Smckusic register struct fs *fs; 9694651Smckusic register struct cg *cgp; 9704651Smckusic daddr_t bpref; 9714651Smckusic int allocsiz; 9724651Smckusic { 9734651Smckusic daddr_t bno; 9744651Smckusic int start, len, loc, i; 9754651Smckusic int blk, field, subfield, pos; 9764651Smckusic 9774651Smckusic /* 9784651Smckusic * find the fragment by searching through the free block 9794651Smckusic * map for an appropriate bit pattern 9804651Smckusic */ 9814651Smckusic if (bpref) 9825377Smckusic start = dtogd(fs, bpref) / NBBY; 9834651Smckusic else 9844651Smckusic start = cgp->cg_frotor / NBBY; 9855398Smckusic len = howmany(fs->fs_fpg, NBBY) - start; 98634143Smckusick loc = scanc((unsigned)len, (caddr_t)&cg_blksfree(cgp)[start], 98712755Ssam (caddr_t)fragtbl[fs->fs_frag], 98812755Ssam (int)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); 9894651Smckusic if (loc == 0) { 9906531Smckusick len = start + 1; 9916531Smckusick start = 0; 99234143Smckusick loc = scanc((unsigned)len, (caddr_t)&cg_blksfree(cgp)[0], 99312755Ssam (caddr_t)fragtbl[fs->fs_frag], 99412755Ssam (int)(1 << (allocsiz - 1 + (fs->fs_frag % NBBY)))); 99516784Smckusick if (loc == 0) { 99616784Smckusick printf("start = %d, len = %d, fs = %s\n", 99716784Smckusick start, len, fs->fs_fsmnt); 99816784Smckusick panic("alloccg: map corrupted"); 99917697Smckusick /* NOTREACHED */ 100016784Smckusick } 10014651Smckusic } 10024651Smckusic bno = (start + len - loc) * NBBY; 10034651Smckusic cgp->cg_frotor = bno; 10044651Smckusic /* 10054651Smckusic * found the byte in the map 10064651Smckusic * sift through the bits to find the selected frag 10074651Smckusic */ 10086294Smckusick for (i = bno + NBBY; bno < i; bno += fs->fs_frag) { 100934143Smckusick blk = blkmap(fs, cg_blksfree(cgp), bno); 10104651Smckusic blk <<= 1; 10114651Smckusic field = around[allocsiz]; 10124651Smckusic subfield = inside[allocsiz]; 10135322Smckusic for (pos = 0; pos <= fs->fs_frag - allocsiz; pos++) { 10146294Smckusick if ((blk & field) == subfield) 10156294Smckusick return (bno + pos); 10164651Smckusic field <<= 1; 10174651Smckusic subfield <<= 1; 10184651Smckusic } 10194651Smckusic } 10206716Smckusick printf("bno = %d, fs = %s\n", bno, fs->fs_fsmnt); 10214651Smckusic panic("alloccg: block not in map"); 10226531Smckusick return (-1); 10234651Smckusic } 10244651Smckusic 10254651Smckusic /* 10265375Smckusic * Fserr prints the name of a file system with an error diagnostic. 10275375Smckusic * 10285375Smckusic * The form of the error message is: 10294359Smckusick * fs: error message 10304359Smckusick */ 10314359Smckusick fserr(fs, cp) 10324359Smckusick struct fs *fs; 10334359Smckusick char *cp; 10344359Smckusick { 10354359Smckusick 103624839Seric log(LOG_ERR, "%s: %s\n", fs->fs_fsmnt, cp); 10374359Smckusick } 1038