Source-Changes-HG archive

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

[src/trunk]: src/sys/ufs Protect various per-fs structures with fs->lfs_inter...



details:   https://anonhg.NetBSD.org/src/rev/c4368df298b3
branches:  trunk
changeset: 579942:c4368df298b3
user:      perseant <perseant%NetBSD.org@localhost>
date:      Fri Apr 01 21:59:46 2005 +0000

description:
Protect various per-fs structures with fs->lfs_interlock simple_lock, to
improve behavior in the multiprocessor case.  Add debugging segment-lock
assertion statements.

diffstat:

 sys/ufs/lfs/TODO            |   11 +--
 sys/ufs/lfs/lfs.h           |   56 ++++++++++++++++--
 sys/ufs/lfs/lfs_alloc.c     |   48 +++++++++++++--
 sys/ufs/lfs/lfs_balloc.c    |   45 +++++++++++++-
 sys/ufs/lfs/lfs_bio.c       |   96 +++++++++++++++++++++++---------
 sys/ufs/lfs/lfs_debug.c     |   26 ++++++--
 sys/ufs/lfs/lfs_inode.c     |   28 +++++++--
 sys/ufs/lfs/lfs_segment.c   |  131 +++++++++++++++++++++++++++++++++----------
 sys/ufs/lfs/lfs_subr.c      |   99 ++++++++++++++++++++++++++-------
 sys/ufs/lfs/lfs_syscalls.c  |   16 ++++-
 sys/ufs/lfs/lfs_vfsops.c    |   43 ++++++++++++--
 sys/ufs/lfs/lfs_vnops.c     |   59 +++++++++++++++----
 sys/ufs/ufs/ufs_readwrite.c |    6 +-
 13 files changed, 522 insertions(+), 142 deletions(-)

diffs (truncated from 2231 to 300 lines):

diff -r 40b1cfb36cff -r c4368df298b3 sys/ufs/lfs/TODO
--- a/sys/ufs/lfs/TODO  Fri Apr 01 21:07:01 2005 +0000
+++ b/sys/ufs/lfs/TODO  Fri Apr 01 21:59:46 2005 +0000
@@ -1,15 +1,10 @@
-#   $NetBSD: TODO,v 1.8 2005/02/26 05:40:42 perseant Exp $
-
-- Lock audit.  Need to check locking for multiprocessor case in particular.
-
-- Get rid of lfs_segclean(); the kernel should clean a dirty segment IFF it
-  has passed two checkpoints containing zero live bytes.
+#   $NetBSD: TODO,v 1.9 2005/04/01 21:59:46 perseant Exp $
 
 - Now that our cache is basically all of physical memory, we need to make
   sure that segwrite is not starving other important things.  Need a way
   to prioritize which blocks are most important to write, and write only
