Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs/lfs Protect inode free list with seglock, instead of...



details:   https://anonhg.NetBSD.org/src/rev/8807376fd7f5
branches:  trunk
changeset: 487374:8807376fd7f5
user:      perseant <perseant%NetBSD.org@localhost>
date:      Tue Jun 06 20:19:14 2000 +0000

description:
Protect inode free list with seglock, instead of separate lock, so that
the head of the inode free list (on the superblock) always matches the
rest of the free list (in the ifile).

Protect lfs_fragextend with seglock, to prevent the segment byte count
fudging from making its way to disk.

Don't try to inactivate dirop vnodes that are still in the middle of
their dirop (may address PR#10285).

diffstat:

 sys/ufs/lfs/lfs.h         |   5 ++++-
 sys/ufs/lfs/lfs_alloc.c   |  46 +++++++++++++++++++++++++---------------------
 sys/ufs/lfs/lfs_balloc.c  |  35 +++++++++++++++++------------------
 sys/ufs/lfs/lfs_bio.c     |  11 +++++++----
 sys/ufs/lfs/lfs_segment.c |  15 +++++++++++----
 5 files changed, 64 insertions(+), 48 deletions(-)

diffs (271 lines):

diff -r dc8bb00f670e -r 8807376fd7f5 sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Tue Jun 06 20:17:34 2000 +0000
+++ b/sys/ufs/lfs/lfs.h Tue Jun 06 20:19:14 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs.h,v 1.24 2000/05/31 01:40:01 perseant Exp $        */
+/*     $NetBSD: lfs.h,v 1.25 2000/06/06 20:19:14 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -291,6 +291,7 @@
        u_int32_t lfs_nactive;          /* Number of segments since last ckp */
        int8_t    lfs_fmod;             /* super block modified flag */
        int8_t    lfs_ronly;            /* mounted read-only flag */
+#define LFS_NOTYET 0x01
        int8_t    lfs_flags;            /* currently unused flag */
        u_int16_t lfs_activesb;         /* toggle between superblocks */
 #ifdef LFS_TRACK_IOS
@@ -303,6 +304,7 @@
        struct vnode *lfs_unlockvp;     /* being inactivated in lfs_segunlock */
        u_int32_t lfs_diropwait;        /* # procs waiting on dirop flush */
        struct lock lfs_freelock;
+       pid_t lfs_rfpid;                /* Process ID of roll-forward agent */
        int       lfs_nadirop;          /* number of active dirop nodes */
 };
 
@@ -488,6 +490,7 @@
 #define        SEGM_CKP        0x01            /* doing a checkpoint */
 #define        SEGM_CLEAN      0x02            /* cleaner call; don't sort */
 #define        SEGM_SYNC       0x04            /* wait for segment */
+#define        SEGM_PROT       0x08            /* don't inactivate at segunlock */
        u_int16_t seg_flags;            /* run-time flags for this segment */
 };
 
diff -r dc8bb00f670e -r 8807376fd7f5 sys/ufs/lfs/lfs_alloc.c
--- a/sys/ufs/lfs/lfs_alloc.c   Tue Jun 06 20:17:34 2000 +0000
+++ b/sys/ufs/lfs/lfs_alloc.c   Tue Jun 06 20:19:14 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_alloc.c,v 1.33 2000/05/31 01:40:02 perseant Exp $  */
+/*     $NetBSD: lfs_alloc.c,v 1.34 2000/06/06 20:19:15 perseant Exp $  */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -122,9 +122,15 @@
        fs = VTOI(ap->a_pvp)->i_lfs;
        
        /*
-        * Prevent a race getting lfs_free.
+        * Use lfs_seglock here, instead of fs->lfs_freelock, to ensure that
+        * the free list is not changed in between the time that the ifile
+        * blocks are written to disk and the time that the superblock is
+        * written to disk.
+        *
+        * XXX this sucks.  We should instead encode the head of the free
+        * list into the CLEANERINFO block of the Ifile.
         */
-       lockmgr(&fs->lfs_freelock, LK_EXCLUSIVE, 0);
+       lfs_seglock(fs, SEGM_PROT);
 
        /* Get the head of the freelist. */
        new_ino = fs->lfs_free;
@@ -163,6 +169,7 @@
                blkno = lblkno(fs, ip->i_ffs_size);
                if ((error = VOP_BALLOC(vp, ip->i_ffs_size, fs->lfs_bsize,
                    NULL, 0, &bp)) != 0) {
+                       lfs_segunlock(fs);
                        return (error);
                }
                ip->i_ffs_size += fs->lfs_bsize;
