[BACK]Return to pass1.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / fsck_lfs

Annotation of src/sbin/fsck_lfs/pass1.c, Revision 1.24

1.24    ! rumble      1: /* $NetBSD: pass1.c,v 1.23 2005/09/13 04:14:17 christos Exp $   */
1.1       perseant    2:
                      3: /*
                      4:  * Copyright (c) 1980, 1986, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
1.17      agc        15:  * 3. Neither the name of the University nor the names of its contributors
1.1       perseant   16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31:
                     32: #include <sys/param.h>
                     33: #include <sys/time.h>
1.14      perseant   34: #include <sys/mount.h>
                     35: #include <sys/buf.h>
                     36:
                     37: #include <ufs/ufs/inode.h>
1.1       perseant   38: #include <ufs/ufs/dir.h>
1.14      perseant   39: #define vnode uvnode
1.1       perseant   40: #include <ufs/lfs/lfs.h>
1.14      perseant   41: #undef vnode
1.1       perseant   42:
1.14      perseant   43: #include <err.h>
1.1       perseant   44: #include <stdio.h>
                     45: #include <stdlib.h>
                     46: #include <string.h>
                     47:
                     48: #include <signal.h>
                     49:
1.14      perseant   50: #include "bufcache.h"
                     51: #include "vnode.h"
1.23      christos   52: #include "lfs_user.h"
1.14      perseant   53:
1.1       perseant   54: #include "fsck.h"
                     55: #include "extern.h"
                     56: #include "fsutil.h"
                     57:
1.14      perseant   58: SEGUSE *seg_table;
                     59: extern ufs_daddr_t *din_table;
1.1       perseant   60:
1.14      perseant   61: ufs_daddr_t badblk;
                     62: static ufs_daddr_t dupblk;
                     63: static int i_d_cmp(const void *, const void *);
1.1       perseant   64:
1.5       perseant   65: struct ino_daddr {
1.14      perseant   66:        ino_t ino;
                     67:        ufs_daddr_t daddr;
1.5       perseant   68: };
                     69:
                     70: static int
                     71: i_d_cmp(const void *va, const void *vb)
                     72: {
1.21      christos   73:        const struct ino_daddr *a, *b;
1.5       perseant   74:
1.21      christos   75:        a = *((const struct ino_daddr *const *) va);
                     76:        b = *((const struct ino_daddr *const *) vb);
1.5       perseant   77:
                     78:        if (a->daddr == b->daddr) {
                     79:                return (a->ino - b->ino);
                     80:        }
                     81:        if (a->daddr > b->daddr) {
                     82:                return 1;
                     83:        }
                     84:        return -1;
                     85: }
                     86:
1.1       perseant   87: void
1.19      xtraeme    88: pass1(void)
1.1       perseant   89: {
1.14      perseant   90:        ino_t inumber;
                     91:        int i;
                     92:        struct inodesc idesc;
1.15      fvdl       93:        struct ufs1_dinode *tinode;
1.14      perseant   94:        struct ifile *ifp;
                     95:        struct ubuf *bp;
1.5       perseant   96:        struct ino_daddr **dins;
1.1       perseant   97:
                     98:        /*
                     99:         * Find all allocated blocks, initialize numdirs.
                    100:         */
                    101:        memset(&idesc, 0, sizeof(struct inodesc));
                    102:        idesc.id_type = ADDR;
                    103:        idesc.id_func = pass1check;
                    104:        idesc.id_lblkno = 0;
                    105:        inumber = 0;
                    106:        n_files = n_blks = 0;
                    107:
1.5       perseant  108:        if (debug)
1.14      perseant  109:                printf("creating sorted inode address table...\n");
1.5       perseant  110:        /* Sort by daddr */
1.14      perseant  111:        dins = (struct ino_daddr **) malloc(maxino * sizeof(*dins));
1.24    ! rumble    112:        if (dins == NULL)
        !           113:                err(1, NULL);
1.8       perseant  114:        for (i = 0; i < maxino; i++) {
1.5       perseant  115:                dins[i] = malloc(sizeof(**dins));
1.24    ! rumble    116:                if (dins[i] == NULL)
        !           117:                        err(1, NULL);
1.5       perseant  118:                dins[i]->ino = i;
1.14      perseant  119:                if (i == fs->lfs_ifile)
                    120:                        dins[i]->daddr = fs->lfs_idaddr;
                    121:                else {
                    122:                        LFS_IENTRY(ifp, fs, i, bp);
                    123:                        dins[i]->daddr = ifp->if_daddr;
                    124:                        brelse(bp);
                    125:                }
1.5       perseant  126:        }
1.8       perseant  127:        qsort(dins, maxino, sizeof(*dins), i_d_cmp);
1.5       perseant  128:
                    129:        /* find a value for numdirs, fill in din_table */
                    130:        if (debug)
                    131:                printf("counting dirs...\n");
1.6       perseant  132:        numdirs = 0;
1.8       perseant  133:        for (i = 0; i < maxino; i++) {
1.5       perseant  134:                inumber = dins[i]->ino;
1.6       perseant  135:                if (inumber == 0 || dins[i]->daddr == 0)
1.5       perseant  136:                        continue;
1.14      perseant  137:                tinode = ginode(inumber);
1.6       perseant  138:                if (tinode && (tinode->di_mode & IFMT) == IFDIR)
1.5       perseant  139:                        numdirs++;
1.1       perseant  140:        }
                    141:
                    142:        /* from setup.c */
1.6       perseant  143:        inplast = 0;
                    144:        listmax = numdirs + 10;
1.14      perseant  145:        inpsort = (struct inoinfo **) calloc((unsigned) listmax,
                    146:            sizeof(struct inoinfo *));
                    147:        inphead = (struct inoinfo **) calloc((unsigned) numdirs,
                    148:            sizeof(struct inoinfo *));
1.6       perseant  149:        if (inpsort == NULL || inphead == NULL) {
                    150:                printf("cannot alloc %lu bytes for inphead\n",
1.14      perseant  151:                    (unsigned long) numdirs * sizeof(struct inoinfo *));
1.1       perseant  152:                exit(1);
1.6       perseant  153:        }
1.5       perseant  154:        if (debug)
                    155:                printf("counting blocks...\n");
1.14      perseant  156:
1.8       perseant  157:        for (i = 0; i < maxino; i++) {
1.5       perseant  158:                inumber = dins[i]->ino;
1.7       perseant  159:                if (inumber == 0 || dins[i]->daddr == 0) {
                    160:                        statemap[inumber] = USTATE;
1.5       perseant  161:                        continue;
1.7       perseant  162:                }
1.14      perseant  163:                if (dins[i]->daddr != LFS_UNUSED_DADDR) {
1.5       perseant  164:                        checkinode(inumber, &idesc);
                    165:                } else {
                    166:                        statemap[inumber] = USTATE;
                    167:                }
                    168:                free(dins[i]);
1.6       perseant  169:        }
1.5       perseant  170:        free(dins);
1.1       perseant  171: }
                    172:
1.14      perseant  173: void
1.6       perseant  174: checkinode(ino_t inumber, struct inodesc * idesc)
1.1       perseant  175: {
1.15      fvdl      176:        struct ufs1_dinode *dp;
1.14      perseant  177:        struct uvnode  *vp;
                    178:        struct zlncnt *zlnp;
                    179:        int ndb, j;
                    180:        mode_t mode;
1.1       perseant  181:
1.14      perseant  182:        vp = vget(fs, inumber);
1.16      yamt      183:        if (vp)
                    184:                dp = VTOD(vp);
                    185:        else
                    186:                dp = NULL;
1.1       perseant  187:
1.6       perseant  188:        if (dp == NULL) {
                    189:                /* pwarn("Could not find inode %ld\n",(long)inumber); */
                    190:                statemap[inumber] = USTATE;
                    191:                return;
                    192:        }
1.1       perseant  193:        mode = dp->di_mode & IFMT;
                    194:
1.6       perseant  195:        /* XXX - LFS doesn't have this particular problem (?) */
1.1       perseant  196:        if (mode == 0) {
1.14      perseant  197:                if (memcmp(dp->di_db, zino.di_db, NDADDR * sizeof(ufs_daddr_t)) ||
                    198:                    memcmp(dp->di_ib, zino.di_ib, NIADDR * sizeof(ufs_daddr_t)) ||
1.1       perseant  199:                    dp->di_mode || dp->di_size) {
                    200:                        pwarn("mode=o%o, ifmt=o%o\n", dp->di_mode, mode);
1.22      christos  201:                        pfatal("PARTIALLY ALLOCATED INODE I=%llu",
                    202:                            (unsigned long long)inumber);
1.1       perseant  203:                        if (reply("CLEAR") == 1) {
1.14      perseant  204:                                vp = vget(fs, inumber);
1.18      yamt      205:                                clearinode(inumber);
                    206:                                vnode_destroy(vp);
1.1       perseant  207:                        }
                    208:                }
                    209:                statemap[inumber] = USTATE;
                    210:                return;
                    211:        }
                    212:        lastino = inumber;
1.14      perseant  213:        if (dp->di_size < 0 || dp->di_size + fs->lfs_bsize - 1 < dp->di_size) {
1.1       perseant  214:                if (debug)
1.9       lukem     215:                        printf("bad size %llu:",
1.14      perseant  216:                            (unsigned long long) dp->di_size);
1.1       perseant  217:                goto unknown;
                    218:        }
                    219:        if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) {
1.14      perseant  220:                vp = vget(fs, inumber);
                    221:                dp = VTOD(vp);
                    222:                dp->di_size = fs->lfs_fsize;
1.6       perseant  223:                dp->di_mode = IFREG | 0600;
1.14      perseant  224:                inodirty(VTOI(vp));
1.1       perseant  225:        }
1.14      perseant  226:        ndb = howmany(dp->di_size, fs->lfs_bsize);
1.1       perseant  227:        if (ndb < 0) {
                    228:                if (debug)
1.9       lukem     229:                        printf("bad size %llu ndb %d:",
1.14      perseant  230:                            (unsigned long long) dp->di_size, ndb);
1.1       perseant  231:                goto unknown;
                    232:        }
                    233:        if (mode == IFBLK || mode == IFCHR)
                    234:                ndb++;
                    235:        if (mode == IFLNK) {
                    236:                /*
                    237:                 * Fake ndb value so direct/indirect block checks below
                    238:                 * will detect any garbage after symlink string.
                    239:                 */
1.14      perseant  240:                if (dp->di_size < fs->lfs_maxsymlinklen ||
                    241:                    (fs->lfs_maxsymlinklen == 0 && dp->di_blocks == 0)) {
                    242:                        ndb = howmany(dp->di_size, sizeof(ufs_daddr_t));
1.1       perseant  243:                        if (ndb > NDADDR) {
                    244:                                j = ndb - NDADDR;
                    245:                                for (ndb = 1; j > 1; j--)
1.14      perseant  246:                                        ndb *= NINDIR(fs);
1.1       perseant  247:                                ndb += NDADDR;
                    248:                        }
                    249:                }
                    250:        }
                    251:        for (j = ndb; j < NDADDR; j++)
                    252:                if (dp->di_db[j] != 0) {
                    253:                        if (debug)
                    254:                                printf("bad direct addr: %d\n", dp->di_db[j]);
                    255:                        goto unknown;
                    256:                }
                    257:        for (j = 0, ndb -= NDADDR; ndb > 0; j++)