-  those before giving up the seglock to do the rest.  How does this change
-  our notion of what a checkpoint is?
+  those, saving the rest for later.  Does this change our notion of what
+  a checkpoint is?
 
 - Investigate alternate inode locking strategy: Inode locks are useful
   for locking against simultaneous changes to inode size (balloc,
diff -r 40b1cfb36cff -r c4368df298b3 sys/ufs/lfs/lfs.h
--- a/sys/ufs/lfs/lfs.h Fri Apr 01 21:07:01 2005 +0000
+++ b/sys/ufs/lfs/lfs.h Fri Apr 01 21:59:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs.h,v 1.77 2005/03/08 00:18:19 perseant Exp $        */
+/*     $NetBSD: lfs.h,v 1.78 2005/04/01 21:59:46 perseant Exp $        */
 
 /*-
  * Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -213,6 +213,7 @@
 struct lfs_log_entry {
        char *op;
        char *file;
+       int pid;
        int line;
        daddr_t block;
        unsigned long flags;
@@ -220,23 +221,26 @@
 extern int lfs_lognum;
 extern struct lfs_log_entry lfs_log[LFS_LOGLENGTH];
 #  define LFS_BWRITE_LOG(bp) lfs_bwrite_log((bp), __FILE__, __LINE__)
-#  define LFS_ENTER_LOG(theop, thefile, theline, lbn, theflags) do {   \
+#  define LFS_ENTER_LOG(theop, thefile, theline, lbn, theflags, thepid) do {\
        int _s;                                                         \
                                                                        \
+       simple_lock(&lfs_subsys_lock);                                  \
        _s = splbio();                                                  \
        lfs_log[lfs_lognum].op = theop;                                 \
        lfs_log[lfs_lognum].file = thefile;                             \
        lfs_log[lfs_lognum].line = (theline);                           \
+       lfs_log[lfs_lognum].pid = (thepid);                             \
        lfs_log[lfs_lognum].block = (lbn);                              \
        lfs_log[lfs_lognum].flags = (theflags);                         \
        lfs_lognum = (lfs_lognum + 1) % LFS_LOGLENGTH;                  \
        splx(_s);                                                       \
+       simple_unlock(&lfs_subsys_lock);                                \
 } while (0)
 
 #  define LFS_BCLEAN_LOG(fs, bp) do {                                  \
        if ((bp)->b_vp == (fs)->lfs_ivnode)                             \
                LFS_ENTER_LOG("clear", __FILE__, __LINE__,              \
-                             bp->b_lblkno, bp->b_flags);               \
+                             bp->b_lblkno, bp->b_flags, curproc->p_pid);\
 } while (0)
 
 /* Must match list in lfs_vfsops.c ! */
@@ -329,7 +333,9 @@
                        _ifp->if_atime_sec = (acc)->tv_sec;             \
                        _ifp->if_atime_nsec = (acc)->tv_nsec;           \
                        LFS_BWRITE_LOG(_ibp);                           \
+                       simple_lock(&_fs->lfs_interlock);               \
                        _fs->lfs_flags |= LFS_IFDIRTY;                  \
+                       simple_unlock(&_fs->lfs_interlock);             \
                } else {                                                \
                        LFS_SET_UINO(ip, IN_ACCESSED);                  \
                }                                                       \
@@ -502,21 +508,32 @@
        (CP) = (CLEANERINFO *)(BP)->b_data;                             \
 } while (0)
 
-/* Synchronize the Ifile cleaner info with current avail and bfree */
+/*
+ * Synchronize the Ifile cleaner info with current avail and bfree.
+ */
 #define LFS_SYNC_CLEANERINFO(cip, fs, bp, w) do {                      \
+    simple_lock(&(fs)->lfs_interlock);                                 \
     if ((w) || (cip)->bfree != (fs)->lfs_bfree ||                      \
        (cip)->avail != (fs)->lfs_avail - (fs)->lfs_ravail -            \
        (fs)->lfs_favail) {                                             \
        (cip)->bfree = (fs)->lfs_bfree;                                 \
        (cip)->avail = (fs)->lfs_avail - (fs)->lfs_ravail -             \
                (fs)->lfs_favail;                                       \
-       if (((bp)->b_flags & B_GATHERED) == 0)                          \
+       if (((bp)->b_flags & B_GATHERED) == 0) {                        \
                (fs)->lfs_flags |= LFS_IFDIRTY;                         \
+       }                                                               \
+        simple_unlock(&(fs)->lfs_interlock);                           \
        (void) LFS_BWRITE_LOG(bp); /* Ifile */                          \
-    } else                                                             \
+    } else {                                                           \
+        simple_unlock(&(fs)->lfs_interlock);                           \
        brelse(bp);                                                     \
+    }                                                                  \
 } while (0)
 
+/*
+ * Get the head of the inode free list.
+ * Always caled with the segment lock held.
+ */
 #define LFS_GET_HEADFREE(FS, CIP, BP, FREEP) do {                      \
        if ((FS)->lfs_version > 1) {                                    \
                LFS_CLEANERINFO((CIP), (FS), (BP));                     \
@@ -532,7 +549,9 @@
                LFS_CLEANERINFO((CIP), (FS), (BP));                     \
                (CIP)->free_head = (VAL);                               \
                LFS_BWRITE_LOG(BP);                                     \
+               simple_lock(&fs->lfs_interlock);                        \
                (FS)->lfs_flags |= LFS_IFDIRTY;                         \
+               simple_unlock(&fs->lfs_interlock);                      \
        }                                                               \
 } while (0)
 
