BSD 4_3_Tahoe release
[unix-history] / usr / src / etc / fsck / utilities.c
index 41b5b7d..f677a21 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)utilities.c        5.2 (Berkeley) 9/10/85";
+static char sccsid[] = "@(#)utilities.c        5.13 (Berkeley) 6/7/88";
 #endif not lint
 
 #include <stdio.h>
 #endif not lint
 
 #include <stdio.h>
@@ -16,6 +16,7 @@ static char sccsid[] = "@(#)utilities.c       5.2 (Berkeley) 9/10/85";
 #include <sys/dir.h>
 #include "fsck.h"
 
 #include <sys/dir.h>
 #include "fsck.h"
 
+long   diskreads, totalreads;  /* Disk cache statistics */
 long   lseek();
 
 ftypeok(dp)
 long   lseek();
 
 ftypeok(dp)
@@ -42,15 +43,16 @@ reply(s)
        char *s;
 {
        char line[80];
        char *s;
 {
        char line[80];
+       int cont = (strcmp(s, "CONTINUE") == 0);
 
        if (preen)
                pfatal("INTERNAL ERROR: GOT TO reply()");
        printf("\n%s? ", s);
 
        if (preen)
                pfatal("INTERNAL ERROR: GOT TO reply()");
        printf("\n%s? ", s);
-       if (nflag || dfile.wfdes < 0) {
+       if (!cont && (nflag || dfile.wfdes < 0)) {
                printf(" no\n\n");
                return (0);
        }
                printf(" no\n\n");
                return (0);
        }
-       if (yflag) {
+       if (yflag || (cont && nflag)) {
                printf(" yes\n\n");
                return (1);
        }
                printf(" yes\n\n");
                return (1);
        }
@@ -82,6 +84,74 @@ getline(fp, loc, maxlen)
        return (p - loc);
 }
 
        return (p - loc);
 }
 
+/*
+ * Malloc buffers and set up cache.
+ */
+bufinit()
+{
+       register BUFAREA *bp;
+       long bufcnt, i;
+       char *bufp;
+
+       bufp = (char *)malloc(sblock.fs_bsize);
+       if (bufp == 0)
+               errexit("cannot allocate buffer pool\n");
+       cgblk.b_un.b_buf = bufp;
+       initbarea(&cgblk);
+       bufhead.b_next = bufhead.b_prev = &bufhead;
+       bufcnt = MAXBUFSPACE / sblock.fs_bsize;
+       if (bufcnt < MINBUFS)
+               bufcnt = MINBUFS;
+       for (i = 0; i < bufcnt; i++) {
+               bp = (BUFAREA *)malloc(sizeof(BUFAREA));
+               bufp = (char *)malloc(sblock.fs_bsize);
+               if (bp == 0 || bufp == 0) {
+                       if (i >= MINBUFS)
+                               break;
+                       errexit("cannot allocate buffer pool\n");
+               }
+               bp->b_un.b_buf = bufp;
+               bp->b_prev = &bufhead;
+               bp->b_next = bufhead.b_next;
+               bufhead.b_next->b_prev = bp;
+               bufhead.b_next = bp;
+               initbarea(bp);
+       }
+       bufhead.b_size = i;     /* save number of buffers */
+}
+
+/*
+ * Manage a cache of directory blocks.
+ */
+BUFAREA *
+getdatablk(blkno, size)
+       daddr_t blkno;
+       long size;
+{
+       register BUFAREA *bp;
+
+       for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next)
+               if (bp->b_bno == fsbtodb(&sblock, blkno))
+                       goto foundit;
+       for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev)
+               if ((bp->b_flags & B_INUSE) == 0)
+                       break;
+       if (bp == &bufhead)
+               errexit("deadlocked buffer pool\n");
+       getblk(bp, blkno, size);
+       /* fall through */
+foundit:
+       totalreads++;
+       bp->b_prev->b_next = bp->b_next;
+       bp->b_next->b_prev = bp->b_prev;
+       bp->b_prev = &bufhead;
+       bp->b_next = bufhead.b_next;
+       bufhead.b_next->b_prev = bp;
+       bufhead.b_next = bp;
+       bp->b_flags |= B_INUSE;
+       return (bp);
+}
+
 BUFAREA *
 getblk(bp, blk, size)
        register BUFAREA *bp;
 BUFAREA *
 getblk(bp, blk, size)
        register BUFAREA *bp;
