-/*
- * 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.
- */
-realloccg(ip, bprev, bpref, osize, nsize, bpp)
- register struct inode *ip;
- daddr_t bprev, bpref;
- int osize, nsize;
- struct buf **bpp;
-{
- register struct fs *fs;
- struct buf *bp, *obp;
- int cg, request;
- daddr_t bno, bn;
- int i, error, count;
-
- *bpp = 0;
- 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
- if (error = chkdq(ip, (long)btodb(nsize - osize), 0))
- return (error);
-#endif
- cg = dtog(fs, bprev);
- bno = fragextend(ip, cg, (long)bprev, osize, nsize);
- if (bno != 0) {
- do {
-#ifdef SECSIZE
- bp = bread(ip->i_dev, fsbtodb(fs, bno), osize,
- fs->fs_dbsize);
-#else SECSIZE
- error = bread(ip->i_devvp, fsbtodb(fs, bno),
- osize, NOCRED, &bp);
- if (error) {
- brelse(bp);
- return (error);
- }
- } 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;
- *bpp = bp;
- return (0);
- }
- if (bpref >= fs->fs_size)
- bpref = 0;
- switch ((int)fs->fs_optim) {
- case FS_OPTSPACE:
- /*
- * Allocate an exact sized fragment. Although this makes
- * best use of space, we will waste time relocating it if
- * the file continues to grow. If the fragmentation is
- * less than half of the minimum free reserve, we choose
- * to begin optimizing for time.
- */
- request = nsize;
- if (fs->fs_minfree < 5 ||
- fs->fs_cstotal.cs_nffree >
- fs->fs_dsize * fs->fs_minfree / (2 * 100))
- break;
- log(LOG_NOTICE, "%s: optimization changed from SPACE to TIME\n",
- fs->fs_fsmnt);
- fs->fs_optim = FS_OPTTIME;
- break;
- case FS_OPTTIME:
- /*
- * At this point we have discovered a file that is trying
- * to grow a small fragment to a larger fragment. To save
- * time, we allocate a full sized block, then free the
- * unused portion. If the file continues to grow, the
- * `fragextend' call above will be able to grow it in place
- * without further copying. If aberrant programs cause
- * disk fragmentation to grow within 2% of the free reserve,
- * we choose to begin optimizing for space.
- */
- request = fs->fs_bsize;
- if (fs->fs_cstotal.cs_nffree <
- fs->fs_dsize * (fs->fs_minfree - 2) / 100)
- break;
- log(LOG_NOTICE, "%s: optimization changed from TIME to SPACE\n",
- fs->fs_fsmnt);
- fs->fs_optim = FS_OPTSPACE;
- break;
- default:
- printf("dev = 0x%x, optim = %d, fs = %s\n",
- ip->i_dev, fs->fs_optim, fs->fs_fsmnt);
- panic("realloccg: bad optim");
- /* NOTREACHED */
- }
- bno = (daddr_t)hashalloc(ip, cg, (long)bpref, request,
- (u_long (*)())alloccg);
- if (bno > 0) {
-#ifdef SECSIZE
- obp = bread(ip->i_dev, fsbtodb(fs, bprev), osize,
- fs->fs_dbsize);
-#else SECSIZE
- error = bread(ip->i_devvp, fsbtodb(fs, bprev),
- osize, NOCRED, &obp);
- if (error) {
- brelse(obp);
- return (error);
- }
- bn = fsbtodb(fs, bno);
-#ifdef SECSIZE
- bp = getblk(ip->i_dev, bn, nsize, fs->fs_dbsize);
-#else SECSIZE
- bp = getblk(ip->i_devvp, bn, nsize);
-#endif SECSIZE
- bcopy(obp->b_un.b_addr, bp->b_un.b_addr, (u_int)osize);
- count = howmany(osize, CLBYTES);
- for (i = 0; i < count; i++)
-#ifdef SECSIZE
- munhash(ip->i_dev, bn + i * CLBYTES / fs->fs_dbsize);
-#else SECSIZE
- munhash(ip->i_dev, bn + i * CLBYTES / DEV_BSIZE);
-#endif SECSIZE
- bzero(bp->b_un.b_addr + osize, (unsigned)nsize - osize);
- if (obp->b_flags & B_DELWRI) {
- obp->b_flags &= ~B_DELWRI;
- u.u_ru.ru_oublock--; /* delete charge */
- }
- brelse(obp);
- blkfree(ip, bprev, (off_t)osize);
- if (nsize < request)
- blkfree(ip, bno + numfrags(fs, nsize),
- (off_t)(request - nsize));
- ip->i_blocks += btodb(nsize - osize);
- ip->i_flag |= IUPD|ICHG;
- *bpp = bp;
- return (0);
- }
-nospace: