Protect various per-fs structures with fs->lfs_interlock simple_lock, to

improve behavior in the multiprocessor case.  Add debugging segment-lock
assertion statements.
This commit is contained in:
perseant 2005-04-01 21:59:46 +00:00
parent 7c4b722858
commit 1ebfc508b6
13 changed files with 523 additions and 143 deletions

View File

@ -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,

View File

@ -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 @@ typedef struct lfs_res_blk {
struct lfs_log_entry {
char *op;
char *file;
int pid;
int line;
daddr_t block;
unsigned long flags;
@ -220,23 +221,26 @@ struct lfs_log_entry {
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 @@ struct lfid {
_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 @@ typedef struct _cleanerinfo {
(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 @@ typedef struct _cleanerinfo {
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 @@ typedef struct _cleanerinfo {
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 @@ struct lfs_fcntl_markv {
((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_ */

View File

@ -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 @@ lfs_rf_valloc(struct lfs *fs, ino_t ino, int version, struct proc *p,
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 @@ lfs_rf_valloc(struct lfs *fs, ino_t ino, int version, struct proc *p,
/* The dirop-nature of this vnode is past */
lfs_unmark_vnode(vp);
(void)lfs_vunref(vp);
--lfs_dirvcount;
vp->v_flag &= ~VDIROP;
simple_lock(&fs->lfs_interlock);
simple_lock(&lfs_subsys_lock);
--lfs_dirvcount;
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 @@ extend_ifile(struct lfs *fs, struct ucred *cred)
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 @@ lfs_valloc(void *v)
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 @@ lfs_valloc(void *v)
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 @@ lfs_valloc(void *v)
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 @@ lfs_ialloc(struct lfs *fs, struct vnode *pvp, ino_t new_ino, int new_gen,
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_ialloc(struct lfs *fs, struct vnode *pvp, ino_t new_ino, int new_gen,
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 @@ lfs_vcreate(struct mount *mp, ino_t ino, struct vnode *vp)
/* 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 @@ lfs_vfree(void *v)
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) {
--lfs_dirvcount;
vp->v_flag &= ~VDIROP;
simple_lock(&fs->lfs_interlock);
simple_lock(&lfs_subsys_lock);
--lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
simple_unlock(&fs->lfs_interlock);
wakeup(&lfs_dirvcount);
lfs_vunref(vp);
}
@ -528,9 +557,12 @@ lfs_vfree(void *v)
}
/* Set superblock modified bit and decrement 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 (0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_balloc.c,v 1.51 2005/03/02 21:16:09 perseant Exp $ */
/* $NetBSD: lfs_balloc.c,v 1.52 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_balloc.c,v 1.51 2005/03/02 21:16:09 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_balloc.c,v 1.52 2005/04/01 21:59:46 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -146,6 +146,8 @@ lfs_balloc(void *v)
/* (void)lfs_check(vp, lbn, 0); */
bpp = ap->a_bpp;
ASSERT_MAYBE_SEGLOCK(fs);
/*
* 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
@ -208,7 +210,9 @@ lfs_balloc(void *v)
clrbuf(bp);
}
ip->i_lfs_effnblks += bb;
simple_lock(&fs->lfs_interlock);
ip->i_lfs->lfs_bfree -= bb;
simple_unlock(&fs->lfs_interlock);
ip->i_ffs1_db[lbn] = UNWRITTEN;
} else {
if (nsize <= osize) {
@ -251,7 +255,9 @@ lfs_balloc(void *v)
}
}
if (ISSPACE(fs, bcount, ap->a_cred)) {
simple_lock(&fs->lfs_interlock);
ip->i_lfs->lfs_bfree -= bcount;
simple_unlock(&fs->lfs_interlock);
ip->i_lfs_effnblks += bcount;
} else {
return ENOSPC;
@ -290,6 +296,13 @@ lfs_balloc(void *v)
UNWRITTEN;
/* XXX ondisk32 */
idaddr = ((int32_t *)ibp->b_data)[indirs[i].in_off];
#ifdef DEBUG
if (vp == fs->lfs_ivnode) {
LFS_ENTER_LOG("balloc", __FILE__,
__LINE__, indirs[i].in_lbn,
ibp->b_flags, curproc->p_pid);
}
#endif
if ((error = VOP_BWRITE(ibp)))
return error;
}
@ -342,6 +355,13 @@ lfs_balloc(void *v)
(long long)idp->in_lbn);
/* XXX ondisk32 */
((int32_t *)ibp->b_data)[idp->in_off] = UNWRITTEN;
#ifdef DEBUG
if (vp == fs->lfs_ivnode) {
LFS_ENTER_LOG("balloc", __FILE__,
__LINE__, idp->in_lbn,
ibp->b_flags, curproc->p_pid);
}
#endif
VOP_BWRITE(ibp);
}
} else if (bpp && !(bp->b_flags & (B_DONE|B_DELWRI))) {
@ -383,6 +403,8 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
bb = (long)fragstofsb(fs, numfrags(fs, nsize - osize));
error = 0;
ASSERT_DUNNO_SEGLOCK(fs);
/*
* Get the seglock so we don't enlarge blocks while a segment
* is being written. If we're called with bpp==NULL, though,
@ -438,7 +460,9 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
fs->lfs_avail -= bb;
}
simple_lock(&fs->lfs_interlock);
fs->lfs_bfree -= bb;
simple_unlock(&fs->lfs_interlock);
ip->i_lfs_effnblks += bb;
ip->i_flag |= IN_CHANGE | IN_UPDATE;
@ -447,8 +471,11 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
allocbuf(*bpp, nsize, 1);
/* Adjust locked-list accounting */
if (((*bpp)->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED)
if (((*bpp)->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) {
simple_lock(&lfs_subsys_lock);
locked_queue_bytes += (*bpp)->b_bufsize - obufsize;
simple_unlock(&lfs_subsys_lock);
}
bzero((char *)((*bpp)->b_data) + osize, (u_int)(nsize - osize));
}
@ -465,7 +492,6 @@ lfs_fragextend(struct vnode *vp, int osize, int nsize, daddr_t lbn, struct buf *
* on the buffer headers, but since pages don't have buffer headers we
* record it here instead.
*/
void
lfs_register_block(struct vnode *vp, daddr_t lbn)
{
@ -481,6 +507,8 @@ lfs_register_block(struct vnode *vp, daddr_t lbn)
ip = VTOI(vp);
fs = ip->i_lfs;
ASSERT_NO_SEGLOCK(fs);
/* If no space, wait for the cleaner */
lfs_availwait(fs, btofsb(fs, 1 << fs->lfs_bshift));
@ -493,19 +521,28 @@ lfs_register_block(struct vnode *vp, daddr_t lbn)
lbp = (struct lbnentry *)pool_get(&lfs_lbnentry_pool, PR_WAITOK);
lbp->lbn = lbn;
LIST_INSERT_HEAD(&(ip->i_lfs_blist[hash]), lbp, entry);
simple_lock(&fs->lfs_interlock);
fs->lfs_favail += btofsb(fs, (1 << fs->lfs_bshift));
++locked_fakequeue_count;
simple_unlock(&fs->lfs_interlock);
}
static void
lfs_do_deregister(struct lfs *fs, struct lbnentry *lbp)
{
ASSERT_MAYBE_SEGLOCK(fs);
LIST_REMOVE(lbp, entry);
pool_put(&lfs_lbnentry_pool, lbp);
simple_lock(&fs->lfs_interlock);
if (fs->lfs_favail > btofsb(fs, (1 << fs->lfs_bshift)))
fs->lfs_favail -= btofsb(fs, (1 << fs->lfs_bshift));
simple_lock(&lfs_subsys_lock);
if (locked_fakequeue_count > 0)
--locked_fakequeue_count;
simple_unlock(&lfs_subsys_lock);
simple_unlock(&fs->lfs_interlock);
}
void

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_bio.c,v 1.81 2005/03/09 22:12:15 perseant Exp $ */
/* $NetBSD: lfs_bio.c,v 1.82 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_bio.c,v 1.81 2005/03/09 22:12:15 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.82 2005/04/01 21:59:46 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -128,6 +128,7 @@ lfs_fits_buf(struct lfs *fs, int n, int bytes)
{
int count_fit, bytes_fit;
ASSERT_NO_SEGLOCK(fs);
LOCK_ASSERT(simple_lock_held(&lfs_subsys_lock));
count_fit =
@ -156,6 +157,7 @@ int
lfs_reservebuf(struct lfs *fs, struct vnode *vp, struct vnode *vp2,
int n, int bytes)
{
ASSERT_MAYBE_SEGLOCK(fs);
KASSERT(locked_queue_rcount >= 0);
KASSERT(locked_queue_rbytes >= 0);
@ -207,8 +209,11 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
struct buf *bp;
int error, slept;
ASSERT_MAYBE_SEGLOCK(fs);
slept = 0;
simple_lock(&fs->lfs_interlock);
while (fsb > 0 && !lfs_fits(fs, fsb + fs->lfs_ravail + fs->lfs_favail)) {
simple_unlock(&fs->lfs_interlock);
#if 0
/*
* XXX ideally, we should unlock vnodes here
@ -226,14 +231,12 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
*/
#endif
#ifdef DEBUG
if (!slept) {
DLOG((DLOG_AVAIL, "lfs_reserve: waiting for %ld (bfree = %d,"
" est_bfree = %d)\n",
fsb + fs->lfs_ravail + fs->lfs_favail,
fs->lfs_bfree, LFS_EST_BFREE(fs)));
}
#endif
++slept;
/* Wake up the cleaner */
@ -242,8 +245,13 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
wakeup(&lfs_allclean_wakeup);
wakeup(&fs->lfs_nextseg);
error = tsleep(&fs->lfs_avail, PCATCH | PUSER, "lfs_reserve",
0);
simple_lock(&fs->lfs_interlock);
/* Cleaner might have run while we were reading, check again */
if (lfs_fits(fs, fsb + fs->lfs_ravail + fs->lfs_favail))
break;
error = ltsleep(&fs->lfs_avail, PCATCH | PUSER, "lfs_reserve",
0, &fs->lfs_interlock);
#if 0
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); /* XXX use lockstatus */
vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY); /* XXX use lockstatus */
@ -257,6 +265,7 @@ lfs_reserveavail(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
}
#endif
fs->lfs_ravail += fsb;
simple_unlock(&fs->lfs_interlock);
return 0;
}
@ -272,6 +281,17 @@ lfs_reserve(struct lfs *fs, struct vnode *vp, struct vnode *vp2, int fsb)
int error;
int cantwait;
ASSERT_MAYBE_SEGLOCK(fs);
if (vp2) {
/* Make sure we're not in the process of reclaiming vp2 */
simple_lock(&fs->lfs_interlock);
while(fs->lfs_flags & LFS_UNDIROP) {
ltsleep(&fs->lfs_flags, PRIBIO + 1, "lfsrundirop", 0,
&fs->lfs_interlock);
}
simple_unlock(&fs->lfs_interlock);
}
KASSERT(fsb < 0 || VOP_ISLOCKED(vp));
KASSERT(vp2 == NULL || fsb < 0 || VOP_ISLOCKED(vp2));
KASSERT(vp2 == NULL || !(VTOI(vp2)->i_flag & IN_ADIROP));
@ -357,6 +377,7 @@ lfs_fits(struct lfs *fs, int fsb)
{
int needed;
ASSERT_NO_SEGLOCK(fs);
needed = fsb + btofsb(fs, fs->lfs_sumsize) +
((howmany(fs->lfs_uinodes + 1, INOPB(fs)) + fs->lfs_segtabsz +
1) << (fs->lfs_blktodb - fs->lfs_fsbtodb));
@ -380,10 +401,10 @@ lfs_availwait(struct lfs *fs, int fsb)
CLEANERINFO *cip;
struct buf *cbp;
ASSERT_NO_SEGLOCK(fs);
/* Push cleaner blocks through regardless */
simple_lock(&fs->lfs_interlock);
if (fs->lfs_seglock &&
fs->lfs_lockpid == curproc->p_pid &&
if (LFS_SEGLOCK_HELD(fs) &&
fs->lfs_sp->seg_flags & (SEGM_CLEAN | SEGM_FORCE_CKP)) {
simple_unlock(&fs->lfs_interlock);
return 0;
@ -408,7 +429,7 @@ lfs_availwait(struct lfs *fs, int fsb)
wakeup(&lfs_allclean_wakeup);
wakeup(&fs->lfs_nextseg);
#ifdef DIAGNOSTIC
if (fs->lfs_seglock && fs->lfs_lockpid == curproc->p_pid)
if (LFS_SEGLOCK_HELD(fs))
panic("lfs_availwait: deadlock");
#endif
error = tsleep(&fs->lfs_avail, PCATCH | PUSER, "cleaner", 0);
@ -425,6 +446,7 @@ lfs_bwrite_ext(struct buf *bp, int flags)
struct inode *ip;
int fsb, s;
ASSERT_MAYBE_SEGLOCK(VFSTOUFS(bp->b_vp->v_mount)->um_lfs);
KASSERT(bp->b_flags & B_BUSY);
KASSERT(flags & BW_CLEAN || !LFS_IS_MALLOC_BUF(bp));
KASSERT((bp->b_flags & (B_DELWRI|B_LOCKED)) != B_DELWRI);
@ -486,25 +508,34 @@ lfs_bwrite_ext(struct buf *bp, int flags)
return (0);
}
/*
* Called and return with the lfs_interlock held, but the lfs_subsys_lock
* not held.
*/
void
lfs_flush_fs(struct lfs *fs, int flags)
{
ASSERT_NO_SEGLOCK(fs);
LOCK_ASSERT(simple_lock_held(&fs->lfs_interlock));
LOCK_ASSERT(!simple_lock_held(&lfs_subsys_lock));
if (fs->lfs_ronly)
return;
simple_lock(&lfs_subsys_lock);
lfs_subsys_pages -= fs->lfs_pages; /* XXXUBC */
if (lfs_subsys_pages < 0) /* XXXUBC */
lfs_subsys_pages = 0; /* XXXUBC */
fs->lfs_pages = 0; /* XXXUBC need a better way to count this */
lfs_writer_enter(fs, "fldirop");
if (lfs_dostats)
++lfs_stats.flush_invoked;
lfs_segwrite(fs->lfs_ivnode->v_mount, flags);
fs->lfs_favail = 0; /* XXX */
simple_unlock(&lfs_subsys_lock);
fs->lfs_pages = 0; /* XXXUBC need a better way to count this */
simple_unlock(&fs->lfs_interlock);
lfs_writer_enter(fs, "fldirop");
lfs_segwrite(fs->lfs_ivnode->v_mount, flags);
lfs_writer_leave(fs);
simple_lock(&fs->lfs_interlock);
fs->lfs_favail = 0; /* XXX */
}
/*
@ -522,6 +553,7 @@ lfs_flush(struct lfs *fs, int flags, int only_onefs)
extern u_int64_t locked_fakequeue_count;
struct mount *mp, *nmp;
ASSERT_NO_SEGLOCK(fs);
LOCK_ASSERT(simple_lock_held(&lfs_subsys_lock));
KDASSERT(fs == NULL || !LFS_SEGLOCK_HELD(fs));
@ -534,7 +566,7 @@ lfs_flush(struct lfs *fs, int flags, int only_onefs)
}
while (lfs_writing)
ltsleep(&lfs_writing, PRIBIO + 1, "lfsflush", 0,
&lfs_subsys_lock);
&lfs_subsys_lock);
lfs_writing = 1;
simple_unlock(&lfs_subsys_lock);
@ -601,10 +633,14 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
fs = ip->i_lfs;
ASSERT_NO_SEGLOCK(fs);
LOCK_ASSERT(!simple_lock_held(&fs->lfs_interlock));
/*
* If we would flush below, but dirops are active, sleep.
* Note that a dirop cannot ever reach this code!
*/
simple_lock(&fs->lfs_interlock);
simple_lock(&lfs_subsys_lock);
while (fs->lfs_dirops > 0 &&
(locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
@ -612,10 +648,12 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
lfs_subsys_pages > LFS_MAX_PAGES ||
lfs_dirvcount > LFS_MAX_DIROP || fs->lfs_diropwait > 0))
{
simple_unlock(&lfs_subsys_lock);
++fs->lfs_diropwait;
ltsleep(&fs->lfs_writer, PRIBIO+1, "bufdirop", 0,
&lfs_subsys_lock);
&fs->lfs_interlock);
--fs->lfs_diropwait;
simple_lock(&lfs_subsys_lock);
}
#ifdef DEBUG
@ -626,13 +664,17 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
DLOG((DLOG_FLUSH, "lfs_check: lqb = %ld, max %ld\n",
locked_queue_bytes + INOBYTES(fs), LFS_MAX_BYTES));
if (lfs_subsys_pages > LFS_MAX_PAGES)
DLOG((DLOG_FLUSH, "lfs_check: lssp = %d, max %d\n", lfs_subsys_pages, LFS_MAX_PAGES));
DLOG((DLOG_FLUSH, "lfs_check: lssp = %d, max %d\n",
lfs_subsys_pages, LFS_MAX_PAGES));
if (lfs_fs_pagetrip && fs->lfs_pages > lfs_fs_pagetrip)
DLOG((DLOG_FLUSH, "lfs_check: fssp = %d, trip at %d\n", fs->lfs_pages, lfs_fs_pagetrip));
DLOG((DLOG_FLUSH, "lfs_check: fssp = %d, trip at %d\n",
fs->lfs_pages, lfs_fs_pagetrip));
if (lfs_dirvcount > LFS_MAX_DIROP)
DLOG((DLOG_FLUSH, "lfs_check: ldvc = %d, max %d\n", lfs_dirvcount, LFS_MAX_DIROP));
DLOG((DLOG_FLUSH, "lfs_check: ldvc = %d, max %d\n",
lfs_dirvcount, LFS_MAX_DIROP));
if (fs->lfs_diropwait > 0)
DLOG((DLOG_FLUSH, "lfs_check: ldvw = %d\n", fs->lfs_diropwait));
DLOG((DLOG_FLUSH, "lfs_check: ldvw = %d\n",
fs->lfs_diropwait));
#endif
if (locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
@ -653,30 +695,29 @@ lfs_check(struct vnode *vp, daddr_t blkno, int flags)
locked_queue_bytes + INOBYTES(fs) > LFS_WAIT_BYTES ||
lfs_subsys_pages > LFS_WAIT_PAGES ||
lfs_dirvcount > LFS_MAX_DIROP) {
simple_unlock(&lfs_subsys_lock);
if (lfs_dostats)
++lfs_stats.wait_exceeded;
DLOG((DLOG_AVAIL, "lfs_check: waiting: count=%d, bytes=%ld\n",
locked_queue_count, locked_queue_bytes));
error = tsleep(&locked_queue_count, PCATCH | PUSER,
"buffers", hz * LFS_BUFWAIT);
if (error != EWOULDBLOCK) {
simple_lock(&lfs_subsys_lock);
error = ltsleep(&locked_queue_count, PCATCH | PUSER,
"buffers", hz * LFS_BUFWAIT, &lfs_subsys_lock);
if (error != EWOULDBLOCK)
break;
}
/*
* lfs_flush might not flush all the buffers, if some of the
* inodes were locked or if most of them were Ifile blocks
* and we weren't asked to checkpoint. Try flushing again
* to keep us from blocking indefinitely.
*/
simple_lock(&lfs_subsys_lock);
if (locked_queue_count + INOCOUNT(fs) > LFS_MAX_BUFS ||
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES) {
lfs_flush(fs, flags | SEGM_CKP, 0);
}
}
simple_unlock(&lfs_subsys_lock);
simple_unlock(&fs->lfs_interlock);
return (error);
}
@ -690,6 +731,7 @@ lfs_newbuf(struct lfs *fs, struct vnode *vp, daddr_t daddr, size_t size, int typ
size_t nbytes;
int s;
ASSERT_MAYBE_SEGLOCK(fs);
nbytes = roundup(size, fsbtob(fs, 1));
s = splbio();

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_debug.c,v 1.29 2005/03/26 19:40:31 christos Exp $ */
/* $NetBSD: lfs_debug.c,v 1.30 2005/04/01 21:59:46 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@ -71,7 +71,7 @@
#include <machine/stdarg.h>
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: lfs_debug.c,v 1.29 2005/03/26 19:40:31 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_debug.c,v 1.30 2005/04/01 21:59:46 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/namei.h>
@ -93,23 +93,35 @@ int lfs_bwrite_log(struct buf *bp, char *file, int line)
a.a_desc = VDESC(vop_bwrite);
a.a_bp = bp;
if (!(bp->b_flags & (B_DELWRI | B_GATHERED)))
LFS_ENTER_LOG("write", file, line, bp->b_lblkno, bp->b_flags);
if (!(bp->b_flags & (B_DELWRI | B_GATHERED))) {
LFS_ENTER_LOG("write", file, line, bp->b_lblkno, bp->b_flags,
curproc->p_pid);
}
return (VCALL(bp->b_vp, VOFFSET(vop_bwrite), &a));
}
void lfs_dumplog(void)
{
int i;
char *cp;
for (i = lfs_lognum; i != (lfs_lognum - 1) % LFS_LOGLENGTH; i = (i + 1) % LFS_LOGLENGTH)
for (i = lfs_lognum; i != (lfs_lognum - 1) % LFS_LOGLENGTH;
i = (i + 1) % LFS_LOGLENGTH)
if (lfs_log[i].file) {
printf("lbn %" PRId64 " %s %lx %d %s\n",
/* Only print out basename, for readability */
cp = lfs_log[i].file;
while(*cp)
++cp;
while(*cp != '/' && cp > lfs_log[i].file)
--cp;
printf("lbn %" PRId64 " %s %lx %d, %d %s\n",
lfs_log[i].block,
lfs_log[i].op,
lfs_log[i].flags,
lfs_log[i].pid,
lfs_log[i].line,
lfs_log[i].file + 56);
cp);
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_inode.c,v 1.90 2005/03/08 00:18:19 perseant Exp $ */
/* $NetBSD: lfs_inode.c,v 1.91 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_inode.c,v 1.90 2005/03/08 00:18:19 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_inode.c,v 1.91 2005/04/01 21:59:46 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -107,6 +107,7 @@ lfs_ifind(struct lfs *fs, ino_t ino, struct buf *bp)
struct ufs1_dinode *dip = (struct ufs1_dinode *)bp->b_data;
struct ufs1_dinode *ldip, *fin;
ASSERT_NO_SEGLOCK(fs);
/*
* Read the inode block backwards, since later versions of the
* inode will supercede earlier ones. Though it is unlikely, it is
@ -143,6 +144,7 @@ lfs_update(void *v)
int s;
int flags;
ASSERT_NO_SEGLOCK(fs);
if (vp->v_mount->mnt_flag & MNT_RDONLY)
return (0);
ip = VTOI(vp);
@ -155,12 +157,14 @@ lfs_update(void *v)
* for our inode completes, if we are called with UPDATE_WAIT set.
*/
s = splbio();
simple_lock(&vp->v_interlock);
while ((ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT &&
WRITEINPROG(vp)) {
DLOG((DLOG_SEG, "lfs_update: sleeping on ino %d"
" (in progress)\n", ip->i_number));
tsleep(vp, (PRIBIO+1), "lfs_update", 0);
ltsleep(vp, (PRIBIO+1), "lfs_update", 0, &vp->v_interlock);
}
simple_unlock(&vp->v_interlock);
splx(s);
TIMEVAL_TO_TIMESPEC(&time, &ts);
LFS_ITIMES(ip,
@ -176,6 +180,7 @@ lfs_update(void *v)
/* If sync, push back the vnode and any dirty blocks it may have. */
if ((ap->a_flags & (UPDATE_WAIT|UPDATE_DIROP)) == UPDATE_WAIT) {
/* Avoid flushing VDIROP. */
simple_lock(&fs->lfs_interlock);
++fs->lfs_diropwait;
while (vp->v_flag & VDIROP) {
DLOG((DLOG_DIROP, "lfs_update: sleeping on inode %d"
@ -185,12 +190,13 @@ lfs_update(void *v)
if (fs->lfs_dirops == 0)
lfs_flush_fs(fs, SEGM_SYNC);
else
tsleep(&fs->lfs_writer, PRIBIO+1, "lfs_fsync",
0);
ltsleep(&fs->lfs_writer, PRIBIO+1, "lfs_fsync",
0, &fs->lfs_interlock);
/* XXX KS - by falling out here, are we writing the vn
twice? */
}
--fs->lfs_diropwait;
simple_unlock(&fs->lfs_interlock);
return lfs_vflush(vp);
}
return 0;
@ -272,6 +278,7 @@ lfs_truncate(void *v)
ioflag = ap->a_flags;
usepc = (ovp->v_type == VREG && ovp != fs->lfs_ivnode);
ASSERT_NO_SEGLOCK(fs);
/*
* Lengthen the size of the file. We must ensure that the
* last byte of the file is allocated. Since the smallest
@ -372,8 +379,11 @@ lfs_truncate(void *v)
memset((char *)bp->b_data + offset, 0,
(u_int)(size - offset));
allocbuf(bp, size, 1);
if ((bp->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED)
if ((bp->b_flags & (B_LOCKED | B_CALL)) == B_LOCKED) {
simple_lock(&lfs_subsys_lock);
locked_queue_bytes -= obufsize - bp->b_bufsize;
simple_unlock(&lfs_subsys_lock);
}
if (bp->b_flags & B_DELWRI)
fs->lfs_avail += odb - btofsb(fs, size);
(void) VOP_BWRITE(bp);
@ -563,7 +573,9 @@ done:
oip->i_size = oip->i_ffs1_size = length;
oip->i_lfs_effnblks -= blocksreleased;
oip->i_ffs1_blocks -= real_released;
simple_lock(&fs->lfs_interlock);
fs->lfs_bfree += blocksreleased;
simple_unlock(&fs->lfs_interlock);
#ifdef DIAGNOSTIC
if (oip->i_size == 0 &&
(oip->i_ffs1_blocks != 0 || oip->i_lfs_effnblks != 0)) {
@ -592,6 +604,7 @@ lfs_blkfree(struct lfs *fs, daddr_t daddr, size_t bsize, long *lastseg,
long seg;
int error = 0;
ASSERT_SEGLOCK(fs);
bsize = fragroundup(fs, bsize);
if (daddr > 0) {
if (*lastseg != (seg = dtosn(fs, daddr))) {
@ -611,6 +624,7 @@ lfs_update_seguse(struct lfs *fs, long lastseg, size_t num)
SEGUSE *sup;
struct buf *bp;
ASSERT_SEGLOCK(fs);
if (lastseg < 0 || num == 0)
return 0;
@ -652,6 +666,7 @@ lfs_indirtrunc(struct inode *ip, daddr_t lbn, daddr_t dbn,
int nblocks, blocksreleased = 0, real_released = 0;
int error = 0, allerror = 0;
ASSERT_SEGLOCK(fs);
/*
* Calculate index in current block of last
* block to be kept. -1 indicates the entire
@ -787,6 +802,7 @@ lfs_vtruncbuf(struct vnode *vp, daddr_t lbn, int slpflag, int slptimeo)
fs = VTOI(vp)->i_lfs;
s = splbio();
ASSERT_SEGLOCK(fs);
restart:
for (bp = LIST_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
nbp = LIST_NEXT(bp, b_vnbufs);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_segment.c,v 1.158 2005/03/08 00:18:19 perseant Exp $ */
/* $NetBSD: lfs_segment.c,v 1.159 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_segment.c,v 1.158 2005/03/08 00:18:19 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.159 2005/04/01 21:59:46 perseant Exp $");
#ifdef DEBUG
# define vndebug(vp, str) do { \
@ -167,6 +167,7 @@ lfs_imtime(struct lfs *fs)
struct timespec ts;
struct inode *ip;
ASSERT_MAYBE_SEGLOCK(fs);
TIMEVAL_TO_TIMESPEC(&time, &ts);
ip = VTOI(fs->lfs_ivnode);
ip->i_ffs1_mtime = ts.tv_sec;
@ -200,6 +201,7 @@ lfs_vflush(struct vnode *vp)
ip = VTOI(vp);
fs = VFSTOUFS(vp->v_mount)->um_lfs;
ASSERT_NO_SEGLOCK(fs);
if (ip->i_flag & IN_CLEANING) {
ivndebug(vp,"vflush/in_cleaning");
LFS_CLR_UINO(ip, IN_CLEANING);
@ -267,12 +269,14 @@ lfs_vflush(struct vnode *vp)
}
/* If the node is being written, wait until that is done */
simple_lock(&vp->v_interlock);
s = splbio();
if (WRITEINPROG(vp)) {
ivndebug(vp,"vflush/writeinprog");
tsleep(vp, PRIBIO+1, "lfs_vw", 0);
ltsleep(vp, (PRIBIO+1), "lfs_vw", 0, &vp->v_interlock);
}
splx(s);
simple_unlock(&vp->v_interlock);
/* Protect against VXLOCK deadlock in vinvalbuf() */
lfs_seglock(fs, SEGM_SYNC);
@ -359,11 +363,15 @@ lfs_vflush(struct vnode *vp)
if (flushed && vp != fs->lfs_ivnode)
lfs_writeseg(fs, sp);
else do {
simple_lock(&fs->lfs_interlock);
fs->lfs_flags &= ~LFS_IFDIRTY;
simple_unlock(&fs->lfs_interlock);
lfs_writefile(fs, sp, vp);
redo = lfs_writeinode(fs, sp, ip);
redo += lfs_writeseg(fs, sp);
simple_lock(&fs->lfs_interlock);
redo += (fs->lfs_flags & LFS_IFDIRTY);
simple_unlock(&fs->lfs_interlock);
} while (redo && vp == fs->lfs_ivnode);
#endif
if (lfs_dostats) {
@ -385,12 +393,11 @@ lfs_vflush(struct vnode *vp)
*/
simple_lock(&fs->lfs_interlock);
if (fs->lfs_seglock > 1) {
simple_unlock(&fs->lfs_interlock);
while (fs->lfs_iocount > 1)
(void)tsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_vflush", 0);
} else
simple_unlock(&fs->lfs_interlock);
(void)ltsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_vflush", 0, &fs->lfs_interlock);
}
simple_unlock(&fs->lfs_interlock);
lfs_segunlock(fs);
@ -416,6 +423,7 @@ lfs_writevnodes(struct lfs *fs, struct mount *mp, struct segment *sp, int op)
struct vnode *vp, *nvp;
int inodes_written = 0, only_cleaning;
ASSERT_SEGLOCK(fs);
#ifndef LFS_NO_BACKVP_HACK
/* BEGIN HACK */
#define VN_OFFSET \
@ -489,17 +497,18 @@ lfs_writevnodes(struct lfs *fs, struct mount *mp, struct segment *sp, int op)
only_cleaning =
((ip->i_flag & IN_ALLMOD) == IN_CLEANING);
if (ip->i_number != LFS_IFILE_INUM)
if (ip->i_number != LFS_IFILE_INUM) {
lfs_writefile(fs, sp, vp);
if (!VPISEMPTY(vp)) {
if (WRITEINPROG(vp)) {
ivndebug(vp,"writevnodes/write2");
} else if (!(ip->i_flag & IN_ALLMOD)) {
LFS_SET_UINO(ip, IN_MODIFIED);
if (!VPISEMPTY(vp)) {
if (WRITEINPROG(vp)) {
ivndebug(vp,"writevnodes/write2");
} else if (!(ip->i_flag & IN_ALLMOD)) {
LFS_SET_UINO(ip, IN_MODIFIED);
}
}
(void) lfs_writeinode(fs, sp, ip);
inodes_written++;
}
(void) lfs_writeinode(fs, sp, ip);
inodes_written++;
}
if (lfs_clean_vnhead && only_cleaning)
@ -529,6 +538,7 @@ lfs_segwrite(struct mount *mp, int flags)
int redo;
fs = VFSTOUFS(mp)->um_lfs;
ASSERT_MAYBE_SEGLOCK(fs);
if (fs->lfs_ronly)
return EROFS;
@ -614,15 +624,19 @@ lfs_segwrite(struct mount *mp, int flags)
}
}
LOCK_ASSERT(LFS_SEGLOCK_HELD(fs));
did_ckp = 0;
if (do_ckp || fs->lfs_doifile) {
vp = fs->lfs_ivnode;
vn_lock(vp, LK_EXCLUSIVE);
do {
vp = fs->lfs_ivnode;
#ifdef DEBUG
LFS_ENTER_LOG("pretend", __FILE__, __LINE__, 0, 0);
LFS_ENTER_LOG("pretend", __FILE__, __LINE__, 0, 0, curproc->p_pid);
#endif
simple_lock(&fs->lfs_interlock);
fs->lfs_flags &= ~LFS_IFDIRTY;
simple_unlock(&fs->lfs_interlock);
ip = VTOI(vp);
@ -633,7 +647,9 @@ lfs_segwrite(struct mount *mp, int flags)
++did_ckp;
redo = lfs_writeinode(fs, sp, ip);
redo += lfs_writeseg(fs, sp);
simple_lock(&fs->lfs_interlock);
redo += (fs->lfs_flags & LFS_IFDIRTY);
simple_unlock(&fs->lfs_interlock);
} while (redo && do_ckp);
/*
@ -649,16 +665,23 @@ lfs_segwrite(struct mount *mp, int flags)
}
#ifdef DIAGNOSTIC
else if (do_ckp) {
int do_panic = 0;
LIST_FOREACH(bp, &vp->v_dirtyblkhd, b_vnbufs) {
if (bp->b_lblkno < fs->lfs_cleansz +
fs->lfs_segtabsz &&
!(bp->b_flags & B_GATHERED)) {
panic("dirty blocks");
printf("ifile lbn %ld still dirty (flags %lx)\n",
(long)bp->b_lblkno,
(long)bp->b_flags);
++do_panic;
}
}
if (do_panic)
panic("dirty blocks");
}
#endif
splx(s);
VOP_UNLOCK(vp, 0);
} else {
(void) lfs_writeseg(fs, sp);
}
@ -703,6 +726,7 @@ lfs_writefile(struct lfs *fs, struct segment *sp, struct vnode *vp)
IFILE *ifp;
int i, frag;
ASSERT_SEGLOCK(fs);
ip = VTOI(vp);
if (sp->seg_bytes_left < fs->lfs_bsize ||
@ -812,6 +836,7 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
struct timespec ts;
int gotblk = 0;
ASSERT_SEGLOCK(fs);
if (!(ip->i_flag & IN_ALLMOD))
return (0);
@ -989,8 +1014,11 @@ lfs_writeinode(struct lfs *fs, struct segment *sp, struct inode *ip)
sup->su_nbytes -= sizeof (struct ufs1_dinode);
redo_ifile =
(ino == LFS_IFILE_INUM && !(bp->b_flags & B_GATHERED));
if (redo_ifile)
if (redo_ifile) {
simple_lock(&fs->lfs_interlock);
fs->lfs_flags |= LFS_IFDIRTY;
simple_unlock(&fs->lfs_interlock);
}
LFS_WRITESEGENTRY(sup, fs, oldsn, bp); /* Ifile */
}
return (redo_ifile);
@ -1003,6 +1031,7 @@ lfs_gatherblock(struct segment *sp, struct buf *bp, int *sptr)
int version;
int j, blksinblk;
ASSERT_SEGLOCK(sp->fs);
/*
* If full, finish this segment. We may be doing I/O, so
* release and reacquire the splbio().
@ -1062,6 +1091,7 @@ lfs_gather(struct lfs *fs, struct segment *sp, struct vnode *vp,
struct buf *bp, *nbp;
int s, count = 0;
ASSERT_SEGLOCK(fs);
KASSERT(sp->vp == NULL);
sp->vp = vp;
s = splbio();
@ -1174,6 +1204,7 @@ lfs_update_single(struct lfs *fs, struct segment *sp, struct vnode *vp,
int num, error;
int bb, osize, obb;
ASSERT_SEGLOCK(fs);
KASSERT(sp == NULL || sp->vp == vp);
ip = VTOI(vp);
@ -1275,8 +1306,11 @@ lfs_update_single(struct lfs *fs, struct segment *sp, struct vnode *vp,
dtosn(fs, daddr), osize,
ip->i_number, lbn, daddr));
sup->su_nbytes -= osize;
if (!(bp->b_flags & B_GATHERED))
if (!(bp->b_flags & B_GATHERED)) {
simple_lock(&fs->lfs_interlock);
fs->lfs_flags |= LFS_IFDIRTY;
simple_unlock(&fs->lfs_interlock);
}
LFS_WRITESEGENTRY(sup, fs, oldsn, bp);
}
/*
@ -1303,6 +1337,7 @@ lfs_updatemeta(struct segment *sp)
int bb;
int bytesleft, size;
ASSERT_SEGLOCK(sp->fs);
vp = sp->vp;
nblocks = &sp->fip->fi_blocks[sp->fip->fi_nblocks] - sp->start_lbp;
KASSERT(nblocks >= 0);
@ -1408,6 +1443,7 @@ lfs_initseg(struct lfs *fs)
struct buf *sbp; /* buffer for SEGSUM */
int repeat = 0; /* return value */
ASSERT_SEGLOCK(fs);
/* Advance to the next segment. */
if (!LFS_PARTIAL_FITS(fs)) {
SEGUSE *sup;
@ -1456,10 +1492,12 @@ lfs_initseg(struct lfs *fs)
fs->lfs_cleanint[fs->lfs_cleanind] = fs->lfs_offset;
if (++fs->lfs_cleanind >= LFS_MAX_CLEANIND) {
/* "1" is the artificial inc in lfs_seglock */
simple_lock(&fs->lfs_interlock);
while (fs->lfs_iocount > 1) {
tsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_initseg", 0);
ltsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_initseg", 0, &fs->lfs_interlock);
}
simple_unlock(&fs->lfs_interlock);
fs->lfs_cleanind = 0;
}
}
@ -1513,6 +1551,7 @@ lfs_newseg(struct lfs *fs)
struct buf *bp;
int curseg, isdirty, sn;
ASSERT_SEGLOCK(fs);
LFS_SEGENTRY(sup, fs, dtosn(fs, fs->lfs_nextseg), bp);
DLOG((DLOG_SU, "lfs_newseg: seg %d := 0 in newseg\n",
dtosn(fs, fs->lfs_nextseg)));
@ -1561,6 +1600,7 @@ lfs_newclusterbuf(struct lfs *fs, struct vnode *vp, daddr_t addr, int n)
struct buf **bpp, *bp;
int s;
ASSERT_SEGLOCK(fs);
cl = (struct lfs_cluster *)pool_get(&fs->lfs_clpool, PR_WAITOK);
bpp = (struct buf **)pool_get(&fs->lfs_bpppool, PR_WAITOK);
memset(cl, 0, sizeof(*cl));
@ -1611,6 +1651,7 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
int changed;
u_int32_t sum;
ASSERT_SEGLOCK(fs);
/*
* If there are no buffers other than the segment summary to write
* and it is not a checkpoint, don't do anything. On a checkpoint,
@ -1672,20 +1713,24 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
bp->b_flags |= B_BUSY;
continue;
}
again:
simple_lock(&bp->b_interlock);
s = splbio();
if (bp->b_flags & B_BUSY) {
while (bp->b_flags & B_BUSY) {
DLOG((DLOG_SEG, "lfs_writeseg: avoiding potential"
" data summary corruption for ino %d, lbn %"
PRId64 "\n",
VTOI(bp->b_vp)->i_number, bp->b_lblkno));
bp->b_flags |= B_WANTED;
tsleep(bp, (PRIBIO + 1), "lfs_writeseg", 0);
ltsleep(bp, (PRIBIO + 1), "lfs_writeseg", 0,
&bp->b_interlock);
splx(s);
goto again;
s = splbio();
}
bp->b_flags |= B_BUSY;
splx(s);
simple_unlock(&bp->b_interlock);
/*
* Check and replace indirect block UNWRITTEN bogosity.
* XXX See comment in lfs_writefile.
@ -1796,8 +1841,10 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
ssp->ss_sumsum = cksum(&ssp->ss_datasum,
fs->lfs_sumsize - sizeof(ssp->ss_sumsum));
simple_lock(&fs->lfs_interlock);
fs->lfs_bfree -= (btofsb(fs, ninos * fs->lfs_ibsize) +
btofsb(fs, fs->lfs_sumsize));
simple_unlock(&fs->lfs_interlock);
/*
* When we simply write the blocks we lose a rotation for every block
@ -1833,7 +1880,9 @@ lfs_writeseg(struct lfs *fs, struct segment *sp)
/*
* Construct the cluster.
*/
simple_lock(&fs->lfs_interlock);
++fs->lfs_iocount;
simple_unlock(&fs->lfs_interlock);
while (i && cbp->b_bcount < CHUNKSIZE) {
bp = *bpp;
@ -1932,6 +1981,7 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
int s;
struct vnode *devvp = VTOI(fs->lfs_ivnode)->i_devvp;
ASSERT_MAYBE_SEGLOCK(fs);
#ifdef DIAGNOSTIC
KASSERT(fs->lfs_magic == LFS_MAGIC);
#endif
@ -1940,12 +1990,15 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
* progress, we risk not having a complete checkpoint if we crash.
* So, block here if a superblock write is in progress.
*/
simple_lock(&fs->lfs_interlock);
s = splbio();
while (fs->lfs_sbactive) {
tsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs sb", 0);
ltsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs sb", 0,
&fs->lfs_interlock);
}
fs->lfs_sbactive = daddr;
splx(s);
simple_unlock(&fs->lfs_interlock);
/* Set timestamp of this version of the superblock */
if (fs->lfs_version == 1)
@ -1972,7 +2025,9 @@ lfs_writesuper(struct lfs *fs, daddr_t daddr)
s = splbio();
V_INCR_NUMOUTPUT(bp->b_vp);
splx(s);
simple_lock(&fs->lfs_interlock);
++fs->lfs_iocount;
simple_unlock(&fs->lfs_interlock);
VOP_STRATEGY(devvp, bp);
}
@ -1984,6 +2039,7 @@ int
lfs_match_fake(struct lfs *fs, struct buf *bp)
{
ASSERT_SEGLOCK(fs);
return LFS_IS_MALLOC_BUF(bp);
}
@ -1992,6 +2048,7 @@ int
lfs_match_real(struct lfs *fs, struct buf *bp)
{
ASSERT_SEGLOCK(fs);
return (lfs_match_data(fs, bp) && !lfs_match_fake(fs, bp));
}
#endif
@ -2000,6 +2057,7 @@ int
lfs_match_data(struct lfs *fs, struct buf *bp)
{
ASSERT_SEGLOCK(fs);
return (bp->b_lblkno >= 0);
}
@ -2008,6 +2066,7 @@ lfs_match_indir(struct lfs *fs, struct buf *bp)
{
daddr_t lbn;
ASSERT_SEGLOCK(fs);
lbn = bp->b_lblkno;
return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 0);
}
@ -2017,6 +2076,7 @@ lfs_match_dindir(struct lfs *fs, struct buf *bp)
{
daddr_t lbn;
ASSERT_SEGLOCK(fs);
lbn = bp->b_lblkno;
return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 1);
}
@ -2026,6 +2086,7 @@ lfs_match_tindir(struct lfs *fs, struct buf *bp)
{
daddr_t lbn;
ASSERT_SEGLOCK(fs);
lbn = bp->b_lblkno;
return (lbn < 0 && (-lbn - NDADDR) % NINDIR(fs) == 2);
}
@ -2043,6 +2104,7 @@ lfs_callback(struct buf *bp)
struct lfs *fs;
fs = bp->b_private;
ASSERT_NO_SEGLOCK(fs);
lfs_freebuf(fs, bp);
}
@ -2052,10 +2114,13 @@ lfs_super_aiodone(struct buf *bp)
struct lfs *fs;
fs = bp->b_private;
ASSERT_NO_SEGLOCK(fs);
simple_lock(&fs->lfs_interlock);
fs->lfs_sbactive = 0;
wakeup(&fs->lfs_sbactive);
if (--fs->lfs_iocount <= 1)
wakeup(&fs->lfs_iocount);
simple_unlock(&fs->lfs_interlock);
wakeup(&fs->lfs_sbactive);
lfs_freebuf(fs, bp);
}
@ -2075,6 +2140,7 @@ lfs_cluster_aiodone(struct buf *bp)
cl = bp->b_private;
fs = cl->fs;
devvp = VTOI(fs->lfs_ivnode)->i_devvp;
ASSERT_NO_SEGLOCK(fs);
/* Put the pages back, and release the buffer */
while (cl->bufcount--) {
@ -2177,12 +2243,14 @@ lfs_cluster_aiodone(struct buf *bp)
if (--cl->seg->seg_iocount == 0)
wakeup(&cl->seg->seg_iocount);
}
simple_lock(&fs->lfs_interlock);
#ifdef DIAGNOSTIC
if (fs->lfs_iocount == 0)
panic("lfs_cluster_aiodone: zero iocount");
#endif
if (--fs->lfs_iocount <= 1)
wakeup(&fs->lfs_iocount);
simple_unlock(&fs->lfs_interlock);
pool_put(&fs->lfs_bpppool, cl->bpp);
cl->bpp = NULL;
@ -2293,6 +2361,7 @@ lfs_shellsort(struct buf **bp_array, int32_t *lb_array, int nmemb, int size)
int
lfs_vref(struct vnode *vp)
{
ASSERT_MAYBE_SEGLOCK(VTOI(vp)->i_lfs);
/*
* If we return 1 here during a flush, we risk vinvalbuf() not
* being able to flush all of the pages from this vnode, which
@ -2314,6 +2383,7 @@ lfs_vref(struct vnode *vp)
void
lfs_vunref(struct vnode *vp)
{
ASSERT_MAYBE_SEGLOCK(VTOI(vp)->i_lfs);
/*
* Analogous to lfs_vref, if the node is flushing, fake it.
*/
@ -2359,6 +2429,7 @@ void
lfs_vunref_head(struct vnode *vp)
{
ASSERT_SEGLOCK(VTOI(vp)->i_lfs);
simple_lock(&vp->v_interlock);
#ifdef DIAGNOSTIC
if (vp->v_usecount == 0) {

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_subr.c,v 1.50 2005/03/08 00:18:20 perseant Exp $ */
/* $NetBSD: lfs_subr.c,v 1.51 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_subr.c,v 1.50 2005/03/08 00:18:20 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_subr.c,v 1.51 2005/04/01 21:59:46 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -144,6 +144,7 @@ lfs_setup_resblks(struct lfs *fs)
int i, j;
int maxbpp;
ASSERT_NO_SEGLOCK(fs);
fs->lfs_resblk = (res_t *)malloc(LFS_N_TOTAL * sizeof(res_t), M_SEGMENT,
M_WAITOK);
for (i = 0; i < LFS_N_TOTAL; i++) {
@ -195,13 +196,16 @@ lfs_free_resblks(struct lfs *fs)
pool_destroy(&fs->lfs_segpool);
pool_destroy(&fs->lfs_clpool);
simple_lock(&fs->lfs_interlock);
for (i = 0; i < LFS_N_TOTAL; i++) {
while (fs->lfs_resblk[i].inuse)
tsleep(&fs->lfs_resblk, PRIBIO + 1, "lfs_free", 0);
ltsleep(&fs->lfs_resblk, PRIBIO + 1, "lfs_free", 0,
&fs->lfs_interlock);
if (fs->lfs_resblk[i].p != NULL)
free(fs->lfs_resblk[i].p, M_SEGMENT);
}
free(fs->lfs_resblk, M_SEGMENT);
simple_unlock(&fs->lfs_interlock);
}
static unsigned int
@ -222,6 +226,7 @@ lfs_malloc(struct lfs *fs, size_t size, int type)
int i, s, start;
unsigned int h;
ASSERT_MAYBE_SEGLOCK(fs);
r = NULL;
/* If no mem allocated for this type, it just waits */
@ -241,6 +246,8 @@ lfs_malloc(struct lfs *fs, size_t size, int type)
* at least one cluster block, at least one superblock,
* and several indirect blocks.
*/
simple_lock(&fs->lfs_interlock);
/* skip over blocks of other types */
for (i = 0, start = 0; i < type; i++)
start += lfs_res_qty[i];
@ -255,14 +262,19 @@ lfs_malloc(struct lfs *fs, size_t size, int type)
s = splbio();
LIST_INSERT_HEAD(&fs->lfs_reshash[h], re, res);
splx(s);
simple_unlock(&fs->lfs_interlock);
return r;
}
}
DLOG((DLOG_MALLOC, "sleeping on %s (%d)\n", lfs_res_names[type], lfs_res_qty[type]));
tsleep(&fs->lfs_resblk, PVM, "lfs_malloc", 0);
DLOG((DLOG_MALLOC, "done sleeping on %s\n", lfs_res_names[type]));
DLOG((DLOG_MALLOC, "sleeping on %s (%d)\n",
lfs_res_names[type], lfs_res_qty[type]));
ltsleep(&fs->lfs_resblk, PVM, "lfs_malloc", 0,
&fs->lfs_interlock);
DLOG((DLOG_MALLOC, "done sleeping on %s\n",
lfs_res_names[type]));
}
/* NOTREACHED */
simple_unlock(&fs->lfs_interlock);
return r;
}
@ -276,7 +288,9 @@ lfs_free(struct lfs *fs, void *p, int type)
int i;
#endif
ASSERT_MAYBE_SEGLOCK(fs);
h = lfs_mhash(p);
simple_lock(&fs->lfs_interlock);
s = splbio();
LIST_FOREACH(re, &fs->lfs_reshash[h], res) {
if (re->p == p) {
@ -285,6 +299,7 @@ lfs_free(struct lfs *fs, void *p, int type)
re->inuse = 0;
wakeup(&fs->lfs_resblk);
splx(s);
simple_unlock(&fs->lfs_interlock);
return;
}
}
@ -295,7 +310,8 @@ lfs_free(struct lfs *fs, void *p, int type)
}
#endif
splx(s);
simple_unlock(&fs->lfs_interlock);
/*
* If we didn't find it, free it.
*/
@ -321,9 +337,12 @@ lfs_seglock(struct lfs *fs, unsigned long flags)
} else if (flags & SEGM_PAGEDAEMON) {
simple_unlock(&fs->lfs_interlock);
return EWOULDBLOCK;
} else while (fs->lfs_seglock)
(void)ltsleep(&fs->lfs_seglock, PRIBIO + 1,
"lfs seglock", 0, &fs->lfs_interlock);
} else {
while (fs->lfs_seglock) {
(void)ltsleep(&fs->lfs_seglock, PRIBIO + 1,
"lfs seglock", 0, &fs->lfs_interlock);
}
}
}
fs->lfs_seglock = 1;
@ -331,6 +350,9 @@ lfs_seglock(struct lfs *fs, unsigned long flags)
simple_unlock(&fs->lfs_interlock);
fs->lfs_cleanind = 0;
#ifdef DEBUG
LFS_ENTER_LOG("seglock", __FILE__, __LINE__, 0, flags, curproc->p_pid);
#endif
/* Drain fragment size changes out */
lockmgr(&fs->lfs_fraglock, LK_EXCLUSIVE, 0);
@ -347,7 +369,9 @@ lfs_seglock(struct lfs *fs, unsigned long flags)
* so we artificially increment it by one until we've scheduled all of
* the writes we intend to do.
*/
simple_lock(&fs->lfs_interlock);
++fs->lfs_iocount;
simple_unlock(&fs->lfs_interlock);
return 0;
}
@ -360,36 +384,53 @@ lfs_unmark_dirop(struct lfs *fs)
struct vnode *vp;
int doit;
ASSERT_NO_SEGLOCK(fs);
simple_lock(&fs->lfs_interlock);
doit = !(fs->lfs_flags & LFS_UNDIROP);
if (doit)
fs->lfs_flags |= LFS_UNDIROP;
simple_unlock(&fs->lfs_interlock);
if (!doit)
if (!doit) {
simple_unlock(&fs->lfs_interlock);
return;
}
for (ip = TAILQ_FIRST(&fs->lfs_dchainhd); ip != NULL; ip = nip) {
nip = TAILQ_NEXT(ip, i_lfs_dchain);
simple_unlock(&fs->lfs_interlock);
vp = ITOV(ip);
simple_lock(&vp->v_interlock);
if (VOP_ISLOCKED(vp) &&
vp->v_lock.lk_lockholder != curproc->p_pid) {
simple_lock(&fs->lfs_interlock);
simple_unlock(&vp->v_interlock);
continue;
}
if ((VTOI(vp)->i_flag & IN_ADIROP) == 0) {
simple_lock(&fs->lfs_interlock);
simple_lock(&lfs_subsys_lock);
--lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
vp->v_flag &= ~VDIROP;
TAILQ_REMOVE(&fs->lfs_dchainhd, ip, i_lfs_dchain);
simple_unlock(&fs->lfs_interlock);
wakeup(&lfs_dirvcount);
simple_unlock(&vp->v_interlock);
simple_lock(&fs->lfs_interlock);
fs->lfs_unlockvp = vp;
simple_unlock(&fs->lfs_interlock);
vrele(vp);
simple_lock(&fs->lfs_interlock);
fs->lfs_unlockvp = NULL;
}
simple_unlock(&fs->lfs_interlock);
} else
simple_unlock(&vp->v_interlock);
simple_lock(&fs->lfs_interlock);
}
simple_lock(&fs->lfs_interlock);
fs->lfs_flags &= ~LFS_UNDIROP;
simple_unlock(&fs->lfs_interlock);
wakeup(&fs->lfs_flags);
}
static void
@ -397,6 +438,7 @@ lfs_auto_segclean(struct lfs *fs)
{
int i, error, s, waited;
ASSERT_SEGLOCK(fs);
/*
* Now that we've swapped lfs_activesb, but while we still
* hold the segment lock, run through the segment list marking
@ -413,11 +455,13 @@ lfs_auto_segclean(struct lfs *fs)
(SEGUSE_DIRTY | SEGUSE_EMPTY)) {
/* Make sure the sb is written before we clean */
simple_lock(&fs->lfs_interlock);
s = splbio();
while (waited == 0 && fs->lfs_sbactive)
tsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs asb",
0);
ltsleep(&fs->lfs_sbactive, PRIBIO+1, "lfs asb",
0, &fs->lfs_interlock);
splx(s);
simple_unlock(&fs->lfs_interlock);
waited = 1;
if ((error = lfs_do_segclean(fs, i)) != 0) {
@ -444,6 +488,7 @@ lfs_segunlock(struct lfs *fs)
sp = fs->lfs_sp;
simple_lock(&fs->lfs_interlock);
LOCK_ASSERT(LFS_SEGLOCK_HELD(fs));
if (fs->lfs_seglock == 1) {
if ((sp->seg_flags & SEGM_PROT) == 0)
do_unmark_dirop = 1;
@ -476,16 +521,21 @@ lfs_segunlock(struct lfs *fs)
* At the moment, the user's process hangs around so we can
* sleep.
*/
simple_lock(&fs->lfs_interlock);
if (--fs->lfs_iocount == 0)
LFS_DEBUG_COUNTLOCKED("lfs_segunlock");
if (fs->lfs_iocount <= 1)
wakeup(&fs->lfs_iocount);
simple_unlock(&fs->lfs_interlock);
/*
* If we're not checkpointing, we don't have to block
* other processes to wait for a synchronous write
* to complete.
*/
if (!ckp) {
#ifdef DEBUG
LFS_ENTER_LOG("segunlock_std", __FILE__, __LINE__, 0, 0, curproc->p_pid);
#endif
simple_lock(&fs->lfs_interlock);
--fs->lfs_seglock;
fs->lfs_lockpid = 0;
@ -499,14 +549,16 @@ lfs_segunlock(struct lfs *fs)
* superblocks to make sure that the checkpoint described
* by a superblock completed.
*/
simple_lock(&fs->lfs_interlock);
while (ckp && sync && fs->lfs_iocount)
(void)tsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_iocount", 0);
(void)ltsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs_iocount", 0, &fs->lfs_interlock);
while (sync && sp->seg_iocount) {
(void)tsleep(&sp->seg_iocount, PRIBIO + 1,
"seg_iocount", 0);
(void)ltsleep(&sp->seg_iocount, PRIBIO + 1,
"seg_iocount", 0, &fs->lfs_interlock);
DLOG((DLOG_SEG, "sleeping on iocount %x == %d\n", sp, sp->seg_iocount));
}
simple_unlock(&fs->lfs_interlock);
if (sync)
pool_put(&fs->lfs_segpool, sp);
@ -524,6 +576,9 @@ lfs_segunlock(struct lfs *fs)
lfs_auto_segclean(fs);
}
fs->lfs_activesb = 1 - fs->lfs_activesb;
#ifdef DEBUG
LFS_ENTER_LOG("segunlock_ckp", __FILE__, __LINE__, 0, 0, curproc->p_pid);
#endif
simple_lock(&fs->lfs_interlock);
--fs->lfs_seglock;
fs->lfs_lockpid = 0;
@ -551,6 +606,7 @@ lfs_writer_enter(struct lfs *fs, const char *wmesg)
{
int error = 0;
ASSERT_MAYBE_SEGLOCK(fs);
simple_lock(&fs->lfs_interlock);
/* disallow dirops during flush */
@ -559,7 +615,7 @@ lfs_writer_enter(struct lfs *fs, const char *wmesg)
while (fs->lfs_dirops > 0) {
++fs->lfs_diropwait;
error = ltsleep(&fs->lfs_writer, PRIBIO+1, wmesg, 0,
&fs->lfs_interlock);
&fs->lfs_interlock);
--fs->lfs_diropwait;
}
@ -576,6 +632,7 @@ lfs_writer_leave(struct lfs *fs)
{
boolean_t dowakeup;
ASSERT_MAYBE_SEGLOCK(fs);
simple_lock(&fs->lfs_interlock);
dowakeup = !(--fs->lfs_writer);
simple_unlock(&fs->lfs_interlock);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_syscalls.c,v 1.103 2005/03/08 00:18:20 perseant Exp $ */
/* $NetBSD: lfs_syscalls.c,v 1.104 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_syscalls.c,v 1.103 2005/03/08 00:18:20 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_syscalls.c,v 1.104 2005/04/01 21:59:46 perseant Exp $");
#ifndef LFS
# define LFS /* for prototypes in syscallargs.h */
@ -884,8 +884,10 @@ lfs_do_segclean(struct lfs *fs, unsigned long segnum)
if (fs->lfs_version > 1 && segnum == 0 &&
fs->lfs_start < btofsb(fs, LFS_LABELPAD))
fs->lfs_avail -= btofsb(fs, LFS_LABELPAD) - fs->lfs_start;
simple_lock(&fs->lfs_interlock);
fs->lfs_bfree += sup->su_nsums * btofsb(fs, fs->lfs_sumsize) +
btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
simple_unlock(&fs->lfs_interlock);
fs->lfs_dmeta -= sup->su_nsums * btofsb(fs, fs->lfs_sumsize) +
btofsb(fs, sup->su_ninos * fs->lfs_ibsize);
if (fs->lfs_dmeta < 0)
@ -898,7 +900,9 @@ lfs_do_segclean(struct lfs *fs, unsigned long segnum)
--cip->dirty;
fs->lfs_nclean = cip->clean;
cip->bfree = fs->lfs_bfree;
simple_lock(&fs->lfs_interlock);
cip->avail = fs->lfs_avail - fs->lfs_ravail - fs->lfs_favail;
simple_unlock(&fs->lfs_interlock);
(void) LFS_BWRITE_LOG(bp);
wakeup(&fs->lfs_avail);
@ -1026,9 +1030,13 @@ lfs_fastvget(struct mount *mp, ino_t ino, daddr_t daddr, struct vnode **vpp, str
* Wait until the filesystem is fully mounted before allowing vget
* to complete. This prevents possible problems with roll-forward.
*/
simple_lock(&fs->lfs_interlock);
while (fs->lfs_flags & LFS_NOTYET) {
tsleep(&fs->lfs_flags, PRIBIO+1, "lfs_fnotyet", 0);
ltsleep(&fs->lfs_flags, PRIBIO+1, "lfs_fnotyet", 0,
&fs->lfs_interlock);
}
simple_unlock(&fs->lfs_interlock);
/*
* This is playing fast and loose. Someone may have the inode
* locked, in which case they are going to be distinctly unhappy
@ -1166,7 +1174,9 @@ lfs_fakebuf(struct lfs *fs, struct vnode *vp, int lbn, size_t size, caddr_t uadd
KDASSERT(bp->b_iodone == lfs_callback);
#if 0
simple_lock(&fs->lfs_interlock);
++fs->lfs_iocount;
simple_unlock(&fs->lfs_interlock);
#endif
bp->b_bufsize = size;
bp->b_bcount = size;

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vfsops.c,v 1.168 2005/03/29 02:41:06 thorpej Exp $ */
/* $NetBSD: lfs_vfsops.c,v 1.169 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_vfsops.c,v 1.168 2005/03/29 02:41:06 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.169 2005/04/01 21:59:46 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@ -212,12 +212,14 @@ lfs_writerd(void *arg)
if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS,
MFSNAMELEN) == 0) {
fs = VFSTOUFS(mp)->um_lfs;
simple_lock(&fs->lfs_interlock);
if (fs->lfs_pdflush ||
!TAILQ_EMPTY(&fs->lfs_pchainhd)) {
DLOG((DLOG_FLUSH, "lfs_writerd: pdflush set\n"));
fs->lfs_pdflush = 0;
lfs_flush_fs(fs, 0);
}
simple_unlock(&fs->lfs_interlock);
}
simple_lock(&mountlist_slock);
@ -1388,8 +1390,11 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
fs->lfs_pflags |= LFS_PF_CLEAN;
lfs_writesuper(fs, fs->lfs_sboffs[0]);
lfs_writesuper(fs, fs->lfs_sboffs[1]);
simple_lock(&fs->lfs_interlock);
while (fs->lfs_iocount)
tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs_umount", 0);
ltsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs_umount", 0,
&fs->lfs_interlock);
simple_unlock(&fs->lfs_interlock);
/* Finish with the Ifile, now that we're done with it */
vrele(fs->lfs_ivnode);
@ -1418,6 +1423,9 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
/*
* Get file system statistics.
*
* NB: We don't lock to access the superblock here, because it's not
* really that important if we get it wrong.
*/
int
lfs_statvfs(struct mount *mp, struct statvfs *sbp, struct proc *p)
@ -1511,8 +1519,11 @@ lfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
* If the filesystem is not completely mounted yet, suspend
* any access requests (wait for roll-forward to complete).
*/
simple_lock(&fs->lfs_interlock);
while ((fs->lfs_flags & LFS_NOTYET) && curproc->p_pid != fs->lfs_rfpid)
tsleep(&fs->lfs_flags, PRIBIO+1, "lfs_notyet", 0);
ltsleep(&fs->lfs_flags, PRIBIO+1, "lfs_notyet", 0,
&fs->lfs_interlock);
simple_unlock(&fs->lfs_interlock);
if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
return (0);
@ -1600,6 +1611,7 @@ lfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
#ifdef DEBUG
/* If the seglock is held look at the bpp to see
what is there anyway */
simple_lock(&fs->lfs_interlock);
if (fs->lfs_seglock > 0) {
struct buf **bpp;
struct ufs1_dinode *dp;
@ -1620,11 +1632,18 @@ lfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
}
}
}
simple_unlock(&fs->lfs_interlock);
#endif /* DEBUG */
panic("lfs_vget: dinode not found");
}
DLOG((DLOG_VNODE, "lfs_vget: dinode %d not found, retrying...\n", ino));
(void)tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs ifind", 1);
simple_lock(&fs->lfs_interlock);
if (fs->lfs_iocount) {
DLOG((DLOG_VNODE, "lfs_vget: dinode %d not found, retrying...\n", ino));
(void)ltsleep(&fs->lfs_iocount, PRIBIO + 1,
"lfs ifind", 1, &fs->lfs_interlock);
} else
retries = LFS_IFIND_RETRIES;
simple_unlock(&fs->lfs_interlock);
goto again;
}
*ip->i_din.ffs1_din = *dip;
@ -1911,6 +1930,8 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
struct segment *sp = fs->lfs_sp;
UVMHIST_FUNC("lfs_gop_write"); UVMHIST_CALLED(ubchist);
ASSERT_SEGLOCK(fs);
/* The Ifile lives in the buffer cache */
KASSERT(vp != fs->lfs_ivnode);
@ -1930,7 +1951,7 @@ lfs_gop_write(struct vnode *vp, struct vm_page **pgs, int npages, int flags)
*
* XXXUBC that last statement is an oversimplification of course.
*/
if (!(fs->lfs_seglock) || fs->lfs_lockpid != curproc->p_pid ||
if (!LFS_SEGLOCK_HELD(fs) ||
(ip->i_lfs_iflags & LFSI_NO_GOP_WRITE) ||
(pgs[0]->offset & fs->lfs_bmask) != 0) {
goto tryagain;
@ -2242,7 +2263,9 @@ warn_ifile_size(struct lfs *fs)
KASSERT(LFS_MAX_BYTES > 0);
if (((fs->lfs_ivnode->v_size >> fs->lfs_bshift) - fs->lfs_segtabsz) >
LFS_MAX_BUFS) {
simple_lock(&fs->lfs_interlock);
fs->lfs_flags |= LFS_WARNED;
simple_unlock(&fs->lfs_interlock);
log(LOG_WARNING, "lfs_mountfs: inode part of ifile of length %"
PRId64 " cannot fit in %d buffers\n",
fs->lfs_ivnode->v_size -
@ -2255,7 +2278,9 @@ warn_ifile_size(struct lfs *fs)
fs->lfs_segtabsz));
} else if ((fs->lfs_ivnode->v_size >> fs->lfs_bshift) > LFS_MAX_BUFS) {
/* Same thing but LOG_NOTICE */
simple_lock(&fs->lfs_interlock);
fs->lfs_flags |= LFS_WARNED;
simple_unlock(&fs->lfs_interlock);
log(LOG_NOTICE, "lfs_mountfs: entire ifile of length %"
PRId64 " cannot fit in %d buffers\n",
fs->lfs_ivnode->v_size, LFS_MAX_BUFS);
@ -2267,7 +2292,9 @@ warn_ifile_size(struct lfs *fs)
if (fs->lfs_ivnode->v_size - (fs->lfs_segtabsz << fs->lfs_bshift) >
LFS_MAX_BYTES) {
simple_lock(&fs->lfs_interlock);
fs->lfs_flags |= LFS_WARNED;
simple_unlock(&fs->lfs_interlock);
log(LOG_WARNING, "lfs_mountfs: inode part of ifile of length %"
PRId64 " cannot fit in %lu bytes\n",
fs->lfs_ivnode->v_size - (fs->lfs_segtabsz <<
@ -2280,7 +2307,9 @@ warn_ifile_size(struct lfs *fs)
fs->lfs_bshift)) >>
PAGE_SHIFT);
} else if(fs->lfs_ivnode->v_size > LFS_MAX_BYTES) {
simple_lock(&fs->lfs_interlock);
fs->lfs_flags |= LFS_WARNED;
simple_unlock(&fs->lfs_interlock);
log(LOG_NOTICE, "lfs_mountfs: entire ifile of length %" PRId64
" cannot fit in %lu buffer bytes\n",
fs->lfs_ivnode->v_size, LFS_MAX_BYTES);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_vnops.c,v 1.140 2005/03/25 01:45:05 perseant Exp $ */
/* $NetBSD: lfs_vnops.c,v 1.141 2005/04/01 21:59:47 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_vnops.c,v 1.140 2005/03/25 01:45:05 perseant Exp $");
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.141 2005/04/01 21:59:47 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -386,6 +386,8 @@ lfs_set_dirop(struct vnode *dvp, struct vnode *vp)
KASSERT(vp == NULL || VOP_ISLOCKED(vp));
fs = VTOI(dvp)->i_lfs;
ASSERT_NO_SEGLOCK(fs);
/*
* LFS_NRESERVE calculates direct and indirect blocks as well
* as an inode block; an overestimate in most cases.
@ -393,15 +395,16 @@ lfs_set_dirop(struct vnode *dvp, struct vnode *vp)
if ((error = lfs_reserve(fs, dvp, vp, LFS_NRESERVE(fs))) != 0)
return (error);
if (fs->lfs_dirops == 0)
lfs_check(dvp, LFS_UNUSED_LBN, 0);
restart:
restart:
simple_lock(&fs->lfs_interlock);
if (fs->lfs_writer) {
ltsleep(&fs->lfs_dirops, (PRIBIO + 1) | PNORELOCK,
"lfs_sdirop", 0, &fs->lfs_interlock);
goto restart;
if (fs->lfs_dirops == 0) {
simple_unlock(&fs->lfs_interlock);
lfs_check(dvp, LFS_UNUSED_LBN, 0);
simple_lock(&fs->lfs_interlock);
}
while (fs->lfs_writer)
ltsleep(&fs->lfs_dirops, (PRIBIO + 1), "lfs_sdirop", 0,
&fs->lfs_interlock);
simple_lock(&lfs_subsys_lock);
if (lfs_dirvcount > LFS_MAX_DIROP && fs->lfs_dirops == 0) {
wakeup(&lfs_writer_daemon);
@ -458,6 +461,7 @@ lfs_set_dirop_create(struct vnode *dvp, struct vnode **vpp)
struct lfs *fs;
fs = VFSTOUFS(dvp->v_mount)->um_lfs;
ASSERT_NO_SEGLOCK(fs);
if (fs->lfs_ronly)
return EROFS;
if (vpp && (error = getnewvnode(VT_LFS, dvp->v_mount, lfs_vnodeop_p, vpp))) {
@ -524,10 +528,13 @@ lfs_mark_vnode(struct vnode *vp)
struct inode *ip = VTOI(vp);
struct lfs *fs = ip->i_lfs;
simple_lock(&fs->lfs_interlock);
if (!(ip->i_flag & IN_ADIROP)) {
if (!(vp->v_flag & VDIROP)) {
(void)lfs_vref(vp);
simple_lock(&lfs_subsys_lock);
++lfs_dirvcount;
simple_unlock(&lfs_subsys_lock);
TAILQ_INSERT_TAIL(&fs->lfs_dchainhd, ip, i_lfs_dchain);
vp->v_flag |= VDIROP;
}
@ -535,6 +542,7 @@ lfs_mark_vnode(struct vnode *vp)
ip->i_flag |= IN_ADIROP;
} else
KASSERT(vp->v_flag & VDIROP);
simple_unlock(&fs->lfs_interlock);
}
void
@ -544,7 +552,9 @@ lfs_unmark_vnode(struct vnode *vp)
if (ip->i_flag & IN_ADIROP) {
KASSERT(vp->v_flag & VDIROP);
simple_lock(&ip->i_lfs->lfs_interlock);
--ip->i_lfs->lfs_nadirop;
simple_unlock(&ip->i_lfs->lfs_interlock);
ip->i_flag &= ~IN_ADIROP;
}
}
@ -1121,8 +1131,12 @@ lfs_strategy(void *v)
DLOG((DLOG_CLEAN,
"lfs_strategy: sleeping on ino %d lbn %"
PRId64 "\n", ip->i_number, bp->b_lblkno));
tsleep(&fs->lfs_seglock, PRIBIO+1,
"lfs_strategy", 0);
simple_lock(&fs->lfs_interlock);
if (fs->lfs_seglock)
ltsleep(&fs->lfs_seglock,
(PRIBIO + 1) | PNORELOCK,
"lfs_strategy", 0,
&fs->lfs_interlock);
/* Things may be different now; start over. */
slept = 1;
break;
@ -1146,11 +1160,17 @@ lfs_flush_dirops(struct lfs *fs)
struct segment *sp;
int needunlock;
ASSERT_NO_SEGLOCK(fs);
if (fs->lfs_ronly)
return;
if (TAILQ_FIRST(&fs->lfs_dchainhd) == NULL)
simple_lock(&fs->lfs_interlock);
if (TAILQ_FIRST(&fs->lfs_dchainhd) == NULL) {
simple_unlock(&fs->lfs_interlock);
return;
} else
simple_unlock(&fs->lfs_interlock);
if (lfs_dostats)
++lfs_stats.flush_invoked;
@ -1177,8 +1197,10 @@ lfs_flush_dirops(struct lfs *fs)
* no dirops are active.
*
*/
simple_lock(&fs->lfs_interlock);
for (ip = TAILQ_FIRST(&fs->lfs_dchainhd); ip != NULL; ip = nip) {
nip = TAILQ_NEXT(ip, i_lfs_dchain);
simple_unlock(&fs->lfs_interlock);
vp = ITOV(ip);
/*
@ -1213,7 +1235,9 @@ lfs_flush_dirops(struct lfs *fs)
VOP_UNLOCK(vp, 0);
else
LFS_SET_UINO(ip, IN_MODIFIED);
simple_lock(&fs->lfs_interlock);
}
simple_unlock(&fs->lfs_interlock);
/* We've written all the dirops there are */
((SEGSUM *)(sp->segsum))->ss_flags &= ~(SS_CONT);
(void) lfs_writeseg(fs, sp);
@ -1414,6 +1438,7 @@ check_dirty(struct lfs *fs, struct vnode *vp,
int tdirty;
int pages_per_block = fs->lfs_bsize >> PAGE_SHIFT;
ASSERT_MAYBE_SEGLOCK(fs);
top:
by_list = (vp->v_uobj.uo_npages <=
((endoffset - startoffset) >> PAGE_SHIFT) *
@ -1545,7 +1570,9 @@ check_dirty(struct lfs *fs, struct vnode *vp,
if (any_dirty) {
if (!(ip->i_flags & IN_PAGING)) {
ip->i_flags |= IN_PAGING;
simple_lock(&fs->lfs_interlock);
TAILQ_INSERT_TAIL(&fs->lfs_pchainhd, ip, i_lfs_pchain);
simple_unlock(&fs->lfs_interlock);
}
}
#endif
@ -1737,7 +1764,9 @@ lfs_putpages(void *v)
* notice the pager inode queue and act on that.
*/
if (pagedaemon) {
simple_lock(&fs->lfs_interlock);
++fs->lfs_pdflush;
simple_unlock(&fs->lfs_interlock);
wakeup(&lfs_writer_daemon);
simple_unlock(&vp->v_interlock);
return EWOULDBLOCK;
@ -1761,7 +1790,9 @@ lfs_putpages(void *v)
if (locked)
VOP_UNLOCK(vp, 0);
simple_lock(&fs->lfs_interlock);
lfs_flush_fs(fs, sync ? SEGM_SYNC : 0);
simple_unlock(&fs->lfs_interlock);
simple_lock(&vp->v_interlock);
if (locked)
@ -1803,7 +1834,9 @@ lfs_putpages(void *v)
* VOP_PUTPAGES should not be called while holding the seglock.
* XXXUBC fix lfs_markv, or do this properly.
*/
/* KASSERT(fs->lfs_seglock == 1); */
#ifdef notyet
KASSERT(fs->lfs_seglock == 1);
#endif /* notyet */
/*
* We assume we're being called with sp->fip pointing at blank space.

View File

@ -1,4 +1,4 @@
/* $NetBSD: ufs_readwrite.c,v 1.61 2005/02/26 05:40:42 perseant Exp $ */
/* $NetBSD: ufs_readwrite.c,v 1.62 2005/04/01 21:59:47 perseant Exp $ */
/*-
* Copyright (c) 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.61 2005/02/26 05:40:42 perseant Exp $");
__KERNEL_RCSID(1, "$NetBSD: ufs_readwrite.c,v 1.62 2005/04/01 21:59:47 perseant Exp $");
#ifdef LFS_READWRITE
#define BLKSIZE(a, b, c) blksize(a, b, c)
@ -283,10 +283,12 @@ WRITE(void *v)
/* Account writes. This overcounts if pages are already dirty. */
if (usepc) {
simple_lock(&fs->lfs_interlock);
simple_lock(&lfs_subsys_lock);
lfs_subsys_pages += round_page(uio->uio_resid) >> PAGE_SHIFT;
fs->lfs_pages += round_page(uio->uio_resid) >> PAGE_SHIFT;
simple_unlock(&lfs_subsys_lock);
simple_unlock(&fs->lfs_interlock);
}
lfs_check(vp, LFS_UNUSED_LBN, 0);
#endif /* !LFS_READWRITE */