@@ -96,6 +166,7 @@ getblk(bp, blk, size)
        if (bp->b_bno == dblk)
                return (bp);
        flush(fcp, bp);
        if (bp->b_bno == dblk)
                return (bp);
        flush(fcp, bp);
+       diskreads++;
        bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size);
        bp->b_bno = dblk;
        bp->b_size = size;
        bp->b_errs = bread(fcp, bp->b_un.b_buf, dblk, size);
        bp->b_bno = dblk;
        bp->b_size = size;
@@ -111,7 +182,9 @@ flush(fcp, bp)
        if (!bp->b_dirty)
                return;
        if (bp->b_errs != 0)
        if (!bp->b_dirty)
                return;
        if (bp->b_errs != 0)
-               pfatal("WRITING ZERO'ED BLOCK %d TO DISK\n", bp->b_bno);
+               pfatal("WRITING %sZERO'ED BLOCK %d TO DISK\n",
+                   (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
+                   bp->b_bno);
        bp->b_dirty = 0;
        bp->b_errs = 0;
        bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
        bp->b_dirty = 0;
        bp->b_errs = 0;
        bwrite(fcp, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size);
@@ -139,16 +212,26 @@ rwerr(s, blk)
 
 ckfini()
 {
 
 ckfini()
 {
+       register BUFAREA *bp;
+       int cnt = 0;
 
 
-       flush(&dfile, &fileblk);
        flush(&dfile, &sblk);
        flush(&dfile, &sblk);
-       if (sblk.b_bno != SBLOCK) {
-               sblk.b_bno = SBLOCK;
+       if (havesb && sblk.b_bno != SBOFF / dev_bsize &&
+           !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
+               sblk.b_bno = SBOFF / dev_bsize;
                sbdirty();
                flush(&dfile, &sblk);
        }
                sbdirty();
                flush(&dfile, &sblk);
        }
-       flush(&dfile, &inoblk);
        flush(&dfile, &cgblk);
        flush(&dfile, &cgblk);
+       for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) {
+               cnt++;
+               flush(&dfile, bp);
+       }
+       if (bufhead.b_size != cnt)
+               errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
+       if (debug)
+               printf("cache missed %d of %d (%d%%)\n", diskreads,
+                   totalreads, diskreads * 100 / totalreads);
        (void)close(dfile.rfdes);
        (void)close(dfile.wfdes);
 }
        (void)close(dfile.rfdes);
        (void)close(dfile.wfdes);
 }
@@ -162,19 +245,25 @@ bread(fcp, buf, blk, size)
        char *cp;
        int i, errs;
 
        char *cp;
        int i, errs;
 
-       if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
+       if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0)
                rwerr("SEEK", blk);
        else if (read(fcp->rfdes, buf, (int)size) == size)
                return (0);
        rwerr("READ", blk);
                rwerr("SEEK", blk);
        else if (read(fcp->rfdes, buf, (int)size) == size)
                return (0);
        rwerr("READ", blk);
-       if (lseek(fcp->rfdes, (long)dbtob(blk), 0) < 0)
+       if (lseek(fcp->rfdes, blk * dev_bsize, 0) < 0)
                rwerr("SEEK", blk);
        errs = 0;
                rwerr("SEEK", blk);
        errs = 0;
