Use VONWORKLST as a heuristic for vnode emptiness, rather than exhaustively
checking the memq. Take greater care not to dirty the Ifile vnode when unmounting the filesystem. This should fix a "(vp->v_flag & VONWORKLST) == 0" assertion panic in vgonel that could occur when unmounting. Do not allow the Ifile to be mapped for writing.
This commit is contained in:
parent
e8d83a0b17
commit
a37f4cf7ec
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs.h,v 1.58 2003/03/15 06:58:49 perseant Exp $ */
|
||||
/* $NetBSD: lfs.h,v 1.59 2003/03/21 06:16:53 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -284,8 +284,9 @@ extern struct lfs_log_entry lfs_log[LFS_LOGLENGTH];
|
|||
* How to find out whether a vnode had dirty buffers or pages,
|
||||
* to know whether it needs to retain IN_MODIFIED after a write.
|
||||
*/
|
||||
int lfs_checkifempty(struct vnode *);
|
||||
#define VPISEMPTY(vp) lfs_checkifempty(vp)
|
||||
#define VPISEMPTY(vp) (LIST_EMPTY(&(vp)->v_dirtyblkhd) && \
|
||||
!((vp)->v_flag & VONWORKLST))
|
||||
|
||||
/*
|
||||
* WRITEINPROG does not use VPISEMPTY because any dirty pages will
|
||||
* have been given buffer headers, if they are "in progress".
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_segment.c,v 1.113 2003/03/20 14:17:21 yamt Exp $ */
|
||||
/* $NetBSD: lfs_segment.c,v 1.114 2003/03/21 06:16:54 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -71,7 +71,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.113 2003/03/20 14:17:21 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_segment.c,v 1.114 2003/03/21 06:16:54 perseant Exp $");
|
||||
|
||||
#define ivndebug(vp,str) printf("ino %d: %s\n",VTOI(vp)->i_number,(str))
|
||||
|
||||
|
@ -538,7 +538,7 @@ lfs_segwrite(struct mount *mp, int flags)
|
|||
struct vnode *vp;
|
||||
SEGUSE *segusep;
|
||||
daddr_t ibno;
|
||||
int do_ckp, did_ckp, error, i;
|
||||
int do_ckp, did_ckp, error, i, s;
|
||||
int writer_set = 0;
|
||||
int dirty;
|
||||
int redo;
|
||||
|
@ -676,6 +676,7 @@ lfs_segwrite(struct mount *mp, int flags)
|
|||
* for other parts of the Ifile to be dirty after the loop
|
||||
* above, since we hold the segment lock.
|
||||
*/
|
||||
s = splbio();
|
||||
if (LIST_EMPTY(&vp->v_dirtyblkhd)) {
|
||||
LFS_CLR_UINO(ip, IN_ALLMOD);
|
||||
}
|
||||
|
@ -690,6 +691,7 @@ lfs_segwrite(struct mount *mp, int flags)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
splx(s);
|
||||
} else {
|
||||
(void) lfs_writeseg(fs, sp);
|
||||
}
|
||||
|
@ -2187,14 +2189,10 @@ lfs_cluster_aiodone(struct buf *bp)
|
|||
* the locked list to be written again.
|
||||
*/
|
||||
vp = tbp->b_vp;
|
||||
|
||||
if ((tbp->b_flags & (B_LOCKED | B_DELWRI)) == B_LOCKED)
|
||||
LFS_UNLOCK_BUF(tbp);
|
||||
#if 0
|
||||
else if (vp != devvp)
|
||||
printf("dirtied while busy?! bp %p, ino %d, lbn %d\n",
|
||||
tbp, vp ? VTOI(vp)->i_number : -1,
|
||||
tbp->b_lblkno);
|
||||
#endif
|
||||
|
||||
tbp->b_flags &= ~B_GATHERED;
|
||||
|
||||
LFS_BCLEAN_LOG(fs, tbp);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_vfsops.c,v 1.108 2003/03/21 06:09:08 yamt Exp $ */
|
||||
/* $NetBSD: lfs_vfsops.c,v 1.109 2003/03/21 06:16:55 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -71,7 +71,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.108 2003/03/21 06:09:08 yamt Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.109 2003/03/21 06:16:55 perseant Exp $");
|
||||
|
||||
#if defined(_KERNEL_OPT)
|
||||
#include "opt_quota.h"
|
||||
|
@ -1345,6 +1345,7 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
|
|||
struct ufsmount *ump;
|
||||
struct lfs *fs;
|
||||
int error, flags, ronly;
|
||||
int s;
|
||||
|
||||
flags = 0;
|
||||
if (mntflags & MNT_FORCE)
|
||||
|
@ -1373,13 +1374,10 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
|
|||
return (error);
|
||||
if ((error = VFS_SYNC(mp, 1, p->p_ucred, p)) != 0)
|
||||
return (error);
|
||||
s = splbio();
|
||||
if (LIST_FIRST(&fs->lfs_ivnode->v_dirtyblkhd))
|
||||
panic("lfs_unmount: still dirty blocks on ifile vnode");
|
||||
|
||||
/* Explicitly write the superblock, to update serial and pflags */
|
||||
fs->lfs_pflags |= LFS_PF_CLEAN;
|
||||
lfs_writesuper(fs, fs->lfs_sboffs[0]);
|
||||
lfs_writesuper(fs, fs->lfs_sboffs[1]);
|
||||
splx(s);
|
||||
|
||||
/* Comment on ifile size if it has become too large */
|
||||
if (!(fs->lfs_flags & LFS_WARNED)) {
|
||||
|
@ -1396,14 +1394,17 @@ lfs_unmount(struct mount *mp, int mntflags, struct proc *p)
|
|||
bufpages / LFS_MAX_BYTES);
|
||||
}
|
||||
|
||||
/* Explicitly write the superblock, to update serial and pflags */
|
||||
fs->lfs_pflags |= LFS_PF_CLEAN;
|
||||
lfs_writesuper(fs, fs->lfs_sboffs[0]);
|
||||
lfs_writesuper(fs, fs->lfs_sboffs[1]);
|
||||
while (fs->lfs_iocount)
|
||||
tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs_umount", 0);
|
||||
|
||||
/* Finish with the Ifile, now that we're done with it */
|
||||
vrele(fs->lfs_ivnode);
|
||||
vgone(fs->lfs_ivnode);
|
||||
|
||||
/* Wait for superblock writes to complete */
|
||||
while (fs->lfs_iocount)
|
||||
tsleep(&fs->lfs_iocount, PRIBIO + 1, "lfs_umount", 0);
|
||||
|
||||
ronly = !fs->lfs_ronly;
|
||||
if (ump->um_devvp->v_type != VBAD)
|
||||
ump->um_devvp->v_specmountpoint = NULL;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: lfs_vnops.c,v 1.96 2003/03/15 06:58:51 perseant Exp $ */
|
||||
/* $NetBSD: lfs_vnops.c,v 1.97 2003/03/21 06:16:56 perseant Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
|
||||
|
@ -71,7 +71,7 @@
|
|||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.96 2003/03/15 06:58:51 perseant Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: lfs_vnops.c,v 1.97 2003/03/21 06:16:56 perseant Exp $");
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
@ -361,6 +361,15 @@ lfs_inactive(void *v)
|
|||
|
||||
lfs_unmark_vnode(ap->a_vp);
|
||||
|
||||
/*
|
||||
* The Ifile is only ever inactivated on unmount.
|
||||
* Streamline this process by not giving it more dirty blocks.
|
||||
*/
|
||||
if (VTOI(ap->a_vp)->i_number == LFS_IFILE_INUM) {
|
||||
LFS_CLR_UINO(VTOI(ap->a_vp), IN_ALLMOD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ufs_inactive(v);
|
||||
}
|
||||
|
||||
|
@ -914,7 +923,11 @@ lfs_close(void *v)
|
|||
struct inode *ip = VTOI(vp);
|
||||
struct timespec ts;
|
||||
|
||||
if (vp->v_usecount > 1) {
|
||||
if (vp == ip->i_lfs->lfs_ivnode &&
|
||||
vp->v_mount->mnt_flag & MNT_UNMOUNT)
|
||||
return 0;
|
||||
|
||||
if (vp->v_usecount > 1 && vp != ip->i_lfs->lfs_ivnode) {
|
||||
TIMEVAL_TO_TIMESPEC(&time, &ts);
|
||||
LFS_ITIMES(ip, &ts, &ts, &ts);
|
||||
}
|
||||
|
@ -1311,6 +1324,10 @@ lfs_getpages(void *v)
|
|||
int a_flags;
|
||||
} */ *ap = v;
|
||||
|
||||
if (VTOI(ap->a_vp)->i_number == LFS_IFILE_INUM &&
|
||||
(ap->a_access_type & VM_PROT_WRITE) != 0) {
|
||||
return EPERM;
|
||||
}
|
||||
if ((ap->a_access_type & VM_PROT_WRITE) != 0) {
|
||||
LFS_SET_UINO(VTOI(ap->a_vp), IN_MODIFIED);
|
||||
}
|
||||
|
@ -1857,61 +1874,6 @@ lfs_putpages(void *v)
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find out whether the vnode has any blocks or pages waiting to be written.
|
||||
* We used to just check LIST_EMPTY(&vp->v_dirtyblkhd), but there is not
|
||||
* presently as simple a mechanism for the page cache.
|
||||
*/
|
||||
int
|
||||
lfs_checkifempty(struct vnode *vp)
|
||||
{
|
||||
struct vm_page *pg;
|
||||
struct buf *bp;
|
||||
int r, s;
|
||||
|
||||
if (vp->v_type != VREG || VTOI(vp)->i_number == LFS_IFILE_INUM)
|
||||
return LIST_EMPTY(&vp->v_dirtyblkhd);
|
||||
|
||||
/*
|
||||
* For vnodes with pages it is a little more complex.
|
||||
* Pages that have been written (i.e. are "clean" for our purposes)
|
||||
* might be in seemingly dirty buffers, so we have to troll
|
||||
* looking for indirect block buffers as well as pages.
|
||||
*/
|
||||
simple_lock(&vp->v_interlock);
|
||||
s = splbio();
|
||||
for (bp = LIST_FIRST(&vp->v_dirtyblkhd); bp;
|
||||
bp = LIST_NEXT(bp, b_vnbufs)) {
|
||||
if (bp->b_lblkno < 0) {
|
||||
splx(s);
|
||||
simple_unlock(&vp->v_interlock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
splx(s);
|
||||
|
||||
/*
|
||||
* Run through the page list to find dirty pages.
|
||||
* Right now I just walk the memq.
|
||||
*/
|
||||
pg = TAILQ_FIRST(&vp->v_uobj.memq);
|
||||
r = 1;
|
||||
while(pg) {
|
||||
if ((pg->flags & PG_CLEAN) == 0 || pmap_is_modified(pg)) {
|
||||
r = 0;
|
||||
break;
|
||||
}
|
||||
pg = TAILQ_NEXT(pg, listq);
|
||||
}
|
||||
#if 0
|
||||
if (r != !(vp->v_flag & VONWORKLST)) {
|
||||
printf("nope, VONWORKLST isn't good enough!\n");
|
||||
}
|
||||
#endif
|
||||
simple_unlock(&vp->v_interlock);
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the last logical file offset that should be written for this file
|
||||
* if we're doing a write that ends at "size". If writing, we need to know
|
||||
|
|
Loading…
Reference in New Issue