diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-10-20 20:33:08 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2008-10-20 20:33:08 +0000 |
commit | a2cfe882740a787014de62d6e78b308489a55b91 (patch) | |
tree | d641026c53efe272e89c06da5c3a4198e12e163e /sys/kern | |
parent | 052b317b866076458c3a1e17f0f20ee9c7411f0b (diff) |
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
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/vfs_cache.c | 23 |
1 files changed, 14 insertions, 9 deletions
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); } } |