Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs Fixes associated with filling an LFS:



details:   https://anonhg.NetBSD.org/src/rev/bc12075e973e
branches:  trunk
changeset: 493950:bc12075e973e
user:      perseant <perseant%NetBSD.org@localhost>
date:      Tue Jun 27 20:57:11 2000 +0000

description:
Fixes associated with filling an LFS:

Change the space computation to appear to change the size of the *disk*
rather than the *bytes used* when more segment summaries and inode
blocks are written.  Try to estimate the amount of space that these will
take up when more files are written, so the disk size doesn't change too
much.

Regularize error returns from lfs_valloc, lfs_balloc, lfs_truncate: they
now fail entirely, rather than succeeding half-way and leaving the fs in
an inconsistent state.

Rewrite lfs_truncate, mostly stealing from ffs_truncate.  The old
lfs_truncate had difficulty truncating a large file to a non-zero size
(indirect blocks were not handled appropriately).

Unmark VDIROP on fvp after ufs_remove, ufs_rmdir, so these can be
reclaimed immediately: this vnode would not be written to disk again
anyway if the removal succeeded, and if it failed, no directory
operation occurred.

ufs_makeinode and ufs_mkdir now remove IN_ADIROP on error.

diffstat:

 sys/ufs/lfs/lfs.h          |   44 +-
 sys/ufs/lfs/lfs_alloc.c    |   49 ++-
 sys/ufs/lfs/lfs_balloc.c   |  224 ++++++------
 sys/ufs/lfs/lfs_bio.c      |   26 +-
 sys/ufs/lfs/lfs_extern.h   |    7 +-
 sys/ufs/lfs/lfs_inode.c    |  786 +++++++++++++++++++++++++-------------------
 sys/ufs/lfs/lfs_segment.c  |   22 +-
 sys/ufs/lfs/lfs_subr.c     |   12 +-
 sys/ufs/lfs/lfs_syscalls.c |   64 +--
 sys/ufs/lfs/lfs_vfsops.c   |   28 +-
 sys/ufs/lfs/lfs_vnops.c    |  125 +++++-
 sys/ufs/ufs/ufs_vnops.c    |   12 +-
 12 files changed, 809 insertions(+), 590 deletions(-)

diffs (truncated from 2190 to 300 lines):

diff -r 83ae99744917 -r bc12075e973e sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Tue Jun 27 20:47:49 2000 +0000
+++ b/sys/ufs/lfs/lfs.h Tue Jun 27 20:57:11 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs.h,v 1.25 2000/06/06 20:19:14 perseant Exp $        */
+/*     $NetBSD: lfs.h,v 1.26 2000/06/27 20:57:11 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -121,7 +121,7 @@
 }
 #endif
 
-#define WRITEINPROG(vp) (vp->v_dirtyblkhd.lh_first && !(VTOI(vp)->i_flag & (IN_MODIFIED|IN_CLEANING)))
+#define WRITEINPROG(vp) (vp->v_dirtyblkhd.lh_first && !(VTOI(vp)->i_flag & (IN_MODIFIED|IN_ACCESSED|IN_CLEANING)))
 
 /* Here begins the berkeley code */
 
@@ -220,9 +220,10 @@
        u_char    dlfs_fsmnt[MNAMELEN];  /* 232: name mounted on */
        /* XXX this is 2 bytes only to pad to a quad boundary */
        u_int16_t dlfs_clean;     /* 322: file system is clean flag */
-        int8_t    dlfs_pad[184];  /* 324: round to 512 bytes */
+       u_int32_t dlfs_dmeta;     /* 324: total number of dirty summaries */
+        int8_t    dlfs_pad[180];  /* 328: round to 512 bytes */
 /* Checksum -- last valid disk field. */
-        u_int32_t dlfs_cksum;     /* 328: checksum for superblock checking */
+        u_int32_t dlfs_cksum;     /* 508: checksum for superblock checking */
 };
 
 /* Maximum number of io's we can have pending at once */
