Fixes to make dirops and lfs_vflush play together well. In particular,

if we are short on vnodes, lfs_vflush from another process can grab a
vnode that lfs_markv has already processed but not yet written; but
lfs_markv holds the seglock.  When lfs_vflush gets around to writing it,
the context for copyin is gone.  So, now lfs_markv calls copyin itself,
rather than having lfs_writeseg do it.
This commit is contained in:
perseant 1999-03-25 22:26:52 +00:00
parent 3eab58ceec
commit a3748f1cc7
3 changed files with 54 additions and 47 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_bio.c,v 1.8 1999/03/25 21:39:18 perseant Exp $ */
/* $NetBSD: lfs_bio.c,v 1.9 1999/03/25 22:26:52 perseant Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -228,7 +228,7 @@ lfs_bwrite_ext(bp, flags)
}
ip = VTOI(bp->b_vp);
if ((bp->b_flags & (B_CALL|B_INVAL)) == (B_CALL|B_INVAL))
if (bp->b_flags & B_CALL)
{
if(!(ip->i_flag & IN_CLEANING))
++fs->lfs_uinodes;
@ -256,9 +256,10 @@ lfs_bwrite_ext(bp, flags)
s = splbio();
reassignbuf(bp, bp->b_vp);
splx(s);
}
if((bp->b_flags & (B_CALL|B_INVAL)) == (B_CALL|B_INVAL))
if(bp->b_flags & B_CALL)
bp->b_flags &= ~B_BUSY;
else
brelse(bp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_segment.c,v 1.18 1999/03/25 22:02:36 perseant Exp $ */
/* $NetBSD: lfs_segment.c,v 1.19 1999/03/25 22:26:52 perseant Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -186,7 +186,25 @@ lfs_vflush(vp)
struct lfs *fs;
struct segment *sp;
int error;
struct buf *bp;
if(ip->i_flag & IN_CLEANING) {
#ifdef DEBUG_LFS
ivndebug(vp,"vflush/in_cleaning");
#endif
ip->i_flag &= ~IN_CLEANING;
if(ip->i_flag & IN_MODIFIED) {
fs->lfs_uinodes--;
} else
ip->i_flag |= IN_MODIFIED;
}
/* If the node is being written, wait until that is done */
if(WRITEINPROG(vp)) {
#ifdef DEBUG_LFS
ivndebug(vp,"vflush/writeinprog");
#endif
tsleep(vp, PRIBIO+1, "lfs_vw", 0);
}
/* Protect against VXLOCK deadlock in vinvalbuf() */
fs = VFSTOUFS(vp->v_mount)->um_lfs;
@ -203,44 +221,29 @@ lfs_vflush(vp)
ip = VTOI(vp);
if (vp->v_dirtyblkhd.lh_first == NULL) {
lfs_writevnodes(fs, vp->v_mount, sp, VN_EMPTY);
} else if((ip->i_flag & IN_CLEANING) && (fs->lfs_sp->seg_flags & SEGM_CLEAN)) {
#ifdef DEBUG_LFS
ivndebug(vp,"vflush/clean");
#endif
lfs_writevnodes(fs, vp->v_mount, sp, VN_CLEAN);
}
else if(lfs_dostats) {
if(vp->v_dirtyblkhd.lh_first || (VTOI(vp)->i_flag & (IN_MODIFIED|IN_UPDATE|IN_ACCESS|IN_CHANGE|IN_CLEANING)))
++lfs_stats.vflush_invoked;
#ifdef DEBUG_LFS
printf("V");
ivndebug(vp,"vflush");
#endif
}
/* XXX KS - can this ever happen? I think so.... */
if(ip->i_flag & IN_CLEANING) {
#ifdef DEBUG_LFS
printf("C");
#endif
ip->i_flag &= ~IN_CLEANING;
/*
* XXX Copyin all of the fake buffers *now* to avoid
* a later panic; and take off B_INVAL.
*/
for(bp=vp->v_dirtyblkhd.lh_first; bp; bp=bp->b_vnbufs.le_next) {
if((bp->b_flags & (B_CALL|B_INVAL))==(B_CALL|B_INVAL)) {
bp->b_data = malloc(bp->b_bufsize, M_SEGMENT, M_WAITOK);
copyin(bp->b_saveaddr, bp->b_data, bp->b_bcount);
bp->b_flags &= ~B_INVAL;
}
}
if(ip->i_flag & IN_MODIFIED) {
fs->lfs_uinodes--;
#ifdef DEBUG_LFS
if((int32_t)fs->lfs_uinodes<0) {
printf("U4");
fs->lfs_uinodes=0;
}
#endif
} else
ip->i_flag |= IN_MODIFIED;
#ifdef DIAGNOSTIC
if(vp->v_flag & VDIROP) {
panic("VDIROP being freed...this can\'t happen");
}
if(vp->v_usecount<0) {
printf("usecount=%d\n",vp->v_usecount);
panic("lfs_vflush: usecount<0");
}
#endif
do {
do {
@ -1248,6 +1251,8 @@ lfs_writeseg(fs, sp)
bp->b_flags &= ~B_NEEDCOMMIT;
wakeup(bp);
}
/* if(vn->v_dirtyblkhd.lh_first == NULL) */
wakeup(vn);
bpp++;
}
++cbp->b_vp->v_numoutput;
@ -1347,7 +1352,7 @@ lfs_match_fake(fs, bp)
struct lfs *fs;
struct buf *bp;
{
return (bp->b_flags & (B_CALL|B_INVAL))==(B_CALL|B_INVAL);
return (bp->b_flags & B_CALL);
}
int

View File

@ -1,4 +1,4 @@
/* $NetBSD: lfs_syscalls.c,v 1.24 1999/03/25 21:54:10 perseant Exp $ */
/* $NetBSD: lfs_syscalls.c,v 1.25 1999/03/25 22:26:52 perseant Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
@ -101,7 +101,6 @@ int debug_cleaner = 0;
int clean_vnlocked = 0;
int clean_inlocked = 0;
int verbose_debug = 0;
int lfs_clean_vnhead = 1;
pid_t lfs_cleaner_pid = 0;
@ -649,7 +648,7 @@ lfs_bmapv(p, v, retval)
v_daddr = LFS_UNUSED_DADDR;
need_unlock = 0;
#ifdef DEBUG_LFS
printf("lfs_bmapv: vget of ino %d failed with %d)",blkp->bi_inode,error);
printf("lfs_bmapv: vget of ino %d failed with %d",blkp->bi_inode,error);
#endif
continue;
} else {
@ -1037,20 +1036,22 @@ lfs_fakebuf(vp, lbn, size, uaddr)
caddr_t uaddr;
{
struct buf *bp;
int error;
#ifdef DEBUG
/* Check for duplicates too */
if(incore(vp,lbn)) {
printf("Fake buffer (%d/%d) is in core\n", VTOI(vp)->i_number,
lbn);
if(bread(vp, lbn, size, NOCRED, &bp))
return NULL;
#ifndef ALLOW_VFLUSH_CORRUPTION
bp = lfs_newbuf(vp, lbn, size);
error = copyin(uaddr, bp->b_data, size);
if(error) {
lfs_freebuf(bp);
return NULL;
}
#endif
#else
bp = lfs_newbuf(vp, lbn, 0);
bp->b_flags |= B_INVAL;
bp->b_saveaddr = uaddr;
#endif
bp->b_bufsize = size;
bp->b_bcount = size;
bp->b_flags |= B_INVAL;
return (bp);
}