Example #1
0
static ufs2_daddr_t journal_balloc( void ) {
	ufs2_daddr_t blk;
	struct cg *cgp;
	int valid;
	static int contig = 1;
	cgp = &disk.d_cg;
	for ( ;; ) {
		blk = cgballoc( &disk );
		if ( blk > 0 ) break;
		if ( cgwrite( &disk ) < 0 ) {
			warn( "Failed to write updated cg" );
			return ( -1 );
		}
		while ( ( valid = cgread( &disk ) ) == 1 ) {
			if ( cgp->cg_cs.cs_nbfree > 256 * 1024 ) break;
			if ( contig == 0 && cgp->cg_cs.cs_nbfree ) break;
		}
		if ( valid ) continue;
		if ( contig ) {
			contig = 0;
			disk.d_ccg = 0;
			warnx( "Journal file fragmented." );
			continue;
		}
		warnx( "Failed to find sufficient free blocks for the journal" );
		return -1;
	}
	if ( bwrite( &disk, fsbtodb( &sblock, blk ), clrbuf,
	sblock.fs_bsize ) <= 0 ) {
		warn( "Failed to initialize new block" );
		return -1;
	}
	return ( blk );
}
Example #2
0
int
cgbfree(struct uufsd *disk, ufs2_daddr_t bno, long size)
{
	u_int8_t *blksfree;
	struct fs *fs;
	struct cg *cgp;
	ufs1_daddr_t fragno, cgbno;
	int i, cg, blk, frags, bbase;

	fs = &disk->d_fs;
	cg = dtog(fs, bno);
	if (cgread1(disk, cg) != 1)
		return (-1);
	cgp = &disk->d_cg;
	cgbno = dtogd(fs, bno);
	blksfree = cg_blksfree(cgp);
	if (size == fs->fs_bsize) {
		fragno = fragstoblks(fs, cgbno);
		ffs_setblock(fs, blksfree, fragno);
		ffs_clusteracct(fs, cgp, fragno, 1);
		cgp->cg_cs.cs_nbfree++;
		fs->fs_cstotal.cs_nbfree++;
		fs->fs_cs(fs, cg).cs_nbfree++;
	} else {
		bbase = cgbno - fragnum(fs, cgbno);
		/*
		 * decrement the counts associated with the old frags
		 */
		blk = blkmap(fs, blksfree, bbase);
		ffs_fragacct(fs, blk, cgp->cg_frsum, -1);
		/*
		 * deallocate the fragment
		 */
		frags = numfrags(fs, size);
		for (i = 0; i < frags; i++)
			setbit(blksfree, cgbno + i);
		cgp->cg_cs.cs_nffree += i;
		fs->fs_cstotal.cs_nffree += i;
		fs->fs_cs(fs, cg).cs_nffree += i;
		/*
		 * add back in counts associated with the new frags
		 */
		blk = blkmap(fs, blksfree, bbase);
		ffs_fragacct(fs, blk, cgp->cg_frsum, 1);
		/*
		 * if a complete block has been reassembled, account for it
		 */
		fragno = fragstoblks(fs, bbase);
		if (ffs_isblock(fs, blksfree, fragno)) {
			cgp->cg_cs.cs_nffree -= fs->fs_frag;
			fs->fs_cstotal.cs_nffree -= fs->fs_frag;
			fs->fs_cs(fs, cg).cs_nffree -= fs->fs_frag;
			ffs_clusteracct(fs, cgp, fragno, 1);
			cgp->cg_cs.cs_nbfree++;
			fs->fs_cstotal.cs_nbfree++;
			fs->fs_cs(fs, cg).cs_nbfree++;
		}
	}
	return cgwrite(disk);
}
Example #3
0
static ufs2_daddr_t
journal_balloc(void)
{
	ufs2_daddr_t blk;
	struct cg *cgp;
	int valid;
	static int contig = 1;

	cgp = &disk.d_cg;
	for (;;) {
		blk = cgballoc(&disk);
		if (blk > 0)
			break;
		/*
		 * If we failed to allocate a block from this cg, move to
		 * the next.
		 */
		if (cgwrite(&disk) < 0) {
			warn("Failed to write updated cg");
			return (-1);
		}
		while ((valid = cgread(&disk)) == 1) {
			/*
			 * Try to minimize fragmentation by requiring a minimum
			 * number of blocks present.
			 */
			if (cgp->cg_cs.cs_nbfree > 256 * 1024)
				break;
			if (contig == 0 && cgp->cg_cs.cs_nbfree)
				break;
		}
		if (valid)
			continue;
		/*
		 * Try once through looking only for large contiguous regions
		 * and again taking any space we can find.
		 */
		if (contig) {
			contig = 0;
			disk.d_ccg = 0;
			warnx("Journal file fragmented.");
			continue;
		}
		warnx("Failed to find sufficient free blocks for the journal");
		return -1;
	}
	if (bwrite(&disk, fsbtodb(&sblock, blk), clrbuf,
	    sblock.fs_bsize) <= 0) {
		warn("Failed to initialize new block");
		return -1;
	}
	return (blk);
}
Example #4
0
static int
journal_alloc(int64_t size)
{
	struct ufs1_dinode *dp1;
	struct ufs2_dinode *dp2;
	ufs2_daddr_t blk;
	void *ip;
	struct cg *cgp;
	int resid;
	ino_t ino;
	int blks;
	int mode;
	time_t utime;
	int i;

	cgp = &disk.d_cg;
	ino = 0;

	/*
	 * If the journal file exists we can't allocate it.
	 */
	ino = journal_findfile();
	if (ino == (ino_t)-1)
		return (-1);
	if (ino > 0) {
		warnx("Journal file %s already exists, please remove.",
		    SUJ_FILE);
		return (-1);
	}
	/*
	 * If the user didn't supply a size pick one based on the filesystem
	 * size constrained with hardcoded MIN and MAX values.  We opt for
	 * 1/1024th of the filesystem up to MAX but not exceeding one CG and
	 * not less than the MIN.
	 */
	if (size == 0) {
		size = (sblock.fs_size * sblock.fs_bsize) / 1024;
		size = MIN(SUJ_MAX, size);
		if (size / sblock.fs_fsize > sblock.fs_fpg)
			size = sblock.fs_fpg * sblock.fs_fsize;
		size = MAX(SUJ_MIN, size);
		/* fsck does not support fragments in journal files. */
		size = roundup(size, sblock.fs_bsize);
	}
	resid = blocks = size / sblock.fs_bsize;
	if (sblock.fs_cstotal.cs_nbfree < blocks) {
		warn("Insufficient free space for %jd byte journal", size);
		return (-1);
	}
	/*
	 * Find a cg with enough blocks to satisfy the journal
	 * size.  Presently the journal does not span cgs.
	 */
	while (cgread(&disk) == 1) {
		if (cgp->cg_cs.cs_nifree == 0)
			continue;
		ino = cgialloc(&disk);
		if (ino <= 0)
			break;
		printf("Using inode %ju in cg %d for %jd byte journal\n",
		    (uintmax_t)ino, cgp->cg_cgx, size);
		if (getino(&disk, &ip, ino, &mode) != 0) {
			warn("Failed to get allocated inode");
			sbdirty();
			goto out;
		}
		/*
		 * We leave fields unrelated to the number of allocated
		 * blocks and size uninitialized.  This causes legacy
		 * fsck implementations to clear the inode.
		 */
		dp2 = ip;
		dp1 = ip;
		time(&utime);
		if (sblock.fs_magic == FS_UFS1_MAGIC) {
			bzero(dp1, sizeof(*dp1));
			dp1->di_size = size;
			dp1->di_mode = IFREG | IREAD;
			dp1->di_nlink = 1;
			dp1->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
			dp1->di_atime = utime;
			dp1->di_mtime = utime;
			dp1->di_ctime = utime;
		} else {
			bzero(dp2, sizeof(*dp2));
			dp2->di_size = size;
			dp2->di_mode = IFREG | IREAD;
			dp2->di_nlink = 1;
			dp2->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
			dp2->di_atime = utime;
			dp2->di_mtime = utime;
			dp2->di_ctime = utime;
			dp2->di_birthtime = utime;
		}
		for (i = 0; i < NDADDR && resid; i++, resid--) {
			blk = journal_balloc();
			if (blk <= 0)
				goto out;
			if (sblock.fs_magic == FS_UFS1_MAGIC) {
				dp1->di_db[i] = blk;
				dp1->di_blocks++;
			} else {
				dp2->di_db[i] = blk;
				dp2->di_blocks++;
			}
		}
		for (i = 0; i < NIADDR && resid; i++) {
			blk = journal_balloc();
			if (blk <= 0)
				goto out;
			blks = indir_fill(blk, i, &resid) + 1;
			if (blks <= 0) {
				sbdirty();
				goto out;
			}
			if (sblock.fs_magic == FS_UFS1_MAGIC) {
				dp1->di_ib[i] = blk;
				dp1->di_blocks += blks;
			} else {
				dp2->di_ib[i] = blk;
				dp2->di_blocks += blks;
			}
		}
		if (sblock.fs_magic == FS_UFS1_MAGIC)
			dp1->di_blocks *= sblock.fs_bsize / disk.d_bsize;
		else
			dp2->di_blocks *= sblock.fs_bsize / disk.d_bsize;
		if (putino(&disk) < 0) {
			warn("Failed to write inode");
			sbdirty();
			return (-1);
		}
		if (cgwrite(&disk) < 0) {
			warn("Failed to write updated cg");
			sbdirty();
			return (-1);
		}
		if (journal_insertfile(ino) < 0) {
			sbdirty();
			return (-1);
		}
		sblock.fs_sujfree = 0;
		return (0);
	}
	warnx("Insufficient free space for the journal.");
out:
	return (-1);
}
Example #5
0
/*
 * Insert the journal file into the ROOTINO directory.  We always extend the
 * last frag
 */
