Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs/lfs Correct accounting of lfs_avail, locked_queue_co...



details:   https://anonhg.NetBSD.org/src/rev/eb3582a8e9cf
branches:  trunk
changeset: 499343:eb3582a8e9cf
user:      perseant <perseant%NetBSD.org@localhost>
date:      Fri Nov 17 19:14:41 2000 +0000

description:
Correct accounting of lfs_avail, locked_queue_count, and locked_queue_bytes.
(PR #11468).  In the case of fragment allocation, check to see if enough
space is available before extending a fragment already scheduled for writing.

The locked_queue_* variables indicate the number of buffer headers and bytes,
respectively, that are unavailable to getnewbuf() because they are locked up
waiting for LFS to flush them; make sure that that is actually what we're
counting, i.e., never count malloced buffers, and always use b_bufsize instead
of b_bcount.

If DEBUG is defined, the periodic calls to lfs_countlocked will now complain
if either counter is incorrect.  (In the future lfs_countlocked will not need
to be called at all if DEBUG is not defined.)

diffstat:

 sys/ufs/lfs/TODO           |  13 +-----
 sys/ufs/lfs/lfs.h          |  32 +++++++++++++++-
 sys/ufs/lfs/lfs_balloc.c   |  36 +++++++++++++++--
 sys/ufs/lfs/lfs_bio.c      |  95 +++++++++++++++++++++++----------------------
 sys/ufs/lfs/lfs_extern.h   |   4 +-
 sys/ufs/lfs/lfs_inode.c    |  14 +-----
 sys/ufs/lfs/lfs_segment.c  |  42 +++++++++++++-------
 sys/ufs/lfs/lfs_syscalls.c |   3 +-
 sys/ufs/lfs/lfs_vnops.c    |   6 +-
 9 files changed, 149 insertions(+), 96 deletions(-)

diffs (truncated from 562 to 300 lines):

diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/TODO
--- a/sys/ufs/lfs/TODO  Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/TODO  Fri Nov 17 19:14:41 2000 +0000
@@ -1,10 +1,10 @@
-#   $NetBSD: TODO,v 1.3 1999/03/15 00:46:47 perseant Exp $
+#   $NetBSD: TODO,v 1.4 2000/11/17 19:14:41 perseant Exp $
 
 - If we put an LFS onto a striped disk, we want to be able to specify
   the segment size to be equal to the stripe size, regardless of whether
   this is a power of two; also, the first segment should just eat the
   label pad, like the segments eat the superblocks.  Then, we could
-  neatly lay out the segments along stripe boundaries.
+  neatly lay out the segments along stripe boundaries. [v2]
 
 - Working fsck_lfs.  (Have something that will verify, need something
   that will fix too.  Really, need a general-purpose external
@@ -14,10 +14,6 @@
   checkpoint (easy) but also to create a valid checkpoint for
   post-checkpoint writes (requires an external partial-segment writer).
 
-- Blocks created in the cache are currently not marked in any way,
-  except that b_blkno == b_lblkno, which can happen naturally too.  LFS
-  needs to know for accounting.
-
 - Inode blocks are currently the same size as the fs block size; but all
   the ones I've seen are mostly empty, and this will be especially true
   if atime information is kept in the ifile instead of the inode.  Could
@@ -67,11 +63,6 @@
   perhaps keep the name, replace the function.  Could it count referenced
   vnodes as well, if it was in vfs_subr.c instead?
 
-- If we clean a DIROP vnode, and we toss a fake buffer in favor of a
-  pending held real buffer, we risk writing part of the dirop during a
-  synchronous checkpoint.  This is bad.  Now that we're doing `stingy'
-  cleaning, is there a good reason to favor real blocks over fake ones?
-
 - Why not delete the lfs_bmapv call, just mark everything dirty that
   isn't deleted/truncated?  Get some numbers about what percentage of
   the stuff that the cleaner thinks might be live is live.  If it's
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/lfs.h Fri Nov 17 19:14:41 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs.h,v 1.34 2000/11/13 00:24:30 perseant Exp $        */
+/*     $NetBSD: lfs.h,v 1.35 2000/11/17 19:14:41 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -89,6 +89,36 @@
 #define LFS_MAX_ACTIVE 10
 #define LFS_MAXDIROP   (desiredvnodes>>2)
 
+/*
+ * #define WRITE_THRESHHOLD    ((nbuf >> 1) - 10)
+ * #define WAIT_THRESHHOLD     (nbuf - (nbuf >> 2) - 10)
+ */
+#define LFS_MAX_BUFS        ((nbuf >> 2) - 10)
+#define LFS_WAIT_BUFS       ((nbuf >> 1) - (nbuf >> 3) - 10)
+/* These are new ... is LFS taking up too much memory in its buffers? */
+#define LFS_MAX_BYTES       (((bufpages >> 2) - 10) * NBPG)
+#define LFS_WAIT_BYTES      (((bufpages >> 1) - (bufpages >> 3) - 10) * NBPG)
+#define LFS_BUFWAIT         2
+
+#define LFS_LOCK_BUF(bp) do {                                          \
+       if (((bp)->b_flags & (B_LOCKED | B_CALL)) == 0) {               \
+               ++locked_queue_count;                                   \
+               locked_queue_bytes += bp->b_bufsize;                    \
+       }                                                               \
+       (bp)->b_flags |= B_LOCKED;                                      \
+} while(0)
+
+#define LFS_UNLOCK_BUF(bp) do {                                                \
+       if (((bp)->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) {        \
+               --locked_queue_count;                                   \
+               locked_queue_bytes -= bp->b_bufsize;                    \
+               if (locked_queue_count < LFS_WAIT_BUFS &&               \
+                   locked_queue_bytes < LFS_WAIT_BYTES)                \
+                       wakeup(&locked_queue_count);                    \
+       }                                                               \
+       (bp)->b_flags &= ~B_LOCKED;                                     \
+} while(0)
+
 /* For convenience */
 #define IN_ALLMOD (IN_MODIFIED|IN_ACCESS|IN_CHANGE|IN_UPDATE|IN_ACCESSED|IN_CLEANING)
 #define LFS_SET_UINO(ip, flags) do {                                    \
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/lfs_balloc.c
--- a/sys/ufs/lfs/lfs_balloc.c  Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/lfs_balloc.c  Fri Nov 17 19:14:41 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_balloc.c,v 1.25 2000/09/09 04:49:54 perseant Exp $ */
+/*     $NetBSD: lfs_balloc.c,v 1.26 2000/11/17 19:14:41 perseant Exp $ */
 
 /*-
  * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -344,6 +344,7 @@
        int error;
        extern long locked_queue_bytes;
        struct buf *ibp;
+       size_t obufsize;
        SEGUSE *sup;
 
        ip = VTOI(vp);
@@ -355,6 +356,7 @@
         * Get the seglock so we don't enlarge blocks or change the segment
         * accounting information while a segment is being written.
         */
+    top:
        lfs_seglock(fs, SEGM_PROT);
 
        if (!ISSPACE(fs, bb, curproc->p_ucred)) {
@@ -372,23 +374,47 @@
        }
 #endif
        /*
+        * Adjust accounting for lfs_avail.  If there's not enough room,
+        * we will have to wait for the cleaner, which we can't do while
+        * holding a block busy or while holding the seglock.  In that case,
+        * release both and start over after waiting.
+        */
+       if ((*bpp)->b_flags & B_DELWRI) {
+               if (!lfs_fits(fs, bb)) {
+                       brelse(*bpp);
+#ifdef QUOTA
+                       chkdq(ip, -bb, curproc->p_ucred, 0);
+#endif
+                       lfs_segunlock(fs);
+                       lfs_availwait(fs, bb);
+                       goto top;
+               }
+               fs->lfs_avail -= bb;
+       }
+
+       /*
         * Fix the allocation for this fragment so that it looks like the
          * source segment contained a block of the new size.  This overcounts;
         * but the overcount only lasts until the block in question
         * is written, so the on-disk live bytes count is always correct.
         */
        if ((*bpp)->b_blkno > 0) {
-               LFS_SEGENTRY(sup, fs, datosn(fs,(*bpp)->b_blkno), ibp);
-               sup->su_nbytes += (nsize-osize);
+               LFS_SEGENTRY(sup, fs, datosn(fs, (*bpp)->b_blkno), ibp);
+               sup->su_nbytes += (nsize - osize);
                VOP_BWRITE(ibp);
                ip->i_ffs_blocks += bb;
        }
        fs->lfs_bfree -= bb;
        ip->i_lfs_effnblks += bb;
        ip->i_flag |= IN_CHANGE | IN_UPDATE;
-       if((*bpp)->b_flags & B_LOCKED)
-               locked_queue_bytes += (nsize - osize);
+
+       obufsize = (*bpp)->b_bufsize;
        allocbuf(*bpp, nsize);
+
+       /* Adjust locked-list accounting */
+       if (((*bpp)->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED)
+               locked_queue_bytes += btodb((*bpp)->b_bufsize - obufsize);
+
        bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize));
 
     out:
