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:
parent
3eab58ceec
commit
a3748f1cc7
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue