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:
perseant 2003-03-21 06:16:53 +00:00
parent e8d83a0b17
commit a37f4cf7ec
4 changed files with 43 additions and 81 deletions

View File

@ -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".

View File

@ -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);

View File

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

View File

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