@@ -186,6 +193,7 @@
                ifp->if_nextfree = LFS_UNUSED_INUM;
                VOP_UNLOCK(vp,0);
                if ((error = VOP_BWRITE(bp)) != 0) {
+                       lfs_segunlock(fs);
                        return (error);
                }
        }
@@ -194,7 +202,7 @@
                panic("inode 0 allocated [3]");
 #endif /* DIAGNOSTIC */
        
-       lockmgr(&fs->lfs_freelock, LK_RELEASE, 0);
+       lfs_segunlock(fs);
 
        lockmgr(&ufs_hashlock, LK_EXCLUSIVE, 0);
        /* Create a vnode to associate with the inode. */
@@ -312,22 +320,18 @@
        ip = VTOI(vp);
        fs = ip->i_lfs;
        ino = ip->i_number;
-       
-       while(WRITEINPROG(vp)
-             || fs->lfs_seglock
-             || lockmgr(&fs->lfs_freelock, LK_EXCLUSIVE|LK_SLEEPFAIL, 0))
-       {
-               if (WRITEINPROG(vp)) {
-                       tsleep(vp, (PRIBIO+1), "lfs_vfree", 0);
-               }
-               if (fs->lfs_seglock) {
-                       if (fs->lfs_lockpid == curproc->p_pid) {
-                               break;
-                       } else {
-                               tsleep(&fs->lfs_seglock, PRIBIO + 1, "lfs_vfr1", 0);
-                       }
-               }
-       }
+
+#if 0
+       /*
+        * Right now this is unnecessary since we take the seglock.
+        * But if the seglock is no longer necessary (e.g. we put the
+        * head of the free list into the Ifile) we will need to drain
+        * this vnode of any pending writes.
+        */
+       if (WRITEINPROG(vp))
+               tsleep(vp, (PRIBIO+1), "lfs_vfree", 0);
+#endif
+       lfs_seglock(fs, SEGM_PROT);
        
        if(vp->v_flag & VDIROP) {
                --lfs_dirvcount;
@@ -377,11 +381,11 @@
                sup->su_nbytes -= DINODE_SIZE;
                (void) VOP_BWRITE(bp);
        }
-       lockmgr(&fs->lfs_freelock, LK_RELEASE, 0);
        
        /* Set superblock modified bit and decrement file count. */
        fs->lfs_fmod = 1;
        --fs->lfs_nfiles;
        
+       lfs_segunlock(fs);
        return (0);
 }
diff -r dc8bb00f670e -r 8807376fd7f5 sys/ufs/lfs/lfs_balloc.c
--- a/sys/ufs/lfs/lfs_balloc.c  Tue Jun 06 20:17:34 2000 +0000
+++ b/sys/ufs/lfs/lfs_balloc.c  Tue Jun 06 20:19:14 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_balloc.c,v 1.17 2000/05/30 04:08:41 perseant Exp $ */
+/*     $NetBSD: lfs_balloc.c,v 1.18 2000/06/06 20:19:15 perseant Exp $ */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -345,15 +345,22 @@
 
        ip = VTOI(vp);
        fs = ip->i_lfs;
-       
        bb = (long)fragstodb(fs, numfrags(fs, nsize - osize));
- top:
+       error = 0;
+
+       /*
+        * Get the seglock so we don't enlarge blocks or change the segment
+        * accounting information while a segment is being written.
+        */
+       lfs_seglock(fs, SEGM_PROT);
+
        if (!ISSPACE(fs, bb, curproc->p_ucred)) {
-               return(ENOSPC);
+               error = ENOSPC;
+               goto out;
        }
        if ((error = bread(vp, lbn, osize, NOCRED, bpp))) {
                brelse(*bpp);
-               return(error);
+               goto out;
        }
 
        /*
@@ -371,19 +378,9 @@
 #ifdef QUOTA
        if ((error = chkdq(ip, bb, curproc->p_ucred, 0))) {
                brelse(*bpp);
-               return (error);
+               goto out;
        }
 #endif
-       /*
-        * XXX - KS - Don't change size while we're gathered, as we could
-        * then overlap another buffer in lfs_writeseg.
-        */
-       if((*bpp)->b_flags & B_GATHERED) {
-               (*bpp)->b_flags |= B_NEEDCOMMIT; /* XXX KS - what flag to use? */
-               brelse(*bpp);
-               tsleep(*bpp, (PRIBIO+1), "lfs_fragextend", 0);
-               goto top;
-       }
        ip->i_ffs_blocks += bb;
        ip->i_flag |= IN_CHANGE | IN_UPDATE;
        fs->lfs_bfree -= fragstodb(fs, numfrags(fs, (nsize - osize)));
