18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni *
48fae3551SRodney W. Grimes * Copyright (c) 1980, 1986, 1993
58fae3551SRodney W. Grimes * The Regents of the University of California. All rights reserved.
68fae3551SRodney W. Grimes *
78fae3551SRodney W. Grimes * Redistribution and use in source and binary forms, with or without
88fae3551SRodney W. Grimes * modification, are permitted provided that the following conditions
98fae3551SRodney W. Grimes * are met:
108fae3551SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright
118fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer.
128fae3551SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright
138fae3551SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the
148fae3551SRodney W. Grimes * documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors
168fae3551SRodney W. Grimes * may be used to endorse or promote products derived from this software
178fae3551SRodney W. Grimes * without specific prior written permission.
188fae3551SRodney W. Grimes *
198fae3551SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
208fae3551SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
218fae3551SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
228fae3551SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
238fae3551SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
248fae3551SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
258fae3551SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
268fae3551SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
278fae3551SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
288fae3551SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
298fae3551SRodney W. Grimes * SUCH DAMAGE.
308fae3551SRodney W. Grimes */
318fae3551SRodney W. Grimes
328fae3551SRodney W. Grimes #include <sys/param.h>
33142d8d2fSKirk McKusick #include <sys/stat.h>
347578c6abSKirk McKusick #include <sys/sysctl.h>
35780a5c1eSPeter Wemm
368fae3551SRodney W. Grimes #include <ufs/ufs/dinode.h>
378fae3551SRodney W. Grimes #include <ufs/ufs/dir.h>
388fae3551SRodney W. Grimes #include <ufs/ffs/fs.h>
39780a5c1eSPeter Wemm
40780a5c1eSPeter Wemm #include <err.h>
4189fdc4e1SMike Barcroft #include <limits.h>
4284fc0d7eSMaxime Henrion #include <stdint.h>
438fae3551SRodney W. Grimes #include <string.h>
44780a5c1eSPeter Wemm
458fae3551SRodney W. Grimes #include "fsck.h"
468fae3551SRodney W. Grimes
471c85e6a3SKirk McKusick static ufs2_daddr_t badblk;
481c85e6a3SKirk McKusick static ufs2_daddr_t dupblk;
49d33e92f9SJulian Elischer static ino_t lastino; /* last inode in use */
508fae3551SRodney W. Grimes
51da86e7a2SKirk McKusick static int checkinode(ino_t inumber, struct inodesc *, int rebuiltcg);
5231f4ab50SBruce Evans
5331f4ab50SBruce Evans void
pass1(void)54b70cd7eeSWarner Losh pass1(void)
558fae3551SRodney W. Grimes {
56d33e92f9SJulian Elischer struct inostat *info;
578fae3551SRodney W. Grimes struct inodesc idesc;
5881fbded2SKirk McKusick struct bufarea *cgbp;
5981fbded2SKirk McKusick struct cg *cgp;
60910b491eSKirk McKusick ino_t inumber, inosused, mininos;
611c85e6a3SKirk McKusick ufs2_daddr_t i, cgd;
621c85e6a3SKirk McKusick u_int8_t *cp;
63da86e7a2SKirk McKusick int c, rebuiltcg;
648fae3551SRodney W. Grimes
657703a6ffSScott Long badblk = dupblk = lastino = 0;
667703a6ffSScott Long
678fae3551SRodney W. Grimes /*
688fae3551SRodney W. Grimes * Set file system reserved blocks in used block map.
698fae3551SRodney W. Grimes */
708fae3551SRodney W. Grimes for (c = 0; c < sblock.fs_ncg; c++) {
718fae3551SRodney W. Grimes cgd = cgdmin(&sblock, c);
728fae3551SRodney W. Grimes if (c == 0) {
738fae3551SRodney W. Grimes i = cgbase(&sblock, c);
748fae3551SRodney W. Grimes } else
758fae3551SRodney W. Grimes i = cgsblock(&sblock, c);
768fae3551SRodney W. Grimes for (; i < cgd; i++)
778fae3551SRodney W. Grimes setbmap(i);
788fae3551SRodney W. Grimes }
793d500078SThomas-Henning von Kamptz i = sblock.fs_csaddr;
803d500078SThomas-Henning von Kamptz cgd = i + howmany(sblock.fs_cssize, sblock.fs_fsize);
813d500078SThomas-Henning von Kamptz for (; i < cgd; i++)
823d500078SThomas-Henning von Kamptz setbmap(i);
833d500078SThomas-Henning von Kamptz
848fae3551SRodney W. Grimes /*
858fae3551SRodney W. Grimes * Find all allocated blocks.
868fae3551SRodney W. Grimes */
87780a5c1eSPeter Wemm memset(&idesc, 0, sizeof(struct inodesc));
888fae3551SRodney W. Grimes idesc.id_func = pass1check;
898fae3551SRodney W. Grimes n_files = n_blks = 0;
908fae3551SRodney W. Grimes for (c = 0; c < sblock.fs_ncg; c++) {
91d33e92f9SJulian Elischer inumber = c * sblock.fs_ipg;
92957fc241SKirk McKusick cgbp = cglookup(c);
9381fbded2SKirk McKusick cgp = cgbp->b_un.b_cg;
94da86e7a2SKirk McKusick rebuiltcg = 0;
9540647558SChuck Silvers if (!check_cgmagic(c, cgbp)) {
9640647558SChuck Silvers if (!reply("REBUILD CYLINDER GROUP")) {
97da86e7a2SKirk McKusick cgheader_corrupt = 1;
9840647558SChuck Silvers if (!nflag) {
99*239597e0SKirk McKusick pwarn("YOU WILL NEED TO RERUN FSCK.\n");
10040647558SChuck Silvers rerun = 1;
10140647558SChuck Silvers }
10240647558SChuck Silvers } else {
10340647558SChuck Silvers rebuild_cg(c, cgbp);
104da86e7a2SKirk McKusick rebuiltcg = 1;
105da86e7a2SKirk McKusick }
10640647558SChuck Silvers }
107da86e7a2SKirk McKusick if (!rebuiltcg && sblock.fs_magic == FS_UFS2_MAGIC) {
10881fbded2SKirk McKusick inosused = cgp->cg_initediblk;
10921be55ccSKirk McKusick if (inosused > sblock.fs_ipg) {
1105cc52631SKirk McKusick pfatal("Too many initialized inodes (%ju > %d) "
1115cc52631SKirk McKusick "in cylinder group %d\nReset to %d\n",
1125cc52631SKirk McKusick (uintmax_t)inosused, sblock.fs_ipg, c,
1135cc52631SKirk McKusick sblock.fs_ipg);
1141aaf5f44SXin LI inosused = sblock.fs_ipg;
11521be55ccSKirk McKusick }
11621be55ccSKirk McKusick } else {
117d33e92f9SJulian Elischer inosused = sblock.fs_ipg;
11821be55ccSKirk McKusick }
1196db798caSIan Dowse if (got_siginfo) {
1206db798caSIan Dowse printf("%s: phase 1: cyl group %d of %d (%d%%)\n",
1216db798caSIan Dowse cdevname, c, sblock.fs_ncg,
1226db798caSIan Dowse c * 100 / sblock.fs_ncg);
1236db798caSIan Dowse got_siginfo = 0;
1246db798caSIan Dowse }
1251660ae87SScott Long if (got_sigalarm) {
1261660ae87SScott Long setproctitle("%s p1 %d%%", cdevname,
1271660ae87SScott Long c * 100 / sblock.fs_ncg);
1281660ae87SScott Long got_sigalarm = 0;
1291660ae87SScott Long }
130d33e92f9SJulian Elischer /*
131d33e92f9SJulian Elischer * If we are using soft updates, then we can trust the
132d33e92f9SJulian Elischer * cylinder group inode allocation maps to tell us which
133d33e92f9SJulian Elischer * inodes are allocated. We will scan the used inode map
134d33e92f9SJulian Elischer * to find the inodes that are really in use, and then
135d33e92f9SJulian Elischer * read only those inodes in from disk.
136d33e92f9SJulian Elischer */
137da86e7a2SKirk McKusick if ((preen || inoopt) && usedsoftdep && !rebuiltcg) {
13881fbded2SKirk McKusick cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT];
139f4247773SKonstantin Belousov for ( ; inosused != 0; cp--) {
140f4247773SKonstantin Belousov if (*cp == 0) {
141f4247773SKonstantin Belousov if (inosused > CHAR_BIT)
142f4247773SKonstantin Belousov inosused -= CHAR_BIT;
143f4247773SKonstantin Belousov else
144f4247773SKonstantin Belousov inosused = 0;
1458fae3551SRodney W. Grimes continue;
146f4247773SKonstantin Belousov }
14789fdc4e1SMike Barcroft for (i = 1 << (CHAR_BIT - 1); i > 0; i >>= 1) {
148d33e92f9SJulian Elischer if (*cp & i)
149d33e92f9SJulian Elischer break;
150d33e92f9SJulian Elischer inosused--;
151d33e92f9SJulian Elischer }
152d33e92f9SJulian Elischer break;
153d33e92f9SJulian Elischer }
154d33e92f9SJulian Elischer }
155d33e92f9SJulian Elischer /*
156d33e92f9SJulian Elischer * Allocate inoinfo structures for the allocated inodes.
157d33e92f9SJulian Elischer */
158d33e92f9SJulian Elischer inostathead[c].il_numalloced = inosused;
159d33e92f9SJulian Elischer if (inosused == 0) {
1607d5e6562SPedro F. Giffuni inostathead[c].il_stat = NULL;
161d33e92f9SJulian Elischer continue;
162d33e92f9SJulian Elischer }
16381fbded2SKirk McKusick info = Calloc((unsigned)inosused, sizeof(struct inostat));
164d33e92f9SJulian Elischer if (info == NULL)
16596e3efc0SColin Percival errx(EEXIT, "cannot alloc %u bytes for inoinfo",
166d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostat) * inosused));
167d33e92f9SJulian Elischer inostathead[c].il_stat = info;
168d33e92f9SJulian Elischer /*
169d33e92f9SJulian Elischer * Scan the allocated inodes.
170d33e92f9SJulian Elischer */
1715cc52631SKirk McKusick setinodebuf(c, inosused);
172d33e92f9SJulian Elischer for (i = 0; i < inosused; i++, inumber++) {
1731dc349abSEd Maste if (inumber < UFS_ROOTINO) {
174da86e7a2SKirk McKusick (void)getnextinode(inumber, rebuiltcg);
175d33e92f9SJulian Elischer continue;
176d33e92f9SJulian Elischer }
177910b491eSKirk McKusick /*
178910b491eSKirk McKusick * NULL return indicates probable end of allocated
179910b491eSKirk McKusick * inodes during cylinder group rebuild attempt.
180910b491eSKirk McKusick * We always keep trying until we get to the minimum
181910b491eSKirk McKusick * valid number for this cylinder group.
182910b491eSKirk McKusick */
183da86e7a2SKirk McKusick if (checkinode(inumber, &idesc, rebuiltcg) == 0 &&
18481fbded2SKirk McKusick i > cgp->cg_initediblk)
185910b491eSKirk McKusick break;
1868fae3551SRodney W. Grimes }
187910b491eSKirk McKusick /*
188910b491eSKirk McKusick * This optimization speeds up future runs of fsck
189910b491eSKirk McKusick * by trimming down the number of inodes in cylinder
190910b491eSKirk McKusick * groups that formerly had many inodes but now have
191910b491eSKirk McKusick * fewer in use.
192910b491eSKirk McKusick */
193910b491eSKirk McKusick mininos = roundup(inosused + INOPB(&sblock), INOPB(&sblock));
194da86e7a2SKirk McKusick if (inoopt && !preen && !rebuiltcg &&
195910b491eSKirk McKusick sblock.fs_magic == FS_UFS2_MAGIC &&
19681fbded2SKirk McKusick cgp->cg_initediblk > 2 * INOPB(&sblock) &&
19781fbded2SKirk McKusick mininos < cgp->cg_initediblk) {
19881fbded2SKirk McKusick i = cgp->cg_initediblk;
199910b491eSKirk McKusick if (mininos < 2 * INOPB(&sblock))
20081fbded2SKirk McKusick cgp->cg_initediblk = 2 * INOPB(&sblock);
201910b491eSKirk McKusick else
20281fbded2SKirk McKusick cgp->cg_initediblk = mininos;
203910b491eSKirk McKusick pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n",
20481fbded2SKirk McKusick c, i, cgp->cg_initediblk, "VALID INODES");
2058ebae128SKirk McKusick cgdirty(cgbp);
206910b491eSKirk McKusick }
207910b491eSKirk McKusick if (inosused < sblock.fs_ipg)
208910b491eSKirk McKusick continue;
209d33e92f9SJulian Elischer lastino += 1;
210910b491eSKirk McKusick if (lastino < (c * sblock.fs_ipg))
211910b491eSKirk McKusick inosused = 0;
212910b491eSKirk McKusick else
213910b491eSKirk McKusick inosused = lastino - (c * sblock.fs_ipg);
214da86e7a2SKirk McKusick if (rebuiltcg && inosused > cgp->cg_initediblk &&
215910b491eSKirk McKusick sblock.fs_magic == FS_UFS2_MAGIC) {
21681fbded2SKirk McKusick cgp->cg_initediblk = roundup(inosused, INOPB(&sblock));
217910b491eSKirk McKusick pwarn("CYLINDER GROUP %d: FOUND %d VALID INODES\n", c,
21881fbded2SKirk McKusick cgp->cg_initediblk);
219910b491eSKirk McKusick }
220d33e92f9SJulian Elischer /*
221d33e92f9SJulian Elischer * If we were not able to determine in advance which inodes
222d33e92f9SJulian Elischer * were in use, then reduce the size of the inoinfo structure
223d33e92f9SJulian Elischer * to the size necessary to describe the inodes that we
22452f97104SKirk McKusick * really found. Always leave map space in the first cylinder
22552f97104SKirk McKusick * group in case we need to a root or lost+found directory.
226d33e92f9SJulian Elischer */
22752f97104SKirk McKusick if (inumber == lastino || c == 0)
228910b491eSKirk McKusick continue;
229d33e92f9SJulian Elischer inostathead[c].il_numalloced = inosused;
230d33e92f9SJulian Elischer if (inosused == 0) {
231d33e92f9SJulian Elischer free(inostathead[c].il_stat);
2327d5e6562SPedro F. Giffuni inostathead[c].il_stat = NULL;
233d33e92f9SJulian Elischer continue;
234d33e92f9SJulian Elischer }
23581fbded2SKirk McKusick info = Calloc((unsigned)inosused, sizeof(struct inostat));
236d33e92f9SJulian Elischer if (info == NULL)
23796e3efc0SColin Percival errx(EEXIT, "cannot alloc %u bytes for inoinfo",
238d33e92f9SJulian Elischer (unsigned)(sizeof(struct inostat) * inosused));
239d33e92f9SJulian Elischer memmove(info, inostathead[c].il_stat, inosused * sizeof(*info));
240d33e92f9SJulian Elischer free(inostathead[c].il_stat);
241d33e92f9SJulian Elischer inostathead[c].il_stat = info;
2428fae3551SRodney W. Grimes }
2438fae3551SRodney W. Grimes freeinodebuf();
2448fae3551SRodney W. Grimes }
2458fae3551SRodney W. Grimes
246910b491eSKirk McKusick static int
checkinode(ino_t inumber,struct inodesc * idesc,int rebuiltcg)247da86e7a2SKirk McKusick checkinode(ino_t inumber, struct inodesc *idesc, int rebuiltcg)
2488fae3551SRodney W. Grimes {
2495cc52631SKirk McKusick struct inode ip;
2501c85e6a3SKirk McKusick union dinode *dp;
2511c85e6a3SKirk McKusick ufs2_daddr_t ndb;
2528fae3551SRodney W. Grimes mode_t mode;
253a3628327SKirk McKusick intmax_t size, fixsize;
254c18ef4c0SKirk McKusick int j, ret, offset;
2558fae3551SRodney W. Grimes
256da86e7a2SKirk McKusick if ((dp = getnextinode(inumber, rebuiltcg)) == NULL) {
2572ddf8cdbSKirk McKusick pfatal("INVALID INODE");
258967d9fa3SKirk McKusick goto unknown;
2592ddf8cdbSKirk McKusick }
260d8ba45e2SEd Maste mode = DIP(dp, di_mode) & IFMT;
2618fae3551SRodney W. Grimes if (mode == 0) {
2621c85e6a3SKirk McKusick if ((sblock.fs_magic == FS_UFS1_MAGIC &&
2635cc52631SKirk McKusick (memcmp(dp->dp1.di_db, zino.dp1.di_db,
2641dc349abSEd Maste UFS_NDADDR * sizeof(ufs1_daddr_t)) ||
2655cc52631SKirk McKusick memcmp(dp->dp1.di_ib, zino.dp1.di_ib,
2661dc349abSEd Maste UFS_NIADDR * sizeof(ufs1_daddr_t)) ||
2671c85e6a3SKirk McKusick dp->dp1.di_mode || dp->dp1.di_size)) ||
2681c85e6a3SKirk McKusick (sblock.fs_magic == FS_UFS2_MAGIC &&
2695cc52631SKirk McKusick (memcmp(dp->dp2.di_db, zino.dp2.di_db,
2701dc349abSEd Maste UFS_NDADDR * sizeof(ufs2_daddr_t)) ||
2715cc52631SKirk McKusick memcmp(dp->dp2.di_ib, zino.dp2.di_ib,
2721dc349abSEd Maste UFS_NIADDR * sizeof(ufs2_daddr_t)) ||
2731c85e6a3SKirk McKusick dp->dp2.di_mode || dp->dp2.di_size))) {
274bf58d635SIan Dowse pfatal("PARTIALLY ALLOCATED INODE I=%lu",
275bf58d635SIan Dowse (u_long)inumber);
2768fae3551SRodney W. Grimes if (reply("CLEAR") == 1) {
2775cc52631SKirk McKusick ginode(inumber, &ip);
2785cc52631SKirk McKusick clearinode(ip.i_dp);
2795cc52631SKirk McKusick inodirty(&ip);
2805cc52631SKirk McKusick irelse(&ip);
2818fae3551SRodney W. Grimes }
2828fae3551SRodney W. Grimes }
283d33e92f9SJulian Elischer inoinfo(inumber)->ino_state = USTATE;
284910b491eSKirk McKusick return (1);
2858fae3551SRodney W. Grimes }
2868fae3551SRodney W. Grimes lastino = inumber;
287101a9ac0SKirk McKusick if (chkfilesize(mode, DIP(dp, di_size)) == 0) {
2882ddf8cdbSKirk McKusick pfatal("BAD FILE SIZE");
2898fae3551SRodney W. Grimes goto unknown;
2908fae3551SRodney W. Grimes }
291d8ba45e2SEd Maste if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
2925cc52631SKirk McKusick ginode(inumber, &ip);
2935cc52631SKirk McKusick dp = ip.i_dp;
294c3b2344bSScott Long DIP_SET(dp, di_size, sblock.fs_fsize);
295d8ba45e2SEd Maste DIP_SET(dp, di_mode, IFREG|0600);
2965cc52631SKirk McKusick inodirty(&ip);
2975cc52631SKirk McKusick irelse(&ip);
2988fae3551SRodney W. Grimes }
299d8ba45e2SEd Maste if ((mode == IFBLK || mode == IFCHR || mode == IFIFO ||
300d8ba45e2SEd Maste mode == IFSOCK) && DIP(dp, di_size) != 0) {
3017932349eSKirk McKusick if (debug)
30284fc0d7eSMaxime Henrion printf("bad special-file size %ju:",
30384fc0d7eSMaxime Henrion (uintmax_t)DIP(dp, di_size));
3042ddf8cdbSKirk McKusick pfatal("BAD SPECIAL-FILE SIZE");
3057932349eSKirk McKusick goto unknown;
3067932349eSKirk McKusick }
307d8ba45e2SEd Maste if ((mode == IFBLK || mode == IFCHR) &&
3081c85e6a3SKirk McKusick (dev_t)DIP(dp, di_rdev) == NODEV) {
309a46d9bceSTor Egge if (debug)
310a46d9bceSTor Egge printf("bad special-file rdev NODEV:");
3112ddf8cdbSKirk McKusick pfatal("BAD SPECIAL-FILE RDEV");
312a46d9bceSTor Egge goto unknown;
313a46d9bceSTor Egge }
3141c85e6a3SKirk McKusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize);
3158fae3551SRodney W. Grimes if (ndb < 0) {
3168fae3551SRodney W. Grimes if (debug)
3172ddf8cdbSKirk McKusick printf("negative size %ju ndb %ju:",
31884fc0d7eSMaxime Henrion (uintmax_t)DIP(dp, di_size), (uintmax_t)ndb);
3192ddf8cdbSKirk McKusick pfatal("NEGATIVE FILE SIZE");
3208fae3551SRodney W. Grimes goto unknown;
3218fae3551SRodney W. Grimes }
322d8ba45e2SEd Maste if (mode == IFBLK || mode == IFCHR)
3238fae3551SRodney W. Grimes ndb++;
324d8ba45e2SEd Maste if (mode == IFLNK) {
3258fae3551SRodney W. Grimes /*
3268fae3551SRodney W. Grimes * Fake ndb value so direct/indirect block checks below
3278fae3551SRodney W. Grimes * will detect any garbage after symlink string.
3288fae3551SRodney W. Grimes */
3291c85e6a3SKirk McKusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) {
3301c85e6a3SKirk McKusick if (sblock.fs_magic == FS_UFS1_MAGIC)
3311c85e6a3SKirk McKusick ndb = howmany(DIP(dp, di_size),
3321c85e6a3SKirk McKusick sizeof(ufs1_daddr_t));
3331c85e6a3SKirk McKusick else
3341c85e6a3SKirk McKusick ndb = howmany(DIP(dp, di_size),
3351c85e6a3SKirk McKusick sizeof(ufs2_daddr_t));
3361dc349abSEd Maste if (ndb > UFS_NDADDR) {
3371dc349abSEd Maste j = ndb - UFS_NDADDR;
3388fae3551SRodney W. Grimes for (ndb = 1; j > 1; j--)
3398fae3551SRodney W. Grimes ndb *= NINDIR(&sblock);
3401dc349abSEd Maste ndb += UFS_NDADDR;
3418fae3551SRodney W. Grimes }
3428fae3551SRodney W. Grimes }
3438fae3551SRodney W. Grimes }
34452f97104SKirk McKusick for (j = ndb; ndb < UFS_NDADDR && j < UFS_NDADDR; j++) {
34552f97104SKirk McKusick if (DIP(dp, di_db[j]) == 0)
34652f97104SKirk McKusick continue;
3478fae3551SRodney W. Grimes if (debug)
3482ddf8cdbSKirk McKusick printf("invalid direct addr[%d]: %ju\n", j,
34984fc0d7eSMaxime Henrion (uintmax_t)DIP(dp, di_db[j]));
3502ddf8cdbSKirk McKusick pfatal("INVALID DIRECT BLOCK");
35152f97104SKirk McKusick ginode(inumber, &ip);
35252f97104SKirk McKusick prtinode(&ip);
35352f97104SKirk McKusick if (reply("CLEAR") == 1) {
35452f97104SKirk McKusick DIP_SET(ip.i_dp, di_db[j], 0);
35552f97104SKirk McKusick inodirty(&ip);
35652f97104SKirk McKusick }
35752f97104SKirk McKusick irelse(&ip);
3588fae3551SRodney W. Grimes }
3591dc349abSEd Maste for (j = 0, ndb -= UFS_NDADDR; ndb > 0; j++)
3608fae3551SRodney W. Grimes ndb /= NINDIR(&sblock);
36152f97104SKirk McKusick for (; j < UFS_NIADDR; j++) {
36252f97104SKirk McKusick if (DIP(dp, di_ib[j]) == 0)
36352f97104SKirk McKusick continue;
3648fae3551SRodney W. Grimes if (debug)
3652ddf8cdbSKirk McKusick printf("invalid indirect addr: %ju\n",
36684fc0d7eSMaxime Henrion (uintmax_t)DIP(dp, di_ib[j]));
3672ddf8cdbSKirk McKusick pfatal("INVALID INDIRECT BLOCK");
36852f97104SKirk McKusick ginode(inumber, &ip);
36952f97104SKirk McKusick prtinode(&ip);
37052f97104SKirk McKusick if (reply("CLEAR") == 1) {
37152f97104SKirk McKusick DIP_SET(ip.i_dp, di_ib[j], 0);
37252f97104SKirk McKusick inodirty(&ip);
37352f97104SKirk McKusick }
37452f97104SKirk McKusick irelse(&ip);
3758fae3551SRodney W. Grimes }
3762ddf8cdbSKirk McKusick if (ftypeok(dp) == 0) {
3772ddf8cdbSKirk McKusick pfatal("UNKNOWN FILE TYPE");
3788fae3551SRodney W. Grimes goto unknown;
3792ddf8cdbSKirk McKusick }
3808fae3551SRodney W. Grimes n_files++;
3811c85e6a3SKirk McKusick inoinfo(inumber)->ino_linkcnt = DIP(dp, di_nlink);
382d8ba45e2SEd Maste if (mode == IFDIR) {
383fe5e6e2cSKirk McKusick if (DIP(dp, di_size) == 0) {
384d33e92f9SJulian Elischer inoinfo(inumber)->ino_state = DCLEAR;
38503a86802SKirk McKusick } else if (DIP(dp, di_nlink) == 0) {
386af6726e6SDon Lewis inoinfo(inumber)->ino_state = DZLINK;
387fe5e6e2cSKirk McKusick } else {
388d33e92f9SJulian Elischer inoinfo(inumber)->ino_state = DSTATE;
38903a86802SKirk McKusick }
3908fae3551SRodney W. Grimes cacheino(dp, inumber);
391d33e92f9SJulian Elischer countdirs++;
392af6726e6SDon Lewis } else if (DIP(dp, di_nlink) <= 0)
393af6726e6SDon Lewis inoinfo(inumber)->ino_state = FZLINK;
394af6726e6SDon Lewis else
395d33e92f9SJulian Elischer inoinfo(inumber)->ino_state = FSTATE;
396d33e92f9SJulian Elischer inoinfo(inumber)->ino_type = IFTODT(mode);
3978fae3551SRodney W. Grimes badblk = dupblk = 0;
3988fae3551SRodney W. Grimes idesc->id_number = inumber;
3991c85e6a3SKirk McKusick if (DIP(dp, di_flags) & SF_SNAPSHOT)
4005cc52631SKirk McKusick inoinfo(inumber)->ino_idtype = SNAP;
401142d8d2fSKirk McKusick else
4025cc52631SKirk McKusick inoinfo(inumber)->ino_idtype = ADDR;
4035cc52631SKirk McKusick idesc->id_type = inoinfo(inumber)->ino_idtype;
4048fae3551SRodney W. Grimes (void)ckinode(dp, idesc);
405c18ef4c0SKirk McKusick if (sblock.fs_magic == FS_UFS2_MAGIC && dp->dp2.di_extsize > 0) {
406c18ef4c0SKirk McKusick ndb = howmany(dp->dp2.di_extsize, sblock.fs_bsize);
4071dc349abSEd Maste for (j = 0; j < UFS_NXADDR; j++) {
408c18ef4c0SKirk McKusick if (--ndb == 0 &&
409c18ef4c0SKirk McKusick (offset = blkoff(&sblock, dp->dp2.di_extsize)) != 0)
410c18ef4c0SKirk McKusick idesc->id_numfrags = numfrags(&sblock,
411c18ef4c0SKirk McKusick fragroundup(&sblock, offset));
412c18ef4c0SKirk McKusick else
413c18ef4c0SKirk McKusick idesc->id_numfrags = sblock.fs_frag;
414c18ef4c0SKirk McKusick if (dp->dp2.di_extb[j] == 0)
415c18ef4c0SKirk McKusick continue;
416c18ef4c0SKirk McKusick idesc->id_blkno = dp->dp2.di_extb[j];
417c18ef4c0SKirk McKusick ret = (*idesc->id_func)(idesc);
418c18ef4c0SKirk McKusick if (ret & STOP)
419c18ef4c0SKirk McKusick break;
420c18ef4c0SKirk McKusick }
421c18ef4c0SKirk McKusick }
42251869213SPoul-Henning Kamp if (sblock.fs_magic == FS_UFS2_MAGIC)
42351869213SPoul-Henning Kamp eascan(idesc, &dp->dp2);
4248fae3551SRodney W. Grimes idesc->id_entryno *= btodb(sblock.fs_fsize);
4251c85e6a3SKirk McKusick if (DIP(dp, di_blocks) != idesc->id_entryno) {
42684fc0d7eSMaxime Henrion pwarn("INCORRECT BLOCK COUNT I=%lu (%ju should be %ju)",
42784fc0d7eSMaxime Henrion (u_long)inumber, (uintmax_t)DIP(dp, di_blocks),
42884fc0d7eSMaxime Henrion (uintmax_t)idesc->id_entryno);
4298fae3551SRodney W. Grimes if (preen)
4308fae3551SRodney W. Grimes printf(" (CORRECTED)\n");
4318fae3551SRodney W. Grimes else if (reply("CORRECT") == 0)
432910b491eSKirk McKusick return (1);
4337578c6abSKirk McKusick if (bkgrdflag == 0) {
4345cc52631SKirk McKusick ginode(inumber, &ip);
4355cc52631SKirk McKusick DIP_SET(ip.i_dp, di_blocks, idesc->id_entryno);
4365cc52631SKirk McKusick inodirty(&ip);
4375cc52631SKirk McKusick irelse(&ip);
4387578c6abSKirk McKusick } else {
4397578c6abSKirk McKusick cmd.value = idesc->id_number;
4401c85e6a3SKirk McKusick cmd.size = idesc->id_entryno - DIP(dp, di_blocks);
4417578c6abSKirk McKusick if (debug)
44284fc0d7eSMaxime Henrion printf("adjblkcnt ino %ju amount %lld\n",
44384fc0d7eSMaxime Henrion (uintmax_t)cmd.value, (long long)cmd.size);
4447578c6abSKirk McKusick if (sysctl(adjblkcnt, MIBSIZE, 0, 0,
4457578c6abSKirk McKusick &cmd, sizeof cmd) == -1)
4467578c6abSKirk McKusick rwerror("ADJUST INODE BLOCK COUNT", cmd.value);
4477578c6abSKirk McKusick }
4488fae3551SRodney W. Grimes }
449ac4b20a0SKirk McKusick /*
450a3628327SKirk McKusick * UFS does not allow files to end with a hole; it requires that
451a3628327SKirk McKusick * the last block of a file be allocated. The last allocated block
452a3628327SKirk McKusick * in a file is tracked in id_lballoc. Here, we check for a size
453a3628327SKirk McKusick * past the last allocated block of the file and if that is found,
454a3628327SKirk McKusick * shorten the file to reference the last allocated block to avoid
455a3628327SKirk McKusick * having it reference a hole at its end.
456a3628327SKirk McKusick *
457ac4b20a0SKirk McKusick * Soft updates will always ensure that the file size is correct
458ac4b20a0SKirk McKusick * for files that contain only direct block pointers. However
459ac4b20a0SKirk McKusick * soft updates does not roll back sizes for files with indirect
460ac4b20a0SKirk McKusick * blocks that it has set to unallocated because their contents
461ac4b20a0SKirk McKusick * have not yet been written to disk. Hence, the file can appear
462ac4b20a0SKirk McKusick * to have a hole at its end because the block pointer has been
463a3628327SKirk McKusick * rolled back to zero. Thus finding a hole at the end of a file
464a3628327SKirk McKusick * that is located in an indirect block receives only a warning
465a3628327SKirk McKusick * while finding a hole at the end of a file in a direct block
466a3628327SKirk McKusick * receives a fatal error message.
467ac4b20a0SKirk McKusick */
468a3628327SKirk McKusick size = DIP(dp, di_size);
469a3628327SKirk McKusick if (idesc->id_lballoc < lblkno(&sblock, size - 1) &&
470a3628327SKirk McKusick /* exclude embedded symbolic links */
471a3628327SKirk McKusick ((mode != IFLNK) || size >= sblock.fs_maxsymlinklen)) {
472ac4b20a0SKirk McKusick fixsize = lblktosize(&sblock, idesc->id_lballoc + 1);
473a3628327SKirk McKusick if (size > UFS_NDADDR * sblock.fs_bsize)
474a3628327SKirk McKusick pwarn("INODE %lu: FILE SIZE %ju BEYOND END OF "
475a3628327SKirk McKusick "ALLOCATED FILE, SIZE SHOULD BE %ju",
476a3628327SKirk McKusick (u_long)inumber, size, fixsize);
477a3628327SKirk McKusick else
478a3628327SKirk McKusick pfatal("INODE %lu: FILE SIZE %ju BEYOND END OF "
479a3628327SKirk McKusick "ALLOCATED FILE, SIZE SHOULD BE %ju",
480a3628327SKirk McKusick (u_long)inumber, size, fixsize);
481ac4b20a0SKirk McKusick if (preen)
482ac4b20a0SKirk McKusick printf(" (ADJUSTED)\n");
483ac4b20a0SKirk McKusick else if (reply("ADJUST") == 0)
484ac4b20a0SKirk McKusick return (1);
485ac4b20a0SKirk McKusick if (bkgrdflag == 0) {
4865cc52631SKirk McKusick ginode(inumber, &ip);
4875cc52631SKirk McKusick DIP_SET(ip.i_dp, di_size, fixsize);
4885cc52631SKirk McKusick inodirty(&ip);
4895cc52631SKirk McKusick irelse(&ip);
490ac4b20a0SKirk McKusick } else {
491ac4b20a0SKirk McKusick cmd.value = idesc->id_number;
492ac4b20a0SKirk McKusick cmd.size = fixsize;
493ac4b20a0SKirk McKusick if (debug)
494ac4b20a0SKirk McKusick printf("setsize ino %ju size set to %ju\n",
495ac4b20a0SKirk McKusick (uintmax_t)cmd.value, (uintmax_t)cmd.size);
496ac4b20a0SKirk McKusick if (sysctl(setsize, MIBSIZE, 0, 0,
497ac4b20a0SKirk McKusick &cmd, sizeof cmd) == -1)
498ac4b20a0SKirk McKusick rwerror("SET INODE SIZE", cmd.value);
499ac4b20a0SKirk McKusick }
500ac4b20a0SKirk McKusick
501ac4b20a0SKirk McKusick }
502910b491eSKirk McKusick return (1);
5038fae3551SRodney W. Grimes unknown:
5045cc52631SKirk McKusick ginode(inumber, &ip);
5052ddf8cdbSKirk McKusick prtinode(&ip);
5062ddf8cdbSKirk McKusick inoinfo(inumber)->ino_state = USTATE;
5072ddf8cdbSKirk McKusick if (reply("CLEAR") == 1) {
5085cc52631SKirk McKusick clearinode(ip.i_dp);
5095cc52631SKirk McKusick inodirty(&ip);
5108fae3551SRodney W. Grimes }
5112ddf8cdbSKirk McKusick irelse(&ip);
512910b491eSKirk McKusick return (1);
5138fae3551SRodney W. Grimes }
5148fae3551SRodney W. Grimes
51531f4ab50SBruce Evans int
pass1check(struct inodesc * idesc)516b70cd7eeSWarner Losh pass1check(struct inodesc *idesc)
5178fae3551SRodney W. Grimes {
5188fae3551SRodney W. Grimes int res = KEEPON;
5198fae3551SRodney W. Grimes int anyout, nfrags;
5201c85e6a3SKirk McKusick ufs2_daddr_t blkno = idesc->id_blkno;
5213d438ad6SDavid E. O'Brien struct dups *dlp;
5228fae3551SRodney W. Grimes struct dups *new;
5238fae3551SRodney W. Grimes
524142d8d2fSKirk McKusick if (idesc->id_type == SNAP) {
525142d8d2fSKirk McKusick if (blkno == BLK_NOCOPY)
526142d8d2fSKirk McKusick return (KEEPON);
527142d8d2fSKirk McKusick if (idesc->id_number == cursnapshot) {
528142d8d2fSKirk McKusick if (blkno == blkstofrags(&sblock, idesc->id_lbn))
529142d8d2fSKirk McKusick return (KEEPON);
530142d8d2fSKirk McKusick if (blkno == BLK_SNAP) {
531142d8d2fSKirk McKusick blkno = blkstofrags(&sblock, idesc->id_lbn);
532142d8d2fSKirk McKusick idesc->id_entryno -= idesc->id_numfrags;
533142d8d2fSKirk McKusick }
534142d8d2fSKirk McKusick } else {
535142d8d2fSKirk McKusick if (blkno == BLK_SNAP)
536142d8d2fSKirk McKusick return (KEEPON);
537142d8d2fSKirk McKusick }
538142d8d2fSKirk McKusick }
5398fae3551SRodney W. Grimes if ((anyout = chkrange(blkno, idesc->id_numfrags)) != 0) {
5408fae3551SRodney W. Grimes blkerror(idesc->id_number, "BAD", blkno);
5418fae3551SRodney W. Grimes if (badblk++ >= MAXBAD) {
5428fae3551SRodney W. Grimes pwarn("EXCESSIVE BAD BLKS I=%lu",
543bf58d635SIan Dowse (u_long)idesc->id_number);
5448fae3551SRodney W. Grimes if (preen)
5458fae3551SRodney W. Grimes printf(" (SKIPPING)\n");
546b1897c19SJulian Elischer else if (reply("CONTINUE") == 0) {
547b1897c19SJulian Elischer ckfini(0);
548780a5c1eSPeter Wemm exit(EEXIT);
549b1897c19SJulian Elischer }
5507703a6ffSScott Long rerun = 1;
5518fae3551SRodney W. Grimes return (STOP);
5528fae3551SRodney W. Grimes }
5538fae3551SRodney W. Grimes }
5548fae3551SRodney W. Grimes for (nfrags = idesc->id_numfrags; nfrags > 0; blkno++, nfrags--) {
5558fae3551SRodney W. Grimes if (anyout && chkrange(blkno, 1)) {
5568fae3551SRodney W. Grimes res = SKIP;
5578fae3551SRodney W. Grimes } else if (!testbmap(blkno)) {
5588fae3551SRodney W. Grimes n_blks++;
5598fae3551SRodney W. Grimes setbmap(blkno);
5608fae3551SRodney W. Grimes } else {
5618fae3551SRodney W. Grimes blkerror(idesc->id_number, "DUP", blkno);
5628fae3551SRodney W. Grimes if (dupblk++ >= MAXDUP) {
5638fae3551SRodney W. Grimes pwarn("EXCESSIVE DUP BLKS I=%lu",
564bf58d635SIan Dowse (u_long)idesc->id_number);
5658fae3551SRodney W. Grimes if (preen)
5668fae3551SRodney W. Grimes printf(" (SKIPPING)\n");
567b1897c19SJulian Elischer else if (reply("CONTINUE") == 0) {
568b1897c19SJulian Elischer ckfini(0);
569780a5c1eSPeter Wemm exit(EEXIT);
570b1897c19SJulian Elischer }
5717703a6ffSScott Long rerun = 1;
5728fae3551SRodney W. Grimes return (STOP);
5738fae3551SRodney W. Grimes }
57481fbded2SKirk McKusick new = (struct dups *)Malloc(sizeof(struct dups));
5758fae3551SRodney W. Grimes if (new == NULL) {
5768fae3551SRodney W. Grimes pfatal("DUP TABLE OVERFLOW.");
577b1897c19SJulian Elischer if (reply("CONTINUE") == 0) {
578b1897c19SJulian Elischer ckfini(0);
579780a5c1eSPeter Wemm exit(EEXIT);
580b1897c19SJulian Elischer }
5817703a6ffSScott Long rerun = 1;
5828fae3551SRodney W. Grimes return (STOP);
5838fae3551SRodney W. Grimes }
5848fae3551SRodney W. Grimes new->dup = blkno;
5857d5e6562SPedro F. Giffuni if (muldup == NULL) {
5868fae3551SRodney W. Grimes duplist = muldup = new;
5877d5e6562SPedro F. Giffuni new->next = NULL;
5888fae3551SRodney W. Grimes } else {
5898fae3551SRodney W. Grimes new->next = muldup->next;
5908fae3551SRodney W. Grimes muldup->next = new;
5918fae3551SRodney W. Grimes }
5928fae3551SRodney W. Grimes for (dlp = duplist; dlp != muldup; dlp = dlp->next)
5938fae3551SRodney W. Grimes if (dlp->dup == blkno)
5948fae3551SRodney W. Grimes break;
5958fae3551SRodney W. Grimes if (dlp == muldup && dlp->dup != blkno)
5968fae3551SRodney W. Grimes muldup = new;
5978fae3551SRodney W. Grimes }
5988fae3551SRodney W. Grimes /*
5998fae3551SRodney W. Grimes * count the number of blocks found in id_entryno
6008fae3551SRodney W. Grimes */
6018fae3551SRodney W. Grimes idesc->id_entryno++;
6028fae3551SRodney W. Grimes }
603d4833913SKirk McKusick if (idesc->id_level == 0 && idesc->id_lballoc < idesc->id_lbn)
604ac4b20a0SKirk McKusick idesc->id_lballoc = idesc->id_lbn;
6058fae3551SRodney W. Grimes return (res);
6068fae3551SRodney W. Grimes }
607