1.14      perseant  258:                ndb /= NINDIR(fs);
1.1       perseant  259:        for (; j < NIADDR; j++)
                    260:                if (dp->di_ib[j] != 0) {
                    261:                        if (debug)
                    262:                                printf("bad indirect addr: %d\n",
1.14      perseant  263:                                    dp->di_ib[j]);
1.5       perseant  264:                        /* goto unknown; */
1.1       perseant  265:                }
                    266:        if (ftypeok(dp) == 0)
                    267:                goto unknown;
                    268:        n_files++;
                    269:        lncntp[inumber] = dp->di_nlink;
                    270:        if (dp->di_nlink <= 0) {
1.14      perseant  271:                zlnp = (struct zlncnt *) malloc(sizeof *zlnp);
1.1       perseant  272:                if (zlnp == NULL) {
                    273:                        pfatal("LINK COUNT TABLE OVERFLOW");
                    274:                        if (reply("CONTINUE") == 0)
1.14      perseant  275:                                err(8, "%s", "");
1.1       perseant  276:                } else {
                    277:                        zlnp->zlncnt = inumber;
                    278:                        zlnp->next = zlnhead;
                    279:                        zlnhead = zlnp;
                    280:                }
                    281:        }
                    282:        if (mode == IFDIR) {
                    283:                if (dp->di_size == 0)
                    284:                        statemap[inumber] = DCLEAR;
                    285:                else
                    286:                        statemap[inumber] = DSTATE;
                    287:                cacheino(dp, inumber);
                    288:        } else
                    289:                statemap[inumber] = FSTATE;
                    290:        typemap[inumber] = IFTODT(mode);
                    291:        badblk = dupblk = 0;
                    292:        idesc->id_number = inumber;
1.14      perseant  293:        (void) ckinode(VTOD(vp), idesc);
1.1       perseant  294:        if (dp->di_blocks != idesc->id_entryno) {
1.22      christos  295:                pwarn("INCORRECT BLOCK COUNT I=%llu (%d should be %d)",
                    296:                    (unsigned long long)inumber, dp->di_blocks,
                    297:                    idesc->id_entryno);
1.1       perseant  298:                if (preen)
                    299:                        printf(" (CORRECTED)\n");
                    300:                else if (reply("CORRECT") == 0)
                    301:                        return;
1.15      fvdl      302:                VTOI(vp)->i_ffs1_blocks = idesc->id_entryno;
1.14      perseant  303:                inodirty(VTOI(vp));
1.1       perseant  304:        }
                    305:        return;
                    306: unknown:
