- return (0);
-noinodes:
- fserr(fs, cred->cr_uid, "out of inodes");
- uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
- return (ENOSPC);
-}
-
-/*
- * 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 using a rotor that sweeps the cylinder groups. When a new group of
- * blocks is needed, the sweep begins in the cylinder group following the
- * cylinder group from which the previous allocation was made. The sweep
- * continues until a cylinder group with greater than the average number
- * of free blocks is found. If the allocation is for the first block in an
- * indirect block, the information on the previous allocation is unavailable;
- * here a best guess is made based upon the logical block number being
- * allocated.
- *
- * 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;
- register int cg;
- int avgbfree, startcg;
- 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.
- */
- if (indx == 0 || bap[indx - 1] == 0)
- startcg = itog(fs, ip->i_number) + lbn / fs->fs_maxbpg;
- else
- startcg = dtog(fs, bap[indx - 1]) + 1;
- startcg %= fs->fs_ncg;
- avgbfree = fs->fs_cstotal.cs_nbfree / fs->fs_ncg;
- for (cg = startcg; 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 <= startcg; 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 cg *cgp;
- struct buf *bp;
- long bno;
- int frags, bbase;
- int i, error;
-
- fs = ip->i_fs;
- if (fs->fs_cs(fs, cg).cs_nffree < numfrags(fs, nsize - osize))
- return (NULL);
- frags = numfrags(fs, nsize);
- bbase = fragnum(fs, bprev);
- if (bbase > fragnum(fs, (bprev + frags - 1))) {
- /* cannot extend across a block boundary */
- return (NULL);
- }
-#ifdef SECSIZE
- bp = bread(ip->i_dev, fsbtodb(fs, cgtod(fs, cg)), (int)fs->fs_cgsize,
- fs->fs_dbsize);
-#else SECSIZE
- error = bread(ip->i_devvp, fsbtodb(fs, cgtod(fs, cg)),
- (int)fs->fs_cgsize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (NULL);
- }
-#endif SECSIZE
- cgp = bp->b_un.b_cg;
- if (!cg_chkmagic(cgp)) {
- brelse(bp);
- return (NULL);
- }
- cgp->cg_time = time.tv_sec;
- bno = dtogd(fs, bprev);
- for (i = numfrags(fs, osize); i < frags; i++)
- if (isclr(cg_blksfree(cgp), 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(cg_blksfree(cgp), 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(cg_blksfree(cgp), 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);
-}