int chkuse( daddr_t blkno, int cnt ) { int cg; daddr_t fsbn, bn; fsbn = dbtofsb( fs, blkno ); if ( (unsigned) ( fsbn + cnt ) > fs->fs_size ) { printf( "block %ld out of range of file system\n", (long) blkno ); return ( 1 ); } cg = dtog( fs, fsbn ); if ( fsbn < cgdmin( fs, cg ) ) { if ( cg == 0 || ( fsbn + cnt ) > cgsblock( fs, cg ) ) { printf( "block %ld in non-data area: cannot attach\n", (long) blkno ); return ( 1 ); } } else { if ( ( fsbn + cnt ) > cgbase( fs, cg + 1 ) ) { printf( "block %ld in non-data area: cannot attach\n", (long) blkno ); return ( 1 ); } } if ( cgread1( &disk, cg ) != 1 ) { fprintf( stderr, "cg %d: could not be read\n", cg ); errs++; return ( 1 ); } if ( !cg_chkmagic( &acg ) ) { fprintf( stderr, "cg %d: bad magic number\n", cg ); errs++; return ( 1 ); } bn = dtogd( fs, fsbn ); if ( isclr( cg_blksfree( &acg ), bn ) ) printf( "Warning: sector %ld is in use\n", (long) blkno ); return ( 0 ); }
/* Callback for wapbl */ void ffs_wapbl_sync_metadata(struct mount *mp, daddr_t *deallocblks, int *dealloclens, int dealloccnt) { struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs = ump->um_fs; int i, error; #ifdef WAPBL_DEBUG_INODES ufs_wapbl_verify_inodes(mp, "ffs_wapbl_sync_metadata"); #endif for (i = 0; i< dealloccnt; i++) { /* * blkfree errors are unreported, might silently fail * if it cannot read the cylinder group block */ ffs_wapbl_blkfree(fs, ump->um_devvp, dbtofsb(fs, deallocblks[i]), dealloclens[i]); } fs->fs_fmod = 0; fs->fs_time = time_second; error = ffs_cgupdate(ump, 0); KASSERT(error == 0); }
int main( int argc, char *argv[] ) { daddr_t diskbn; daddr_t number; struct stat stbuf, devstat; struct dirent *dp; DIR *dirp; char name[2 * MAXPATHLEN]; char *name_dir_end; if ( argc < 3 ) usage(); if ( chdir( argv[1] ) < 0 || stat( ".", &stbuf ) < 0 ) err( 2, "%s", argv[1] ); strcpy( name, _PATH_DEV ); if ( ( dirp = opendir( name ) ) == NULL ) err( 3, "%s", name ); name_dir_end = name + strlen( name ); while ( ( dp = readdir( dirp ) ) != NULL ) { strcpy( name_dir_end, dp->d_name ); if ( lstat( name, &devstat ) < 0 ) err( 4, "%s", name ); if ( stbuf.st_dev == devstat.st_rdev && ( devstat.st_mode & IFMT ) == IFCHR ) break; } closedir( dirp ); if ( dp == NULL ) { printf( "Cannot find dev 0%lo corresponding to %s\n", (u_long) stbuf.st_rdev, argv[1] ); exit( 5 ); } if ( ufs_disk_fillout( &disk, name ) == -1 ) { if ( disk.d_error != NULL ) errx( 6, "%s: %s", name, disk.d_error ); else err( 7, "%s", name ); } for ( argc -= 2, argv += 2; argc > 0; argc--, argv++ ) { number = strtol( *argv, NULL, 0 ); if ( errno == EINVAL || errno == ERANGE ) err( 8, "%s", *argv ); if ( chkuse( number, 1 ) ) continue; diskbn = dbtofsb( fs, number ); if ( (dev_t) diskbn != diskbn ) { printf( "sector %ld cannot be represented as a dev_t\n", (long) number ); errs++; } else if ( mknod( *argv, IFMT | 0600, (dev_t) diskbn ) < 0 ) { warn( "%s", *argv ); errs++; } } ufs_disk_close( &disk ); printf( "Don't forget to run ``fsck %s''\n", name ); exit( errs ); }
void ffs_wapbl_abort_sync_metadata(struct mount *mp, daddr_t *deallocblks, int *dealloclens, int dealloccnt) { struct ufsmount *ump = VFSTOUFS(mp); struct fs *fs = ump->um_fs; int i; for (i = 0; i < dealloccnt; i++) { /* * Since the above blkfree may have failed, this blkalloc might * fail as well, so don't check its error. Note that if the * blkfree succeeded above, then this shouldn't fail because * the buffer will be locked in the current transaction. */ ffs_blkalloc_ump(ump, dbtofsb(fs, deallocblks[i]), dealloclens[i]); } }
/* * Balloc defines the structure of filesystem storage * by allocating the physical blocks on a device given * the inode and the logical block number in a file. */ int ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred, struct buf **bpp, int flags) { struct m_ext2fs *fs; struct ext2mount *ump; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[NIADDR + 2]; e4fs_daddr_t nb, newb; e2fs_daddr_t *bap, pref; int osize, nsize, num, i, error; *bpp = NULL; if (lbn < 0) return (EFBIG); fs = ip->i_e2fs; ump = ip->i_ump; /* * check if this is a sequential block allocation. * If so, increment next_alloc fields to allow ext2_blkpref * to make a good guess */ if (lbn == ip->i_next_alloc_block + 1) { ip->i_next_alloc_block++; ip->i_next_alloc_goal++; } /* * The first NDADDR blocks are direct blocks */ if (lbn < NDADDR) { nb = ip->i_db[lbn]; /* no new block is to be allocated, and no need to expand the file */ if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) { error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); *bpp = bp; return (0); } if (nb != 0) { /* * Consider need to reallocate a fragment. */ osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { error = bread(vp, lbn, osize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); } else { /* Godmar thinks: this shouldn't happen w/o fragments */ printf("nsize %d(%d) > osize %d(%d) nb %d\n", (int)nsize, (int)size, (int)osize, (int)ip->i_size, (int)nb); panic( "ext2_balloc: Something is terribly wrong"); /* * please note there haven't been any changes from here on - * FFS seems to work. */ } } else { if (ip->i_size < (lbn + 1) * fs->e2fs_bsize) nsize = fragroundup(fs, size); else nsize = fs->e2fs_bsize; EXT2_LOCK(ump); error = ext2_alloc(ip, lbn, ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0), nsize, cred, &newb); if (error) return (error); bp = getblk(vp, lbn, nsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & BA_CLRBUF) vfs_bio_clrbuf(bp); } ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); } /* * Determine the number of levels of indirection. */ pref = 0; if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0) return (error); #ifdef INVARIANTS if (num < 1) panic ("ext2_balloc: ext2_getlbns returned indirect block"); #endif /* * Fetch the first indirect block allocating if necessary. */ --num; nb = ip->i_ib[indirs[0].in_off]; if (nb == 0) { EXT2_LOCK(ump); pref = ext2_blkpref(ip, lbn, indirs[0].in_off + EXT2_NDIR_BLOCKS, &ip->i_db[0], 0); if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred, &newb))) return (error); nb = newb; bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); vfs_bio_clrbuf(bp); /* * Write synchronously so that indirect blocks * never point at garbage. */ if ((error = bwrite(bp)) != 0) { ext2_blkfree(ip, nb, fs->e2fs_bsize); return (error); } ip->i_ib[indirs[0].in_off] = newb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* * Fetch through the indirect blocks, allocating as necessary. */ for (i = 1;;) { error = bread(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bap = (e2fs_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; i += 1; if (nb != 0) { bqrelse(bp); continue; } EXT2_LOCK(ump); if (pref == 0) pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap, bp->b_lblkno); error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb); if (error) { brelse(bp); return (error); } nb = newb; nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); /* * Write synchronously so that indirect blocks * never point at garbage. */ if ((error = bwrite(nbp)) != 0) { ext2_blkfree(ip, nb, fs->e2fs_bsize); EXT2_UNLOCK(ump); brelse(bp); return (error); } bap[indirs[i - 1].in_off] = nb; /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & IO_SYNC) { bwrite(bp); } else { if (bp->b_bufsize == fs->e2fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } } /* * Get the data block, allocating if necessary. */ if (nb == 0) { EXT2_LOCK(ump); pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0], bp->b_lblkno); if ((error = ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) { brelse(bp); return (error); } nb = newb; nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); if (flags & BA_CLRBUF) vfs_bio_clrbuf(nbp); bap[indirs[i].in_off] = nb; /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & IO_SYNC) { bwrite(bp); } else { if (bp->b_bufsize == fs->e2fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } *bpp = nbp; return (0); } brelse(bp); if (flags & BA_CLRBUF) { int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { error = cluster_read(vp, ip->i_size, lbn, (int)fs->e2fs_bsize, NOCRED, MAXBSIZE, seqcount, 0, &nbp); } else { error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp); } if (error) { brelse(nbp); return (error); } } else {
void mkfs(struct partition *pp, char *fsys, int fi, int fo, mode_t mfsmode, uid_t mfsuid, gid_t mfsgid) { time_t utime; quad_t sizepb; int i, j, width, origdensity, fragsperinode, minfpg, optimalfpg; int lastminfpg, mincylgrps; long cylno, csfrags; char tmpbuf[100]; /* XXX this will break in about 2,500 years */ if ((fsun = calloc(1, sizeof (union fs_u))) == NULL || (cgun = calloc(1, sizeof (union cg_u))) == NULL) err(1, "calloc"); #ifndef STANDALONE time(&utime); #endif if (mfs) { quad_t sz = (quad_t)fssize * sectorsize; if (sz > SIZE_T_MAX) { errno = ENOMEM; err(12, "mmap"); } membase = mmap(NULL, sz, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, (off_t)0); if (membase == MAP_FAILED) err(12, "mmap"); madvise(membase, sz, MADV_RANDOM); } fsi = fi; fso = fo; /* * Validate the given file system size. * Verify that its last block can actually be accessed. */ if (Oflag <= 1 && fssize > INT_MAX) errx(13, "preposterous size %lld, max is %d", fssize, INT_MAX); if (Oflag == 2 && fssize > MAXDISKSIZE) errx(13, "preposterous size %lld, max is %lld", fssize, MAXDISKSIZE); wtfs(fssize - 1, sectorsize, (char *)&sblock); sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT; sblock.fs_avgfilesize = avgfilesize; sblock.fs_avgfpdir = avgfilesperdir; /* * Collect and verify the block and fragment sizes. */ if (!POWEROF2(bsize)) { errx(16, "block size must be a power of 2, not %d", bsize); } if (!POWEROF2(fsize)) { errx(17, "fragment size must be a power of 2, not %d", fsize); } if (fsize < sectorsize) { errx(18, "fragment size %d is too small, minimum is %d", fsize, sectorsize); } if (bsize < MINBSIZE) { errx(19, "block size %d is too small, minimum is %d", bsize, MINBSIZE); } if (bsize > MAXBSIZE) { errx(19, "block size %d is too large, maximum is %d", bsize, MAXBSIZE); } if (bsize < fsize) { errx(20, "block size (%d) cannot be smaller than fragment size (%d)", bsize, fsize); } sblock.fs_bsize = bsize; sblock.fs_fsize = fsize; /* * Calculate the superblock bitmasks and shifts. */ sblock.fs_bmask = ~(sblock.fs_bsize - 1); sblock.fs_fmask = ~(sblock.fs_fsize - 1); sblock.fs_qbmask = ~sblock.fs_bmask; sblock.fs_qfmask = ~sblock.fs_fmask; sblock.fs_bshift = ilog2(sblock.fs_bsize); sblock.fs_fshift = ilog2(sblock.fs_fsize); sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); if (sblock.fs_frag > MAXFRAG) { errx(21, "fragment size %d is too small, minimum with block " "size %d is %d", sblock.fs_fsize, sblock.fs_bsize, sblock.fs_bsize / MAXFRAG); } sblock.fs_fragshift = ilog2(sblock.fs_frag); sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); sblock.fs_size = dbtofsb(&sblock, fssize); sblock.fs_nspf = sblock.fs_fsize / sectorsize; sblock.fs_maxcontig = 1; sblock.fs_nrpos = 1; sblock.fs_cpg = 1; /* * Before the file system is fully initialized, mark it as invalid. */ sblock.fs_magic = FS_BAD_MAGIC; /* * Set the remaining superblock fields. Note that for FFS1, media * geometry fields are set to fake values. This is for compatibility * with really ancient kernels that might still inspect these values. */ if (Oflag <= 1) { sblock.fs_sblockloc = SBLOCK_UFS1; sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); if (Oflag == 0) { sblock.fs_maxsymlinklen = 0; sblock.fs_inodefmt = FS_42INODEFMT; } else { sblock.fs_maxsymlinklen = MAXSYMLINKLEN_UFS1; sblock.fs_inodefmt = FS_44INODEFMT; } sblock.fs_cgoffset = 0; sblock.fs_cgmask = 0xffffffff; sblock.fs_ffs1_size = sblock.fs_size; sblock.fs_rotdelay = 0; sblock.fs_rps = 60; sblock.fs_interleave = 1; sblock.fs_trackskew = 0; sblock.fs_cpc = 0; } else { sblock.fs_inodefmt = FS_44INODEFMT; sblock.fs_sblockloc = SBLOCK_UFS2; sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); sblock.fs_maxsymlinklen = MAXSYMLINKLEN_UFS2; } sblock.fs_sblkno = roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag); sblock.fs_cblkno = (int32_t)(sblock.fs_sblkno + roundup(howmany(SBSIZE, sblock.fs_fsize), sblock.fs_frag)); sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { sizepb *= NINDIR(&sblock); sblock.fs_maxfilesize += sizepb; } #ifdef notyet /* * It is impossible to create a snapshot in case fs_maxfilesize is * smaller than fssize. */ if (sblock.fs_maxfilesize < (u_quad_t)fssize) warnx("WARNING: You will be unable to create snapshots on this " "file system. Correct by using a larger blocksize."); #endif /* * Calculate the number of blocks to put into each cylinder group. The * first goal is to have at least enough data blocks in each cylinder * group to meet the density requirement. Once this goal is achieved * we try to expand to have at least mincylgrps cylinder groups. Once * this goal is achieved, we pack as many blocks into each cylinder * group map as will fit. * * We start by calculating the smallest number of blocks that we can * put into each cylinder group. If this is too big, we reduce the * density until it fits. */ origdensity = density; for (;;) { fragsperinode = MAX(numfrags(&sblock, density), 1); minfpg = fragsperinode * INOPB(&sblock); if (minfpg > sblock.fs_size) minfpg = sblock.fs_size; sblock.fs_ipg = INOPB(&sblock); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) break; density -= sblock.fs_fsize; } if (density != origdensity) warnx("density reduced from %d to %d bytes per inode", origdensity, density); /* * Use a lower value for mincylgrps if the user specified a large * number of blocks per cylinder group. This is needed for, e.g. the * install media which needs to pack 2 files very tightly. */ mincylgrps = MINCYLGRPS; if (maxfrgspercg != INT_MAX) { i = sblock.fs_size / maxfrgspercg; if (i < MINCYLGRPS) mincylgrps = i <= 0 ? 1 : i; } /* * Start packing more blocks into the cylinder group until it cannot * grow any larger, the number of cylinder groups drops below * mincylgrps, or we reach the requested size. */ for (;;) { sblock.fs_fpg += sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (sblock.fs_fpg > maxfrgspercg || sblock.fs_size / sblock.fs_fpg < mincylgrps || CGSIZE(&sblock) > (unsigned long)sblock.fs_bsize) break; } sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (sblock.fs_fpg > maxfrgspercg) warnx("can't honour -c: minimum is %d", sblock.fs_fpg); /* * Check to be sure that the last cylinder group has enough blocks to * be viable. If it is too small, reduce the number of blocks per * cylinder group which will have the effect of moving more blocks into * the last cylinder group. */ optimalfpg = sblock.fs_fpg; for (;;) { sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); lastminfpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_size < lastminfpg) errx(28, "file system size %jd < minimum size of %d", (intmax_t)sblock.fs_size, lastminfpg); if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || sblock.fs_size % sblock.fs_fpg == 0) break; sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); } if (optimalfpg != sblock.fs_fpg) warnx("reduced number of fragments per cylinder group from %d" " to %d to enlarge last cylinder group", optimalfpg, sblock.fs_fpg); /* * Back to filling superblock fields. */ if (Oflag <= 1) { sblock.fs_spc = sblock.fs_fpg * sblock.fs_nspf; sblock.fs_nsect = sblock.fs_spc; sblock.fs_npsect = sblock.fs_spc; sblock.fs_ncyl = sblock.fs_ncg; } sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); sblock.fs_csaddr = cgdmin(&sblock, 0); sblock.fs_cssize = fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); fscs = (struct csum *)calloc(1, sblock.fs_cssize); if (fscs == NULL) errx(31, "calloc failed"); sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); if (sblock.fs_sbsize > SBLOCKSIZE) sblock.fs_sbsize = SBLOCKSIZE; sblock.fs_minfree = minfree; sblock.fs_maxbpg = maxbpg; sblock.fs_optim = opt; sblock.fs_cgrotor = 0; sblock.fs_pendingblocks = 0; sblock.fs_pendinginodes = 0; sblock.fs_fmod = 0; sblock.fs_ronly = 0; sblock.fs_state = 0; sblock.fs_clean = 1; sblock.fs_id[0] = (u_int32_t)utime; sblock.fs_id[1] = (u_int32_t)arc4random(); sblock.fs_fsmnt[0] = '\0'; csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); sblock.fs_cstotal.cs_nbfree = fragstoblks(&sblock, sblock.fs_dsize) - howmany(csfrags, sblock.fs_frag); sblock.fs_cstotal.cs_nffree = fragnum(&sblock, sblock.fs_size) + (fragnum(&sblock, csfrags) > 0 ? sblock.fs_frag - fragnum(&sblock, csfrags) : 0); sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_dsize -= csfrags; sblock.fs_time = utime; if (Oflag <= 1) { sblock.fs_ffs1_time = sblock.fs_time; sblock.fs_ffs1_dsize = sblock.fs_dsize; sblock.fs_ffs1_csaddr = sblock.fs_csaddr; sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } /* * Dump out summary information about file system. */ if (!mfs) { #define B2MBFACTOR (1 / (1024.0 * 1024.0)) printf("%s: %.1fMB in %jd sectors of %d bytes\n", fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, (intmax_t)fsbtodb(&sblock, sblock.fs_size), sectorsize); printf("%d cylinder groups of %.2fMB, %d blocks, %d" " inodes each\n", sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); #undef B2MBFACTOR } /* * Wipe out old FFS1 superblock if necessary. */ if (Oflag >= 2) { union fs_u *fsun1; struct fs *fs1; fsun1 = calloc(1, sizeof(union fs_u)); if (fsun1 == NULL) err(39, "calloc"); fs1 = &fsun1->fs; rdfs(SBLOCK_UFS1 / sectorsize, SBSIZE, (char *)fs1); if (fs1->fs_magic == FS_UFS1_MAGIC) { fs1->fs_magic = FS_BAD_MAGIC; wtfs(SBLOCK_UFS1 / sectorsize, SBSIZE, (char *)fs1); } free(fsun1); } wtfs((int)sblock.fs_sblockloc / sectorsize, SBSIZE, (char *)&sblock); sblock.fs_magic = (Oflag <= 1) ? FS_UFS1_MAGIC : FS_UFS2_MAGIC; /* * Now build the cylinders group blocks and * then print out indices of cylinder groups. */ if (!quiet) printf("super-block backups (for fsck -b #) at:\n"); #ifndef STANDALONE else if (!mfs && isatty(STDIN_FILENO)) { signal(SIGINFO, siginfo); cur_fsys = fsys; } #endif i = 0; width = charsperline(); /* * Allocate space for superblock, cylinder group map, and two sets of * inode blocks. */ if (sblock.fs_bsize < SBLOCKSIZE) iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; else iobufsize = 4 * sblock.fs_bsize; if ((iobuf = malloc(iobufsize)) == 0) errx(38, "cannot allocate I/O buffer"); bzero(iobuf, iobufsize); /* * Make a copy of the superblock into the buffer that we will be * writing out in each cylinder group. */ bcopy((char *)&sblock, iobuf, SBLOCKSIZE); for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { cur_cylno = (sig_atomic_t)cylno; initcg(cylno, utime); if (quiet) continue; j = snprintf(tmpbuf, sizeof tmpbuf, " %lld,", fsbtodb(&sblock, cgsblock(&sblock, cylno))); if (j >= sizeof tmpbuf) j = sizeof tmpbuf - 1; if (j == -1 || i+j >= width) { printf("\n"); i = 0; } i += j; printf("%s", tmpbuf); fflush(stdout); } if (!quiet) printf("\n"); if (Nflag && !mfs) exit(0); /* * Now construct the initial file system, then write out the superblock. */ if (Oflag <= 1) { if (fsinit1(utime, mfsmode, mfsuid, mfsgid)) errx(32, "fsinit1 failed"); sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } else { if (fsinit2(utime)) errx(32, "fsinit2 failed"); } wtfs((int)sblock.fs_sblockloc / sectorsize, SBSIZE, (char *)&sblock); for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize, ((char *)fscs) + i); /* * Update information about this partion in pack label, to that it may * be updated on disk. */ pp->p_fstype = FS_BSDFFS; pp->p_fragblock = DISKLABELV1_FFS_FRAGBLOCK(sblock.fs_fsize, sblock.fs_frag); pp->p_cpg = sblock.fs_cpg; }
void mke2fs(const char *fsys, int fi, int fo) { struct timeval tv; int64_t minfssize; uint bcount, fbcount, ficount; uint blocks_gd, blocks_per_cg, inodes_per_cg, iblocks_per_cg; uint minblocks_per_cg, blocks_lastcg; uint ncg, cylno, sboff; uuid_t uuid; uint32_t uustat; int i, len, col, delta, fld_width, max_cols; struct winsize winsize; gettimeofday(&tv, NULL); fsi = fi; fso = fo; /* * collect and verify the block and fragment sizes */ if (!powerof2(bsize)) { errx(EXIT_FAILURE, "block size must be a power of 2, not %u\n", bsize); } if (!powerof2(fsize)) { errx(EXIT_FAILURE, "fragment size must be a power of 2, not %u\n", fsize); } if (fsize < sectorsize) { errx(EXIT_FAILURE, "fragment size %u is too small, minimum is %u\n", fsize, sectorsize); } if (bsize < MINBSIZE) { errx(EXIT_FAILURE, "block size %u is too small, minimum is %u\n", bsize, MINBSIZE); } if (bsize > EXT2_MAXBSIZE) { errx(EXIT_FAILURE, "block size %u is too large, maximum is %u\n", bsize, MAXBSIZE); } if (bsize != fsize) { /* * There is no fragment support on current ext2fs (yet?), * but some kernel code refers fsize or fpg as bsize or bpg * and Linux seems to set the same values to them. */ errx(EXIT_FAILURE, "block size (%u) can't be different from " "fragment size (%u)\n", bsize, fsize); } /* variable inodesize is REV1 feature */ if (Oflag == 0 && inodesize != EXT2_REV0_DINODE_SIZE) { errx(EXIT_FAILURE, "GOOD_OLD_REV file system format" " doesn't support %d byte inode\n", inodesize); } sblock.e2fs.e2fs_log_bsize = ilog2(bsize) - LOG_MINBSIZE; /* Umm, why not e2fs_log_fsize? */ sblock.e2fs.e2fs_fsize = ilog2(fsize) - LOG_MINBSIZE; sblock.e2fs_bsize = bsize; sblock.e2fs_bshift = sblock.e2fs.e2fs_log_bsize + LOG_MINBSIZE; sblock.e2fs_qbmask = sblock.e2fs_bsize - 1; sblock.e2fs_bmask = ~sblock.e2fs_qbmask; sblock.e2fs_fsbtodb = ilog2(sblock.e2fs_bsize) - ilog2(sectorsize); sblock.e2fs_ipb = sblock.e2fs_bsize / inodesize; /* * Ext2fs preserves BBSIZE (1024 bytes) space at the top for * bootloader (though it is not enough at all for our bootloader). * If bsize == BBSIZE we have to preserve one block. * If bsize > BBSIZE, the first block already contains BBSIZE space * before superblock because superblock is allocated at SBOFF and * bsize is a power of two (i.e. 2048 bytes or more). */ sblock.e2fs.e2fs_first_dblock = (sblock.e2fs_bsize > BBSIZE) ? 0 : 1; minfssize = fsbtodb(&sblock, sblock.e2fs.e2fs_first_dblock + NBLOCK_SUPERBLOCK + 1 /* at least one group descriptor */ + NBLOCK_BLOCK_BITMAP + NBLOCK_INODE_BITMAP + 1 /* at least one inode table block */ + 1 /* at least one data block for rootdir */ + 1 /* at least one data block for data */ ); /* XXX and more? */ if (fssize < minfssize) errx(EXIT_FAILURE, "Filesystem size %" PRId64 " < minimum size of %" PRId64 "\n", fssize, minfssize); bcount = dbtofsb(&sblock, fssize); /* * While many people claim that ext2fs is a (bad) clone of ufs/ffs, * it isn't actual ffs so maybe we should call it "block group" * as their native name rather than ffs derived "cylinder group." * But we'll use the latter here since other kernel sources use it. * (I also agree "cylinder" based allocation is obsolete though) */ /* maybe "simple is the best" */ blocks_per_cg = sblock.e2fs_bsize * NBBY; ncg = howmany(bcount - sblock.e2fs.e2fs_first_dblock, blocks_per_cg); blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize); /* check range of inode number */ if (num_inodes < EXT2_FIRSTINO) num_inodes = EXT2_FIRSTINO; /* needs reserved inodes + 1 */ if (num_inodes > UINT16_MAX * ncg) num_inodes = UINT16_MAX * ncg; /* ext2bgd_nifree is uint16_t */ inodes_per_cg = num_inodes / ncg; iblocks_per_cg = howmany(inodesize * inodes_per_cg, bsize); /* Check that the last cylinder group has enough space for inodes */ minblocks_per_cg = NBLOCK_BLOCK_BITMAP + NBLOCK_INODE_BITMAP + iblocks_per_cg + 1; /* at least one data block */ if (Oflag == 0 || cg_has_sb(ncg - 1) != 0) minblocks_per_cg += NBLOCK_SUPERBLOCK + blocks_gd; blocks_lastcg = bcount - sblock.e2fs.e2fs_first_dblock - blocks_per_cg * (ncg - 1); if (blocks_lastcg < minblocks_per_cg) { /* * Since we make all the cylinder groups the same size, the * last will only be small if there are more than one * cylinder groups. If the last one is too small to store * filesystem data, just kill it. * * XXX: Does fsck_ext2fs(8) properly handle this case? */ bcount -= blocks_lastcg; ncg--; blocks_lastcg = blocks_per_cg; blocks_gd = howmany(sizeof(struct ext2_gd) * ncg, bsize); inodes_per_cg = num_inodes / ncg; } /* roundup inodes_per_cg to make it use whole inode table blocks */ inodes_per_cg = roundup(inodes_per_cg, sblock.e2fs_ipb); num_inodes = inodes_per_cg * ncg; iblocks_per_cg = inodes_per_cg / sblock.e2fs_ipb; /* XXX: probably we should check these adjusted values again */ sblock.e2fs.e2fs_bcount = bcount; sblock.e2fs.e2fs_icount = num_inodes; sblock.e2fs_ncg = ncg; sblock.e2fs_ngdb = blocks_gd; sblock.e2fs_itpg = iblocks_per_cg; sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * minfree / 100; /* e2fs_fbcount will be accounted later */ /* e2fs_ficount will be accounted later */ sblock.e2fs.e2fs_bpg = blocks_per_cg; sblock.e2fs.e2fs_fpg = blocks_per_cg; sblock.e2fs.e2fs_ipg = inodes_per_cg; sblock.e2fs.e2fs_mtime = 0; sblock.e2fs.e2fs_wtime = tv.tv_sec; sblock.e2fs.e2fs_mnt_count = 0; /* XXX: should add some entropy to avoid checking all fs at once? */ sblock.e2fs.e2fs_max_mnt_count = EXT2_DEF_MAX_MNT_COUNT; sblock.e2fs.e2fs_magic = E2FS_MAGIC; sblock.e2fs.e2fs_state = E2FS_ISCLEAN; sblock.e2fs.e2fs_beh = E2FS_BEH_DEFAULT; sblock.e2fs.e2fs_minrev = 0; sblock.e2fs.e2fs_lastfsck = tv.tv_sec; sblock.e2fs.e2fs_fsckintv = EXT2_DEF_FSCKINTV; /* * Maybe we can use E2FS_OS_FREEBSD here and it would be more proper, * but the purpose of this newfs_ext2fs(8) command is to provide * a filesystem which can be recognized by firmware on some * Linux based appliances that can load bootstrap files only from * (their native) ext2fs, and anyway we will (and should) try to * act like them as much as possible. * * Anyway, I hope that all newer such boxes will keep their support * for the "GOOD_OLD_REV" ext2fs. */ sblock.e2fs.e2fs_creator = E2FS_OS_LINUX; if (Oflag == 0) { sblock.e2fs.e2fs_rev = E2FS_REV0; sblock.e2fs.e2fs_features_compat = 0; sblock.e2fs.e2fs_features_incompat = 0; sblock.e2fs.e2fs_features_rocompat = 0; } else { sblock.e2fs.e2fs_rev = E2FS_REV1; /* * e2fsprogs say "REV1" is "dynamic" so * it isn't quite a version and maybe it means * "extended from REV0 so check compat features." * * XXX: We don't have any native tool to activate * the EXT2F_COMPAT_RESIZE feature and * fsck_ext2fs(8) might not fix structures for it. */ sblock.e2fs.e2fs_features_compat = EXT2F_COMPAT_RESIZE; sblock.e2fs.e2fs_features_incompat = EXT2F_INCOMPAT_FTYPE; sblock.e2fs.e2fs_features_rocompat = EXT2F_ROCOMPAT_SPARSESUPER | EXT2F_ROCOMPAT_LARGEFILE; } sblock.e2fs.e2fs_ruid = geteuid(); sblock.e2fs.e2fs_rgid = getegid(); sblock.e2fs.e2fs_first_ino = EXT2_FIRSTINO; sblock.e2fs.e2fs_inode_size = inodesize; /* e2fs_block_group_nr is set on writing superblock to each group */ uuid_create(&uuid, &uustat); if (uustat != uuid_s_ok) errx(EXIT_FAILURE, "Failed to generate uuid\n"); uuid_enc_le(sblock.e2fs.e2fs_uuid, &uuid); if (volname != NULL) { if (strlen(volname) > sizeof(sblock.e2fs.e2fs_vname)) errx(EXIT_FAILURE, "Volume name is too long"); strlcpy(sblock.e2fs.e2fs_vname, volname, sizeof(sblock.e2fs.e2fs_vname)); } sblock.e2fs.e2fs_fsmnt[0] = '\0'; sblock.e2fs_fsmnt[0] = '\0'; sblock.e2fs.e2fs_algo = 0; /* XXX unsupported? */ sblock.e2fs.e2fs_prealloc = 0; /* XXX unsupported? */ sblock.e2fs.e2fs_dir_prealloc = 0; /* XXX unsupported? */ /* calculate blocks for reserved group descriptors for resize */ sblock.e2fs.e2fs_reserved_ngdb = 0; if (sblock.e2fs.e2fs_rev > E2FS_REV0 && (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0) { uint64_t target_blocks; uint target_ncg, target_ngdb, reserved_ngdb; /* reserve descriptors for size as 1024 times as current */ target_blocks = (sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock) * 1024ULL; /* number of blocks must be in uint32_t */ if (target_blocks > UINT32_MAX) target_blocks = UINT32_MAX; target_ncg = howmany(target_blocks, sblock.e2fs.e2fs_bpg); target_ngdb = howmany(sizeof(struct ext2_gd) * target_ncg, sblock.e2fs_bsize); /* * Reserved group descriptor blocks are preserved as * the second level double indirect reference blocks in * the EXT2_RESIZEINO inode, so the maximum number of * the blocks is NINDIR(fs). * (see also descriptions in init_resizeino() function) * * We check a number including current e2fs_ngdb here * because they will be moved into reserved gdb on * possible future size shrink, though e2fsprogs don't * seem to care about it. */ if (target_ngdb > NINDIR(&sblock)) target_ngdb = NINDIR(&sblock); reserved_ngdb = target_ngdb - sblock.e2fs_ngdb; /* make sure reserved_ngdb fits in the last cg */ if (reserved_ngdb >= blocks_lastcg - cgoverhead(ncg - 1)) reserved_ngdb = blocks_lastcg - cgoverhead(ncg - 1); if (reserved_ngdb == 0) { /* if no space for reserved gdb, disable the feature */ sblock.e2fs.e2fs_features_compat &= ~EXT2F_COMPAT_RESIZE; } sblock.e2fs.e2fs_reserved_ngdb = reserved_ngdb; } /* * Initialize group descriptors */ gd = malloc(sblock.e2fs_ngdb * bsize); if (gd == NULL) errx(EXIT_FAILURE, "Can't allocate descriptors buffer"); memset(gd, 0, sblock.e2fs_ngdb * bsize); fbcount = 0; ficount = 0; for (cylno = 0; cylno < ncg; cylno++) { uint boffset; boffset = cgbase(&sblock, cylno); if (sblock.e2fs.e2fs_rev == E2FS_REV0 || (sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) == 0 || cg_has_sb(cylno)) { boffset += NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb; if (sblock.e2fs.e2fs_rev > E2FS_REV0 && (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0) boffset += sblock.e2fs.e2fs_reserved_ngdb; } gd[cylno].ext2bgd_b_bitmap = boffset; boffset += NBLOCK_BLOCK_BITMAP; gd[cylno].ext2bgd_i_bitmap = boffset; boffset += NBLOCK_INODE_BITMAP; gd[cylno].ext2bgd_i_tables = boffset; if (cylno == (ncg - 1)) gd[cylno].ext2bgd_nbfree = blocks_lastcg - cgoverhead(cylno); else gd[cylno].ext2bgd_nbfree = sblock.e2fs.e2fs_bpg - cgoverhead(cylno); fbcount += gd[cylno].ext2bgd_nbfree; gd[cylno].ext2bgd_nifree = sblock.e2fs.e2fs_ipg; if (cylno == 0) { /* take reserved inodes off nifree */ gd[cylno].ext2bgd_nifree -= EXT2_RESERVED_INODES; } ficount += gd[cylno].ext2bgd_nifree; gd[cylno].ext2bgd_ndirs = 0; } sblock.e2fs.e2fs_fbcount = fbcount; sblock.e2fs.e2fs_ficount = ficount; /* * Dump out summary information about file system. */ if (verbosity > 0) { printf("%s: %u.%1uMB (%" PRId64 " sectors) " "block size %u, fragment size %u\n", fsys, (uint)(((uint64_t)bcount * bsize) / (1024 * 1024)), (uint)((uint64_t)bcount * bsize - rounddown((uint64_t)bcount * bsize, 1024 * 1024)) / 1024 / 100, fssize, bsize, fsize); printf("\tusing %u block groups of %u.0MB, %u blks, " "%u inodes.\n", ncg, bsize * sblock.e2fs.e2fs_bpg / (1024 * 1024), sblock.e2fs.e2fs_bpg, sblock.e2fs.e2fs_ipg); } /* * allocate space for superblock and group descriptors */ iobufsize = (NBLOCK_SUPERBLOCK + sblock.e2fs_ngdb) * sblock.e2fs_bsize; iobuf = mmap(0, iobufsize, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); if (iobuf == NULL) errx(EXIT_FAILURE, "Cannot allocate I/O buffer\n"); memset(iobuf, 0, iobufsize); /* * We now start writing to the filesystem */ if (!Nflag) { static const uint pbsize[] = { 1024, 2048, 4096, 0 }; uint pblock, epblock; /* * Validate the given file system size. * Verify that its last block can actually be accessed. * Convert to file system fragment sized units. */ if (fssize <= 0) errx(EXIT_FAILURE, "Preposterous size %" PRId64 "\n", fssize); wtfs(fssize - 1, sectorsize, iobuf); /* * Ensure there is nothing that looks like a filesystem * superblock anywhere other than where ours will be. * If fsck_ext2fs finds the wrong one all hell breaks loose! * * XXX: needs to check how fsck_ext2fs programs even * on other OSes determine alternate superblocks */ for (i = 0; pbsize[i] != 0; i++) { epblock = (uint64_t)bcount * bsize / pbsize[i]; for (pblock = ((pbsize[i] == SBSIZE) ? 1 : 0); pblock < epblock; pblock += pbsize[i] * NBBY /* bpg */) zap_old_sblock((daddr_t)pblock * pbsize[i] / sectorsize); } } if (verbosity >= 3) printf("super-block backups (for fsck_ext2fs -b #) at:\n"); /* If we are printing more than one line of numbers, line up columns */ fld_width = verbosity < 4 ? 1 : snprintf(NULL, 0, "%" PRIu64, (uint64_t)cgbase(&sblock, ncg - 1)); /* Get terminal width */ if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) == 0) max_cols = winsize.ws_col; else max_cols = 80; if (Nflag && verbosity == 3) /* Leave space to add " ..." after one row of numbers */ max_cols -= 4; #define BASE 0x10000 /* For some fixed-point maths */ col = 0; delta = verbosity > 2 ? 0 : max_cols * BASE / ncg; for (cylno = 0; cylno < ncg; cylno++) { fflush(stdout); initcg(cylno); if (verbosity < 2) continue; /* the first one is a master, not backup */ if (cylno == 0) continue; /* skip if this cylinder doesn't have a backup */ if (sblock.e2fs.e2fs_rev > E2FS_REV0 && (sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) != 0 && cg_has_sb(cylno) == 0) continue; if (delta > 0) { if (Nflag) /* No point doing dots for -N */ break; /* Print dots scaled to end near RH margin */ for (col += delta; col > BASE; col -= BASE) printf("."); continue; } /* Print superblock numbers */ len = printf(" %*" PRIu64 "," + !col, fld_width, (uint64_t)cgbase(&sblock, cylno)); col += len; if (col + len < max_cols) /* Next number fits */ continue; /* Next number won't fit, need a newline */ if (verbosity <= 3) { /* Print dots for subsequent cylinder groups */ delta = sblock.e2fs_ncg - cylno - 1; if (delta != 0) { if (Nflag) { printf(" ..."); break; } delta = max_cols * BASE / delta; } } col = 0; printf("\n"); } #undef BASE if (col > 0) printf("\n"); if (Nflag) return; /* * Now construct the initial file system, */ if (fsinit(&tv) == 0) errx(EXIT_FAILURE, "Error making filesystem"); /* * Write out the superblock and group descriptors */ sblock.e2fs.e2fs_block_group_nr = 0; sboff = 0; if (cgbase(&sblock, 0) == 0) { /* * If the first block contains the boot block sectors, * (i.e. in case of sblock.e2fs.e2fs_bsize > BBSIZE) * we have to preserve data in it. */ sboff = SBOFF; } e2fs_sbsave(&sblock.e2fs, (struct ext2fs *)(iobuf + sboff)); e2fs_cgsave(gd, (struct ext2_gd *)(iobuf + sblock.e2fs_bsize), sizeof(struct ext2_gd) * sblock.e2fs_ncg); wtfs(fsbtodb(&sblock, cgbase(&sblock, 0)) + sboff / sectorsize, iobufsize - sboff, iobuf + sboff); munmap(iobuf, iobufsize); }
static int update_inoblk(struct lfs *fs, daddr_t offset, kauth_cred_t cred, struct lwp *l) { struct vnode *devvp, *vp; struct inode *ip; struct ufs1_dinode *dip; struct buf *dbp, *ibp; int error; daddr_t daddr; IFILE *ifp; SEGUSE *sup; devvp = VTOI(fs->lfs_ivnode)->i_devvp; /* * Get the inode, update times and perms. * DO NOT update disk blocks, we do that separately. */ error = bread(devvp, fsbtodb(fs, offset), fs->lfs_ibsize, cred, 0, &dbp); if (error) { DLOG((DLOG_RF, "update_inoblk: bread returned %d\n", error)); return error; } dip = ((struct ufs1_dinode *)(dbp->b_data)) + INOPB(fs); while (--dip >= (struct ufs1_dinode *)dbp->b_data) { if (dip->di_inumber > LFS_IFILE_INUM) { error = lfs_rf_valloc(fs, dip->di_inumber, dip->di_gen, l, &vp); if (error) { DLOG((DLOG_RF, "update_inoblk: lfs_rf_valloc" " returned %d\n", error)); continue; } ip = VTOI(vp); if (dip->di_size != ip->i_size) lfs_truncate(vp, dip->di_size, 0, NOCRED); /* Get mode, link count, size, and times */ memcpy(ip->i_din.ffs1_din, dip, offsetof(struct ufs1_dinode, di_db[0])); /* Then the rest, except di_blocks */ ip->i_flags = ip->i_ffs1_flags = dip->di_flags; ip->i_gen = ip->i_ffs1_gen = dip->di_gen; ip->i_uid = ip->i_ffs1_uid = dip->di_uid; ip->i_gid = ip->i_ffs1_gid = dip->di_gid; ip->i_mode = ip->i_ffs1_mode; ip->i_nlink = ip->i_ffs1_nlink; ip->i_size = ip->i_ffs1_size; LFS_SET_UINO(ip, IN_CHANGE | IN_UPDATE); /* Re-initialize to get type right */ ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp); vput(vp); /* Record change in location */ LFS_IENTRY(ifp, fs, dip->di_inumber, ibp); daddr = ifp->if_daddr; ifp->if_daddr = dbtofsb(fs, dbp->b_blkno); error = LFS_BWRITE_LOG(ibp); /* Ifile */ /* And do segment accounting */ if (dtosn(fs, daddr) != dtosn(fs, dbtofsb(fs, dbp->b_blkno))) { if (daddr > 0) { LFS_SEGENTRY(sup, fs, dtosn(fs, daddr), ibp); sup->su_nbytes -= sizeof (struct ufs1_dinode); LFS_WRITESEGENTRY(sup, fs, dtosn(fs, daddr), ibp); } LFS_SEGENTRY(sup, fs, dtosn(fs, dbtofsb(fs, dbp->b_blkno)), ibp); sup->su_nbytes += sizeof (struct ufs1_dinode); LFS_WRITESEGENTRY(sup, fs, dtosn(fs, dbtofsb(fs, dbp->b_blkno)), ibp); } } }
/* * Balloc defines the structure of file system storage * by allocating the physical blocks on a device given * the inode and the logical block number in a file. * This is the allocation strategy for UFS2. Above is * the allocation strategy for UFS1. */ int ffs_balloc_ufs2(vnode *vp, off_t startoffset, int size, Ucred *cred, int flags, Buf **bpp) { int error = 0; print("HARVEY TODO: %s\n", __func__); #if 0 struct inode *ip; struct ufs2_dinode *dp; ufs_lbn_t lbn, lastlbn; struct fs *fs; struct buf *bp, *nbp; struct ufsmount *ump; struct indir indirs[UFS_NIADDR + 2]; ufs2_daddr_t nb, newb, *bap, pref; ufs2_daddr_t *allocib, *blkp, *allocblk, allociblk[UFS_NIADDR + 1]; ufs2_daddr_t *lbns_remfree, lbns[UFS_NIADDR + 1]; int deallocated, osize, nsize, num, i, error; int unwindidx = -1; int saved_inbdflush; static struct timeval lastfail; static int curfail; int gbflags, reclaimed; ip = VTOI(vp); dp = ip->i_din2; fs = ITOFS(ip); ump = ITOUMP(ip); lbn = lblkno(fs, startoffset); size = blkoff(fs, startoffset) + size; reclaimed = 0; if (size > fs->fs_bsize) panic("ffs_balloc_ufs2: blk too big"); *bpp = nil; if (lbn < 0) return (EFBIG); gbflags = (flags & BA_UNMAPPED) != 0 ? GB_UNMAPPED : 0; if (DOINGSOFTDEP(vp)) softdep_prealloc(vp, MNT_WAIT); /* * Check for allocating external data. */ if (flags & IO_EXT) { if (lbn >= UFS_NXADDR) return (EFBIG); /* * If the next write will extend the data into a new block, * and the data is currently composed of a fragment * this fragment has to be extended to be a full block. */ lastlbn = lblkno(fs, dp->di_extsize); if (lastlbn < lbn) { nb = lastlbn; osize = sblksize(fs, dp->di_extsize, nb); if (osize < fs->fs_bsize && osize > 0) { UFS_LOCK(ump); error = ffs_realloccg(ip, -1 - nb, dp->di_extb[nb], ffs_blkpref_ufs2(ip, lastlbn, (int)nb, &dp->di_extb[0]), osize, (int)fs->fs_bsize, flags, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocext(ip, nb, dbtofsb(fs, bp->b_blkno), dp->di_extb[nb], fs->fs_bsize, osize, bp); dp->di_extsize = smalllblktosize(fs, nb + 1); dp->di_extb[nb] = dbtofsb(fs, bp->b_blkno); bp->b_xflags |= BX_ALTDATA; ip->i_flag |= IN_CHANGE; if (flags & IO_SYNC) bwrite(bp); else bawrite(bp); } } /* * All blocks are direct blocks */ if (flags & BA_METAONLY) panic("ffs_balloc_ufs2: BA_METAONLY for ext block"); nb = dp->di_extb[lbn]; if (nb != 0 && dp->di_extsize >= smalllblktosize(fs, lbn + 1)) { error = bread_gb(vp, -1 - lbn, fs->fs_bsize, NOCRED, gbflags, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); bp->b_xflags |= BX_ALTDATA; *bpp = bp; return (0); } if (nb != 0) { /* * Consider need to reallocate a fragment. */ osize = fragroundup(fs, blkoff(fs, dp->di_extsize)); nsize = fragroundup(fs, size); if (nsize <= osize) { error = bread_gb(vp, -1 - lbn, osize, NOCRED, gbflags, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); bp->b_xflags |= BX_ALTDATA; } else { UFS_LOCK(ump); error = ffs_realloccg(ip, -1 - lbn, dp->di_extb[lbn], ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]), osize, nsize, flags, cred, &bp); if (error) return (error); bp->b_xflags |= BX_ALTDATA; if (DOINGSOFTDEP(vp)) softdep_setup_allocext(ip, lbn, dbtofsb(fs, bp->b_blkno), nb, nsize, osize, bp); } } else { if (dp->di_extsize < smalllblktosize(fs, lbn + 1)) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; UFS_LOCK(ump); error = ffs_alloc(ip, lbn, ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_extb[0]), nsize, flags, cred, &newb); if (error) return (error); bp = getblk(vp, -1 - lbn, nsize, 0, 0, gbflags); bp->b_blkno = fsbtodb(fs, newb); bp->b_xflags |= BX_ALTDATA; if (flags & BA_CLRBUF) vfs_bio_clrbuf(bp); if (DOINGSOFTDEP(vp)) softdep_setup_allocext(ip, lbn, newb, 0, nsize, 0, bp); } dp->di_extb[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE; *bpp = bp; return (0); } /* * If the next write will extend the file into a new block, * and the file is currently composed of a fragment * this fragment has to be extended to be a full block. */ lastlbn = lblkno(fs, ip->i_size); if (lastlbn < UFS_NDADDR && lastlbn < lbn) { nb = lastlbn; osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { UFS_LOCK(ump); error = ffs_realloccg(ip, nb, dp->di_db[nb], ffs_blkpref_ufs2(ip, lastlbn, (int)nb, &dp->di_db[0]), osize, (int)fs->fs_bsize, flags, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, nb, dbtofsb(fs, bp->b_blkno), dp->di_db[nb], fs->fs_bsize, osize, bp); ip->i_size = smalllblktosize(fs, nb + 1); dp->di_size = ip->i_size; dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; if (flags & IO_SYNC) bwrite(bp); else bawrite(bp); } } /* * The first UFS_NDADDR blocks are direct blocks */ if (lbn < UFS_NDADDR) { if (flags & BA_METAONLY) panic("ffs_balloc_ufs2: BA_METAONLY for direct block"); nb = dp->di_db[lbn]; if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { error = bread_gb(vp, lbn, fs->fs_bsize, NOCRED, gbflags, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); *bpp = bp; return (0); } if (nb != 0) { /* * Consider need to reallocate a fragment. */ osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { error = bread_gb(vp, lbn, osize, NOCRED, gbflags, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); } else { UFS_LOCK(ump); error = ffs_realloccg(ip, lbn, dp->di_db[lbn], ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_db[0]), osize, nsize, flags, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, dbtofsb(fs, bp->b_blkno), nb, nsize, osize, bp); } } else { if (ip->i_size < smalllblktosize(fs, lbn + 1)) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; UFS_LOCK(ump); error = ffs_alloc(ip, lbn, ffs_blkpref_ufs2(ip, lbn, (int)lbn, &dp->di_db[0]), nsize, flags, cred, &newb); if (error) return (error); bp = getblk(vp, lbn, nsize, 0, 0, gbflags); bp->b_blkno = fsbtodb(fs, newb); if (flags & BA_CLRBUF) vfs_bio_clrbuf(bp); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, newb, 0, nsize, 0, bp); } dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); } /* * Determine the number of levels of indirection. */ pref = 0; if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) return(error); #ifdef INVARIANTS if (num < 1) panic ("ffs_balloc_ufs2: ufs_getlbns returned indirect block"); #endif saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); /* * Fetch the first indirect block allocating if necessary. */ --num; nb = dp->di_ib[indirs[0].in_off]; allocib = nil; allocblk = allociblk; lbns_remfree = lbns; if (nb == 0) { UFS_LOCK(ump); pref = ffs_blkpref_ufs2(ip, lbn, -indirs[0].in_off - 1, (ufs2_daddr_t *)0); if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags, cred, &newb)) != 0) { curthread_pflags_restore(saved_inbdflush); return (error); } pref = newb + fs->fs_frag; nb = newb; MPASS(allocblk < allociblk + nitems(allociblk)); MPASS(lbns_remfree < lbns + nitems(lbns)); *allocblk++ = nb; *lbns_remfree++ = indirs[1].in_lbn; bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, GB_UNMAPPED); bp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(bp); if (DOINGSOFTDEP(vp)) { softdep_setup_allocdirect(ip, UFS_NDADDR + indirs[0].in_off, newb, 0, fs->fs_bsize, 0, bp); bdwrite(bp); } else if ((flags & IO_SYNC) == 0 && DOINGASYNC(vp)) { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } else { if ((error = bwrite(bp)) != 0) goto fail; } allocib = &dp->di_ib[indirs[0].in_off]; *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* * Fetch through the indirect blocks, allocating as necessary. */ retry: for (i = 1;;) { error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); goto fail; } bap = (ufs2_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; i += 1; if (nb != 0) { bqrelse(bp); continue; } UFS_LOCK(ump); /* * If parent indirect has just been allocated, try to cluster * immediately following it. */ if (pref == 0) pref = ffs_blkpref_ufs2(ip, lbn, i - num - 1, (ufs2_daddr_t *)0); if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags | IO_BUFLOCKED, cred, &newb)) != 0) { brelse(bp); if (DOINGSOFTDEP(vp) && ++reclaimed == 1) { UFS_LOCK(ump); softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); UFS_UNLOCK(ump); goto retry; } if (ppsratecheck(&lastfail, &curfail, 1)) { ffs_fserr(fs, ip->i_number, "filesystem full"); uprintf("\n%s: write failed, filesystem " "is full\n", fs->fs_fsmnt); } goto fail; } pref = newb + fs->fs_frag; nb = newb; MPASS(allocblk < allociblk + nitems(allociblk)); MPASS(lbns_remfree < lbns + nitems(lbns)); *allocblk++ = nb; *lbns_remfree++ = indirs[i].in_lbn; nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, GB_UNMAPPED); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); if (DOINGSOFTDEP(vp)) { softdep_setup_allocindir_meta(nbp, ip, bp, indirs[i - 1].in_off, nb); bdwrite(nbp); } else if ((flags & IO_SYNC) == 0 && DOINGASYNC(vp)) { if (nbp->b_bufsize == fs->fs_bsize) nbp->b_flags |= B_CLUSTEROK; bdwrite(nbp); } else { if ((error = bwrite(nbp)) != 0) { brelse(bp); goto fail; } } bap[indirs[i - 1].in_off] = nb; if (allocib == nil && unwindidx < 0) unwindidx = i - 1; /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & IO_SYNC) { bwrite(bp); } else { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } } /* * If asked only for the indirect block, then return it. */ if (flags & BA_METAONLY) { curthread_pflags_restore(saved_inbdflush); *bpp = bp; return (0); } /* * Get the data block, allocating if necessary. */ if (nb == 0) { UFS_LOCK(ump); /* * If allocating metadata at the front of the cylinder * group and parent indirect block has just been allocated, * then cluster next to it if it is the first indirect in * the file. Otherwise it has been allocated in the metadata * area, so we want to find our own place out in the data area. */ if (pref == 0 || (lbn > UFS_NDADDR && fs->fs_metaspace != 0)) pref = ffs_blkpref_ufs2(ip, lbn, indirs[i].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags | IO_BUFLOCKED, cred, &newb); if (error) { brelse(bp); if (DOINGSOFTDEP(vp) && ++reclaimed == 1) { UFS_LOCK(ump); softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); UFS_UNLOCK(ump); goto retry; } if (ppsratecheck(&lastfail, &curfail, 1)) { ffs_fserr(fs, ip->i_number, "filesystem full"); uprintf("\n%s: write failed, filesystem " "is full\n", fs->fs_fsmnt); } goto fail; } nb = newb; MPASS(allocblk < allociblk + nitems(allociblk)); MPASS(lbns_remfree < lbns + nitems(lbns)); *allocblk++ = nb; *lbns_remfree++ = lbn; nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, gbflags); nbp->b_blkno = fsbtodb(fs, nb); if (flags & BA_CLRBUF) vfs_bio_clrbuf(nbp); if (DOINGSOFTDEP(vp)) softdep_setup_allocindir_page(ip, lbn, bp, indirs[i].in_off, nb, 0, nbp); bap[indirs[i].in_off] = nb; /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & IO_SYNC) { bwrite(bp); } else { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } curthread_pflags_restore(saved_inbdflush); *bpp = nbp; return (0); } brelse(bp); /* * If requested clear invalid portions of the buffer. If we * have to do a read-before-write (typical if BA_CLRBUF is set), * try to do some read-ahead in the sequential case to reduce * the number of I/O transactions. */ if (flags & BA_CLRBUF) { int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; if (seqcount != 0 && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0 && !(vm_page_count_severe() || buf_dirty_count_severe())) { error = cluster_read(vp, ip->i_size, lbn, (int)fs->fs_bsize, NOCRED, MAXBSIZE, seqcount, gbflags, &nbp); } else { error = bread_gb(vp, lbn, (int)fs->fs_bsize, NOCRED, gbflags, &nbp); } if (error) { brelse(nbp); goto fail; } } else {
int ext2_reallocblks(struct vop_reallocblks_args *ap) { struct m_ext2fs *fs; struct inode *ip; struct vnode *vp; struct buf *sbp, *ebp; uint32_t *bap, *sbap, *ebap = 0; struct ext2mount *ump; struct cluster_save *buflist; struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp; e2fs_lbn_t start_lbn, end_lbn; int soff; e2fs_daddr_t newblk, blkno; int i, len, start_lvl, end_lvl, pref, ssize; if (doreallocblks == 0) return (ENOSPC); vp = ap->a_vp; ip = VTOI(vp); fs = ip->i_e2fs; ump = ip->i_ump; if (fs->e2fs_contigsumsize <= 0) return (ENOSPC); buflist = ap->a_buflist; len = buflist->bs_nchildren; start_lbn = buflist->bs_children[0]->b_lblkno; end_lbn = start_lbn + len - 1; #ifdef INVARIANTS for (i = 1; i < len; i++) if (buflist->bs_children[i]->b_lblkno != start_lbn + i) panic("ext2_reallocblks: non-cluster"); #endif /* * If the cluster crosses the boundary for the first indirect * block, leave space for the indirect block. Indirect blocks * are initially laid out in a position after the last direct * block. Block reallocation would usually destroy locality by * moving the indirect block out of the way to make room for * data blocks if we didn't compensate here. We should also do * this for other indirect block boundaries, but it is only * important for the first one. */ if (start_lbn < NDADDR && end_lbn >= NDADDR) return (ENOSPC); /* * If the latest allocation is in a new cylinder group, assume that * the filesystem has decided to move and do not force it back to * the previous cylinder group. */ if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) != dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno))) return (ENOSPC); if (ext2_getlbns(vp, start_lbn, start_ap, &start_lvl) || ext2_getlbns(vp, end_lbn, end_ap, &end_lvl)) return (ENOSPC); /* * Get the starting offset and block map for the first block. */ if (start_lvl == 0) { sbap = &ip->i_db[0]; soff = start_lbn; } else { idp = &start_ap[start_lvl - 1]; if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &sbp)) { brelse(sbp); return (ENOSPC); } sbap = (u_int *)sbp->b_data; soff = idp->in_off; } /* * If the block range spans two block maps, get the second map. */ if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) { ssize = len; } else { #ifdef INVARIANTS if (start_ap[start_lvl-1].in_lbn == idp->in_lbn) panic("ext2_reallocblks: start == end"); #endif ssize = len - (idp->in_off + 1); if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp)) goto fail; ebap = (u_int *)ebp->b_data; } /* * Find the preferred location for the cluster. */ EXT2_LOCK(ump); pref = ext2_blkpref(ip, start_lbn, soff, sbap, 0); /* * Search the block map looking for an allocation of the desired size. */ if ((newblk = (e2fs_daddr_t)ext2_hashalloc(ip, dtog(fs, pref), pref, len, ext2_clusteralloc)) == 0) { EXT2_UNLOCK(ump); goto fail; } /* * We have found a new contiguous block. * * First we have to replace the old block pointers with the new * block pointers in the inode and indirect blocks associated * with the file. */ #ifdef DEBUG printf("realloc: ino %d, lbns %jd-%jd\n\told:", ip->i_number, (intmax_t)start_lbn, (intmax_t)end_lbn); #endif /* DEBUG */ blkno = newblk; for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) { if (i == ssize) { bap = ebap; soff = -i; } #ifdef INVARIANTS if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap)) panic("ext2_reallocblks: alloc mismatch"); #endif #ifdef DEBUG printf(" %d,", *bap); #endif /* DEBUG */ *bap++ = blkno; } /* * Next we must write out the modified inode and indirect blocks. * For strict correctness, the writes should be synchronous since * the old block values may have been written to disk. In practise * they are almost never written, but if we are concerned about * strict correctness, the `doasyncfree' flag should be set to zero. * * The test on `doasyncfree' should be changed to test a flag * that shows whether the associated buffers and inodes have * been written. The flag should be set when the cluster is * started and cleared whenever the buffer or inode is flushed. * We can then check below to see if it is set, and do the * synchronous write only when it has been cleared. */ if (sbap != &ip->i_db[0]) { if (doasyncfree) bdwrite(sbp); else bwrite(sbp); } else { ip->i_flag |= IN_CHANGE | IN_UPDATE; if (!doasyncfree) ext2_update(vp, 1); } if (ssize < len) { if (doasyncfree) bdwrite(ebp); else bwrite(ebp); } /* * Last, free the old blocks and assign the new blocks to the buffers. */ #ifdef DEBUG printf("\n\tnew:"); #endif /* DEBUG */ for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) { ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno), fs->e2fs_bsize); buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno); #ifdef DEBUG printf(" %d,", blkno); #endif /* DEBUG */ } #ifdef DEBUG printf("\n"); #endif /* DEBUG */ return (0); fail: if (ssize < len) brelse(ebp); if (sbap != &ip->i_db[0]) brelse(sbp); return (ENOSPC); }
/* ARGSUSED2 */ static int lqfs_alloc(qfsvfs_t *qfsvfsp, struct fiolog *flp, cred_t *cr) { int error = 0; buf_t *bp = NULL; extent_t *ep, *nep; extent_block_t *ebp; fs_lqfs_common_t *fs = VFS_FS_PTR(qfsvfsp); daddr_t fno; /* in frags */ #ifdef LUFS daddr_t bno; /* in disk blocks */ #endif /* LUFS */ int32_t logbno = INT32_C(0); /* will be fs_logbno */ ushort_t logord = 0; /* will be fs_logord */ inode_t *ip = NULL; #ifndef LUFS sam_bn_t bno; #endif /* LUFS */ size_t nb = flp->nbytes_actual; size_t tb = 0; int ord = 0; uchar_t save_unit; /* * Mark the file system as FSACTIVE */ UL_SBOWNER_SET(qfsvfsp, curthread); VFS_LOCK_MUTEX_ENTER(qfsvfsp); LQFS_SET_FS_CLEAN(fs, FSACTIVE); #ifdef LUFS qfs_sbwrite(qfsvfsp); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); sam_update_sblk(qfsvfsp, 0, 1, TRUE); #endif /* LUFS */ VFS_LOCK_MUTEX_EXIT(qfsvfsp); UL_SBOWNER_SET(qfsvfsp, -1); /* * Allocate the allocation block (need dummy shadow inode; * we use a shadow inode so the quota sub-system ignores * the block allocations.) * superblock -> one block of extents -> log data */ #ifdef LUFS ip = qfs_alloc_inode(qfsvfsp, QFSROOTINO); ip->i_mode = IFSHAD; /* make the dummy a shadow inode */ #else /* * Although QFS has "extension" inodes, it doesn't really implement * the concept of "shadow" inodes. We can't bypass having the quota * system track the allocation of log blocks. For now, use the * .inodes inode (SAM_INO_INO) to which we we will allocate space * for a UFS-like log of the requested size. Allocate space at mount * time BEFORE the quota system is initialized. */ ip = qfsvfsp->mi.m_inodir; #endif /* LUFS */ rw_enter(&ip->i_contents, RW_WRITER); #ifdef LUFS /* Allocate first log block (extent info). */ fno = contigpref(qfsvfsp, nb + FS_BSIZE(fs)); error = alloc(ip, fno, FS_BSIZE(fs), &fno, cr); #else save_unit = ip->di.unit; ip->di.unit = 0; if ((error = sam_alloc_block(ip, SM, &bno, &ord)) == 0) { /* Convert 4K block offset to 1K frag offset. */ fno = fsblktologb(fs, bno); } #endif /* LUFS */ if (error) { goto errout; } /* Convert 1K frag offset to 512B disk block offset. */ bno = fsbtodb(fs, fno); sam_bread_db(qfsvfsp, qfsvfsp->mi.m_fs[ord].dev, bno, FS_BSIZE(fs), &bp); if (bp->b_flags & B_ERROR) { error = EIO; goto errout; } ebp = (void *)bp->b_un.b_addr; ebp->type = LQFS_EXTENTS; ebp->nextbno = UINT32_C(0); ebp->nextord = 0; ebp->nextents = UINT32_C(0); ebp->chksum = INT32_C(0); #ifdef LUFS if (fs->fs_magic == SAM_MAGIC) { logbno = bno; } else { #endif /* LUFS */ logbno = dbtofsb(fs, bno); #ifdef LUFS } #endif /* LUFS */ logord = (ushort_t)ord; /* * Initialize the first extent */ ep = &ebp->extents[0]; #ifdef LUFS error = alloc(ip, fno + FS_FRAG(fs), FS_BSIZE(fs), &fno, cr); #else ip->di.unit = 0; if ((error = sam_alloc_block(ip, SM, &bno, &ord)) == 0) { /* Convert 4K block offset to 1K block (frag) offset. */ fno = fsblktologb(fs, bno); } #endif /* LUFS */ if (error) { goto errout; } /* Convert frag offset to physical disk block (512B block) offset. */ bno = fsbtodb(fs, fno); ep->lbno = UINT32_C(0); #ifdef LUFS if (fs->fs_magic == SAM_MAGIC) { ep->pbno = (uint32_t)bno; } else { #endif /* LUFS */ ep->pbno = (uint32_t)fno; #ifdef LUFS } #endif /* LUFS */ ep->nbno = (uint32_t)fsbtodb(fs, FS_FRAG(fs)); /* Has 8 disk blocks */ ep->ord = ord; ebp->nextents = UINT32_C(1); tb = FS_BSIZE(fs); nb -= FS_BSIZE(fs); while (nb) { #ifdef LUFS error = alloc(ip, fno + FS_FRAG(fs), FS_BSIZE(fs), &fno, cr); #else ip->di.unit = 0; error = sam_alloc_block(ip, SM, &bno, &ord); if (!error) { fno = fsblktologb(fs, bno); } #endif /* LUFS */ if (error) { if (tb < ldl_minlogsize) { goto errout; } error = 0; break; } bno = fsbtodb(fs, fno); if ((ep->ord == ord) && ((daddr_t)((logbtodb(fs, ep->pbno) + ep->nbno) == bno))) { ep->nbno += (uint32_t)(fsbtodb(fs, FS_FRAG(fs))); } else { nep = ep + 1; if ((caddr_t)(nep + 1) > (bp->b_un.b_addr + FS_BSIZE(fs))) { #ifdef LUFS free(ip, fno, FS_BSIZE(fs), 0); #else sam_free_block(qfsvfsp, SM, logbtofsblk(fs, fno), ord); #endif /* LUFS */ break; } nep->lbno = ep->lbno + ep->nbno; #ifdef LUFS if (fs->fs_magic == SAM_MAGIC) { nep->pbno = (uint32_t)bno; } else { #endif /* LUFS */ nep->pbno = (uint32_t)fno; #ifdef LUFS } #endif /* LUFS */ nep->nbno = (uint32_t)(fsbtodb(fs, FS_FRAG(fs))); nep->ord = ord; ebp->nextents++; ep = nep; } tb += FS_BSIZE(fs); nb -= FS_BSIZE(fs); } ebp->nbytes = (uint32_t)tb; setsum(&ebp->chksum, (int32_t *)(void *)bp->b_un.b_addr, FS_BSIZE(fs)); if ((error = SAM_BWRITE2(qfsvfsp, bp)) != 0) { goto errout; } /* * Initialize the first two sectors of the log */ error = lqfs_initialize(qfsvfsp, logbtodb(fs, ebp->extents[0].pbno), ebp->extents[0].ord, tb, flp); if (error) { goto errout; } /* * We are done initializing the allocation block and the log */ brelse(bp); bp = NULL; /* * Update the superblock and push the dirty metadata */ UL_SBOWNER_SET(qfsvfsp, curthread); #ifdef LUFS sbupdate(qfsvfsp->vfs_vfs); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); #endif /* LUFS */ UL_SBOWNER_SET(qfsvfsp, -1); bflush(qfsvfsp->mi.m_fs[logord].dev); error = bfinval(qfsvfsp->mi.m_fs[logord].dev, 1); if (error) { goto errout; } #ifdef LUFS if (qfsvfsp->vfs_bufp->b_flags & B_ERROR) { error = EIO; goto errout; } #endif /* LUFS */ /* * Everything is safely on disk; update log space pointer in sb */ UL_SBOWNER_SET(qfsvfsp, curthread); VFS_LOCK_MUTEX_ENTER(qfsvfsp); LQFS_SET_LOGBNO(fs, (uint32_t)logbno); LQFS_SET_LOGORD(fs, logord); #ifdef LUFS qfs_sbwrite(qfsvfsp); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); sam_update_sblk(qfsvfsp, 0, 1, TRUE); #endif /* LUFS */ VFS_LOCK_MUTEX_EXIT(qfsvfsp); UL_SBOWNER_SET(qfsvfsp, -1); ip->di.unit = save_unit; /* * Free the dummy inode */ rw_exit(&ip->i_contents); #ifdef LUFS qfs_free_inode(ip); #endif /* LUFS */ /* inform user of real log size */ flp->nbytes_actual = tb; return (0); errout: /* * Free all resources */ if (bp) { brelse(bp); } if (logbno) { LQFS_SET_LOGBNO(fs, logbno); LQFS_SET_LOGORD(fs, logord); (void) lqfs_free(qfsvfsp); } if (ip) { ip->di.unit = save_unit; rw_exit(&ip->i_contents); #ifdef LUFS qfs_free_inode(ip); #endif /* LUFS */ } return (error); }
/* * Free log space * Assumes the file system is write locked and is not logging */ int lqfs_free(qfsvfs_t *qfsvfsp) { int error = 0, i, j; buf_t *bp = NULL; extent_t *ep; extent_block_t *ebp; fs_lqfs_common_t *fs = VFS_FS_PTR(qfsvfsp); daddr_t fno; int32_t logbno; ushort_t logord; long nfno; inode_t *ip = NULL; char clean; /* * Nothing to free */ if (LQFS_GET_LOGBNO(fs) == 0) { return (0); } /* * Mark the file system as FSACTIVE and no log but honor the * current value of fs_reclaim. The reclaim thread could have * been active when lqfs_disable() was called and if fs_reclaim * is reset to zero here it could lead to lost inodes. */ UL_SBOWNER_SET(qfsvfsp, curthread); VFS_LOCK_MUTEX_ENTER(qfsvfsp); clean = LQFS_GET_FS_CLEAN(fs); logbno = LQFS_GET_LOGBNO(fs); logord = LQFS_GET_LOGORD(fs); LQFS_SET_FS_CLEAN(fs, FSACTIVE); LQFS_SET_LOGBNO(fs, INT32_C(0)); LQFS_SET_LOGORD(fs, 0); #ifdef LUFS qfs_sbwrite(qfsvfsp); error = (qfsvfsp->vfs_bufp->b_flags & B_ERROR); #else error = sam_update_sblk(qfsvfsp, 0, 0, TRUE); error = sam_update_sblk(qfsvfsp, 0, 1, TRUE); #endif /* LUFS */ VFS_LOCK_MUTEX_EXIT(qfsvfsp); UL_SBOWNER_SET(qfsvfsp, -1); if (error) { error = EIO; LQFS_SET_FS_CLEAN(fs, clean); LQFS_SET_LOGBNO(fs, logbno); LQFS_SET_LOGORD(fs, logord); goto errout; } /* * fetch the allocation block * superblock -> one block of extents -> log data */ sam_bread_db(qfsvfsp, qfsvfsp->mi.m_fs[logord].dev, logbtodb(fs, logbno), FS_BSIZE(fs), &bp); if (bp->b_flags & B_ERROR) { error = EIO; goto errout; } #ifdef LUFS /* * Free up the allocated space (dummy inode needed for free()) */ ip = qfs_alloc_inode(qfsvfsp, QFSROOTINO); #else /* * QFS doesn't need an inode to free blocks. */ #endif /* LUFS */ ebp = (void *)bp->b_un.b_addr; for (i = 0, ep = &ebp->extents[0]; i < ebp->nextents; ++i, ++ep) { fno = logbtofrag(fs, ep->pbno); nfno = dbtofsb(fs, ep->nbno); for (j = 0; j < nfno; j += FS_FRAG(fs), fno += FS_FRAG(fs)) { #ifdef LUFS free(ip, fno, FS_BSIZE(fs), 0); #else sam_free_block(qfsvfsp, SM, logbtofsblk(fs, fno), ep->ord); #endif /* LUFS */ } } #ifdef LUFS free(ip, logbtofrag(fs, logbno), FS_BSIZE(fs), 0); #else sam_free_block(qfsvfsp, SM, logbtofsblk(fs, logbno), logord); #endif /* LUFS */ brelse(bp); bp = NULL; /* * Push the metadata dirtied during the allocations */ UL_SBOWNER_SET(qfsvfsp, curthread); #ifdef LUFS sbupdate(qfsvfsp->vfs_vfs); #else sam_update_sblk(qfsvfsp, 0, 0, TRUE); #endif /* LUFS */ UL_SBOWNER_SET(qfsvfsp, -1); bflush(qfsvfsp->mi.m_fs[logord].dev); error = bfinval(qfsvfsp->mi.m_fs[logord].dev, 0); if (error) { goto errout; } /* * Free the dummy inode */ #ifdef LUFS qfs_free_inode(ip); #else /* QFS uses a reserved inode */ VN_RELE(SAM_ITOV(ip)); #endif /* LUFS */ return (0); errout: /* * Free up all resources */ if (bp) { brelse(bp); } if (ip) { #ifdef LUFS qfs_free_inode(ip); #else /* QFS uses a reserved inode */ VN_RELE(SAM_ITOV(ip)); #endif /* LUFS */ } return (error); }
/* ARGSUSED */ static int lqfs_log_validate(qfsvfs_t *qfsvfsp, struct fiolog *flp, cred_t *cr) { int error = 0; buf_t *bp = NULL; extent_t *ep; extent_block_t *ebp; fs_lqfs_common_t *fs = VFS_FS_PTR(qfsvfsp); daddr_t fno; /* in frags */ #ifdef LUFS extent_t *nep; daddr_t bno; /* in disk blocks */ #endif /* LUFS */ int32_t logbno; int logord; int i; int j; long nfno; logbno = LQFS_GET_LOGBNO(fs); logord = LQFS_GET_LOGORD(fs); if (logbno == 0) { error = EINVAL; goto errout; } LQFS_MSG(CE_WARN, "lqfs_log_validate: Extent alloc block offset 0x%x ord %d.\n", (dbtob(logbtodb(fs, logbno))), logord); sam_bread_db(qfsvfsp, qfsvfsp->mi.m_fs[logord].dev, logbtodb(fs, logbno), FS_BSIZE(fs), &bp); if (bp->b_flags & B_ERROR) { LQFS_MSG(CE_WARN, "lqfs_log_validate: Can't read extent alloc block\n"); error = EIO; goto errout; } ebp = (void *)bp->b_un.b_addr; LQFS_MSG(CE_WARN, "lqfs_log_validate: Ext alloc block type 0x%x chksum 0x%x\n", ebp->type, ebp->chksum); LQFS_MSG(CE_WARN, "lqfs_log_validate: Ext alloc block nextents 0x%x nb 0x%x.\n", ebp->nextents, ebp->nbytes); LQFS_MSG(CE_WARN, "lqfs_log_validate: Ext alloc block nxtbno 0x%x nxtord 0x%x.\n", ebp->nextbno, ebp->nextord); for (i = 0, ep = &ebp->extents[0]; i < ebp->nextents; ++i, ++ep) { fno = logbtofrag(fs, ep->pbno); nfno = dbtofsb(fs, ep->nbno); LQFS_MSG(CE_WARN, " Extent # %d - 0x%x 1K blocks:\n", i, nfno); for (j = 0; j < nfno; j += FS_FRAG(fs), fno += FS_FRAG(fs)) { int lastord; if (j == 0) { LQFS_MSG(CE_WARN, " First 4K block at offset 0x%x " "ord %d (incl. last 1K frag 0x%x, last " "sector 0x%x)\n", logbtofsblk(fs, fno), ep->ord, fno+FS_FRAG(fs)-1, logbtodb(fs, fno+1)-1); lastord = ep->ord; } else if (j >= (nfno - (FS_FRAG(fs)))) { LQFS_MSG(CE_WARN, " Last 4K block at offset 0x%x " "ord %d (incl. last 1K frag 0x%x, last " "sector 0x%x)\n", logbtofsblk(fs, fno), ep->ord, fno+FS_FRAG(fs)-1, logbtodb(fs, fno+1)-1); } else if (ep->ord != lastord) { LQFS_MSG(CE_WARN, " Includes 4K block at offset " "0x%x ord %d (incl. last 1K frag 0x%x, " "last sector 0x%x)\n", logbtofsblk(fs, fno), ep->ord, fno+FS_FRAG(fs)-1, logbtodb(fs, fno+1)-1); lastord = ep->ord; } } } errout: if (bp) { brelse(bp); } if (!error) { LQFS_MSG(CE_WARN, "lqfs_log_validate(): Returning OK.\n"); } else { LQFS_MSG(CE_WARN, "lqfs_log_validate(): Returning error code %d\n", error); } return (error); }
void mkfs(struct partition *pp, char *fsys) { int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; long i, j, csfrags; uint cg; time_t utime; quad_t sizepb; int width; ino_t maxinum; int minfragsperinode; /* minimum ratio of frags to inodes */ char tmpbuf[100]; /* XXX this will break in about 2,500 years */ union { struct fs fdummy; char cdummy[SBLOCKSIZE]; } dummy; #define fsdummy dummy.fdummy #define chdummy dummy.cdummy /* * Our blocks == sector size, and the version of UFS we are using is * specified by Oflag. */ disk.d_bsize = sectorsize; disk.d_ufs = Oflag; if (Rflag) { utime = 1000000000; } else { time(&utime); arc4random_stir(); } sblock.fs_old_flags = FS_FLAGS_UPDATED; sblock.fs_flags = 0; if (Uflag) sblock.fs_flags |= FS_DOSOFTDEP; if (Lflag) strlcpy(sblock.fs_volname, volumelabel, MAXVOLLEN); if (Jflag) sblock.fs_flags |= FS_GJOURNAL; if (lflag) sblock.fs_flags |= FS_MULTILABEL; if (tflag) sblock.fs_flags |= FS_TRIM; /* * Validate the given file system size. * Verify that its last block can actually be accessed. * Convert to file system fragment sized units. */ if (fssize <= 0) { printf("preposterous size %jd\n", (intmax_t)fssize); exit(13); } wtfs(fssize - (realsectorsize / DEV_BSIZE), realsectorsize, (char *)&sblock); /* * collect and verify the file system density info */ sblock.fs_avgfilesize = avgfilesize; sblock.fs_avgfpdir = avgfilesperdir; if (sblock.fs_avgfilesize <= 0) printf("illegal expected average file size %d\n", sblock.fs_avgfilesize), exit(14); if (sblock.fs_avgfpdir <= 0) printf("illegal expected number of files per directory %d\n", sblock.fs_avgfpdir), exit(15); restart: /* * collect and verify the block and fragment sizes */ sblock.fs_bsize = bsize; sblock.fs_fsize = fsize; if (!POWEROF2(sblock.fs_bsize)) { printf("block size must be a power of 2, not %d\n", sblock.fs_bsize); exit(16); } if (!POWEROF2(sblock.fs_fsize)) { printf("fragment size must be a power of 2, not %d\n", sblock.fs_fsize); exit(17); } if (sblock.fs_fsize < sectorsize) { printf("increasing fragment size from %d to sector size (%d)\n", sblock.fs_fsize, sectorsize); sblock.fs_fsize = sectorsize; } if (sblock.fs_bsize > MAXBSIZE) { printf("decreasing block size from %d to maximum (%d)\n", sblock.fs_bsize, MAXBSIZE); sblock.fs_bsize = MAXBSIZE; } if (sblock.fs_bsize < MINBSIZE) { printf("increasing block size from %d to minimum (%d)\n", sblock.fs_bsize, MINBSIZE); sblock.fs_bsize = MINBSIZE; } if (sblock.fs_fsize > MAXBSIZE) { printf("decreasing fragment size from %d to maximum (%d)\n", sblock.fs_fsize, MAXBSIZE); sblock.fs_fsize = MAXBSIZE; } if (sblock.fs_bsize < sblock.fs_fsize) { printf("increasing block size from %d to fragment size (%d)\n", sblock.fs_bsize, sblock.fs_fsize); sblock.fs_bsize = sblock.fs_fsize; } if (sblock.fs_fsize * MAXFRAG < sblock.fs_bsize) { printf( "increasing fragment size from %d to block size / %d (%d)\n", sblock.fs_fsize, MAXFRAG, sblock.fs_bsize / MAXFRAG); sblock.fs_fsize = sblock.fs_bsize / MAXFRAG; } if (maxbsize == 0) maxbsize = bsize; if (maxbsize < bsize || !POWEROF2(maxbsize)) { sblock.fs_maxbsize = sblock.fs_bsize; printf("Extent size set to %d\n", sblock.fs_maxbsize); } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; printf("Extent size reduced to %d\n", sblock.fs_maxbsize); } else { sblock.fs_maxbsize = maxbsize; } /* * Maxcontig sets the default for the maximum number of blocks * that may be allocated sequentially. With file system clustering * it is possible to allocate contiguous blocks up to the maximum * transfer size permitted by the controller or buffering. */ if (maxcontig == 0) maxcontig = MAX(1, MAXPHYS / bsize); sblock.fs_maxcontig = maxcontig; if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); } if (sblock.fs_maxcontig > 1) sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); sblock.fs_bmask = ~(sblock.fs_bsize - 1); sblock.fs_fmask = ~(sblock.fs_fsize - 1); sblock.fs_qbmask = ~sblock.fs_bmask; sblock.fs_qfmask = ~sblock.fs_fmask; sblock.fs_bshift = ilog2(sblock.fs_bsize); sblock.fs_fshift = ilog2(sblock.fs_fsize); sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); sblock.fs_fragshift = ilog2(sblock.fs_frag); if (sblock.fs_frag > MAXFRAG) { printf("fragment size %d is still too small (can't happen)\n", sblock.fs_bsize / MAXFRAG); exit(21); } sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); sblock.fs_size = fssize = dbtofsb(&sblock, fssize); sblock.fs_providersize = dbtofsb(&sblock, mediasize / sectorsize); /* * Before the filesystem is finally initialized, mark it * as incompletely initialized. */ sblock.fs_magic = FS_BAD_MAGIC; if (Oflag == 1) { sblock.fs_sblockloc = SBLOCK_UFS1; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * sizeof(ufs1_daddr_t)); sblock.fs_old_inodefmt = FS_44INODEFMT; sblock.fs_old_cgoffset = 0; sblock.fs_old_cgmask = 0xffffffff; sblock.fs_old_size = sblock.fs_size; sblock.fs_old_rotdelay = 0; sblock.fs_old_rps = 60; sblock.fs_old_nspf = sblock.fs_fsize / sectorsize; sblock.fs_old_cpg = 1; sblock.fs_old_interleave = 1; sblock.fs_old_trackskew = 0; sblock.fs_old_cpc = 0; sblock.fs_old_postblformat = 1; sblock.fs_old_nrpos = 1; } else { sblock.fs_sblockloc = SBLOCK_UFS2; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * sizeof(ufs2_daddr_t)); } sblock.fs_sblkno = roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag); sblock.fs_cblkno = sblock.fs_sblkno + roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag); sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { sizepb *= NINDIR(&sblock); sblock.fs_maxfilesize += sizepb; } /* * It's impossible to create a snapshot in case that fs_maxfilesize * is smaller than the fssize. */ if (sblock.fs_maxfilesize < (u_quad_t)fssize) { warnx("WARNING: You will be unable to create snapshots on this " "file system. Correct by using a larger blocksize."); } /* * Calculate the number of blocks to put into each cylinder group. * * This algorithm selects the number of blocks per cylinder * group. The first goal is to have at least enough data blocks * in each cylinder group to meet the density requirement. Once * this goal is achieved we try to expand to have at least * MINCYLGRPS cylinder groups. Once this goal is achieved, we * pack as many blocks into each cylinder group map as will fit. * * We start by calculating the smallest number of blocks that we * can put into each cylinder group. If this is too big, we reduce * the density until it fits. */ maxinum = (((int64_t)(1)) << 32) - INOPB(&sblock); minfragsperinode = 1 + fssize / maxinum; if (density == 0) { density = MAX(NFPI, minfragsperinode) * fsize; } else if (density < minfragsperinode * fsize) { origdensity = density; density = minfragsperinode * fsize; fprintf(stderr, "density increased from %d to %d\n", origdensity, density); } origdensity = density; for (;;) { fragsperinode = MAX(numfrags(&sblock, density), 1); if (fragsperinode < minfragsperinode) { bsize <<= 1; fsize <<= 1; printf("Block size too small for a file system %s %d\n", "of this size. Increasing blocksize to", bsize); goto restart; } minfpg = fragsperinode * INOPB(&sblock); if (minfpg > sblock.fs_size) minfpg = sblock.fs_size; sblock.fs_ipg = INOPB(&sblock); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) break; density -= sblock.fs_fsize; } if (density != origdensity) printf("density reduced from %d to %d\n", origdensity, density); /* * Start packing more blocks into the cylinder group until * it cannot grow any larger, the number of cylinder groups * drops below MINCYLGRPS, or we reach the size requested. * For UFS1 inodes per cylinder group are stored in an int16_t * so fs_ipg is limited to 2^15 - 1. */ for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (Oflag > 1 || (Oflag == 1 && sblock.fs_ipg <= 0x7fff)) { if (sblock.fs_size / sblock.fs_fpg < MINCYLGRPS) break; if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) continue; if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) break; } sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); break; } /* * Check to be sure that the last cylinder group has enough blocks * to be viable. If it is too small, reduce the number of blocks * per cylinder group which will have the effect of moving more * blocks into the last cylinder group. */ optimalfpg = sblock.fs_fpg; for (;;) { sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); lastminfpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_size < lastminfpg) { printf("Filesystem size %jd < minimum size of %d\n", (intmax_t)sblock.fs_size, lastminfpg); exit(28); } if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || sblock.fs_size % sblock.fs_fpg == 0) break; sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); } if (optimalfpg != sblock.fs_fpg) printf("Reduced frags per cylinder group from %d to %d %s\n", optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); if (Oflag == 1) { sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf; sblock.fs_old_nsect = sblock.fs_old_spc; sblock.fs_old_npsect = sblock.fs_old_spc; sblock.fs_old_ncyl = sblock.fs_ncg; } /* * fill in remaining fields of the super block */ sblock.fs_csaddr = cgdmin(&sblock, 0); sblock.fs_cssize = fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); fscs = (struct csum *)calloc(1, sblock.fs_cssize); if (fscs == NULL) errx(31, "calloc failed"); sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); if (sblock.fs_sbsize > SBLOCKSIZE) sblock.fs_sbsize = SBLOCKSIZE; sblock.fs_minfree = minfree; if (metaspace > 0 && metaspace < sblock.fs_fpg / 2) sblock.fs_metaspace = blknum(&sblock, metaspace); else if (metaspace != -1) /* reserve half of minfree for metadata blocks */ sblock.fs_metaspace = blknum(&sblock, (sblock.fs_fpg * minfree) / 200); if (maxbpg == 0) sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize); else sblock.fs_maxbpg = maxbpg; sblock.fs_optim = opt; sblock.fs_cgrotor = 0; sblock.fs_pendingblocks = 0; sblock.fs_pendinginodes = 0; sblock.fs_fmod = 0; sblock.fs_ronly = 0; sblock.fs_state = 0; sblock.fs_clean = 1; sblock.fs_id[0] = (long)utime; sblock.fs_id[1] = newfs_random(); sblock.fs_fsmnt[0] = '\0'; csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); sblock.fs_cstotal.cs_nbfree = fragstoblks(&sblock, sblock.fs_dsize) - howmany(csfrags, sblock.fs_frag); sblock.fs_cstotal.cs_nffree = fragnum(&sblock, sblock.fs_size) + (fragnum(&sblock, csfrags) > 0 ? sblock.fs_frag - fragnum(&sblock, csfrags) : 0); sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_dsize -= csfrags; sblock.fs_time = utime; if (Oflag == 1) { sblock.fs_old_time = utime; sblock.fs_old_dsize = sblock.fs_dsize; sblock.fs_old_csaddr = sblock.fs_csaddr; sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } /* * Dump out summary information about file system. */ # define B2MBFACTOR (1 / (1024.0 * 1024.0)) printf("%s: %.1fMB (%jd sectors) block size %d, fragment size %d\n", fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, (intmax_t)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, sblock.fs_fsize); printf("\tusing %d cylinder groups of %.2fMB, %d blks, %d inodes.\n", sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); if (sblock.fs_flags & FS_DOSOFTDEP) printf("\twith soft updates\n"); # undef B2MBFACTOR if (Eflag && !Nflag) { printf("Erasing sectors [%jd...%jd]\n", sblock.fs_sblockloc / disk.d_bsize, fsbtodb(&sblock, sblock.fs_size) - 1); berase(&disk, sblock.fs_sblockloc / disk.d_bsize, sblock.fs_size * sblock.fs_fsize - sblock.fs_sblockloc); } /* * Wipe out old UFS1 superblock(s) if necessary. */ if (!Nflag && Oflag != 1) { i = bread(&disk, part_ofs + SBLOCK_UFS1 / disk.d_bsize, chdummy, SBLOCKSIZE); if (i == -1) err(1, "can't read old UFS1 superblock: %s", disk.d_error); if (fsdummy.fs_magic == FS_UFS1_MAGIC) { fsdummy.fs_magic = 0; bwrite(&disk, part_ofs + SBLOCK_UFS1 / disk.d_bsize, chdummy, SBLOCKSIZE); for (cg = 0; cg < fsdummy.fs_ncg; cg++) { if (fsbtodb(&fsdummy, cgsblock(&fsdummy, cg)) > fssize) break; bwrite(&disk, part_ofs + fsbtodb(&fsdummy, cgsblock(&fsdummy, cg)), chdummy, SBLOCKSIZE); } } } if (!Nflag) do_sbwrite(&disk); if (Xflag == 1) { printf("** Exiting on Xflag 1\n"); exit(0); } if (Xflag == 2) printf("** Leaving BAD MAGIC on Xflag 2\n"); else sblock.fs_magic = (Oflag != 1) ? FS_UFS2_MAGIC : FS_UFS1_MAGIC; /* * Now build the cylinders group blocks and * then print out indices of cylinder groups. */ printf("super-block backups (for fsck -b #) at:\n"); i = 0; width = charsperline(); /* * allocate space for superblock, cylinder group map, and * two sets of inode blocks. */ if (sblock.fs_bsize < SBLOCKSIZE) iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; else iobufsize = 4 * sblock.fs_bsize; if ((iobuf = calloc(1, iobufsize)) == 0) { printf("Cannot allocate I/O buffer\n"); exit(38); } /* * Make a copy of the superblock into the buffer that we will be * writing out in each cylinder group. */ bcopy((char *)&sblock, iobuf, SBLOCKSIZE); for (cg = 0; cg < sblock.fs_ncg; cg++) { initcg(cg, utime); j = snprintf(tmpbuf, sizeof(tmpbuf), " %jd%s", (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cg)), cg < (sblock.fs_ncg-1) ? "," : ""); if (j < 0) tmpbuf[j = 0] = '\0'; if (i + j >= width) { printf("\n"); i = 0; } i += j; printf("%s", tmpbuf); fflush(stdout); } printf("\n"); if (Nflag) exit(0); /* * Now construct the initial file system, * then write out the super-block. */ fsinit(utime); if (Oflag == 1) { sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } if (Xflag == 3) { printf("** Exiting on Xflag 3\n"); exit(0); } if (!Nflag) { do_sbwrite(&disk); /* * For UFS1 filesystems with a blocksize of 64K, the first * alternate superblock resides at the location used for * the default UFS2 superblock. As there is a valid * superblock at this location, the boot code will use * it as its first choice. Thus we have to ensure that * all of its statistcs on usage are correct. */ if (Oflag == 1 && sblock.fs_bsize == 65536) wtfs(fsbtodb(&sblock, cgsblock(&sblock, 0)), sblock.fs_bsize, (char *)&sblock); } for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), sblock.fs_cssize - i < sblock.fs_bsize ? sblock.fs_cssize - i : sblock.fs_bsize, ((char *)fscs) + i); /* * Update information about this partition in pack * label, to that it may be updated on disk. */ if (pp != NULL) { pp->p_fstype = FS_BSDFFS; pp->p_fsize = sblock.fs_fsize; pp->p_frag = sblock.fs_frag; pp->p_cpg = sblock.fs_fpg; } }
/* * Balloc defines the structure of file system storage * by allocating the physical blocks on a device given * the inode and the logical block number in a file. */ ffs_balloc( register struct inode *ip, register ufs_daddr_t lbn, int size, kauth_cred_t cred, struct buf **bpp, int flags, int * blk_alloc) { register struct fs *fs; register ufs_daddr_t nb; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[NIADDR + 2]; ufs_daddr_t newb, *bap, pref; int deallocated, osize, nsize, num, i, error; ufs_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; int devBlockSize=0; int alloc_buffer = 1; struct mount *mp=vp->v_mount; #if REV_ENDIAN_FS int rev_endian=(mp->mnt_flag & MNT_REVEND); #endif /* REV_ENDIAN_FS */ *bpp = NULL; if (lbn < 0) return (EFBIG); fs = ip->i_fs; if (flags & B_NOBUFF) alloc_buffer = 0; if (blk_alloc) *blk_alloc = 0; /* * If the next write will extend the file into a new block, * and the file is currently composed of a fragment * this fragment has to be extended to be a full block. */ nb = lblkno(fs, ip->i_size); if (nb < NDADDR && nb < lbn) { /* the filesize prior to this write can fit in direct * blocks (ie. fragmentaion is possibly done) * we are now extending the file write beyond * the block which has end of file prior to this write */ osize = blksize(fs, ip, nb); /* osize gives disk allocated size in the last block. It is * either in fragments or a file system block size */ if (osize < fs->fs_bsize && osize > 0) { /* few fragments are already allocated,since the * current extends beyond this block * allocate the complete block as fragments are only * in last block */ error = ffs_realloccg(ip, nb, ffs_blkpref(ip, nb, (int)nb, &ip->i_db[0]), osize, (int)fs->fs_bsize, cred, &bp); if (error) return (error); /* adjust the inode size we just grew */ /* it is in nb+1 as nb starts from 0 */ ip->i_size = (nb + 1) * fs->fs_bsize; ubc_setsize(vp, (off_t)ip->i_size); ip->i_db[nb] = dbtofsb(fs, (ufs_daddr_t)buf_blkno(bp)); ip->i_flag |= IN_CHANGE | IN_UPDATE; if ((flags & B_SYNC) || (!alloc_buffer)) { if (!alloc_buffer) buf_setflags(bp, B_NOCACHE); buf_bwrite(bp); } else buf_bdwrite(bp); /* note that bp is already released here */ } } /* * The first NDADDR blocks are direct blocks */ if (lbn < NDADDR) { nb = ip->i_db[lbn]; if (nb != 0 && ip->i_size >= (lbn + 1) * fs->fs_bsize) { if (alloc_buffer) { error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, NOCRED, &bp); if (error) { buf_brelse(bp); return (error); } *bpp = bp; } return (0); } if (nb != 0) { /* * Consider need to reallocate a fragment. */ osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { if (alloc_buffer) { error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), osize, NOCRED, &bp); if (error) { buf_brelse(bp); return (error); } ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); } else { ip->i_flag |= IN_CHANGE | IN_UPDATE; return (0); } } else { error = ffs_realloccg(ip, lbn, ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), osize, nsize, cred, &bp); if (error) return (error); ip->i_db[lbn] = dbtofsb(fs, (ufs_daddr_t)buf_blkno(bp)); ip->i_flag |= IN_CHANGE | IN_UPDATE; /* adjust the inode size we just grew */ ip->i_size = (lbn * fs->fs_bsize) + size; ubc_setsize(vp, (off_t)ip->i_size); if (!alloc_buffer) { buf_setflags(bp, B_NOCACHE); if (flags & B_SYNC) buf_bwrite(bp); else buf_bdwrite(bp); } else *bpp = bp; return (0); } } else { if (ip->i_size < (lbn + 1) * fs->fs_bsize) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; error = ffs_alloc(ip, lbn, ffs_blkpref(ip, lbn, (int)lbn, &ip->i_db[0]), nsize, cred, &newb); if (error) return (error); if (alloc_buffer) { bp = buf_getblk(vp, (daddr64_t)((unsigned)lbn), nsize, 0, 0, BLK_WRITE); buf_setblkno(bp, (daddr64_t)((unsigned)fsbtodb(fs, newb))); if (flags & B_CLRBUF) buf_clear(bp); } ip->i_db[lbn] = newb; ip->i_flag |= IN_CHANGE | IN_UPDATE; if (blk_alloc) { *blk_alloc = nsize; } if (alloc_buffer) *bpp = bp; return (0); } } /* * Determine the number of levels of indirection. */ pref = 0; if (error = ufs_getlbns(vp, lbn, indirs, &num)) return(error); #if DIAGNOSTIC if (num < 1) panic ("ffs_balloc: ufs_bmaparray returned indirect block"); #endif /* * Fetch the first indirect block allocating if necessary. */ --num; nb = ip->i_ib[indirs[0].in_off]; allocib = NULL; allocblk = allociblk; if (nb == 0) { pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) return (error); nb = newb; *allocblk++ = nb; bp = buf_getblk(vp, (daddr64_t)((unsigned)(indirs[1].in_lbn)), fs->fs_bsize, 0, 0, BLK_META); buf_setblkno(bp, (daddr64_t)((unsigned)fsbtodb(fs, nb))); buf_clear(bp); /* * Write synchronously conditional on mount flags. */ if ((vp)->v_mount->mnt_flag & MNT_ASYNC) { error = 0; buf_bdwrite(bp); } else if ((error = buf_bwrite(bp)) != 0) { goto fail; } allocib = &ip->i_ib[indirs[0].in_off]; *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* * Fetch through the indirect blocks, allocating as necessary. */ for (i = 1;;) { error = (int)buf_meta_bread(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), (int)fs->fs_bsize, NOCRED, &bp); if (error) { buf_brelse(bp); goto fail; } bap = (ufs_daddr_t *)buf_dataptr(bp); #if REV_ENDIAN_FS if (rev_endian) nb = OSSwapInt32(bap[indirs[i].in_off]); else { #endif /* REV_ENDIAN_FS */ nb = bap[indirs[i].in_off]; #if REV_ENDIAN_FS } #endif /* REV_ENDIAN_FS */ if (i == num) break; i += 1; if (nb != 0) { buf_brelse(bp); continue; } if (pref == 0) pref = ffs_blkpref(ip, lbn, 0, (ufs_daddr_t *)0); if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { buf_brelse(bp); goto fail; } nb = newb; *allocblk++ = nb; nbp = buf_getblk(vp, (daddr64_t)((unsigned)(indirs[i].in_lbn)), fs->fs_bsize, 0, 0, BLK_META); buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb))); buf_clear(nbp); /* * Write synchronously conditional on mount flags. */ if ((vp)->v_mount->mnt_flag & MNT_ASYNC) { error = 0; buf_bdwrite(nbp); } else if (error = buf_bwrite(nbp)) { buf_brelse(bp); goto fail; } #if REV_ENDIAN_FS if (rev_endian) bap[indirs[i - 1].in_off] = OSSwapInt32(nb); else { #endif /* REV_ENDIAN_FS */ bap[indirs[i - 1].in_off] = nb; #if REV_ENDIAN_FS } #endif /* REV_ENDIAN_FS */ /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & B_SYNC) { buf_bwrite(bp); } else { buf_bdwrite(bp); } } /* * Get the data block, allocating if necessary. */ if (nb == 0) { pref = ffs_blkpref(ip, lbn, indirs[i].in_off, &bap[0]); if (error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb)) { buf_brelse(bp); goto fail; } nb = newb; *allocblk++ = nb; #if REV_ENDIAN_FS if (rev_endian) bap[indirs[i].in_off] = OSSwapInt32(nb); else { #endif /* REV_ENDIAN_FS */ bap[indirs[i].in_off] = nb; #if REV_ENDIAN_FS } #endif /* REV_ENDIAN_FS */ /* * If required, write synchronously, otherwise use * delayed write. */ if ((flags & B_SYNC)) { buf_bwrite(bp); } else { buf_bdwrite(bp); } if(alloc_buffer ) { nbp = buf_getblk(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, 0, 0, BLK_WRITE); buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb))); if (flags & B_CLRBUF) buf_clear(nbp); } if (blk_alloc) { *blk_alloc = fs->fs_bsize; } if(alloc_buffer) *bpp = nbp; return (0); } buf_brelse(bp); if (alloc_buffer) { if (flags & B_CLRBUF) { error = (int)buf_bread(vp, (daddr64_t)((unsigned)lbn), (int)fs->fs_bsize, NOCRED, &nbp); if (error) { buf_brelse(nbp); goto fail; } } else { nbp = buf_getblk(vp, (daddr64_t)((unsigned)lbn), fs->fs_bsize, 0, 0, BLK_WRITE); buf_setblkno(nbp, (daddr64_t)((unsigned)fsbtodb(fs, nb))); } *bpp = nbp; } return (0); fail: /* * If we have failed part way through block allocation, we * have to deallocate any indirect blocks that we have allocated. */ for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { ffs_blkfree(ip, *blkp, fs->fs_bsize); deallocated += fs->fs_bsize; } if (allocib != NULL) *allocib = 0; if (deallocated) { devBlockSize = vfs_devblocksize(mp); #if QUOTA /* * Restore user's disk quota because allocation failed. */ (void) chkdq(ip, (int64_t)-deallocated, cred, FORCE); #endif /* QUOTA */ ip->i_blocks -= btodb(deallocated, devBlockSize); ip->i_flag |= IN_CHANGE | IN_UPDATE; } return (error); }
/* * Load the appropriate indirect block, and change the appropriate pointer. * Mark the block dirty. Do segment and avail accounting. */ static int update_meta(struct lfs *fs, ino_t ino, int vers, daddr_t lbn, daddr_t ndaddr, size_t size, struct lwp *l) { int error; struct vnode *vp; struct inode *ip; #ifdef DEBUG daddr_t odaddr; struct indir a[NIADDR]; int num; int i; #endif /* DEBUG */ struct buf *bp; SEGUSE *sup; KASSERT(lbn >= 0); /* no indirect blocks */ if ((error = lfs_rf_valloc(fs, ino, vers, l, &vp)) != 0) { DLOG((DLOG_RF, "update_meta: ino %d: lfs_rf_valloc" " returned %d\n", ino, error)); return error; } if ((error = lfs_balloc(vp, (lbn << fs->lfs_bshift), size, NOCRED, 0, &bp)) != 0) { vput(vp); return (error); } /* No need to write, the block is already on disk */ if (bp->b_oflags & BO_DELWRI) { LFS_UNLOCK_BUF(bp); fs->lfs_avail += btofsb(fs, bp->b_bcount); } brelse(bp, BC_INVAL); /* * Extend the file, if it is not large enough already. * XXX this is not exactly right, we don't know how much of the * XXX last block is actually used. We hope that an inode will * XXX appear later to give the correct size. */ ip = VTOI(vp); if (ip->i_size <= (lbn << fs->lfs_bshift)) { u_int64_t newsize; if (lbn < NDADDR) newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) + (size - fs->lfs_fsize) + 1; else newsize = ip->i_ffs1_size = (lbn << fs->lfs_bshift) + 1; if (ip->i_size < newsize) { ip->i_size = newsize; /* * tell vm our new size for the case the inode won't * appear later. */ uvm_vnp_setsize(vp, newsize); } } lfs_update_single(fs, NULL, vp, lbn, ndaddr, size); LFS_SEGENTRY(sup, fs, dtosn(fs, ndaddr), bp); sup->su_nbytes += size; LFS_WRITESEGENTRY(sup, fs, dtosn(fs, ndaddr), bp); /* differences here should be due to UNWRITTEN indirect blocks. */ KASSERT((lblkno(fs, ip->i_size) > NDADDR && ip->i_lfs_effnblks == ip->i_ffs1_blocks) || ip->i_lfs_effnblks >= ip->i_ffs1_blocks); #ifdef DEBUG /* Now look again to make sure it worked */ ufs_bmaparray(vp, lbn, &odaddr, &a[0], &num, NULL, NULL); for (i = num; i > 0; i--) { if (!a[i].in_exists) panic("update_meta: absent %d lv indirect block", i); } if (dbtofsb(fs, odaddr) != ndaddr) DLOG((DLOG_RF, "update_meta: failed setting ino %d lbn %" PRId64 " to %" PRId64 "\n", ino, lbn, ndaddr)); #endif /* DEBUG */ vput(vp); return 0; }
/* * Balloc defines the structure of filesystem storage * by allocating the physical blocks on a device given * the inode and the logical block number in a file. * This is the allocation strategy for UFS1. Below is * the allocation strategy for UFS2. */ int ffs_balloc_ufs1(struct vnode *vp, off_t startoffset, int size, struct ucred *cred, int flags, struct buf **bpp) { struct inode *ip; struct ufs1_dinode *dp; ufs_lbn_t lbn, lastlbn; struct fs *fs; ufs1_daddr_t nb; struct buf *bp, *nbp; struct ufsmount *ump; struct indir indirs[NIADDR + 2]; int deallocated, osize, nsize, num, i, error; ufs2_daddr_t newb; ufs1_daddr_t *bap, pref; ufs1_daddr_t *allocib, *blkp, *allocblk, allociblk[NIADDR + 1]; ufs2_daddr_t *lbns_remfree, lbns[NIADDR + 1]; int unwindidx = -1; int saved_inbdflush; static struct timeval lastfail; static int curfail; int reclaimed; ip = VTOI(vp); dp = ip->i_din1; fs = ip->i_fs; ump = ip->i_ump; lbn = lblkno(fs, startoffset); size = blkoff(fs, startoffset) + size; reclaimed = 0; if (size > fs->fs_bsize) panic("ffs_balloc_ufs1: blk too big"); *bpp = NULL; if (flags & IO_EXT) return (EOPNOTSUPP); if (lbn < 0) return (EFBIG); if (DOINGSOFTDEP(vp)) softdep_prealloc(vp, MNT_WAIT); /* * If the next write will extend the file into a new block, * and the file is currently composed of a fragment * this fragment has to be extended to be a full block. */ lastlbn = lblkno(fs, ip->i_size); if (lastlbn < NDADDR && lastlbn < lbn) { nb = lastlbn; osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { UFS_LOCK(ump); error = ffs_realloccg(ip, nb, dp->di_db[nb], ffs_blkpref_ufs1(ip, lastlbn, (int)nb, &dp->di_db[0]), osize, (int)fs->fs_bsize, flags, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, nb, dbtofsb(fs, bp->b_blkno), dp->di_db[nb], fs->fs_bsize, osize, bp); ip->i_size = smalllblktosize(fs, nb + 1); dp->di_size = ip->i_size; dp->di_db[nb] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; if (flags & IO_SYNC) bwrite(bp); else bawrite(bp); } } /* * The first NDADDR blocks are direct blocks */ if (lbn < NDADDR) { if (flags & BA_METAONLY) panic("ffs_balloc_ufs1: BA_METAONLY for direct block"); nb = dp->di_db[lbn]; if (nb != 0 && ip->i_size >= smalllblktosize(fs, lbn + 1)) { error = bread(vp, lbn, fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); *bpp = bp; return (0); } if (nb != 0) { /* * Consider need to reallocate a fragment. */ osize = fragroundup(fs, blkoff(fs, ip->i_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { error = bread(vp, lbn, osize, NOCRED, &bp); if (error) { brelse(bp); return (error); } bp->b_blkno = fsbtodb(fs, nb); } else { UFS_LOCK(ump); error = ffs_realloccg(ip, lbn, dp->di_db[lbn], ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]), osize, nsize, flags, cred, &bp); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, dbtofsb(fs, bp->b_blkno), nb, nsize, osize, bp); } } else { if (ip->i_size < smalllblktosize(fs, lbn + 1)) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; UFS_LOCK(ump); error = ffs_alloc(ip, lbn, ffs_blkpref_ufs1(ip, lbn, (int)lbn, &dp->di_db[0]), nsize, flags, cred, &newb); if (error) return (error); bp = getblk(vp, lbn, nsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, newb); if (flags & BA_CLRBUF) vfs_bio_clrbuf(bp); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, newb, 0, nsize, 0, bp); } dp->di_db[lbn] = dbtofsb(fs, bp->b_blkno); ip->i_flag |= IN_CHANGE | IN_UPDATE; *bpp = bp; return (0); } /* * Determine the number of levels of indirection. */ pref = 0; if ((error = ufs_getlbns(vp, lbn, indirs, &num)) != 0) return(error); #ifdef INVARIANTS if (num < 1) panic ("ffs_balloc_ufs1: ufs_getlbns returned indirect block"); #endif saved_inbdflush = curthread_pflags_set(TDP_INBDFLUSH); /* * Fetch the first indirect block allocating if necessary. */ --num; nb = dp->di_ib[indirs[0].in_off]; allocib = NULL; allocblk = allociblk; lbns_remfree = lbns; if (nb == 0) { UFS_LOCK(ump); pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0); if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags, cred, &newb)) != 0) { curthread_pflags_restore(saved_inbdflush); return (error); } nb = newb; *allocblk++ = nb; *lbns_remfree++ = indirs[1].in_lbn; bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0, 0); bp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(bp); if (DOINGSOFTDEP(vp)) { softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, newb, 0, fs->fs_bsize, 0, bp); bdwrite(bp); } else { /* * Write synchronously so that indirect blocks * never point at garbage. */ if (DOINGASYNC(vp)) bdwrite(bp); else if ((error = bwrite(bp)) != 0) goto fail; } allocib = &dp->di_ib[indirs[0].in_off]; *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* * Fetch through the indirect blocks, allocating as necessary. */ retry: for (i = 1;;) { error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, NOCRED, &bp); if (error) { brelse(bp); goto fail; } bap = (ufs1_daddr_t *)bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; i += 1; if (nb != 0) { bqrelse(bp); continue; } UFS_LOCK(ump); if (pref == 0) pref = ffs_blkpref_ufs1(ip, lbn, 0, (ufs1_daddr_t *)0); if ((error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags | IO_BUFLOCKED, cred, &newb)) != 0) { brelse(bp); if (++reclaimed == 1) { UFS_LOCK(ump); softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); UFS_UNLOCK(ump); goto retry; } if (ppsratecheck(&lastfail, &curfail, 1)) { ffs_fserr(fs, ip->i_number, "filesystem full"); uprintf("\n%s: write failed, filesystem " "is full\n", fs->fs_fsmnt); } goto fail; } nb = newb; *allocblk++ = nb; *lbns_remfree++ = indirs[i].in_lbn; nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); vfs_bio_clrbuf(nbp); if (DOINGSOFTDEP(vp)) { softdep_setup_allocindir_meta(nbp, ip, bp, indirs[i - 1].in_off, nb); bdwrite(nbp); } else { /* * Write synchronously so that indirect blocks * never point at garbage. */ if ((error = bwrite(nbp)) != 0) { brelse(bp); goto fail; } } bap[indirs[i - 1].in_off] = nb; if (allocib == NULL && unwindidx < 0) unwindidx = i - 1; /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & IO_SYNC) { bwrite(bp); } else { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } } /* * If asked only for the indirect block, then return it. */ if (flags & BA_METAONLY) { curthread_pflags_restore(saved_inbdflush); *bpp = bp; return (0); } /* * Get the data block, allocating if necessary. */ if (nb == 0) { UFS_LOCK(ump); pref = ffs_blkpref_ufs1(ip, lbn, indirs[i].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, flags | IO_BUFLOCKED, cred, &newb); if (error) { brelse(bp); if (++reclaimed == 1) { UFS_LOCK(ump); softdep_request_cleanup(fs, vp, cred, FLUSH_BLOCKS_WAIT); UFS_UNLOCK(ump); goto retry; } if (ppsratecheck(&lastfail, &curfail, 1)) { ffs_fserr(fs, ip->i_number, "filesystem full"); uprintf("\n%s: write failed, filesystem " "is full\n", fs->fs_fsmnt); } goto fail; } nb = newb; *allocblk++ = nb; *lbns_remfree++ = lbn; nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); if (flags & BA_CLRBUF) vfs_bio_clrbuf(nbp); if (DOINGSOFTDEP(vp)) softdep_setup_allocindir_page(ip, lbn, bp, indirs[i].in_off, nb, 0, nbp); bap[indirs[i].in_off] = nb; /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & IO_SYNC) { bwrite(bp); } else { if (bp->b_bufsize == fs->fs_bsize) bp->b_flags |= B_CLUSTEROK; bdwrite(bp); } curthread_pflags_restore(saved_inbdflush); *bpp = nbp; return (0); } brelse(bp); if (flags & BA_CLRBUF) { int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT; if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { error = cluster_read(vp, ip->i_size, lbn, (int)fs->fs_bsize, NOCRED, MAXBSIZE, seqcount, &nbp); } else { error = bread(vp, lbn, (int)fs->fs_bsize, NOCRED, &nbp); } if (error) { brelse(nbp); goto fail; } } else {
struct fs * ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp) { int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; int32_t cylno, i, csfrags; long long sizepb; void *space; int size, blks; int nprintcols, printcolwidth; ffs_opt_t *ffs_opts = fsopts->fs_specific; Oflag = ffs_opts->version; fssize = fsopts->size / fsopts->sectorsize; sectorsize = fsopts->sectorsize; fsize = ffs_opts->fsize; bsize = ffs_opts->bsize; maxbsize = ffs_opts->maxbsize; maxblkspercg = ffs_opts->maxblkspercg; minfree = ffs_opts->minfree; opt = ffs_opts->optimization; density = ffs_opts->density; maxcontig = ffs_opts->maxcontig; maxbpg = ffs_opts->maxbpg; avgfilesize = ffs_opts->avgfilesize; avgfpdir = ffs_opts->avgfpdir; bbsize = BBSIZE; sbsize = SBLOCKSIZE; strlcpy(sblock.fs_volname, ffs_opts->label, sizeof(sblock.fs_volname)); if (Oflag == 0) { sblock.fs_old_inodefmt = FS_42INODEFMT; sblock.fs_maxsymlinklen = 0; sblock.fs_old_flags = 0; } else { sblock.fs_old_inodefmt = FS_44INODEFMT; sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 : MAXSYMLINKLEN_UFS2); sblock.fs_old_flags = FS_FLAGS_UPDATED; sblock.fs_flags = 0; } /* * Validate the given file system size. * Verify that its last block can actually be accessed. * Convert to file system fragment sized units. */ if (fssize <= 0) { printf("preposterous size %lld\n", (long long)fssize); exit(13); } ffs_wtfs(fssize - 1, sectorsize, (char *)&sblock, fsopts); /* * collect and verify the filesystem density info */ sblock.fs_avgfilesize = avgfilesize; sblock.fs_avgfpdir = avgfpdir; if (sblock.fs_avgfilesize <= 0) printf("illegal expected average file size %d\n", sblock.fs_avgfilesize), exit(14); if (sblock.fs_avgfpdir <= 0) printf("illegal expected number of files per directory %d\n", sblock.fs_avgfpdir), exit(15); /* * collect and verify the block and fragment sizes */ sblock.fs_bsize = bsize; sblock.fs_fsize = fsize; if (!POWEROF2(sblock.fs_bsize)) { printf("block size must be a power of 2, not %d\n", sblock.fs_bsize); exit(16); } if (!POWEROF2(sblock.fs_fsize)) { printf("fragment size must be a power of 2, not %d\n", sblock.fs_fsize); exit(17); } if (sblock.fs_fsize < sectorsize) { printf("fragment size %d is too small, minimum is %d\n", sblock.fs_fsize, sectorsize); exit(18); } if (sblock.fs_bsize < MINBSIZE) { printf("block size %d is too small, minimum is %d\n", sblock.fs_bsize, MINBSIZE); exit(19); } if (sblock.fs_bsize > FFS_MAXBSIZE) { printf("block size %d is too large, maximum is %d\n", sblock.fs_bsize, FFS_MAXBSIZE); exit(19); } if (sblock.fs_bsize < sblock.fs_fsize) { printf("block size (%d) cannot be smaller than fragment size (%d)\n", sblock.fs_bsize, sblock.fs_fsize); exit(20); } if (maxbsize < bsize || !POWEROF2(maxbsize)) { sblock.fs_maxbsize = sblock.fs_bsize; printf("Extent size set to %d\n", sblock.fs_maxbsize); } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; printf("Extent size reduced to %d\n", sblock.fs_maxbsize); } else { sblock.fs_maxbsize = maxbsize; } sblock.fs_maxcontig = maxcontig; if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); } if (sblock.fs_maxcontig > 1) sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); sblock.fs_bmask = ~(sblock.fs_bsize - 1); sblock.fs_fmask = ~(sblock.fs_fsize - 1); sblock.fs_qbmask = ~sblock.fs_bmask; sblock.fs_qfmask = ~sblock.fs_fmask; for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) sblock.fs_bshift++; for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) sblock.fs_fshift++; sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) sblock.fs_fragshift++; if (sblock.fs_frag > MAXFRAG) { printf("fragment size %d is too small, " "minimum with block size %d is %d\n", sblock.fs_fsize, sblock.fs_bsize, sblock.fs_bsize / MAXFRAG); exit(21); } sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); sblock.fs_size = sblock.fs_providersize = fssize = dbtofsb(&sblock, fssize); if (Oflag <= 1) { sblock.fs_magic = FS_UFS1_MAGIC; sblock.fs_sblockloc = SBLOCK_UFS1; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs1_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * sizeof (ufs1_daddr_t)); sblock.fs_old_inodefmt = FS_44INODEFMT; sblock.fs_old_cgoffset = 0; sblock.fs_old_cgmask = 0xffffffff; sblock.fs_old_size = sblock.fs_size; sblock.fs_old_rotdelay = 0; sblock.fs_old_rps = 60; sblock.fs_old_nspf = sblock.fs_fsize / sectorsize; sblock.fs_old_cpg = 1; sblock.fs_old_interleave = 1; sblock.fs_old_trackskew = 0; sblock.fs_old_cpc = 0; sblock.fs_old_postblformat = 1; sblock.fs_old_nrpos = 1; } else { sblock.fs_magic = FS_UFS2_MAGIC; sblock.fs_sblockloc = SBLOCK_UFS2; sblock.fs_nindir = sblock.fs_bsize / sizeof(ufs2_daddr_t); sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * sizeof (ufs2_daddr_t)); } sblock.fs_sblkno = roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag); sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag)); sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { sizepb *= NINDIR(&sblock); sblock.fs_maxfilesize += sizepb; } /* * Calculate the number of blocks to put into each cylinder group. * * This algorithm selects the number of blocks per cylinder * group. The first goal is to have at least enough data blocks * in each cylinder group to meet the density requirement. Once * this goal is achieved we try to expand to have at least * 1 cylinder group. Once this goal is achieved, we pack as * many blocks into each cylinder group map as will fit. * * We start by calculating the smallest number of blocks that we * can put into each cylinder group. If this is too big, we reduce * the density until it fits. */ origdensity = density; for (;;) { fragsperinode = MAX(numfrags(&sblock, density), 1); minfpg = fragsperinode * INOPB(&sblock); if (minfpg > sblock.fs_size) minfpg = sblock.fs_size; sblock.fs_ipg = INOPB(&sblock); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); sblock.fs_fpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_fpg < minfpg) sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) break; density -= sblock.fs_fsize; } if (density != origdensity) printf("density reduced from %d to %d\n", origdensity, density); if (maxblkspercg <= 0 || maxblkspercg >= fssize) maxblkspercg = fssize - 1; /* * Start packing more blocks into the cylinder group until * it cannot grow any larger, the number of cylinder groups * drops below 1, or we reach the size requested. */ for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); if (sblock.fs_size / sblock.fs_fpg < 1) break; if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) continue; if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) break; sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); break; } /* * Check to be sure that the last cylinder group has enough blocks * to be viable. If it is too small, reduce the number of blocks * per cylinder group which will have the effect of moving more * blocks into the last cylinder group. */ optimalfpg = sblock.fs_fpg; for (;;) { sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); lastminfpg = roundup(sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); if (sblock.fs_size < lastminfpg) { printf("Filesystem size %lld < minimum size of %d\n", (long long)sblock.fs_size, lastminfpg); exit(28); } if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || sblock.fs_size % sblock.fs_fpg == 0) break; sblock.fs_fpg -= sblock.fs_frag; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); } if (optimalfpg != sblock.fs_fpg) printf("Reduced frags per cylinder group from %d to %d %s\n", optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); if (Oflag <= 1) { sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf; sblock.fs_old_nsect = sblock.fs_old_spc; sblock.fs_old_npsect = sblock.fs_old_spc; sblock.fs_old_ncyl = sblock.fs_ncg; } /* * fill in remaining fields of the super block */ sblock.fs_csaddr = cgdmin(&sblock, 0); sblock.fs_cssize = fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); /* * Setup memory for temporary in-core cylgroup summaries. * Cribbed from ffs_mountfs(). */ size = sblock.fs_cssize; blks = howmany(size, sblock.fs_fsize); if (sblock.fs_contigsumsize > 0) size += sblock.fs_ncg * sizeof(int32_t); if ((space = (char *)calloc(1, size)) == NULL) err(1, "memory allocation error for cg summaries"); sblock.fs_csp = space; space = (char *)space + sblock.fs_cssize; if (sblock.fs_contigsumsize > 0) { int32_t *lp; sblock.fs_maxcluster = lp = space; for (i = 0; i < sblock.fs_ncg; i++) *lp++ = sblock.fs_contigsumsize; } sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); if (sblock.fs_sbsize > SBLOCKSIZE) sblock.fs_sbsize = SBLOCKSIZE; sblock.fs_minfree = minfree; sblock.fs_maxcontig = maxcontig; sblock.fs_maxbpg = maxbpg; sblock.fs_optim = opt; sblock.fs_cgrotor = 0; sblock.fs_pendingblocks = 0; sblock.fs_pendinginodes = 0; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_cstotal.cs_nbfree = 0; sblock.fs_cstotal.cs_nifree = 0; sblock.fs_cstotal.cs_nffree = 0; sblock.fs_fmod = 0; sblock.fs_ronly = 0; sblock.fs_state = 0; sblock.fs_clean = FS_ISCLEAN; sblock.fs_ronly = 0; sblock.fs_id[0] = tstamp; sblock.fs_id[1] = random(); sblock.fs_fsmnt[0] = '\0'; csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); sblock.fs_cstotal.cs_nbfree = fragstoblks(&sblock, sblock.fs_dsize) - howmany(csfrags, sblock.fs_frag); sblock.fs_cstotal.cs_nffree = fragnum(&sblock, sblock.fs_size) + (fragnum(&sblock, csfrags) > 0 ? sblock.fs_frag - fragnum(&sblock, csfrags) : 0); sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; sblock.fs_cstotal.cs_ndir = 0; sblock.fs_dsize -= csfrags; sblock.fs_time = tstamp; if (Oflag <= 1) { sblock.fs_old_time = tstamp; sblock.fs_old_dsize = sblock.fs_dsize; sblock.fs_old_csaddr = sblock.fs_csaddr; sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } /* * Dump out summary information about file system. */ #define B2MBFACTOR (1 / (1024.0 * 1024.0)) printf("%s: %.1fMB (%lld sectors) block size %d, " "fragment size %d\n", fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, (long long)fsbtodb(&sblock, sblock.fs_size), sblock.fs_bsize, sblock.fs_fsize); printf("\tusing %d cylinder groups of %.2fMB, %d blks, " "%d inodes.\n", sblock.fs_ncg, (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); #undef B2MBFACTOR /* * Now determine how wide each column will be, and calculate how * many columns will fit in a 76 char line. 76 is the width of the * subwindows in sysinst. */ printcolwidth = count_digits( fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1))); nprintcols = 76 / (printcolwidth + 2); /* * allocate space for superblock, cylinder group map, and * two sets of inode blocks. */ if (sblock.fs_bsize < SBLOCKSIZE) iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; else iobufsize = 4 * sblock.fs_bsize; if ((iobuf = malloc(iobufsize)) == NULL) { printf("Cannot allocate I/O buffer\n"); exit(38); } memset(iobuf, 0, iobufsize); /* * Make a copy of the superblock into the buffer that we will be * writing out in each cylinder group. */ memcpy(writebuf, &sblock, sbsize); if (fsopts->needswap) ffs_sb_swap(&sblock, (struct fs*)writebuf); memcpy(iobuf, writebuf, SBLOCKSIZE); printf("super-block backups (for fsck -b #) at:"); for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { initcg(cylno, tstamp, fsopts); if (cylno % nprintcols == 0) printf("\n"); printf(" %*lld,", printcolwidth, (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno))); fflush(stdout); } printf("\n"); /* * Now construct the initial file system, * then write out the super-block. */ sblock.fs_time = tstamp; if (Oflag <= 1) { sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; } if (fsopts->needswap) sblock.fs_flags |= FS_SWAPPED; ffs_write_superblock(&sblock, fsopts); return (&sblock); }
int ffs2_balloc(struct inode *ip, off_t off, int size, struct ucred *cred, int flags, struct buf **bpp) { daddr_t lbn, lastlbn, nb, newb, *blkp; daddr_t pref, *allocblk, allociblk[NIADDR + 1]; daddr_t *bap, *allocib; int deallocated, osize, nsize, num, i, error, unwindidx, r; struct buf *bp, *nbp; struct indir indirs[NIADDR + 2]; struct fs *fs; struct vnode *vp; struct proc *p; vp = ITOV(ip); fs = ip->i_fs; p = curproc; unwindidx = -1; lbn = lblkno(fs, off); size = blkoff(fs, off) + size; if (size > fs->fs_bsize) panic("ffs2_balloc: block too big"); if (bpp != NULL) *bpp = NULL; if (lbn < 0) return (EFBIG); /* * If the next write will extend the file into a new block, and the * file is currently composed of a fragment, this fragment has to be * extended to be a full block. */ lastlbn = lblkno(fs, ip->i_ffs2_size); if (lastlbn < NDADDR && lastlbn < lbn) { nb = lastlbn; osize = blksize(fs, ip, nb); if (osize < fs->fs_bsize && osize > 0) { error = ffs_realloccg(ip, nb, ffs2_blkpref(ip, lastlbn, nb, &ip->i_ffs2_db[0]), osize, (int) fs->fs_bsize, cred, bpp, &newb); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, nb, newb, ip->i_ffs2_db[nb], fs->fs_bsize, osize, bpp ? *bpp : NULL); ip->i_ffs2_size = lblktosize(fs, nb + 1); uvm_vnp_setsize(vp, ip->i_ffs2_size); ip->i_ffs2_db[nb] = newb; ip->i_flag |= IN_CHANGE | IN_UPDATE; if (bpp) { if (flags & B_SYNC) bwrite(*bpp); else bawrite(*bpp); } } } /* * The first NDADDR blocks are direct. */ if (lbn < NDADDR) { nb = ip->i_ffs2_db[lbn]; if (nb != 0 && ip->i_ffs2_size >= lblktosize(fs, lbn + 1)) { /* * The direct block is already allocated and the file * extends past this block, thus this must be a whole * block. Just read it, if requested. */ if (bpp != NULL) { error = bread(vp, lbn, fs->fs_bsize, bpp); if (error) { brelse(*bpp); return (error); } } return (0); } if (nb != 0) { /* * Consider the need to allocate a fragment. */ osize = fragroundup(fs, blkoff(fs, ip->i_ffs2_size)); nsize = fragroundup(fs, size); if (nsize <= osize) { /* * The existing block is already at least as * big as we want. Just read it, if requested. */ if (bpp != NULL) { error = bread(vp, lbn, fs->fs_bsize, bpp); if (error) { brelse(*bpp); return (error); } (*bpp)->b_bcount = osize; } return (0); } else { /* * The existing block is smaller than we want, * grow it. */ error = ffs_realloccg(ip, lbn, ffs2_blkpref(ip, lbn, (int) lbn, &ip->i_ffs2_db[0]), osize, nsize, cred, bpp, &newb); if (error) return (error); if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, newb, nb, nsize, osize, bpp ? *bpp : NULL); } } else { /* * The block was not previously allocated, allocate a * new block or fragment. */ if (ip->i_ffs2_size < lblktosize(fs, lbn + 1)) nsize = fragroundup(fs, size); else nsize = fs->fs_bsize; error = ffs_alloc(ip, lbn, ffs2_blkpref(ip, lbn, (int) lbn, &ip->i_ffs2_db[0]), nsize, cred, &newb); if (error) return (error); if (bpp != NULL) { bp = getblk(vp, lbn, fs->fs_bsize, 0, 0); if (nsize < fs->fs_bsize) bp->b_bcount = nsize; bp->b_blkno = fsbtodb(fs, newb); if (flags & B_CLRBUF) clrbuf(bp); *bpp = bp; } if (DOINGSOFTDEP(vp)) softdep_setup_allocdirect(ip, lbn, newb, 0, nsize, 0, bpp ? *bpp : NULL); } ip->i_ffs2_db[lbn] = newb; ip->i_flag |= IN_CHANGE | IN_UPDATE; return (0); } /* * Determine the number of levels of indirection. */ pref = 0; error = ufs_getlbns(vp, lbn, indirs, &num); if (error) return (error); #ifdef DIAGNOSTIC if (num < 1) panic("ffs2_balloc: ufs_bmaparray returned indirect block"); #endif /* * Fetch the first indirect block allocating it necessary. */ --num; nb = ip->i_ffs2_ib[indirs[0].in_off]; allocib = NULL; allocblk = allociblk; if (nb == 0) { pref = ffs2_blkpref(ip, lbn, -indirs[0].in_off - 1, NULL); error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred, &newb); if (error) goto fail; nb = newb; *allocblk++ = nb; bp = getblk(vp, indirs[1].in_lbn, fs->fs_bsize, 0, 0); bp->b_blkno = fsbtodb(fs, nb); clrbuf(bp); if (DOINGSOFTDEP(vp)) { softdep_setup_allocdirect(ip, NDADDR + indirs[0].in_off, newb, 0, fs->fs_bsize, 0, bp); bdwrite(bp); } else { /* * Write synchronously so that indirect blocks never * point at garbage. */ error = bwrite(bp); if (error) goto fail; } unwindidx = 0; allocib = &ip->i_ffs2_ib[indirs[0].in_off]; *allocib = nb; ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* * Fetch through the indirect blocks, allocating as necessary. */ for (i = 1;;) { error = bread(vp, indirs[i].in_lbn, (int)fs->fs_bsize, &bp); if (error) { brelse(bp); goto fail; } bap = (int64_t *) bp->b_data; nb = bap[indirs[i].in_off]; if (i == num) break; i++; if (nb != 0) { brelse(bp); continue; } if (pref == 0) pref = ffs2_blkpref(ip, lbn, i - num - 1, NULL); error = ffs_alloc(ip, lbn, pref, (int) fs->fs_bsize, cred, &newb); if (error) { brelse(bp); goto fail; } nb = newb; *allocblk++ = nb; nbp = getblk(vp, indirs[i].in_lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); if (DOINGSOFTDEP(vp)) { softdep_setup_allocindir_meta(nbp, ip, bp, indirs[i - 1].in_off, nb); bdwrite(nbp); } else { /* * Write synchronously so that indirect blocks never * point at garbage. */ error = bwrite(nbp); if (error) { brelse(bp); goto fail; } } if (unwindidx < 0) unwindidx = i - 1; bap[indirs[i - 1].in_off] = nb; /* * If required, write synchronously, otherwise use delayed * write. */ if (flags & B_SYNC) bwrite(bp); else bdwrite(bp); } /* * Get the data block, allocating if necessary. */ if (nb == 0) { pref = ffs2_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); error = ffs_alloc(ip, lbn, pref, (int)fs->fs_bsize, cred, &newb); if (error) { brelse(bp); goto fail; } nb = newb; *allocblk++ = nb; if (bpp != NULL) { nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); if (flags & B_CLRBUF) clrbuf(nbp); *bpp = nbp; } if (DOINGSOFTDEP(vp)) softdep_setup_allocindir_page(ip, lbn, bp, indirs[num].in_off, nb, 0, bpp ? *bpp : NULL); bap[indirs[num].in_off] = nb; if (allocib == NULL && unwindidx < 0) unwindidx = i - 1; /* * If required, write synchronously, otherwise use delayed * write. */ if (flags & B_SYNC) bwrite(bp); else bdwrite(bp); return (0); } brelse(bp); if (bpp != NULL) { if (flags & B_CLRBUF) { error = bread(vp, lbn, (int)fs->fs_bsize, &nbp); if (error) { brelse(nbp); goto fail; } } else { nbp = getblk(vp, lbn, fs->fs_bsize, 0, 0); nbp->b_blkno = fsbtodb(fs, nb); clrbuf(nbp); } *bpp = nbp; } return (0); fail: /* * If we have failed to allocate any blocks, simply return the error. * This is the usual case and avoids the need to fsync the file. */ if (allocblk == allociblk && allocib == NULL && unwindidx == -1) return (error); /* * If we have failed part way through block allocation, we have to * deallocate any indirect blocks that we have allocated. We have to * fsync the file before we start to get rid of all of its * dependencies so that we do not leave them dangling. We have to sync * it at the end so that the softdep code does not find any untracked * changes. Although this is really slow, running out of disk space is * not expected to be a common occurrence. The error return from fsync * is ignored as we already have an error to return to the user. */ VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); if (unwindidx >= 0) { /* * First write out any buffers we've created to resolve their * softdeps. This must be done in reverse order of creation so * that we resolve the dependencies in one pass. * Write the cylinder group buffers for these buffers too. */ for (i = num; i >= unwindidx; i--) { if (i == 0) break; bp = getblk(vp, indirs[i].in_lbn, (int) fs->fs_bsize, 0, 0); if (bp->b_flags & B_DELWRI) { nb = fsbtodb(fs, cgtod(fs, dtog(fs, dbtofsb(fs, bp->b_blkno)))); bwrite(bp); bp = getblk(ip->i_devvp, nb, (int) fs->fs_cgsize, 0, 0); if (bp->b_flags & B_DELWRI) bwrite(bp); else { bp->b_flags |= B_INVAL; brelse(bp); } } else { bp->b_flags |= B_INVAL; brelse(bp); } } if (DOINGSOFTDEP(vp) && unwindidx == 0) { ip->i_flag |= IN_CHANGE | IN_UPDATE; ffs_update(ip, 1); } /* * Now that any dependencies that we created have been * resolved, we can undo the partial allocation. */ if (unwindidx == 0) { *allocib = 0; ip->i_flag |= IN_CHANGE | IN_UPDATE; if (DOINGSOFTDEP(vp)) ffs_update(ip, 1); } else { r = bread(vp, indirs[unwindidx].in_lbn, (int)fs->fs_bsize, &bp); if (r) panic("ffs2_balloc: unwind failed"); bap = (int64_t *) bp->b_data; bap[indirs[unwindidx].in_off] = 0; bwrite(bp); } for (i = unwindidx + 1; i <= num; i++) { bp = getblk(vp, indirs[i].in_lbn, (int)fs->fs_bsize, 0, 0); bp->b_flags |= B_INVAL; brelse(bp); } } for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { ffs_blkfree(ip, *blkp, fs->fs_bsize); deallocated += fs->fs_bsize; } if (deallocated) { /* * Restore user's disk quota because allocation failed. */ (void) ufs_quota_free_blocks(ip, btodb(deallocated), cred); ip->i_ffs2_blocks -= btodb(deallocated); ip->i_flag |= IN_CHANGE | IN_UPDATE; } VOP_FSYNC(vp, p->p_ucred, MNT_WAIT, p); return (error); }