diff -r 627f537bc58c -r eb3582a8e9cf sys/ufs/lfs/lfs_bio.c
--- a/sys/ufs/lfs/lfs_bio.c     Fri Nov 17 19:08:00 2000 +0000
+++ b/sys/ufs/lfs/lfs_bio.c     Fri Nov 17 19:14:41 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_bio.c,v 1.31 2000/11/12 07:58:36 perseant Exp $    */
+/*     $NetBSD: lfs_bio.c,v 1.32 2000/11/17 19:14:41 perseant Exp $    */
 
 /*-
  * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc.
@@ -107,20 +107,6 @@
                                           because of buffer space */
 extern int lfs_dostats;
 
-
-/*
- * #define WRITE_THRESHHOLD    ((nbuf >> 1) - 10)
- * #define WAIT_THRESHHOLD     (nbuf - (nbuf >> 2) - 10)
- */
-#define LFS_MAX_BUFS        ((nbuf >> 2) - 10)
-#define LFS_WAIT_BUFS       ((nbuf >> 1) - (nbuf >> 3) - 10)
-/* These are new ... is LFS taking up too much memory in its buffers? */
-#define LFS_MAX_BYTES       (((bufpages >> 2) - 10) * NBPG)
-#define LFS_WAIT_BYTES      (((bufpages >> 1) - (bufpages >> 3) - 10) * NBPG)
-#define LFS_BUFWAIT         2
-
-inline static int lfs_fits(struct lfs *, int);
-
 /*
  * Try to reserve some blocks, prior to performing a sensitive operation that
  * requires the vnode lock to be honored.  If there is not enough space, give
@@ -208,7 +194,7 @@
  * inode blocks, a summary block, plus potentially the ifile inode and
  * the segment usage table, plus an ifile page.
  */