@@ -546,7 +565,9 @@
        LFS_CLEANERINFO((CIP), (FS), (BP));                             \
        (CIP)->free_tail = (VAL);                                       \
        LFS_BWRITE_LOG(BP);                                             \
+       simple_lock(&fs->lfs_interlock);                                \
        (FS)->lfs_flags |= LFS_IFDIRTY;                                 \
+       simple_unlock(&fs->lfs_interlock);                              \
 } while (0)
 
 /*
@@ -1031,4 +1052,27 @@
        ((fs)->lfs_seglock != 0 && (fs)->lfs_lockpid == curproc->p_pid)
 #endif /* _KERNEL */
 
+/* Debug segment lock */
+#ifdef notyet
+# define ASSERT_SEGLOCK(fs) KASSERT(LFS_SEGLOCK_HELD(fs))
+# define ASSERT_NO_SEGLOCK(fs) KASSERT(!LFS_SEGLOCK_HELD(fs))
+# define ASSERT_DUNNO_SEGLOCK(fs)
+# define ASSERT_MAYBE_SEGLOCK(fs)
+#else /* !notyet */
+# define ASSERT_DUNNO_SEGLOCK(fs) \
+       DLOG((DLOG_SEG, "lfs func %s seglock wrong (%d)\n", __func__, \
+               LFS_SEGLOCK_HELD(fs)))
+# define ASSERT_SEGLOCK(fs) do {                                       \
+       if (!LFS_SEGLOCK_HELD(fs)) {                                    \
+               DLOG((DLOG_SEG, "lfs func %s seglock wrong (0)\n", __func__)); \
+       }                                                               \
+} while(0)
+# define ASSERT_NO_SEGLOCK(fs) do {                                    \
+       if (LFS_SEGLOCK_HELD(fs)) {                                     \
+               DLOG((DLOG_SEG, "lfs func %s seglock wrong (1)\n", __func__)); \
+       }                                                               \
+} while(0)
+# define ASSERT_MAYBE_SEGLOCK(x)
+#endif /* !notyet */
+
 #endif /* !_UFS_LFS_LFS_H_ */
diff -r 40b1cfb36cff -r c4368df298b3 sys/ufs/lfs/lfs_alloc.c
--- a/sys/ufs/lfs/lfs_alloc.c   Fri Apr 01 21:07:01 2005 +0000
+++ b/sys/ufs/lfs/lfs_alloc.c   Fri Apr 01 21:59:46 2005 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lfs_alloc.c,v 1.77 2005/03/23 00:12:51 perseant Exp $  */
+/*     $NetBSD: lfs_alloc.c,v 1.78 2005/04/01 21:59: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.77 2005/03/23 00:12:51 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_alloc.c,v 1.78 2005/04/01 21:59:46 perseant Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_quota.h"
@@ -120,6 +120,8 @@
        int error;
        CLEANERINFO *cip;
 
+       ASSERT_SEGLOCK(fs); /* XXX it doesn't, really */
+
        /*
         * First, just try a vget. If the version number is the one we want,
         * we don't have to do anything else.  If the version number is wrong,
@@ -201,9 +203,13 @@
                /* The dirop-nature of this vnode is past */
                lfs_unmark_vnode(vp);
                (void)lfs_vunref(vp);
+               vp->v_flag &= ~VDIROP;
+               simple_lock(&fs->lfs_interlock);
+               simple_lock(&lfs_subsys_lock);
                --lfs_dirvcount;
-               vp->v_flag &= ~VDIROP;
+               simple_unlock(&lfs_subsys_lock);
                TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
+               simple_unlock(&fs->lfs_interlock);
        }
        *vpp = vp;
        return error;