@@ -391,6 +388,8 @@
                locked_queue_bytes += (nsize - osize);
        allocbuf(*bpp, nsize);
        bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize));
-       
-       return(0);
+
+    out:
+       lfs_segunlock(fs);
+       return (error);
 }
diff -r dc8bb00f670e -r 8807376fd7f5 sys/ufs/lfs/lfs_bio.c
--- a/sys/ufs/lfs/lfs_bio.c     Tue Jun 06 20:17:34 2000 +0000
+++ b/sys/ufs/lfs/lfs_bio.c     Tue Jun 06 20:19:14 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_bio.c,v 1.22 2000/05/31 03:37:34 fredb Exp $       */
+/*     $NetBSD: lfs_bio.c,v 1.23 2000/06/06 20:19:15 perseant Exp $    */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -138,10 +138,12 @@
                struct buf *a_bp;
        } */ *ap = v;
        struct buf *bp = ap->a_bp;
+       struct inode *ip;
+
+       ip = VTOI(bp->b_vp);
 
 #ifdef DIAGNOSTIC
-        if(VTOI(bp->b_vp)->i_lfs->lfs_ronly == 0
-          && (bp->b_flags & B_ASYNC)) {
+        if (VTOI(bp->b_vp)->i_lfs->lfs_ronly == 0 && (bp->b_flags & B_ASYNC)) {
                panic("bawrite LFS buffer");
        }
 #endif /* DIAGNOSTIC */
@@ -154,7 +156,8 @@
  * inode blocks, a summary block, plus potentially the ifile inode and
  * the segment usage table, plus an ifile page.
  */
-inline static int lfs_fits(struct lfs *fs, int db)
+inline static int
+lfs_fits(struct lfs *fs, int db)
 {
        if(((db + (fs->lfs_uinodes + INOPB((fs))) /
             INOPB(fs) + fsbtodb(fs, 1) + LFS_SUMMARY_SIZE / DEV_BSIZE +
diff -r dc8bb00f670e -r 8807376fd7f5 sys/ufs/lfs/lfs_segment.c
--- a/sys/ufs/lfs/lfs_segment.c Tue Jun 06 20:17:34 2000 +0000
+++ b/sys/ufs/lfs/lfs_segment.c Tue Jun 06 20:19:14 2000 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_segment.c,v 1.48 2000/05/31 03:37:35 fredb Exp $   */
+/*     $NetBSD: lfs_segment.c,v 1.49 2000/06/06 20:19:16 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -813,8 +813,10 @@
         * No need to update segment usage if there was no former inode address 
         * or if the last inode address is in the current partial segment.
         */
-       if (daddr != LFS_UNUSED_DADDR &&
-           !(daddr >= fs->lfs_lastpseg && daddr <= bp->b_blkno)) {
+       if (daddr >= fs->lfs_lastpseg && daddr <= bp->b_blkno)
+               printf("lfs_writeinode: last inode addr in current pseg "
+                      "(ino %d daddr 0x%x)\n" /* XXX ANSI */, ino, daddr);
+       if (daddr != LFS_UNUSED_DADDR) {
                LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
 #ifdef DIAGNOSTIC
                if (sup->su_nbytes < DINODE_SIZE) {
@@ -1087,7 +1089,12 @@
                        }
                }
                /* Update segment usage information. */
-               if (daddr > 0 && !(daddr >= fs->lfs_lastpseg && daddr <= off)) {
+               if (daddr >= fs->lfs_lastpseg && daddr <= off) {
+                       printf("lfs_updatemeta: ino %d, lbn %d, addr = %x "
+                              "in same pseg\n", VTOI(sp->vp)->i_number,
+                              (*sp->start_bpp)->b_lblkno, daddr);
+               }
+               if (daddr > 0) {
                        LFS_SEGENTRY(sup, fs, datosn(fs, daddr), bp);
 #ifdef DIAGNOSTIC
                        if (sup->su_nbytes < (*sp->start_bpp)->b_bcount) {



Home | Main Index | Thread Index | Old Index