static int
journal_insertfile(ino_t ino)
{
	struct ufs1_dinode *dp1;
	struct ufs2_dinode *dp2;
	void *ip;
	ufs2_daddr_t nblk;
	ufs2_daddr_t blk;
	ufs_lbn_t lbn;
	int size;
	int mode;
	int off;

	if (getino(&disk, &ip, ROOTINO, &mode) != 0) {
		warn("Failed to get root inode");
		sbdirty();
		return (-1);
	}
	dp2 = ip;
	dp1 = ip;
	blk = 0;
	size = 0;
	nblk = journal_balloc();
	if (nblk <= 0)
		return (-1);
	/*
	 * For simplicity sake we aways extend the ROOTINO into a new
	 * directory block rather than searching for space and inserting
	 * into an existing block.  However, if the rootino has frags
	 * have to free them and extend the block.
	 */
	if (sblock.fs_magic == FS_UFS1_MAGIC) {
		lbn = lblkno(&sblock, dp1->di_size);
		off = blkoff(&sblock, dp1->di_size);
		blk = dp1->di_db[lbn];
		size = sblksize(&sblock, (off_t)dp1->di_size, lbn);
	} else {
		lbn = lblkno(&sblock, dp2->di_size);
		off = blkoff(&sblock, dp2->di_size);
		blk = dp2->di_db[lbn];
		size = sblksize(&sblock, (off_t)dp2->di_size, lbn);
	}
	if (off != 0) {
		if (dir_extend(blk, nblk, off, ino) == -1)
			return (-1);
	} else {
		blk = 0;
		if (dir_insert(nblk, 0, ino) == -1)
			return (-1);
	}
	if (sblock.fs_magic == FS_UFS1_MAGIC) {
		dp1->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE;
		dp1->di_db[lbn] = nblk;
		dp1->di_size = lblktosize(&sblock, lbn+1);
	} else {
		dp2->di_blocks += (sblock.fs_bsize - size) / DEV_BSIZE;
		dp2->di_db[lbn] = nblk;
		dp2->di_size = lblktosize(&sblock, lbn+1);
	}
	if (putino(&disk) < 0) {
		warn("Failed to write root inode");
		return (-1);
	}
	if (cgwrite(&disk) < 0) {
		warn("Failed to write updated cg");
		sbdirty();
		return (-1);
	}
	if (blk) {
		if (cgbfree(&disk, blk, size) < 0) {
			warn("Failed to write cg");
			return (-1);
		}
	}

	return (0);
}
Example #6
0
static int journal_alloc( int64_t size ) {
	struct ufs1_dinode *dp1;
	struct ufs2_dinode *dp2;
	ufs2_daddr_t blk;
	void *ip;
	struct cg *cgp;
	int resid;
	ino_t ino;
	int blks;
	int mode;
	time_t utime;
	int i;
	cgp = &disk.d_cg;
	ino = 0;
	ino = journal_findfile();
	if ( ino == ( ino_t ) - 1 ) return ( -1 );
	if ( ino > 0 ) {
		warnx( "Journal file %s already exists, please remove.", SUJ_FILE );
		return ( -1 );
	}
	if ( size == 0 ) {
		size = ( sblock.fs_size * sblock.fs_bsize ) / 1024;
		size = MIN( SUJ_MAX, size );
		if ( size / sblock.fs_fsize > sblock.fs_fpg ) size = sblock.fs_fpg * sblock.fs_fsize;
		size = MAX( SUJ_MIN, size );
		size = roundup( size, sblock.fs_bsize );
	}
	resid = blocks = size / sblock.fs_bsize;
	if ( sblock.fs_cstotal.cs_nbfree < blocks ) {
		warn( "Insufficient free space for %jd byte journal", size );
		return ( -1 );
	}
	while ( cgread( &disk ) == 1 ) {
		if ( cgp->cg_cs.cs_nifree == 0 ) continue;
		ino = cgialloc( &disk );
		if ( ino <= 0 ) break;
		printf( "Using inode %ju in cg %d for %jd byte journal\n", (uintmax_t) ino, cgp->cg_cgx, size );
		if ( getino( &disk, &ip, ino, &mode ) != 0 ) {
			warn( "Failed to get allocated inode" );
			sbdirty();
			goto out;
		}
		dp2 = ip;
		dp1 = ip;
		time( &utime );
		if ( sblock.fs_magic == FS_UFS1_MAGIC ) {
			bzero( dp1, sizeof( *dp1 ) );
			dp1->di_size = size;
			dp1->di_mode = IFREG | IREAD;
			dp1->di_nlink = 1;
			dp1->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
			dp1->di_atime = utime;
			dp1->di_mtime = utime;
			dp1->di_ctime = utime;
		} else {
			bzero( dp2, sizeof( *dp2 ) );
			dp2->di_size = size;
			dp2->di_mode = IFREG | IREAD;
			dp2->di_nlink = 1;
			dp2->di_flags = SF_IMMUTABLE | SF_NOUNLINK | UF_NODUMP;
			dp2->di_atime = utime;
			dp2->di_mtime = utime;
			dp2->di_ctime = utime;
			dp2->di_birthtime = utime;
		}
		for ( i = 0; i < NDADDR && resid; i++, resid-- ) {
			blk = journal_balloc();
			if ( blk <= 0 ) goto out;
			if ( sblock.fs_magic == FS_UFS1_MAGIC ) {
				dp1->di_db[i] = blk;
				dp1->di_blocks++;
			} else {
				dp2->di_db[i] = blk;
				dp2->di_blocks++;
			}
		}
		for ( i = 0; i < NIADDR && resid; i++ ) {
			blk = journal_balloc();
			if ( blk <= 0 ) goto out;
			blks = indir_fill( blk, i, &resid ) + 1;
			if ( blks <= 0 ) {
				sbdirty();
				goto out;
			}
			if ( sblock.fs_magic == FS_UFS1_MAGIC ) {
				dp1->di_ib[i] = blk;
				dp1->di_blocks += blks;
			} else {
				dp2->di_ib[i] = blk;
				dp2->di_blocks += blks;
			}
		}
		if ( sblock.fs_magic == FS_UFS1_MAGIC ) dp1->di_blocks *= sblock.fs_bsize / disk.d_bsize;
		else dp2->di_blocks *= sblock.fs_bsize / disk.d_bsize;
		if ( putino( &disk ) < 0 ) {
			warn( "Failed to write inode" );
			sbdirty();
			return ( -1 );
		}
		if ( cgwrite( &disk ) < 0 ) {
			warn( "Failed to write updated cg" );
			sbdirty();
			return ( -1 );
		}
		if ( journal_insertfile( ino ) < 0 ) {
			sbdirty();
			return ( -1 );
		}
		sblock.fs_sujfree = 0;
		return ( 0 );
	}
	warnx( "Insufficient free space for the journal." );
	out: return ( -1 );
}
Example #7
0
static int journal_insertfile( ino_t ino ) {
	struct ufs1_dinode *dp1;
	struct ufs2_dinode *dp2;
	void *ip;
	ufs2_daddr_t nblk;
	ufs2_daddr_t blk;
	ufs_lbn_t lbn;
	int size;
	int mode;
	int off;
	if ( getino( &disk, &ip, ROOTINO, &mode ) != 0 ) {
		warn( "Failed to get root inode" );
		sbdirty();
		return ( -1 );
	}
	dp2 = ip;
	dp1 = ip;
	blk = 0;
	size = 0;
	nblk = journal_balloc();
	if ( nblk <= 0 ) return ( -1 );
	if ( sblock.fs_magic == FS_UFS1_MAGIC ) {
		lbn = lblkno( &sblock, dp1->di_size );
		off = blkoff( &sblock, dp1->di_size );
		blk = dp1->di_db[lbn];
		size = sblksize( &sblock, (off_t) dp1->di_size, lbn );
	} else {
		lbn = lblkno( &sblock, dp2->di_size );
		off = blkoff( &sblock, dp2->di_size );
		blk = dp2->di_db[lbn];
		size = sblksize( &sblock, (off_t) dp2->di_size, lbn );
	}
	if ( off != 0 ) {
		if ( dir_extend( blk, nblk, off, ino ) == -1 ) return ( -1 );
	} else {
		blk = 0;
		if ( dir_insert( nblk, 0, ino ) == -1 ) return ( -1 );
	}
	if ( sblock.fs_magic == FS_UFS1_MAGIC ) {
		dp1->di_blocks += ( sblock.fs_bsize - size ) / DEV_BSIZE;
		dp1->di_db[lbn] = nblk;
		dp1->di_size = lblktosize( &sblock, lbn + 1 );
	} else {
		dp2->di_blocks += ( sblock.fs_bsize - size ) / DEV_BSIZE;
		dp2->di_db[lbn] = nblk;
		dp2->di_size = lblktosize( &sblock, lbn + 1 );
	}
	if ( putino( &disk ) < 0 ) {
		warn( "Failed to write root inode" );
		return ( -1 );
	}
	if ( cgwrite( &disk ) < 0 ) {
		warn( "Failed to write updated cg" );
		sbdirty();
		return ( -1 );
	}
	if ( blk ) {
		if ( cgbfree( &disk, blk, size ) < 0 ) {
			warn( "Failed to write cg" );
			return ( -1 );
		}
	}
	return ( 0 );
}