Page MenuHomeFreeBSD

D34282.diff
No OneTemporary

D34282.diff

diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c
--- a/sys/fs/unionfs/union_vnops.c
+++ b/sys/fs/unionfs/union_vnops.c
@@ -1764,33 +1764,52 @@
static int
unionfs_getwritemount(struct vop_getwritemount_args *ap)
{
+ struct unionfs_node *unp;
struct vnode *uvp;
- struct vnode *vp;
+ struct vnode *vp, *ovp;
int error;
UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: enter\n");
error = 0;
vp = ap->a_vp;
+ uvp = NULLVP;
- if (vp == NULLVP || (vp->v_mount->mnt_flag & MNT_RDONLY))
- return (EACCES);
-
- KASSERT_UNIONFS_VNODE(vp);
-
- uvp = UNIONFSVPTOUPPERVP(vp);
- if (uvp == NULLVP && VREG == vp->v_type)
- uvp = UNIONFSVPTOUPPERVP(VTOUNIONFS(vp)->un_dvp);
+ VI_LOCK(vp);
+ unp = VTOUNIONFS(vp);
+ if (unp != NULL)
+ uvp = unp->un_uppervp;
- if (uvp != NULLVP)
- error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
- else {
+ /*
+ * If our node has no upper vnode, check the parent directory.
+ * We may be initiating a write operation that will produce a
+ * new upper vnode through CoW.
+ */
+ if (uvp == NULLVP && unp != NULL) {
+ ovp = vp;
+ vp = unp->un_dvp;
+ /*
+ * Only the root vnode should have an empty parent, but it
+ * should not have an empty uppervp, so we shouldn't get here.
+ */
+ VNASSERT(vp != NULL, ovp, ("%s: NULL parent vnode", __func__));
+ VI_UNLOCK(ovp);
VI_LOCK(vp);
- if (vp->v_holdcnt == 0)
- error = EOPNOTSUPP;
- else
+ unp = VTOUNIONFS(vp);
+ if (unp != NULL)
+ uvp = unp->un_uppervp;
+ if (uvp == NULLVP)
error = EACCES;
+ }
+
+ if (uvp != NULLVP) {
+ vholdnz(uvp);
+ VI_UNLOCK(vp);
+ error = VOP_GETWRITEMOUNT(uvp, ap->a_mpp);
+ vdrop(uvp);
+ } else {
VI_UNLOCK(vp);
+ *(ap->a_mpp) = NULL;
}
UNIONFS_INTERNAL_DEBUG("unionfs_getwritemount: leave (%d)\n", error);

File Metadata

Mime Type
text/plain
Expires
Fri, Nov 15, 4:00 PM (17 h, 51 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14645012
Default Alt Text
D34282.diff (1 KB)

Event Timeline