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.
This commit is contained in:
parent
33b53e37dc
commit
016344807a
@ -1155,38 +1155,33 @@ union_vn_close(vp, fmode, cred, td)
|
|||||||
return (VOP_CLOSE(vp, fmode, cred, td));
|
return (VOP_CLOSE(vp, fmode, cred, td));
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* union_removed_upper:
|
* 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
|
void
|
||||||
union_removed_upper(un)
|
union_removed_upper(un)
|
||||||
struct union_node *un;
|
struct union_node *un;
|
||||||
{
|
{
|
||||||
struct thread *td = curthread; /* XXX */
|
struct thread *td = curthread;
|
||||||
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);
|
|
||||||
|
|
||||||
if (un->un_flags & UN_CACHED) {
|
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;
|
un->un_flags &= ~UN_CACHED;
|
||||||
LIST_REMOVE(un, un_cache);
|
LIST_REMOVE(un, un_cache);
|
||||||
|
union_list_unlock(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine whether a whiteout is needed
|
* Determine whether a whiteout is needed
|
||||||
* during a remove/rmdir operation.
|
* during a remove/rmdir operation.
|
||||||
|
@ -1225,11 +1225,8 @@ union_remove(ap)
|
|||||||
if (union_dowhiteout(un, cnp->cn_cred, td))
|
if (union_dowhiteout(un, cnp->cn_cred, td))
|
||||||
cnp->cn_flags |= DOWHITEOUT;
|
cnp->cn_flags |= DOWHITEOUT;
|
||||||
error = VOP_REMOVE(upperdvp, uppervp, cnp);
|
error = VOP_REMOVE(upperdvp, uppervp, cnp);
|
||||||
#if 0
|
|
||||||
/* XXX */
|
|
||||||
if (!error)
|
if (!error)
|
||||||
union_removed_upper(un);
|
union_removed_upper(un);
|
||||||
#endif
|
|
||||||
union_unlock_upper(uppervp, td);
|
union_unlock_upper(uppervp, td);
|
||||||
} else {
|
} else {
|
||||||
error = union_mkwhiteout(
|
error = union_mkwhiteout(
|
||||||
@ -1542,6 +1539,8 @@ union_rmdir(ap)
|
|||||||
if (union_dowhiteout(un, cnp->cn_cred, td))
|
if (union_dowhiteout(un, cnp->cn_cred, td))
|
||||||
cnp->cn_flags |= DOWHITEOUT;
|
cnp->cn_flags |= DOWHITEOUT;
|
||||||
error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp);
|
error = VOP_RMDIR(upperdvp, uppervp, ap->a_cnp);
|
||||||
|
if (!error)
|
||||||
|
union_removed_upper(un);
|
||||||
union_unlock_upper(uppervp, td);
|
union_unlock_upper(uppervp, td);
|
||||||
} else {
|
} else {
|
||||||
error = union_mkwhiteout(
|
error = union_mkwhiteout(
|
||||||
|
Loading…
Reference in New Issue
Block a user