prevent in-core vnode being freed from getting new references.

otherwise, once the corresponding bit in the inode bitmap is cleared,
an unrelated inode with the same inode number can be allocated and
ufs_ihashget() picks a stale in-core vnode for it.

PR/32301 by Matthias Scheler.
This commit is contained in:
yamt 2005-12-23 15:31:40 +00:00
parent 0616e4b566
commit 523e856cba
4 changed files with 14 additions and 34 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_subr.c,v 1.256 2005/12/11 12:24:30 christos Exp $ */
/* $NetBSD: vfs_subr.c,v 1.257 2005/12/23 15:31:40 yamt Exp $ */
/*-
* Copyright (c) 1997, 1998, 2004, 2005 The NetBSD Foundation, Inc.
@ -80,7 +80,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.256 2005/12/11 12:24:30 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.257 2005/12/23 15:31:40 yamt Exp $");
#include "opt_inet.h"
#include "opt_ddb.h"
@ -1175,7 +1175,7 @@ vget(struct vnode *vp, int flags)
if ((flags & LK_INTERLOCK) == 0)
simple_lock(&vp->v_interlock);
if (vp->v_flag & VXLOCK) {
if ((vp->v_flag & (VXLOCK | VFREEING)) != 0) {
if (flags & LK_NOWAIT) {
simple_unlock(&vp->v_interlock);
return EBUSY;
@ -1201,32 +1201,7 @@ vget(struct vnode *vp, int flags)
#endif
if (flags & LK_TYPE_MASK) {
if ((error = vn_lock(vp, flags | LK_INTERLOCK))) {
/*
* must expand vrele here because we do not want
* to call VOP_INACTIVE if the reference count
* drops back to zero since it was never really
* active. We must remove it from the free list
* before sleeping so that multiple processes do
* not try to recycle it.
*/
simple_lock(&vp->v_interlock);
vp->v_usecount--;
if (vp->v_usecount > 0) {
simple_unlock(&vp->v_interlock);
return (error);
}
/*
* insert at tail of LRU list
*/
simple_lock(&vnode_free_list_slock);
if (vp->v_holdcnt > 0)
TAILQ_INSERT_TAIL(&vnode_hold_list, vp,
v_freelist);
else
TAILQ_INSERT_TAIL(&vnode_free_list, vp,
v_freelist);
simple_unlock(&vnode_free_list_slock);
simple_unlock(&vp->v_interlock);
vrele(vp);
}
return (error);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: vnode.h,v 1.147 2005/12/14 21:57:11 reinoud Exp $ */
/* $NetBSD: vnode.h,v 1.148 2005/12/23 15:31:40 yamt Exp $ */
/*
* Copyright (c) 1989, 1993
@ -165,6 +165,7 @@ struct vnode {
#define VDIROP 0x1000 /* LFS: vnode is involved in a directory op */
#define VLAYER 0x2000 /* vnode is on a layer filesystem */
#define VONWORKLST 0x4000 /* On syncer work-list */
#define VFREEING 0x8000 /* vnode is being freed */
#define VNODE_FLAGBITS \
"\20\1ROOT\2TEXT\3SYSTEM\4ISTTY\5EXECMAP\6WRITEMAP\7WRITEMAPDIRTY" \

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_alloc.c,v 1.89 2005/11/27 11:45:56 dsl Exp $ */
/* $NetBSD: ffs_alloc.c,v 1.90 2005/12/23 15:31:40 yamt Exp $ */
/*
* Copyright (c) 2002 Networks Associates Technology, Inc.
@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.89 2005/11/27 11:45:56 dsl Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_alloc.c,v 1.90 2005/12/23 15:31:40 yamt Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@ -684,6 +684,7 @@ ffs_valloc(struct vnode *pvp, int mode, struct ucred *cred,
ffs_vfree(pvp, ino, mode);
return (error);
}
KASSERT((*vpp)->v_type == VNON);
ip = VTOI(*vpp);
if (ip->i_mode) {
#if 0

View File

@ -1,4 +1,4 @@
/* $NetBSD: ufs_inode.c,v 1.55 2005/12/11 12:25:28 christos Exp $ */
/* $NetBSD: ufs_inode.c,v 1.56 2005/12/23 15:31:40 yamt Exp $ */
/*
* Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.55 2005/12/11 12:25:28 christos Exp $");
__KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.56 2005/12/23 15:31:40 yamt Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@ -118,6 +118,9 @@ ufs_inactive(void *v)
ip->i_mode = 0;
DIP_ASSIGN(ip, mode, 0);
ip->i_flag |= IN_CHANGE | IN_UPDATE;
simple_lock(&vp->v_interlock);
vp->v_flag |= VFREEING;
simple_unlock(&vp->v_interlock);
if (DOINGSOFTDEP(vp))
softdep_change_linkcnt(ip);
UFS_VFREE(vp, ip->i_number, mode);