Exemple #1
0
/*
 * allocate an unused inode
 */
ino_t
allocino(ino_t request, int type)
{
	ino_t ino;
	union dinode *dp;
	struct bufarea *cgbp;
	struct cg *cgp;
	int cg;

	if (request == 0)
		request = ROOTINO;
	else if (inoinfo(request)->ino_state != USTATE)
		return (0);
	for (ino = request; ino < maxino; ino++)
		if (inoinfo(ino)->ino_state == USTATE)
			break;
	if (ino == maxino)
		return (0);
	cg = ino_to_cg(&sblock, ino);
	cgbp = cgget(cg);
	cgp = cgbp->b_un.b_cg;
	if (!check_cgmagic(cg, cgbp))
		return (0);
	setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
	cgp->cg_cs.cs_nifree--;
	switch (type & IFMT) {
	case IFDIR:
		inoinfo(ino)->ino_state = DSTATE;
		cgp->cg_cs.cs_ndir++;
		break;
	case IFREG:
	case IFLNK:
		inoinfo(ino)->ino_state = FSTATE;
		break;
	default:
		return (0);
	}
	dirty(cgbp);
	dp = ginode(ino);
	DIP_SET(dp, di_db[0], allocblk((long)1));
	if (DIP(dp, di_db[0]) == 0) {
		inoinfo(ino)->ino_state = USTATE;
		return (0);
	}
	DIP_SET(dp, di_mode, type);
	DIP_SET(dp, di_flags, 0);
	DIP_SET(dp, di_atime, time(NULL));
	DIP_SET(dp, di_ctime, DIP(dp, di_atime));
	DIP_SET(dp, di_mtime, DIP(dp, di_ctime));
	DIP_SET(dp, di_mtimensec, 0);
	DIP_SET(dp, di_ctimensec, 0);
	DIP_SET(dp, di_atimensec, 0);
	DIP_SET(dp, di_size, sblock.fs_fsize);
	DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize));
	n_files++;
	inodirty();
	inoinfo(ino)->ino_type = IFTODT(type);
	return (ino);
}
Exemple #2
0
void
pass1(void)
{
    struct inostat *info;
    struct inodesc idesc;
    struct bufarea *cgbp;
    struct cg *cgp;
    ino_t inumber, inosused, mininos;
    ufs2_daddr_t i, cgd;
    u_int8_t *cp;
    int c, rebuildcg;

    badblk = dupblk = lastino = 0;

    /*
     * Set file system reserved blocks in used block map.
     */
    for (c = 0; c < sblock.fs_ncg; c++) {
        cgd = cgdmin(&sblock, c);
        if (c == 0) {
            i = cgbase(&sblock, c);
        } else
            i = cgsblock(&sblock, c);
        for (; i < cgd; i++)
            setbmap(i);
    }
    i = sblock.fs_csaddr;
    cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize);
    for (; i < cgd; i++)
        setbmap(i);

    /*
     * Find all allocated blocks.
     */
    memset(&idesc, 0, sizeof(struct inodesc));
    idesc.id_func = pass1check;
    n_files = n_blks = 0;
    for (c = 0; c < sblock.fs_ncg; c++) {
        inumber = c * sblock.fs_ipg;
        setinodebuf(inumber);
        cgbp = cgget(c);
        cgp = cgbp->b_un.b_cg;
        rebuildcg = 0;
        if (!check_cgmagic(c, cgbp))
            rebuildcg = 1;
        if (!rebuildcg && sblock.fs_magic == FS_UFS2_MAGIC) {
            inosused = cgp->cg_initediblk;
            if (inosused > sblock.fs_ipg) {
                pfatal(
                    "Too many initialized inodes (%ju > %d) in cylinder group %d\nReset to %d\n",
                    (uintmax_t)inosused,
                    sblock.fs_ipg, c, sblock.fs_ipg);
                inosused = sblock.fs_ipg;
            }
        } else {
            inosused = sblock.fs_ipg;
        }
        if (got_siginfo) {
            printf("%s: phase 1: cyl group %d of %d (%d%%)\n",
                   cdevname, c, sblock.fs_ncg,
                   c * 100 / sblock.fs_ncg);
            got_siginfo = 0;
        }
        if (got_sigalarm) {
            setproctitle("%s p1 %d%%", cdevname,
                         c * 100 / sblock.fs_ncg);
            got_sigalarm = 0;
        }
        /*
         * If we are using soft updates, then we can trust the
         * cylinder group inode allocation maps to tell us which
         * inodes are allocated. We will scan the used inode map
         * to find the inodes that are really in use, and then
         * read only those inodes in from disk.
         */
        if ((preen || inoopt) && usedsoftdep && !rebuildcg) {
            cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT];
            for ( ; inosused > 0; inosused -= CHAR_BIT, cp--) {
                if (*cp == 0)
                    continue;
                for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
                    if (*cp & i)
                        break;
                    inosused--;
                }
                break;
            }
            if (inosused < 0)
                inosused = 0;
        }
        /*
         * Allocate inoinfo structures for the allocated inodes.
         */
        inostathead[c].il_numalloced = inosused;
        if (inosused == 0) {
            inostathead[c].il_stat = NULL;
            continue;
        }
        info = Calloc((unsigned)inosused, sizeof(struct inostat));
        if (info == NULL)
            errx(EEXIT, "cannot alloc %u bytes for inoinfo",
                 (unsigned)(sizeof(struct inostat) * inosused));
        inostathead[c].il_stat = info;
        /*
         * Scan the allocated inodes.
         */
        for (i = 0; i < inosused; i++, inumber++) {
            if (inumber < ROOTINO) {
                (void)getnextinode(inumber, rebuildcg);
                continue;
            }
            /*
             * NULL return indicates probable end of allocated
             * inodes during cylinder group rebuild attempt.
             * We always keep trying until we get to the minimum
             * valid number for this cylinder group.
             */
            if (checkinode(inumber, &idesc, rebuildcg) == 0 &&
                    i > cgp->cg_initediblk)
                break;
        }
        /*
         * This optimization speeds up future runs of fsck
         * by trimming down the number of inodes in cylinder
         * groups that formerly had many inodes but now have
         * fewer in use.
         */
        mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock));
        if (inoopt && !preen && !rebuildcg &&
                sblock.fs_magic == FS_UFS2_MAGIC &&
                cgp->cg_initediblk > 2 * INOPB(&sblock) &&
                mininos < cgp->cg_initediblk) {
            i = cgp->cg_initediblk;
            if (mininos < 2 * INOPB(&sblock))
                cgp->cg_initediblk = 2 * INOPB(&sblock);
            else
                cgp->cg_initediblk = mininos;
            pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n",
                  c, i, cgp->cg_initediblk, "VALID INODES");
            dirty(cgbp);
        }
        if (inosused < sblock.fs_ipg)
            continue;
        lastino += 1;
        if (lastino < (c * sblock.fs_ipg))
            inosused = 0;
        else
            inosused = lastino - (c * sblock.fs_ipg);
        if (rebuildcg && inosused > cgp->cg_initediblk &&
                sblock.fs_magic == FS_UFS2_MAGIC) {
            cgp->cg_initediblk = roundup(inosused, INOPB(&sblock));
            pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c,
                  cgp->cg_initediblk);
        }
        /*
         * If we were not able to determine in advance which inodes
         * were in use, then reduce the size of the inoinfo structure
         * to the size necessary to describe the inodes that we
         * really found.
         */
        if (inumber == lastino)
            continue;
        inostathead[c].il_numalloced = inosused;
        if (inosused == 0) {
            free(inostathead[c].il_stat);
            inostathead[c].il_stat = NULL;
            continue;
        }
        info = Calloc((unsigned)inosused, sizeof(struct inostat));
        if (info == NULL)
            errx(EEXIT, "cannot alloc %u bytes for inoinfo",
                 (unsigned)(sizeof(struct inostat) * inosused));
        memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
        free(inostathead[c].il_stat);
        inostathead[c].il_stat = info;
    }
