/* * Clear the flag bits so the journal can be removed. */ static void journal_clear(void) { struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; ino_t ino; int mode; void *ip; ino = journal_findfile(); if (ino == (ino_t)-1 || ino == 0) { warnx("Journal file does not exist"); return; } printf("Clearing journal flags from inode %ju\n", (uintmax_t)ino); if (getino(&disk, &ip, ino, &mode) != 0) { warn("Failed to get journal inode"); return; } dp2 = ip; dp1 = ip; if (sblock.fs_magic == FS_UFS1_MAGIC) dp1->di_flags = 0; else dp2->di_flags = 0; if (putino(&disk) < 0) { warn("Failed to write journal inode"); return; } }
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 ); }
/* * 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_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 ); }