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 ); }
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); }
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); }
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); }
/* * 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); }
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 ); }
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 ); }