コード例 #1
0
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 );
}
コード例 #2
0
ファイル: ffs_wapbl.c プロジェクト: SylvestreG/bitrig
/* 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);
}
コード例 #3
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 );
}
コード例 #4
0
ファイル: ffs_wapbl.c プロジェクト: SylvestreG/bitrig
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]);
	}
}
コード例 #5
0
ファイル: ext2_balloc.c プロジェクト: kwitaszczyk/freebsd
/*
 * 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 {
コード例 #6
0
ファイル: mkfs.c プロジェクト: repos-holder/openbsd-patches
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;
}
コード例 #7
0
ファイル: mke2fs.c プロジェクト: AgamAgarwal/minix
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);
}
コード例 #8
0
ファイル: lfs_rfw.c プロジェクト: AgamAgarwal/minix
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);
			}
		}
	}
コード例 #9
0
ファイル: ffs_balloc.c プロジェクト: dancrossnyc/harvey
/*
 * 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 {
コード例 #10
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
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);
}
コード例 #11
0
ファイル: lqfs.c プロジェクト: BackupTheBerlios/samqfs
/* 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);
}
コード例 #12
0
ファイル: lqfs.c プロジェクト: BackupTheBerlios/samqfs
/*
 * 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);
}
コード例 #13
0
ファイル: lqfs.c プロジェクト: BackupTheBerlios/samqfs
/* 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);
}
コード例 #14
0
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;
	}
}
コード例 #15
0
/*
 * 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);
}
コード例 #16
0
ファイル: lfs_rfw.c プロジェクト: AgamAgarwal/minix
/*
 * 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;
}
コード例 #17
0
ファイル: ffs_balloc.c プロジェクト: AhmadTux/freebsd
/*
 * 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 {
コード例 #18
0
ファイル: mkfs.c プロジェクト: lwhsu/freebsd-makefs
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);
}
コード例 #19
0
ファイル: ffs_balloc.c プロジェクト: orumin/openbsd-efivars
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);
}