1.22      christos  307:        pfatal("UNKNOWN FILE TYPE I=%llu", (unsigned long long)inumber);
1.1       perseant  308:        statemap[inumber] = FCLEAR;
                    309:        if (reply("CLEAR") == 1) {
                    310:                statemap[inumber] = USTATE;
1.14      perseant  311:                vp = vget(fs, inumber);
1.18      yamt      312:                clearinode(inumber);
                    313:                vnode_destroy(vp);
1.1       perseant  314:        }
                    315: }
                    316:
                    317: int
1.14      perseant  318: pass1check(struct inodesc *idesc)
1.1       perseant  319: {
1.14      perseant  320:        int res = KEEPON;
                    321:        int anyout, ndblks;
                    322:        daddr_t blkno = idesc->id_blkno;
1.20      perry     323:        struct dups *dlp;
1.14      perseant  324:        struct dups *new;
1.1       perseant  325:
1.14      perseant  326:        if ((anyout = chkrange(blkno, fragstofsb(fs, idesc->id_numfrags))) != 0) {
1.1       perseant  327:                blkerror(idesc->id_number, "BAD", blkno);
                    328:                if (badblk++ >= MAXBAD) {
1.22      christos  329:                        pwarn("EXCESSIVE BAD BLKS I=%llu",
                    330:                            (unsigned long long)idesc->id_number);
1.1       perseant  331:                        if (preen)
                    332:                                printf(" (SKIPPING)\n");
                    333:                        else if (reply("CONTINUE") == 0)
1.14      perseant  334:                                err(8, "%s", "");
1.1       perseant  335:                        return (STOP);
                    336:                }
1.8       perseant  337:        } else if (!testbmap(blkno)) {
1.14      perseant  338:                seg_table[dtosn(fs, blkno)].su_nbytes += idesc->id_numfrags * fs->lfs_fsize;
1.1       perseant  339:        }
1.14      perseant  340:        for (ndblks = fragstofsb(fs, idesc->id_numfrags); ndblks > 0; blkno++, ndblks--) {
1.1       perseant  341:                if (anyout && chkrange(blkno, 1)) {
                    342:                        res = SKIP;
                    343:                } else if (!testbmap(blkno)) {
                    344:                        n_blks++;
                    345: #ifndef VERBOSE_BLOCKMAP
                    346:                        setbmap(blkno);
                    347: #else
1.6       perseant  348:                        setbmap(blkno, idesc->id_number);
1.1       perseant  349: #endif
                    350:                } else {
                    351:                        blkerror(idesc->id_number, "DUP", blkno);
                    352: #ifdef VERBOSE_BLOCKMAP
1.6       perseant  353:                        pwarn("(lbn %d: Holder is %d)\n", idesc->id_lblkno,
1.14      perseant  354:                            testbmap(blkno));
1.1       perseant  355: #endif
                    356:                        if (dupblk++ >= MAXDUP) {
1.22      christos  357:                                pwarn("EXCESSIVE DUP BLKS I=%llu",
                    358:                                    (unsigned long long)idesc->id_number);
1.1       perseant  359:                                if (preen)
                    360:                                        printf(" (SKIPPING)\n");
                    361:                                else if (reply("CONTINUE") == 0)
1.14      perseant  362:                                        err(8, "%s", "");
1.1       perseant  363:                                return (STOP);
                    364:                        }
1.14      perseant  365:                        new = (struct dups *) malloc(sizeof(struct dups));
1.1       perseant  366:                        if (new == NULL) {
                    367:                                pfatal("DUP TABLE OVERFLOW.");
                    368:                                if (reply("CONTINUE") == 0)
1.14      perseant  369:                                        err(8, "%s", "");
1.1       perseant  370:                                return (STOP);
                    371:                        }
                    372:                        new->dup = blkno;
                    373:                        if (muldup == 0) {
                    374:                                duplist = muldup = new;
                    375:                                new->next = 0;
                    376:                        } else {
                    377:                                new->next = muldup->next;
                    378:                                muldup->next = new;
                    379:                        }
                    380:                        for (dlp = duplist; dlp != muldup; dlp = dlp->next)
                    381:                                if (dlp->dup == blkno)
                    382:                                        break;
                    383:                        if (dlp == muldup && dlp->dup != blkno)
                    384:                                muldup = new;
                    385:                }
                    386:                /*
                    387:                 * count the number of blocks found in id_entryno
                    388:                 */
1.6       perseant  389:                idesc->id_entryno++;
1.1       perseant  390:        }
                    391:        return (res);
                    392: }

CVSweb <webmaster@jp.NetBSD.org>