Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/ufs/lfs Keep track of the highest block held by an LFS i...



details:   https://anonhg.NetBSD.org/src/rev/fc9a41a18d76
branches:  trunk
changeset: 580181:fc9a41a18d76
user:      perseant <perseant%NetBSD.org@localhost>
date:      Thu Apr 14 00:02:46 2005 +0000

description:
Keep track of the highest block held by an LFS inode, so that we can
be assured that the last byte of a file is always allocated.  Previously
a file extension could cause the filesystem to be flushed, writing an
inconsistent inode to disk.  Although this condition would be corrected
the next time blocks were written to disk, an intervening crash would leave
the filesystem in an inconsistent state, leaving fsck_lfs to complain
of an inode "partially truncated".

diffstat:

 sys/ufs/lfs/lfs.h         |   4 ++-
 sys/ufs/lfs/lfs_alloc.c   |   8 ++++-
 sys/ufs/lfs/lfs_inode.c   |   7 ++++-
 sys/ufs/lfs/lfs_segment.c |  57 ++++++++++++++++++++++++++++++++++++++++------
 sys/ufs/lfs/lfs_vfsops.c  |   7 ++++-
 5 files changed, 68 insertions(+), 15 deletions(-)

diffs (231 lines):

diff -r 805c956cd070 -r fc9a41a18d76 sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Wed Apr 13 23:12:01 2005 +0000
+++ b/sys/ufs/lfs/lfs.h Thu Apr 14 00:02:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs.h,v 1.78 2005/04/01 21:59:46 perseant Exp $        */
+/*     $NetBSD: lfs.h,v 1.79 2005/04/14 00:02:46 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -963,6 +963,7 @@
        LIST_HEAD(, lbnentry) lfs_blist[LFS_BLIST_HASH_WIDTH];
 #define LFSI_NO_GOP_WRITE 0x01
        u_int32_t lfs_iflags;           /* Inode flags */
+       daddr_t   lfs_hiblk;            /* Highest lbn held by inode */
 };
 #define i_lfs_osize            inode_ext.lfs->lfs_osize
 #define i_lfs_effnblks         inode_ext.lfs->lfs_effnblocks
@@ -970,6 +971,7 @@
 #define i_lfs_dchain           inode_ext.lfs->lfs_dchain
 #define i_lfs_blist            inode_ext.lfs->lfs_blist
 #define i_lfs_iflags           inode_ext.lfs->lfs_iflags
+#define i_lfs_hiblk            inode_ext.lfs->lfs_hiblk
 
 /*
  * Macros for determining free space on the disk, with the variable metadata
diff -r 805c956cd070 -r fc9a41a18d76 sys/ufs/lfs/lfs_alloc.c
--- a/sys/ufs/lfs/lfs_alloc.c   Wed Apr 13 23:12:01 2005 +0000
+++ b/sys/ufs/lfs/lfs_alloc.c   Thu Apr 14 00:02:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_alloc.c,v 1.78 2005/04/01 21:59:46 perseant Exp $  */
+/*     $NetBSD: lfs_alloc.c,v 1.79 2005/04/14 00:02:46 perseant Exp $  */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.78 2005/04/01 21:59:46 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.79 2005/04/14 00:02:46 perseant Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -83,6 +83,7 @@
 #include <sys/mount.h>
 #include <sys/pool.h>
 #include <sys/proc.h>
+#include <sys/malloc.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
@@ -383,6 +384,9 @@
        /* on-disk structure has been zeroed out by lfs_vcreate */
        ip->i_din.ffs1_din->di_inumber = new_ino;
 
+       /* Note no blocks yet */
+       ip->i_lfs_hiblk = -1;
+
        /* Set a new generation number for this inode. */
        if (new_gen) {
                ip->i_gen = new_gen;
diff -r 805c956cd070 -r fc9a41a18d76 sys/ufs/lfs/lfs_inode.c
--- a/sys/ufs/lfs/lfs_inode.c   Wed Apr 13 23:12:01 2005 +0000
+++ b/sys/ufs/lfs/lfs_inode.c   Thu Apr 14 00:02:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_inode.c,v 1.91 2005/04/01 21:59:46 perseant Exp $  */
+/*     $NetBSD: lfs_inode.c,v 1.92 2005/04/14 00:02:46 perseant Exp $  */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.91 2005/04/01 21:59:46 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.92 2005/04/14 00:02:46 perseant Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -321,6 +321,7 @@
                        uvm_vnp_setsize(ovp, length);
                        oip->i_flag |= IN_CHANGE | IN_UPDATE;
                        KASSERT(ovp->v_size == oip->i_size);
+                       oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
                        return (VOP_UPDATE(ovp, NULL, NULL, 0));
                } else {
                        error = lfs_reserve(fs, ovp, NULL,
@@ -337,6 +338,7 @@
                        uvm_vnp_setsize(ovp, length);
                        (void) VOP_BWRITE(bp);
                        oip->i_flag |= IN_CHANGE | IN_UPDATE;
+                       oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
                        return (VOP_UPDATE(ovp, NULL, NULL, 0));
                }
        }
@@ -592,6 +594,7 @@
            -btofsb(fs, (2 * NIADDR + 3) << fs->lfs_bshift));
        lockmgr(&gp->g_glock, LK_RELEASE, NULL);
   errout:
+       oip->i_lfs_hiblk = lblkno(fs, oip->i_size + fs->lfs_bsize - 1) - 1;
        lfs_segunlock(fs);
        return (allerror ? allerror : error);
 }