@@ -279,6 +280,8 @@
 #define lfs_clean lfs_dlfs.dlfs_clean
 #define lfs_fsmnt lfs_dlfs.dlfs_fsmnt
 #define lfs_nclean lfs_dlfs.dlfs_nclean
+#define lfs_dmeta lfs_dlfs.dlfs_dmeta
+
 /* These fields are set at mount time and are meaningless on disk. */
        struct segment *lfs_sp;         /* current segment being written */
        struct vnode *lfs_ivnode;       /* vnode for the ifile */
@@ -494,15 +497,36 @@
        u_int16_t seg_flags;            /* run-time flags for this segment */
 };
 
+/*
+ * Mecros for determining free space on the disk, with the variable metadata
+ * of segment summaries and inode blocks taken into account.
+ */
+/* Estimate number of clean blocks not available for writing */
+#define LFS_EST_CMETA(F) ((u_int32_t)(((F)->lfs_dmeta *                     \
+                                      (u_int64_t)(F)->lfs_nclean) /        \
+                                     ((F)->lfs_nseg - (F)->lfs_nclean)))
+
+/* Estimate total size of the disk not including metadata */
+#define LFS_EST_NONMETA(F) ((F)->lfs_dsize - fsbtodb((F), MIN_FREE_SEGS *   \
+                                                    (F)->lfs_ssize) -      \
+                           (F)->lfs_dmeta - LFS_EST_CMETA(F))
+
+/* Estimate number of blocks actually available for writing */
+#define LFS_EST_BFREE(F) ((F)->lfs_bfree - LFS_EST_CMETA(F))
+
+/* Amount of non-meta space not available to mortal man */
+#define LFS_EST_RSVD(F) ((u_int32_t)(((LFS_EST_NONMETA(F) *         \
+                                      (u_int64_t)(F)->lfs_minfree)) / 100))
+
+/* Can credential C write BB blocks */
 #define ISSPACE(F, BB, C)                                              \
-       (((C)->cr_uid == 0 && (F)->lfs_bfree >= (BB)) ||                \
-       ((C)->cr_uid != 0 && IS_FREESPACE(F, BB)))
+       ((((C) == NOCRED || (C)->cr_uid == 0) &&                        \
+          LFS_EST_BFREE(F) >= (BB)) ||                                 \
+        ((C)->cr_uid != 0 && IS_FREESPACE(F, BB)))
 
+/* Can an ordinary user write BB blocks */
 #define IS_FREESPACE(F, BB)                                            \
-       ((F)->lfs_bfree > ((F)->lfs_dsize * (F)->lfs_minfree / 100 + (BB)))
-
-#define ISSPACE_XXX(F, BB)                                             \
-       ((F)->lfs_bfree >= (BB))
+          (LFS_EST_BFREE(F) >= (BB) + LFS_EST_RSVD(F))
 
 /* Statistics Counters */
 struct lfs_stats {
diff -r 83ae99744917 -r bc12075e973e sys/ufs/lfs/lfs_alloc.c
--- a/sys/ufs/lfs/lfs_alloc.c   Tue Jun 27 20:47:49 2000 +0000
+++ b/sys/ufs/lfs/lfs_alloc.c   Tue Jun 27 20:57:11 2000 +0000
@@ -1,7 +1,7 @@
-/*     $NetBSD: lfs_alloc.c,v 1.37 2000/06/22 18:46:57 perseant Exp $  */
+/*     $NetBSD: lfs_alloc.c,v 1.38 2000/06/27 20:57:12 perseant Exp $  */
 
 /*-
- * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -94,6 +94,7 @@
 #include <ufs/lfs/lfs.h>
 #include <ufs/lfs/lfs_extern.h>
 
+extern int lfs_dirvcount;
 extern struct lock ufs_hashlock;
 
 /* Allocate a new inode. */
@@ -121,6 +122,9 @@
        extern int lfs_dirvcount;
 
        fs = VTOI(ap->a_pvp)->i_lfs;
+       if (fs->lfs_ronly)
+               return EROFS;
+       *ap->a_vpp = NULL;
        
        /*
         * Use lfs_seglock here, instead of fs->lfs_freelock, to ensure that
@@ -166,17 +170,21 @@
        /* Extend IFILE so that the next lfs_valloc will succeed. */
        if (fs->lfs_free == LFS_UNUSED_INUM) {
                vp = fs->lfs_ivnode;
-               VOP_LOCK(vp,LK_EXCLUSIVE);
+               (void)lfs_vref(vp);
+               vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
                ip = VTOI(vp);
                blkno = lblkno(fs, ip->i_ffs_size);
                if ((error = VOP_BALLOC(vp, ip->i_ffs_size, fs->lfs_bsize,
-                   NULL, 0, &bp)) != 0) {
+                                       ap->a_cred, 0, &bp)) != 0) {
+                       VOP_UNLOCK(vp, 0);
                        lfs_segunlock(fs);
+                       fs->lfs_free = new_ino;
                        return (error);
                }
                ip->i_ffs_size += fs->lfs_bsize;
                uvm_vnp_setsize(vp, ip->i_ffs_size);
                (void)uvm_vnp_uncache(vp);
