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