diff -r 805c956cd070 -r fc9a41a18d76 sys/ufs/lfs/lfs_segment.c
--- a/sys/ufs/lfs/lfs_segment.c Wed Apr 13 23:12:01 2005 +0000
+++ b/sys/ufs/lfs/lfs_segment.c Thu Apr 14 00:02:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_segment.c,v 1.159 2005/04/01 21:59:46 perseant Exp $       */
+/*     $NetBSD: lfs_segment.c,v 1.160 2005/04/14 00:02:46 perseant Exp $       */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.159 2005/04/01 21:59:46 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.160 2005/04/14 00:02:46 perseant Exp $");
 
 #ifdef DEBUG
 # define vndebug(vp, str) do {                                         \
@@ -897,16 +897,31 @@
 
        /*
         * If we are cleaning, ensure that we don't write UNWRITTEN disk
-        * addresses to disk; possibly revert the inode size.
-        * XXX By not writing these blocks, we are making the lfs_avail
+        * addresses to disk; possibly change the on-disk record of
+        * the inode size, either by reverting to the previous size
+        * (in the case of cleaning) or by verifying the inode's block
+        * holdings (in the case of files being allocated as they are being
+        * written).
+        * XXX By not writing UNWRITTEN blocks, we are making the lfs_avail
         * XXX count on disk wrong by the same amount.  We should be
         * XXX able to "borrow" from lfs_avail and return it after the
         * XXX Ifile is written.  See also in lfs_writeseg.
         */
+
+       /* Check file size based on highest allocated block */
+       if (((ip->i_ffs1_mode & IFMT) == IFREG ||
+            (ip->i_ffs1_mode & IFMT) == IFREG) &&
+           ip->i_size > ((ip->i_lfs_hiblk + 1) << fs->lfs_bshift)) {
+               cdp->di_size = (ip->i_lfs_hiblk + 1) << fs->lfs_bshift;
+               DLOG((DLOG_SEG, "lfs_writeinode: ino %d size %" PRId64 " -> %"
+                     PRId64 "\n", (int)ip->i_number, ip->i_size, cdp->di_size));
+       }
        if (ip->i_lfs_effnblks != ip->i_ffs1_blocks) {
-               cdp->di_size = ip->i_lfs_osize;
-               DLOG((DLOG_VNODE, "lfs_writeinode: cleansing ino %d (%d != %d)\n",
-                     ip->i_number, ip->i_lfs_effnblks, ip->i_ffs1_blocks));
+               if (ip->i_flags & IN_CLEANING)
+                       cdp->di_size = ip->i_lfs_osize;
+               DLOG((DLOG_SEG, "lfs_writeinode: cleansing ino %d eff %d != nblk %d)"
+                     " at %x\n", ip->i_number, ip->i_lfs_effnblks,
+                     ip->i_ffs1_blocks, fs->lfs_offset));
                for (daddrp = cdp->di_db; daddrp < cdp->di_ib + NIADDR;
                     daddrp++) {
                        if (*daddrp == UNWRITTEN) {
@@ -915,10 +930,32 @@
                        }
                }
        } else {
-               /* If all blocks are goig to disk, update the "size on disk" */
+               /* If all blocks are going to disk, update "size on disk" */
                ip->i_lfs_osize = ip->i_size;
        }
 
+#ifdef DIAGNOSTIC
+       /*
+        * Check dinode held blocks against dinode size.
+        * This should be identical to the check in lfs_vget().
+        */
+       for (i = (cdp->di_size + fs->lfs_bsize - 1) >> fs->lfs_bshift;
+            i < NDADDR; i++) {
+               KASSERT(i >= 0);
+               if ((cdp->di_mode & IFMT) == IFLNK)
+                       continue;
+               if (((cdp->di_mode & IFMT) == IFBLK ||
+                    (cdp->di_mode & IFMT) == IFCHR) && i == 0)
+                       continue;
+               if (cdp->di_db[i] != 0) {
+# ifdef DEBUG
+                       lfs_dump_dinode(cdp);
+# endif
+                       panic("writing inconsistent inode");
+               }
+       }
+#endif /* DIAGNOSTIC */
+
        if (ip->i_flag & IN_CLEANING)
                LFS_CLR_UINO(ip, IN_CLEANING);
        else {
@@ -1256,6 +1293,10 @@
 
        KASSERT(ooff == 0 || ooff == UNWRITTEN || ooff == daddr);
 
+       /* Update hiblk when extending the file */
+       if (lbn > ip->i_lfs_hiblk)
+               ip->i_lfs_hiblk = lbn;
+
        /*
         * Though we'd rather it couldn't, this *can* happen right now
         * if cleaning blocks and regular blocks coexist.
diff -r 805c956cd070 -r fc9a41a18d76 sys/ufs/lfs/lfs_vfsops.c
--- a/sys/ufs/lfs/lfs_vfsops.c  Wed Apr 13 23:12:01 2005 +0000
+++ b/sys/ufs/lfs/lfs_vfsops.c  Thu Apr 14 00:02:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_vfsops.c,v 1.171 2005/04/08 00:08:42 perseant Exp $        */
+/*     $NetBSD: lfs_vfsops.c,v 1.172 2005/04/14 00:02:46 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.171 2005/04/08 00:08:42 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.172 2005/04/14 00:02:46 perseant Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -2298,6 +2298,9 @@
        genfs_node_init(vp, &lfs_genfsops);
        uvm_vnp_setsize(vp, ip->i_size);
 
+       /* Initialize hiblk from file size */
+       ip->i_lfs_hiblk = lblkno(ip->i_lfs, ip->i_size + ip->i_lfs->lfs_bsize - 1) - 1;
+
        *vpp = vp;
 }
 



Home | Main Index | Thread Index | Old Index