summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2005-03-29 09:58:41 +0000
committerjeff <jeff@FreeBSD.org>2005-03-29 09:58:41 +0000
commit16b7e8d14e336f94303ebf74c5a427d03bce4b81 (patch)
tree0267a68a7e9bda32580fd1aec3c78e9f30652bf2 /sys/kern
parenta018db09b47b8021098c3596b0f7f744dd150017 (diff)
downloadFreeBSD-src-16b7e8d14e336f94303ebf74c5a427d03bce4b81.zip
FreeBSD-src-16b7e8d14e336f94303ebf74c5a427d03bce4b81.tar.gz
- Invalidate the childrens v_dd pointers when we cache_purge() a directory.
Otherwise the stale pointer may be accessed after a vnode is freed. Sponsored by: Isilon Systems, Inc.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/vfs_cache.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 10942a3..b12d16a 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -553,23 +553,30 @@ SYSINIT(vfs, SI_SUB_VFS, SI_ORDER_SECOND, nchinit, NULL)
* XXX: by incrementing each vnodes v_id individually instead of
* XXX: using the global v_id.
*/
-
-/*
- * XXX This is sometimes called when a vnode may still be re-used, in which
- * case v_dd may be invalid. Need to look this up.
- */
void
cache_purge(vp)
struct vnode *vp;
{
+ struct namecache *ncp;
static u_long nextid;
CACHE_LOCK();
- while (!LIST_EMPTY(&vp->v_cache_src))
- cache_zap(LIST_FIRST(&vp->v_cache_src));
+ while (!LIST_EMPTY(&vp->v_cache_src)) {
+ struct vnode *cvp;
+
+ ncp = LIST_FIRST(&vp->v_cache_src);
+ /*
+ * We must reset v_dd of any children so they don't
+ * continue to point to us.
+ */
+ if ((cvp = ncp->nc_vp) && cvp->v_dd == vp) {
+ cvp->v_dd = cvp;
+ cvp->v_ddid = 0;
+ }
+ cache_zap(ncp);
+ }
while (!TAILQ_EMPTY(&vp->v_cache_dst))
cache_zap(TAILQ_FIRST(&vp->v_cache_dst));
-
do
nextid++;
while (nextid == vp->v_id || !nextid);
OpenPOWER on IntegriCloud