-       pfatal("THE FOLLOWING SECTORS COULD NOT BE READ:");
-       for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE) {
-               if (read(fcp->rfdes, cp, DEV_BSIZE) < 0) {
-                       printf(" %d,", blk + i / DEV_BSIZE);
-                       bzero(cp, DEV_BSIZE);
+       bzero(buf, size);
+       printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
+       for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
+               if (read(fcp->rfdes, cp, secsize) < 0) {
+                       lseek(fcp->rfdes, blk * dev_bsize + i + secsize, 0);
+                       if (secsize != dev_bsize && dev_bsize != 1)
+                               printf(" %d (%d),",
+                                   (blk * dev_bsize + i) / secsize,
+                                   blk + i / dev_bsize);
+                       else
+                               printf(" %d,", blk + i / dev_bsize);
                        errs++;
                }
        }
                        errs++;
                }
        }
@@ -193,19 +282,21 @@ bwrite(fcp, buf, blk, size)
 
        if (fcp->wfdes < 0)
                return;
 
        if (fcp->wfdes < 0)
                return;
-       if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
+       if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0)
                rwerr("SEEK", blk);
        else if (write(fcp->wfdes, buf, (int)size) == size) {
                fcp->mod = 1;
                return;
        }
        rwerr("WRITE", blk);
                rwerr("SEEK", blk);
        else if (write(fcp->wfdes, buf, (int)size) == size) {
                fcp->mod = 1;
                return;
        }
        rwerr("WRITE", blk);
-       if (lseek(fcp->wfdes, (long)dbtob(blk), 0) < 0)
+       if (lseek(fcp->wfdes, blk * dev_bsize, 0) < 0)
                rwerr("SEEK", blk);
                rwerr("SEEK", blk);
-       pfatal("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
-       for (cp = buf, i = 0; i < size; i += DEV_BSIZE, cp += DEV_BSIZE)
-               if (write(fcp->wfdes, cp, DEV_BSIZE) < 0)
-                       printf(" %d,", blk + i / DEV_BSIZE);
+       printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
+       for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
+               if (write(fcp->wfdes, cp, dev_bsize) < 0) {
+                       lseek(fcp->rfdes, blk * dev_bsize + i + dev_bsize, 0);
+                       printf(" %d,", blk + i / dev_bsize);
+               }
        printf("\n");
        return;
 }
        printf("\n");
        return;
 }
@@ -273,7 +364,7 @@ getpathname(namebuf, curdir, ino)
        bzero(&idesc, sizeof(struct inodesc));
        idesc.id_type = DATA;
        cp = &namebuf[BUFSIZ - 1];
        bzero(&idesc, sizeof(struct inodesc));
        idesc.id_type = DATA;
        cp = &namebuf[BUFSIZ - 1];
-       *cp-- = '\0';
+       *cp = '\0';
        if (curdir != ino) {
                idesc.id_parent = curdir;
                goto namelookup;
        if (curdir != ino) {
                idesc.id_parent = curdir;
                goto namelookup;
@@ -282,14 +373,14 @@ getpathname(namebuf, curdir, ino)
                idesc.id_number = ino;
                idesc.id_func = findino;
                idesc.id_name = "..";
                idesc.id_number = ino;
                idesc.id_func = findino;
                idesc.id_name = "..";
-               if ((ckinode(ginode(ino), &idesc) & STOP) == 0)
+               if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
                        break;
        namelookup:
                idesc.id_number = idesc.id_parent;
                idesc.id_parent = ino;
                idesc.id_func = findname;
                idesc.id_name = namebuf;
                        break;
        namelookup:
                idesc.id_number = idesc.id_parent;
                idesc.id_parent = ino;
                idesc.id_func = findname;
                idesc.id_name = namebuf;
-               if ((ckinode(ginode(idesc.id_number), &idesc) & STOP) == 0)
+               if ((ckinode(ginode(idesc.id_number), &idesc) & FOUND) == 0)
                        break;
                len = strlen(namebuf);
                cp -= len;
                        break;
                len = strlen(namebuf);
                cp -= len;