-inline static int
+int
 lfs_fits(struct lfs *fs, int db)
 {
        int needed;
@@ -229,6 +215,41 @@
 }
 
 int
+lfs_availwait(fs, db)
+       struct lfs *fs;
+       int db;
+{
+       int error;
+       CLEANERINFO *cip;
+       struct buf *cbp;
+
+       while (!lfs_fits(fs, db)) {
+               /*
+                * Out of space, need cleaner to run.
+                * Update the cleaner info, then wake it up.
+                * Note the cleanerinfo block is on the ifile
+                * so it CANT_WAIT.
+                */
+               LFS_CLEANERINFO(cip, fs, cbp);
+               LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
+               
+               printf("lfs_availwait: out of available space, "
+                      "waiting on cleaner\n");
+               
+               wakeup(&lfs_allclean_wakeup);
+               wakeup(&fs->lfs_nextseg);
+#ifdef DIAGNOSTIC
+               if (fs->lfs_seglock && fs->lfs_lockpid == curproc->p_pid)
+                       panic("lfs_availwait: deadlock");
+#endif
+               error = tsleep(&fs->lfs_avail, PCATCH | PUSER, "cleaner", 0);
+               if (error)
+                       return (error);
+       }
+       return 0;
+}
+
+int
 lfs_bwrite_ext(bp, flags)
        struct buf *bp;
        int flags;
@@ -236,15 +257,14 @@
        struct lfs *fs;
        struct inode *ip;
        int db, error, s;
-       struct buf *cbp;
-       CLEANERINFO *cip;
        
        /*
         * Don't write *any* blocks if we're mounted read-only.
         * In particular the cleaner can't write blocks either.
         */
         if(VTOI(bp->b_vp)->i_lfs->lfs_ronly) {
-               bp->b_flags &= ~(B_DELWRI|B_LOCKED|B_READ|B_ERROR);
+               bp->b_flags &= ~(B_DELWRI | B_READ | B_ERROR);
+               LFS_UNLOCK_BUF(bp);
                if(bp->b_flags & B_CALL)
                        bp->b_flags &= ~B_BUSY;
                else
@@ -269,27 +289,10 @@
        if (!(bp->b_flags & B_LOCKED)) {
                fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs;
                db = fragstodb(fs, numfrags(fs, bp->b_bcount));
-               while (!lfs_fits(fs, db) && !CANT_WAIT(bp,flags)) {
-                       /*
-                        * Out of space, need cleaner to run.
-                        * Update the cleaner info, then wake it up.
-                        * Note the cleanerinfo block is on the ifile
-                        * so it CANT_WAIT.
-                        */
-                       LFS_CLEANERINFO(cip, fs, cbp);
-                       LFS_SYNC_CLEANERINFO(cip, fs, cbp, 0);
-
-                       printf("lfs_bwrite: out of available space, "
-                              "waiting on cleaner\n");
-
-                       wakeup(&lfs_allclean_wakeup);
-                       wakeup(&fs->lfs_nextseg);
-                       error = tsleep(&fs->lfs_avail, PCATCH | PUSER,
-                           "cleaner", 0);
-                       if (error) {
-                               /* printf("lfs_bwrite: error in tsleep"); */
+               if (!CANT_WAIT(bp, flags)) {
+                       if ((error = lfs_availwait(fs, db)) != 0) {
                                brelse(bp);
-                               return (error);
+                               return error;
                        }
                }
                
@@ -300,11 +303,11 @@
                        LFS_SET_UINO(ip, IN_CHANGE | IN_MODIFIED | IN_UPDATE);
                }
                fs->lfs_avail -= db;
-               ++locked_queue_count;
-               locked_queue_bytes += bp->b_bufsize;
+               bp->b_flags |= B_DELWRI;
+



Home | Main Index | Thread Index | Old Index