Exemple #3
0
void
pass5(void)
{
	int c, i, j, blk, frags, basesize, mapsize;
	int inomapsize, blkmapsize;
	struct fs *fs = &sblock;
	ufs2_daddr_t d, dbase, dmax, start;
	int rewritecg = 0;
	struct csum *cs;
	struct csum_total cstotal;
	struct inodesc idesc[3];
	char buf[MAXBSIZE];
	struct cg *cg, *newcg = (struct cg *)buf;
	struct bufarea *cgbp;

	inoinfo(WINO)->ino_state = USTATE;
	memset(newcg, 0, (size_t)fs->fs_cgsize);
	newcg->cg_niblk = fs->fs_ipg;
	if (cvtlevel >= 3) {
		if (fs->fs_maxcontig < 2 && fs->fs_contigsumsize > 0) {
			if (preen)
				pwarn("DELETING CLUSTERING MAPS\n");
			if (preen || reply("DELETE CLUSTERING MAPS")) {
				fs->fs_contigsumsize = 0;
				rewritecg = 1;
				sbdirty();
			}
		}
		if (fs->fs_maxcontig > 1) {
			const char *doit = 0;

			if (fs->fs_contigsumsize < 1) {
				doit = "CREAT";
			} else if (fs->fs_contigsumsize < fs->fs_maxcontig &&
				   fs->fs_contigsumsize < FS_MAXCONTIG) {
				doit = "EXPAND";
			}
			if (doit) {
				i = fs->fs_contigsumsize;
				fs->fs_contigsumsize =
				    MIN(fs->fs_maxcontig, FS_MAXCONTIG);
				if (CGSIZE(fs) > (u_int)fs->fs_bsize) {
					pwarn("CANNOT %s CLUSTER MAPS\n", doit);
					fs->fs_contigsumsize = i;
				} else if (preen ||
				    reply("CREATE CLUSTER MAPS")) {
					if (preen)
						pwarn("%sING CLUSTER MAPS\n",
						    doit);
					fs->fs_cgsize =
					    fragroundup(fs, CGSIZE(fs));
					rewritecg = 1;
					sbdirty();
				}
			}
		}
	}
	basesize = &newcg->cg_space[0] - (u_char *)(&newcg->cg_firstfield);
	if (sblock.fs_magic == FS_UFS2_MAGIC) {
		newcg->cg_iusedoff = basesize;
	} else {
		/*
		 * We reserve the space for the old rotation summary
		 * tables for the benefit of old kernels, but do not
		 * maintain them in modern kernels. In time, they can
		 * go away.
		 */
		newcg->cg_old_btotoff = basesize;
		newcg->cg_old_boff = newcg->cg_old_btotoff +
		    fs->fs_old_cpg * sizeof(int32_t);
		newcg->cg_iusedoff = newcg->cg_old_boff +
		    fs->fs_old_cpg * fs->fs_old_nrpos * sizeof(u_int16_t);
		memset(&newcg->cg_space[0], 0, newcg->cg_iusedoff - basesize);
	}
	inomapsize = howmany(fs->fs_ipg, CHAR_BIT);
	newcg->cg_freeoff = newcg->cg_iusedoff + inomapsize;
	blkmapsize = howmany(fs->fs_fpg, CHAR_BIT);
	newcg->cg_nextfreeoff = newcg->cg_freeoff + blkmapsize;
	if (fs->fs_contigsumsize > 0) {
		newcg->cg_clustersumoff = newcg->cg_nextfreeoff -
		    sizeof(u_int32_t);
		newcg->cg_clustersumoff =
		    roundup(newcg->cg_clustersumoff, sizeof(u_int32_t));
		newcg->cg_clusteroff = newcg->cg_clustersumoff +
		    (fs->fs_contigsumsize + 1) * sizeof(u_int32_t);
		newcg->cg_nextfreeoff = newcg->cg_clusteroff +
		    howmany(fragstoblks(fs, fs->fs_fpg), CHAR_BIT);
	}
	newcg->cg_magic = CG_MAGIC;
	mapsize = newcg->cg_nextfreeoff - newcg->cg_iusedoff;
	memset(&idesc[0], 0, sizeof idesc);
	for (i = 0; i < 3; i++)
		idesc[i].id_type = ADDR;
	memset(&cstotal, 0, sizeof(struct csum_total));
	dmax = blknum(fs, fs->fs_size + fs->fs_frag - 1);
	for (d = fs->fs_size; d < dmax; d++)
		setbmap(d);
	for (c = 0; c < fs->fs_ncg; c++) {
		if (got_siginfo) {
			printf("%s: phase 5: cyl group %d of %d (%d%%)\n",
			    cdevname, c, sblock.fs_ncg,
			    c * 100 / sblock.fs_ncg);
			got_siginfo = 0;
		}
		if (got_sigalarm) {
			setproctitle("%s p5 %d%%", cdevname,
			    c * 100 / sblock.fs_ncg);
			got_sigalarm = 0;
		}
		cgbp = cgget(c);
		cg = cgbp->b_un.b_cg;
		if (!cg_chkmagic(cg))
			pfatal("CG %d: BAD MAGIC NUMBER\n", c);
		newcg->cg_time = cg->cg_time;
		newcg->cg_old_time = cg->cg_old_time;
		newcg->cg_unrefs = cg->cg_unrefs;
		newcg->cg_cgx = c;
		dbase = cgbase(fs, c);
		dmax = dbase + fs->fs_fpg;
		if (dmax > fs->fs_size)
			dmax = fs->fs_size;
		newcg->cg_ndblk = dmax - dbase;
		if (fs->fs_magic == FS_UFS1_MAGIC) {
			if (c == fs->fs_ncg - 1)
				newcg->cg_old_ncyl = howmany(newcg->cg_ndblk,
				    fs->fs_fpg / fs->fs_old_cpg);
			else
				newcg->cg_old_ncyl = fs->fs_old_cpg;
			newcg->cg_old_niblk = fs->fs_ipg;
			newcg->cg_niblk = 0;
		}
		if (fs->fs_contigsumsize > 0)
			newcg->cg_nclusterblks = newcg->cg_ndblk / fs->fs_frag;
		newcg->cg_cs.cs_ndir = 0;
		newcg->cg_cs.cs_nffree = 0;
		newcg->cg_cs.cs_nbfree = 0;
		newcg->cg_cs.cs_nifree = fs->fs_ipg;
		if (cg->cg_rotor >= 0 && cg->cg_rotor < newcg->cg_ndblk)
			newcg->cg_rotor = cg->cg_rotor;
		else
			newcg->cg_rotor = 0;
		if (cg->cg_frotor >= 0 && cg->cg_frotor < newcg->cg_ndblk)
			newcg->cg_frotor = cg->cg_frotor;
		else
			newcg->cg_frotor = 0;
		if (cg->cg_irotor >= 0 && cg->cg_irotor < fs->fs_ipg)
			newcg->cg_irotor = cg->cg_irotor;
		else
			newcg->cg_irotor = 0;
		if (fs->fs_magic == FS_UFS1_MAGIC) {
			newcg->cg_initediblk = 0;
		} else {
			if ((unsigned)cg->cg_initediblk > fs->fs_ipg)
				newcg->cg_initediblk = fs->fs_ipg;
			else
				newcg->cg_initediblk = cg->cg_initediblk;
		}
		memset(&newcg->cg_frsum[0], 0, sizeof newcg->cg_frsum);
		memset(cg_inosused(newcg), 0, (size_t)(mapsize));
		j = fs->fs_ipg * c;
		for (i = 0; i < inostathead[c].il_numalloced; j++, i++) {
			switch (inoinfo(j)->ino_state) {

			case USTATE:
				break;

			case DSTATE:
			case DCLEAR:
			case DFOUND:
			case DZLINK:
				newcg->cg_cs.cs_ndir++;
				/* FALLTHROUGH */

			case FSTATE:
			case FCLEAR:
			case FZLINK:
				newcg->cg_cs.cs_nifree--;
				setbit(cg_inosused(newcg), i);
				break;

			default:
				if (j < (int)ROOTINO)
					break;
				errx(EEXIT, "BAD STATE %d FOR INODE I=%d",
				    inoinfo(j)->ino_state, j);
			}
		}
		if (c == 0)
			for (i = 0; i < (int)ROOTINO; i++) {
				setbit(cg_inosused(newcg), i);
				newcg->cg_cs.cs_nifree--;
			}
		start = -1;
		for (i = 0, d = dbase;
		     d < dmax;
		     d += fs->fs_frag, i += fs->fs_frag) {
			frags = 0;
			for (j = 0; j < fs->fs_frag; j++) {
				if (testbmap(d + j)) {
					if (Eflag && start != -1) {
						clear_blocks(start, d + j - 1);
						start = -1;
					}
					continue;
				}
				if (start == -1)
					start = d + j;
				setbit(cg_blksfree(newcg), i + j);
				frags++;
			}
			if (frags == fs->fs_frag) {
				newcg->cg_cs.cs_nbfree++;
				if (fs->fs_contigsumsize > 0)
					setbit(cg_clustersfree(newcg),
					    i / fs->fs_frag);
			} else if (frags > 0) {
				newcg->cg_cs.cs_nffree += frags;
				blk = blkmap(fs, cg_blksfree(newcg), i);
				ffs_fragacct(fs, blk, newcg->cg_frsum, 1);
			}
		}
		if (Eflag && start != -1)
			clear_blocks(start, d - 1);
		if (fs->fs_contigsumsize > 0) {
			int32_t *sump = cg_clustersum(newcg);
			u_char *mapp = cg_clustersfree(newcg);
			int map = *mapp++;
			int bit = 1;
			int run = 0;

			for (i = 0; i < newcg->cg_nclusterblks; i++) {
				if ((map & bit) != 0) {
					run++;
				} else if (run != 0) {
					if (run > fs->fs_contigsumsize)
						run = fs->fs_contigsumsize;
					sump[run]++;
					run = 0;
				}
				if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) {
					bit <<= 1;
				} else {
					map = *mapp++;
					bit = 1;
				}
			}
			if (run != 0) {
				if (run > fs->fs_contigsumsize)
					run = fs->fs_contigsumsize;
				sump[run]++;
			}
		}
		if (bkgrdflag != 0) {
			cstotal.cs_nffree += cg->cg_cs.cs_nffree;
			cstotal.cs_nbfree += cg->cg_cs.cs_nbfree;
			cstotal.cs_nifree += cg->cg_cs.cs_nifree;
			cstotal.cs_ndir += cg->cg_cs.cs_ndir;
		} else {
			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;
		}
		cs = &fs->fs_cs(fs, c);
		if (cursnapshot == 0 &&
		    memcmp(&newcg->cg_cs, cs, sizeof *cs) != 0 &&
		    dofix(&idesc[0], "FREE BLK COUNT(S) WRONG IN SUPERBLK")) {
			memmove(cs, &newcg->cg_cs, sizeof *cs);
			sbdirty();
		}
		if (rewritecg) {
			memmove(cg, newcg, (size_t)fs->fs_cgsize);
			dirty(cgbp);
			continue;
		}
		if (cursnapshot == 0 &&
		    memcmp(newcg, cg, basesize) != 0 &&
		    dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
			memmove(cg, newcg, (size_t)basesize);
			dirty(cgbp);
		}
		if (bkgrdflag != 0 || usedsoftdep || debug)
			update_maps(cg, newcg, bkgrdflag);
		if (cursnapshot == 0 &&
		    memcmp(cg_inosused(newcg), cg_inosused(cg), mapsize) != 0 &&
		    dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
			memmove(cg_inosused(cg), cg_inosused(newcg),
			      (size_t)mapsize);
			dirty(cgbp);
		}
	}
	if (cursnapshot == 0 &&
	    memcmp(&cstotal, &fs->fs_cstotal, sizeof cstotal) != 0
	    && dofix(&idesc[0], "SUMMARY BLK COUNT(S) WRONG IN SUPERBLK")) {
		memmove(&fs->fs_cstotal, &cstotal, sizeof cstotal);
		fs->fs_ronly = 0;
		fs->fs_fmod = 0;
		sbdirty();
	}

	/*
	 * When doing background fsck on a snapshot, figure out whether
	 * the superblock summary is inaccurate and correct it when
	 * necessary.
	 */
	if (cursnapshot != 0) {
		cmd.size = 1;

		cmd.value = cstotal.cs_ndir - fs->fs_cstotal.cs_ndir;
		if (cmd.value != 0) {
			if (debug)
				printf("adjndir by %+" PRIi64 "\n", cmd.value);
			if (bkgrdsumadj == 0 || sysctl(adjndir, MIBSIZE, 0, 0,
			    &cmd, sizeof cmd) == -1)
				rwerror("ADJUST NUMBER OF DIRECTORIES", cmd.value);
		}

		cmd.value = cstotal.cs_nbfree - fs->fs_cstotal.cs_nbfree;
		if (cmd.value != 0) {
			if (debug)
				printf("adjnbfree by %+" PRIi64 "\n", cmd.value);
			if (bkgrdsumadj == 0 || sysctl(adjnbfree, MIBSIZE, 0, 0,
			    &cmd, sizeof cmd) == -1)
				rwerror("ADJUST NUMBER OF FREE BLOCKS", cmd.value);
		}

		cmd.value = cstotal.cs_nifree - fs->fs_cstotal.cs_nifree;
		if (cmd.value != 0) {
			if (debug)
				printf("adjnifree by %+" PRIi64 "\n", cmd.value);
			if (bkgrdsumadj == 0 || sysctl(adjnifree, MIBSIZE, 0, 0,
			    &cmd, sizeof cmd) == -1)
				rwerror("ADJUST NUMBER OF FREE INODES", cmd.value);
		}

		cmd.value = cstotal.cs_nffree - fs->fs_cstotal.cs_nffree;
		if (cmd.value != 0) {
			if (debug)
				printf("adjnffree by %+" PRIi64 "\n", cmd.value);
			if (bkgrdsumadj == 0 || sysctl(adjnffree, MIBSIZE, 0, 0,
			    &cmd, sizeof cmd) == -1)
				rwerror("ADJUST NUMBER OF FREE FRAGS", cmd.value);
		}

		cmd.value = cstotal.cs_numclusters - fs->fs_cstotal.cs_numclusters;
		if (cmd.value != 0) {
			if (debug)
				printf("adjnumclusters by %+" PRIi64 "\n", cmd.value);
			if (bkgrdsumadj == 0 || sysctl(adjnumclusters, MIBSIZE, 0, 0,
			    &cmd, sizeof cmd) == -1)
				rwerror("ADJUST NUMBER OF FREE CLUSTERS", cmd.value);
		}
	}
}