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