+               VOP_UNLOCK(vp, 0);
 
                i = (blkno - fs->lfs_segtabsz - fs->lfs_cleansz) *
                        fs->lfs_ifpb;
@@ -193,11 +201,8 @@
                }
                ifp--;
                ifp->if_nextfree = LFS_UNUSED_INUM;
-               VOP_UNLOCK(vp,0);
-               if ((error = VOP_BWRITE(bp)) != 0) {
-                       lfs_segunlock(fs);
-                       return (error);
-               }
+               VOP_BWRITE(bp);
+               lfs_vunref(vp);
        }
 #ifdef DIAGNOSTIC
        if(fs->lfs_free == LFS_UNUSED_INUM)
@@ -210,7 +215,7 @@
        /* Create a vnode to associate with the inode. */
        if ((error = lfs_vcreate(ap->a_pvp->v_mount, new_ino, &vp)) != 0) {
                lockmgr(&ufs_hashlock, LK_RELEASE, 0);
-               return (error);
+               goto errout;
        }
        
        ip = VTOI(vp);
@@ -228,26 +233,38 @@
        error = ufs_vinit(vp->v_mount, lfs_specop_p, lfs_fifoop_p, &vp);
        if (error) {
                vput(vp);
-               *ap->a_vpp = NULL;
-               return (error);
+               goto errout;
        }
        
        *ap->a_vpp = vp;
+#if 1
        if(!(vp->v_flag & VDIROP)) {
                (void)lfs_vref(vp);
                ++lfs_dirvcount;
        }
        vp->v_flag |= VDIROP;
-       VREF(ip->i_devvp);
        
        if(!(ip->i_flag & IN_ADIROP))
                ++fs->lfs_nadirop;
        ip->i_flag |= IN_ADIROP;
-
+#endif
+       VREF(ip->i_devvp);
        /* Set superblock modified bit and increment file count. */
        fs->lfs_fmod = 1;
        ++fs->lfs_nfiles;
        return (0);
+
+    errout:
+       /*
+        * Put the new inum back on the free list.
+        */
+       LFS_IENTRY(ifp, fs, new_ino, bp);
+       ifp->if_daddr = LFS_UNUSED_DADDR;
+       ifp->if_nextfree = fs->lfs_free;
+       fs->lfs_free = new_ino;
+       VOP_BWRITE(bp);
+
+       return (error);
 }
 
 /* Create a new vnode/inode pair and initialize what fields we can. */
@@ -341,6 +358,10 @@
                wakeup(&lfs_dirvcount);
                lfs_vunref(vp);
        }
