From a2cfe882740a787014de62d6e78b308489a55b91 Mon Sep 17 00:00:00 2001 From: Theo de Raadt Date: Mon, 20 Oct 2008 20:33:08 +0000 Subject: The optimization done in 1.19 (and repaired in 1.20) results in cache entries which are freed (and potentially reused), but which are currently in use by another kernel thread which was sleeping in vput() or vget(). This causes the crash in PR 5960, but potentially a bunch of other side effects. figured out with pedro. ok kettenis --- sys/kern/vfs_cache.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'sys/kern') diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index f11e4240b99..9356cb32039 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_cache.c,v 1.26 2008/05/06 20:57:19 thib Exp $ */ +/* $OpenBSD: vfs_cache.c,v 1.27 2008/10/20 20:33:07 deraadt Exp $ */ /* $NetBSD: vfs_cache.c,v 1.13 1996/02/04 02:18:09 christos Exp $ */ /* @@ -244,8 +244,7 @@ remove: ncp->nc_vhash.le_prev = NULL; } - pool_put(&nch_pool, ncp); - numcache--; + TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); return (-1); } @@ -393,7 +392,7 @@ cache_enter(struct vnode *dvp, struct vnode *vp, struct componentname *cnp) * Name cache initialization, from vfs_init() when we are booting */ void -nchinit(void) +nchinit() { TAILQ_INIT(&nclruhead); @@ -428,17 +427,22 @@ cache_purge(struct vnode *vp) /* * Cache flush, a whole filesystem; called when filesys is umounted to * remove entries that would now be invalid + * + * The line "nxtcp = nchhead" near the end is to avoid potential problems + * if the cache lru chain is modified while we are dumping the + * inode. This makes the algorithm O(n^2), but do you think I care? */ void cache_purgevfs(struct mount *mp) { struct namecache *ncp, *nxtcp; - + for (ncp = TAILQ_FIRST(&nclruhead); ncp != TAILQ_END(&nclruhead); ncp = nxtcp) { - nxtcp = TAILQ_NEXT(ncp, nc_lru); - if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) + if (ncp->nc_dvp == NULL || ncp->nc_dvp->v_mount != mp) { + nxtcp = TAILQ_NEXT(ncp, nc_lru); continue; + } /* free the resources we had */ ncp->nc_vp = NULL; ncp->nc_dvp = NULL; @@ -451,7 +455,8 @@ cache_purgevfs(struct mount *mp) LIST_REMOVE(ncp, nc_vhash); ncp->nc_vhash.le_prev = NULL; } - pool_put(&nch_pool, ncp); - numcache--; + /* cause rescan of list, it may have altered */ + nxtcp = TAILQ_FIRST(&nclruhead); + TAILQ_INSERT_HEAD(&nclruhead, ncp, nc_lru); } } -- cgit v1.2.3