summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ufs-fsck/pass5.c299
1 files changed, 295 insertions, 4 deletions
diff --git a/ufs-fsck/pass5.c b/ufs-fsck/pass5.c
index 9a8818f7..631e634c 100644
--- a/ufs-fsck/pass5.c
+++ b/ufs-fsck/pass5.c
@@ -23,13 +23,304 @@ pass5 ()
{
char cgbuf[MAXBSIZE];
struct cg *newcg = cgbuf;
- struct cg *cg;
-
-
-
+ struct ocg *ocg = (struct ocg *)cgbuf;
+ int savednrpos;
+ struct csum cstotal;
+ int i, j;
+ int c;
+ struct cg *cg = alloca (sblock.fs_cgsize);
+ char csumbuf[fragroundup (sizeof (struct csum) * sblock.fs_ncg)];
+ struct csum *sbcsums = (struct csum *)csumbuf;
+
+ int basesize; /* size of cg not counting flexibly sized */
+ int sumsize; /* size of block totals and pos tbl */
+ int mapsize; /* size of inode map + block map */
+
+ int writesb;
+ int writecg;
+ int writecsum;
+
+ writesb = 0;
+ writecsum = 0;
+
+ readblock (fsbtodb (&sblock, sblock.fs_csaddr), csumbuf,
+ fsbtodb (&sblock, howmany (sblock->fs_cssize, sblock->fs_fsize)));
+
+ /* Construct a CG structure; initialize everything that's the same
+ in each cylinder group. */
+ bzero (newcg, sblock.fs_cgsize);
+ newcg->cg_niblk = sblock.fs_ipg;
+ switch (sblock.fs_postblformat)
+ {
+ case FS_42POSTBLFMT:
+ /* Initialize size information */
+ basesize = (char *)(&ocg->cg_btot[0]) - (char *)(&ocg->cg_link);
+ sumsize = &ocg->cg_iused[0] - (char *)(&ocg->cg_btot[0]);
+ mapsize = (&ocg->cg_free[howmany(sblock.fs_fpg, NBBY)]
+ - (u_char *)&ocg->cg_iused[0]);
+ savednrpos = sblock.fs_nrpos;
+ sblock.fs_nrpos = 8;
+ break;
+
+ case FS_DYNAMICPOSTBLFMT;
+ /* Set fields unique to new cg structure */
+ newcg->cg_btotoff = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
+ newcg->cg_boff = newcg->cg_btotoff + sblock.fs_cpg * sizeof (long);
+ newcg->cg_iusedoff = newcg->cg_boff + (sblock.fs_cpg
+ * block.fs_nrpos
+ * sizeof (short));
+ newcg->cg_freeoff = newcg->cg_iusedoff + howmany (sblock.fs_ipg, NBBY);
+ /* Only support sblock.fs_contigsumsize == 0 here */
+ /* If we supported clustered filesystems, then we would set
+ clustersumoff and clusteroff and nextfree off would be past
+ them. */
+ newcg->cg_nextfreeoff =
+ (newcg->cg_freeoff
+ + howmany (sblock.fs_cpg * sblock.fs_spc / NSPF (&sblock), NBBY));
+ newcg->cg_magic = CG_MAGIC;
+
+ /* Set map sizes */
+ basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_link);
+ sumsize = newcg->cg_iusedoff - newcg->cg_btotoff;
+ mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
+ break;
+ }
+ bzero (&cstotal, sizeof (struct csum));
+ /* Mark fragments past the end of the filesystem as used. */
+ j = blknum (&sblock, sblock->fs_size + fs->fs_frag - 1);
+ for (i = sblock.fs_size; i < j; i++)
+ setbmap (i);
+ /* Now walk through the cylinder groups, checking each one. */
+ for (c = 0; c < sblock.fs_ncg; c++)
+ {
+ int dbase, dmax;
+
+ /* Read the cylinder group structure */
+ readblock (fsbtodb (cgtod (&sblock, c)), cg,
+ sblock.fs_cgsize / DEV_BSIZE);
+ writecg = 0;
+
+ if (!cg_chkmagic (cg))
+ pfatal ("CG %d: BAD MAGIC NUMBER\n", c);
+
+ /* Compute first and last data block addresses in this group */
+ dbase = cgbase (&sblock, c);
+ dmax = dbase + sblock.fs_fpg;
+ if (dmax > sblock.fs_size)
+ dmax = sblock.fs_size;
+
+ /* Initialize newcg fully; values from cg for those
+ we can't check. */
+ newcg->cg_time = cg->cg_time;
+ newcg->cg_cgx = c;
+ if (c == sblock.fs_ncg - 1)
+ newcg->cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
+ else
+ newcg->cg_ncyl = sblock.fs_cpg;
+ newcg->cg_ndblk = dmax - dbase;
+ /* Don't set nclusterblks; we don't support that */
+
+ newcg->cg_cs.cs_ndir = 0;
+ newcg->cg_cs.cs_nffree = 0;
+ newcg->cg_cs.cs_nbfree = 0;
+ newcg->cg_cs.cs_nifree = sblock.fs_ipg;
+
+ /* Check these for basic viability; if they are wrong
+ then clear them. */
+ newcg->cg_rotor = cg->cg_rotor;
+ newcg->cg_frotor = cg->cg_frotor;
+ newcg->cg_irotor = cg->cg_irotor;
+ if (newcg->cg_rotor > newcg->cg_ndblk)
+ {
+ pwarn ("ILLEGAL ROTOR VALUE IN CG %d", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ newcg->cg_rotor = 0;
+ cg->cg_rotor = 0;
+ writecg = 1;
+ }
+ }
+ if (newcg->cg_frotor > newcg->cg_ndblk)
+ {
+ pwarn ("ILLEGAL FROTOR VALUE IN CG %d", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ newcg->cg_frotor = 0;
+ cg->cg_frotor = 0;
+ writecg = 1;
+ }
+ }
+ if (newcg->cg_irotor > newcg->cg_niblk)
+ {
+ pwarn ("ILLEGAL IROTOR VALUE IN CG %d", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ newcg->cg_irotor = 0;
+ cg->cg_irotor = 0;
+ writecg = 1;
+ }
+ }
+
+ /* Zero the block maps and summary areas */
+ bzero (&newcg->cg_frsum[0], sizeof newcg->cg_frsum);
+ bzero (&cg_blktot (newcg)[0], sumsize + mapsize);
+ if (sblock.fs_postblformat == FS_42POSTBLFMT)
+ ocg->cg_magic = CG_MAGIC;
+
+ /* Walk through each inode, accounting for it in
+ the inode map and in newcg->cg_cs. */
+ j = fs->fs_ipg * c;
+ for (i = 0; i < fs->fs_ipg; j++, i++)
+ switch (inodestate[i])
+ {
+ case DIR:
+ case DIR | DIR_REF:
+ newcg->cg_cs.cs_ndir++;
+ /* Fall through... */
+ case FILE:
+ newcg->cg_cs.cs_nifree--;
+ setbit (cg_inosused (newcg), i);
+ }
+ /* Account for inodes 0 and 1 */
+ if (c == 0)
+ for (i = 0; i < ROOTINO; i++)
+ {
+ setbit (cg_inosused (newcg), i);
+ newcg->cg_cs.cs_nifree--;
+ }
+
+ /* Walk through each data block, accounting for it in
+ the block map and in newcg->cg_cs. */
+ for (i = 0, d = dbase;
+ d < dmax;
+ d += sblock.fs_frag, i += sblock.fs_frag)
+ {
+ int frags = 0;
+
+ /* Set each free frag of this block in the block map;
+ count how many frags were free. */
+ for (j = 0; j < fs->fs_frag; j++)
+ {
+ if (testbmap (d + j))
+ continue;
+ setbit (cg_blksfree (newcg), i + j);
+ frags++;
+ }
+
+ /* If all the frags were free, then count this as
+ a free block too. */
+ if (frags == fs->fs_frag)
+ {
+ newcg->cg_cs.cs_nbfree++;
+ j = cbtocylno (&sblock, i);
+ cg_blktot(newcg)[j]++;
+ cg_blks(&sblock, newcg, j)[cktorpos(&sblock, i)]++;
+ /* If we support clustering, then we'd account for this
+ in the cluster map too. */
+ }
+ else if (frags)
+ {
+ /* Partial; account for the frags. */
+ newcg->cg_cs.cs_nffree += frags;
+ blk = blkmap (&sblock, cg_blksfree (newcg), i);
+ ffs_fragacct (&sblock, blk, newcg->cg_frsum, 1);
+ }
+ }
+
+ /* Add this cylinder group's totals into the superblock's
+ totals. */
+ cstotal.cs.nffree += newcg->cg_cs.cs_nffree;
+ cstotal.cs_nbfree += newcg->cg_cs.cs_nbfree;
+ cstotal.cs_nifree += newcg->cg_cs.cs_nifree;
+ cstotal.cs_ndir += newcg->cg_cs.cs_ndir;
+ /* Check counts in superblock */
+ if (bcmp (&newcg->cg_cs, cs, sizeof (struct csum)))
+ {
+ pwarn ("FREE BLK COUNTS FOR CG %d WRONG IN SUPERBLOCK", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ bcopy (newcg->cg_cs, cs, sizeof (struct csum));
+ writecsum = 1;
+ }
+ }
+
+ /* Check inode and block maps */
+ if (bcmp (cg_inosused (newcg), cg_inosused (cg), mapsize))
+ {
+ pwarn ("BLKS OR INOS MISSING IN CG %d BIT MAPS", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ bcopy (cg_inosused (newcg), cg_inosused (cg), mapsize);
+ writecg = 1;
+ }
+ }
+
+ if (bcmp (&cg_blktot(newcg)[0], &cg_blktot(cg)[0], sumsize))
+ {
+ pwarn ("SUMMARY INFORMATION FOR CG %d BAD", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ bcopy (cg_blktot(newcg)[0], &cg_blktot(cg)[0], sumsize);
+ writecg = 1;
+ }
+ }
+
+ if (bcmp (newcg, cg, basesize))
+ {
+ pwarn ("CYLINDER GROUP %d BAD", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ bcopy (newcg, cg, basesize);
+ writecg = 1;
+ }
+ }
+
+ if (writecg)
+ writeblock (fsbtodb (cgtod (&sblock, c)), cg,
+ sblock.fs_cgsize / DEV_BSIZE);
+ }
+
+ /* Restore nrpos */
+ if (sblock.fs_postblformat == FS_42POSTBLFMT)
+ sblock.fs_nrpos = savednrpos;
+ if (bcmp (cstotal, sblock.fs_cstotal, sizeof (struct csum)))
+ {
+ pwarn ("TOTAL FREE BLK COUNTS WRONG IN SUPERBLOCK", c);
+ if (preen || reply ("FIX"))
+ {
+ if (preen)
+ printf (" (FIXED)");
+ bcopy (&cstotal, sblock.fs_cstotal, sizeof (struct csum));
+ sblock.fs_ronly = 0;
+ sblock.fs_fmod = 0;
+ writesb = 1;
+ }
+ }
+
+ if (writesb)
+ writeblock (SBLOCK, &sblock, btodb (SBSIZE));
+ if (writecsum)
+ writeblock (fsbtodb (&sblock, sblock.fs_csaddr), csumbuf,
+ fsbtodb (&sblock, howmany (sblock->fs_cssize,
+ sblock->fs_fsize)));
+}