summaryrefslogtreecommitdiffstats
path: root/sys/fs/unionfs/union_subr.c
diff options
context:
space:
mode:
authorgreen <green@FreeBSD.org>2004-01-16 16:31:01 +0000
committergreen <green@FreeBSD.org>2004-01-16 16:31:01 +0000
commitb67f04e53c2968bad8783b4321a7ec2e1f325d86 (patch)
tree81ba36b02da8b4548511d223c780587ec2586b3d /sys/fs/unionfs/union_subr.c
parente491a39ed82b58b2f2496efdcd848e169f0c89ce (diff)
downloadFreeBSD-src-b67f04e53c2968bad8783b4321a7ec2e1f325d86.zip
FreeBSD-src-b67f04e53c2968bad8783b4321a7ec2e1f325d86.tar.gz
Fix an upper-vnode leak created in revision 1.52. When an upper-layer
file has been removed, it should be purged from the cache, but it need not be removed from the directory stack causing corruption; instead, it will simply be removed once the last references and holds on it are dropped at the end of the unlink/rmdir system calls, and the normal !UN_CACHED VOP_INACTIVE() handler for unionfs finishes it off. This is easily reproduced by repeated "echo >file; rm file" on a unionfs mount. Strangely, "echo -n >file; rm file" didn't make it happen.
Diffstat (limited to 'sys/fs/unionfs/union_subr.c')
-rw-r--r--sys/fs/unionfs/union_subr.c27
1 files changed, 11 insertions, 16 deletions
diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c
index 896a5b9..fab061a 100644
--- a/sys/fs/unionfs/union_subr.c
+++ b/sys/fs/unionfs/union_subr.c
@@ -1155,38 +1155,33 @@ union_vn_close(vp, fmode, cred, td)
return (VOP_CLOSE(vp, fmode, cred, td));
}
-#if 0
-
/*
* union_removed_upper:
*
- * called with union_node unlocked. XXX
+ * An upper-only file/directory has been removed; un-cache it so
+ * that unionfs vnode gets reclaimed and the last uppervp reference
+ * disappears.
+ *
+ * Called with union_node unlocked.
*/
void
union_removed_upper(un)
struct union_node *un;
{
- struct thread *td = curthread; /* XXX */
- struct vnode **vpp;
-
- /*
- * Do not set the uppervp to NULLVP. If lowervp is NULLVP,
- * union node will have neither uppervp nor lowervp. We remove
- * the union node from cache, so that it will not be referrenced.
- */
- union_newupper(un, NULLVP);
- if (un->un_dircache != NULL)
- union_dircache_free(un);
+ struct thread *td = curthread;
if (un->un_flags & UN_CACHED) {
+ int hash = UNION_HASH(un->un_uppervp, un->un_lowervp);
+
+ while (union_list_lock(hash))
+ continue;
un->un_flags &= ~UN_CACHED;
LIST_REMOVE(un, un_cache);
+ union_list_unlock(hash);
}
}
-#endif
-
/*
* Determine whether a whiteout is needed
* during a remove/rmdir operation.
OpenPOWER on IntegriCloud