+       if (ip->i_flag & IN_ADIROP) {
+               --fs->lfs_nadirop;
+               ip->i_flag &= ~IN_ADIROP;
+       }
 
        if (ip->i_flag & IN_CLEANING) {
                --fs->lfs_uinodes;
diff -r 83ae99744917 -r bc12075e973e sys/ufs/lfs/lfs_balloc.c
--- a/sys/ufs/lfs/lfs_balloc.c  Tue Jun 27 20:47:49 2000 +0000
+++ b/sys/ufs/lfs/lfs_balloc.c  Tue Jun 27 20:57:11 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_balloc.c,v 1.18 2000/06/06 20:19:15 perseant Exp $ */
+/*     $NetBSD: lfs_balloc.c,v 1.19 2000/06/27 20:57:12 perseant Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -127,13 +127,13 @@
        struct vnode *vp;
        int offset;
        u_long iosize;
-       daddr_t lbn;
+       daddr_t daddr, idaddr;
        struct buf *ibp, *bp;
        struct inode *ip;
        struct lfs *fs;
        struct indir indirs[NIADDR+2], *idp;
-       ufs_daddr_t     daddr, lastblock;
-       int bb;         /* number of disk blocks in a block disk blocks */
+       ufs_daddr_t     lbn, lastblock;
+       int bb, bcount;
        int error, frags, i, nsize, osize, num;
 
        vp = ap->a_vp;  
@@ -153,20 +153,20 @@
        /* 
         * Three cases: it's a block beyond the end of file, it's a block in
         * the file that may or may not have been assigned a disk address or
-        * we're writing an entire block.  Note, if the daddr is unassigned,
-        * the block might still have existed in the cache (if it was read
-        * or written earlier).  If it did, make sure we don't count it as a
-        * new block or zero out its contents.  If it did not, make sure
-        * we allocate any necessary indirect blocks.
+        * we're writing an entire block.
+        *
+        * Note, if the daddr is UNWRITTEN, the block already exists in
+        * the cache (it was read or written earlier).  If so, make sure
+        * we don't count it as a new block or zero out its contents. If
+        * it did not, make sure we allocate any necessary indirect
+        * blocks.
+        *
         * If we are writing a block beyond the end of the file, we need to
         * check if the old last block was a fragment.  If it was, we need
         * to rewrite it.
         */
        
        *ap->a_bpp = NULL;
-       error = ufs_bmaparray(vp, lbn, &daddr, &indirs[0], &num, NULL );
-       if (error)
-               return (error);
        
        /* Check for block beyond end of file and fragment extension needed. */
        lastblock = lblkno(fs, ip->i_ffs_size);
@@ -182,47 +182,7 @@
                        VOP_BWRITE(bp);
                }
        }
-       
-       bb = VFSTOUFS(vp->v_mount)->um_seqinc;
-       if (daddr == UNASSIGNED) {
-               if (num > 0 && ip->i_ffs_ib[indirs[0].in_off] == 0) {
-                       ip->i_ffs_ib[indirs[0].in_off] = UNWRITTEN;
-               }
-               /* May need to allocate indirect blocks */
-               for (i = 1; i < num; ++i) {
-                       ibp = getblk(vp, indirs[i].in_lbn, fs->lfs_bsize, 0,0);
-                       if (!indirs[i].in_exists) {
-#ifdef DIAGNOSTIC
-                               if ((ibp->b_flags & (B_DONE | B_DELWRI)))
-                                       panic ("Indirect block should not exist");
-#endif
 
-                               if (!ISSPACE(fs, bb, curproc->p_ucred)){
-                                       ibp->b_flags |= B_INVAL;
-                                       brelse(ibp);
-                                       /* XXX might leave some UNWRITTENs hanging, do this better */
-                                       return(ENOSPC);
-                               } else {
-                                       ip->i_ffs_blocks += bb;
-                                       ip->i_lfs->lfs_bfree -= bb;
-                                       clrbuf(ibp);
-                                       ((ufs_daddr_t *)ibp->b_data)[indirs[i].in_off] = UNWRITTEN;
-                                       ibp->b_blkno = UNWRITTEN;



Home | Main Index | Thread Index | Old Index