From 32b6dcd8a4c816ca8c4b51b50acffc6c957028eb Mon Sep 17 00:00:00 2001 From: Jeff Roberson Date: Fri, 17 Jun 2005 01:05:13 +0000 Subject: [PATCH] - Fix a leaked reference to a vnode via v_dd. We rely on cache_purge() and cache_zap() to clear the v_dd pointers when a directory vnode is forcibly discarded. For this to work, all vnodes with v_dd pointers to a directory must also have name cache entries linked via v_cache_dst to that dvp otherwise we could not find them at cache_purge() time. The following code snipit could break this guarantee by unlinking a directory before fetching it's dotdot. The dotdot lookup would initialize the v_dd field of the unlinked directory which could never be cleared. To fix this we don't initialize v_dd for orphaned vnodes. printf("rmdir: %d\n", rmdir("../foo")); /* foo is cwd */ printf("chdir: %d\n", chdir("..")); printf("%s\n", getwd(NULL)); Sponsored by: Isilon Systems, Inc. Discovered by: kkenn Approved by: re (blanket vfs) --- sys/kern/vfs_cache.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c index 88ecc3569fa1..4dfbe93669e1 100644 --- a/sys/kern/vfs_cache.c +++ b/sys/kern/vfs_cache.c @@ -493,8 +493,18 @@ cache_enter(dvp, vp, cnp) if (cnp->cn_namelen == 1) { return; } + /* + * For dotdot lookups only cache the v_dd pointer if the + * directory has a link back to its parent via v_cache_dst. + * Without this an unlinked directory would keep a soft + * reference to its parent which could not be NULLd at + * cache_purge() time. + */ if (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.') { - dvp->v_dd = vp; + CACHE_LOCK(); + if (!TAILQ_EMPTY(&dvp->v_cache_dst)) + dvp->v_dd = vp; + CACHE_UNLOCK(); return; } }