@@ -226,6 +232,8 @@
        ino_t oldlast;
        CLEANERINFO *cip;
 
+       ASSERT_SEGLOCK(fs);
+
        vp = fs->lfs_ivnode;
        ip = VTOI(vp);
        blkno = lblkno(fs, ip->i_size);
@@ -295,7 +303,10 @@
        if (fs->lfs_ronly)
                return EROFS;
 
+       ASSERT_NO_SEGLOCK(fs);
+
        lfs_seglock(fs, SEGM_PROT);
+       vn_lock(fs->lfs_ivnode, LK_EXCLUSIVE);
 
        /* Get the head of the freelist. */
        LFS_GET_HEADFREE(fs, cip, cbp, &new_ino);
@@ -328,6 +339,7 @@
        if (fs->lfs_freehd == LFS_UNUSED_INUM) {
                if ((error = extend_ifile(fs, ap->a_cred)) != 0) {
                        LFS_PUT_HEADFREE(fs, cip, cbp, new_ino);
+                       VOP_UNLOCK(fs->lfs_ivnode, 0);
                        lfs_segunlock(fs);
                        return error;
                }
@@ -337,6 +349,13 @@
                panic("inode 0 allocated [3]");
 #endif /* DIAGNOSTIC */
 
+       /* Set superblock modified bit and increment file count. */
+       simple_lock(&fs->lfs_interlock);
+       fs->lfs_fmod = 1;
+       simple_unlock(&fs->lfs_interlock);
+       ++fs->lfs_nfiles;
+
+       VOP_UNLOCK(fs->lfs_ivnode, 0);
        lfs_segunlock(fs);
 
        return lfs_ialloc(fs, ap->a_pvp, new_ino, new_gen, ap->a_vpp);
@@ -352,6 +371,8 @@
        struct inode *ip;
        struct vnode *vp;
 
+       ASSERT_NO_SEGLOCK(fs);
+
        vp = *vpp;
        lockmgr(&ufs_hashlock, LK_EXCLUSIVE, 0);
        /* Create an inode to associate with the vnode. */
@@ -382,9 +403,6 @@
        lfs_mark_vnode(vp);
        genfs_node_init(vp, &lfs_genfsops);
        VREF(ip->i_devvp);
-       /* Set superblock modified bit and increment file count. */
-       fs->lfs_fmod = 1;
-       ++fs->lfs_nfiles;
        return (0);
 }
 
@@ -400,6 +418,8 @@
        /* Get a pointer to the private mount structure. */
        ump = VFSTOUFS(mp);
 
+       ASSERT_NO_SEGLOCK(ump->um_lfs);
+
        /* Initialize the inode. */
        ip = pool_get(&lfs_inode_pool, PR_WAITOK);
        memset(ip, 0, sizeof(*ip));
@@ -456,19 +476,28 @@
        fs = ip->i_lfs;
        ino = ip->i_number;
 
+       ASSERT_NO_SEGLOCK(fs);
+
        /* Drain of pending writes */
+       simple_lock(&vp->v_interlock);
        s = splbio();
        if (fs->lfs_version > 1 && WRITEINPROG(vp))
-               tsleep(vp, (PRIBIO+1), "lfs_vfree", 0);
+               ltsleep(vp, (PRIBIO+1), "lfs_vfree", 0, &vp->v_interlock);
        splx(s);
+       simple_unlock(&vp->v_interlock);
 
        lfs_seglock(fs, SEGM_PROT);
+       vn_lock(fs->lfs_ivnode, LK_EXCLUSIVE);
 
        lfs_unmark_vnode(vp);
        if (vp->v_flag & VDIROP) {
+               vp->v_flag &= ~VDIROP;
+               simple_lock(&fs->lfs_interlock);
+               simple_lock(&lfs_subsys_lock);
                --lfs_dirvcount;
-               vp->v_flag &= ~VDIROP;
+               simple_unlock(&lfs_subsys_lock);



Home | Main Index | Thread Index | Old Index