Page MenuHomeFreeBSD

D33611.id100745.diff
No OneTemporary

D33611.id100745.diff

Index: sys/fs/unionfs/union_subr.c
===================================================================
--- sys/fs/unionfs/union_subr.c
+++ sys/fs/unionfs/union_subr.c
@@ -57,6 +57,8 @@
#include <sys/taskqueue.h>
#include <sys/resourcevar.h>
+#include <machine/atomic.h>
+
#include <security/mac/mac_framework.h>
#include <vm/uma.h>
@@ -435,6 +437,7 @@
struct vnode *uvp;
struct vnode *dvp;
int count;
+ int writerefs;
KASSERT(vp->v_vnlock->lk_recurse == 0,
("%s: vnode %p locked recursively", __func__, vp));
@@ -454,13 +457,6 @@
vp->v_vnlock = &(vp->v_lock);
vp->v_data = NULL;
vp->v_object = NULL;
- if (vp->v_writecount > 0) {
- if (uvp != NULL)
- VOP_ADD_WRITECOUNT(uvp, -vp->v_writecount);
- else if (lvp != NULL)
- VOP_ADD_WRITECOUNT(lvp, -vp->v_writecount);
- } else if (vp->v_writecount < 0)
- vp->v_writecount = 0;
if (unp->un_hashtbl != NULL) {
/*
* Clear out any cached child vnodes. This should only
@@ -479,6 +475,19 @@
}
VI_UNLOCK(vp);
+ writerefs = atomic_load_int(&vp->v_writecount);
+ VNASSERT(writerefs >= 0, vp,
+ ("%s: write count %d, unexpected text ref", __func__, writerefs));
+ /*
+ * If we were opened for write, we leased the write reference
+ * to the lower vnode. If this is a reclamation due to the
+ * forced unmount, undo the reference now.
+ */
+ if (writerefs > 0) {
+ VNASSERT(uvp != NULL, vp,
+ ("%s: write reference without upper vnode", __func__));
+ VOP_ADD_WRITECOUNT(uvp, -writerefs);
+ }
if (lvp != NULLVP)
VOP_UNLOCK(lvp);
if (uvp != NULLVP)
@@ -805,6 +814,8 @@
ASSERT_VOP_ELOCKED(uvp, __func__);
dvp = unp->un_dvp;
+ VNASSERT(vp->v_writecount == 0, vp,
+ ("%s: non-zero writecount", __func__));
/*
* Uppdate the upper vnode's lock state to match the lower vnode,
* and then switch the unionfs vnode's lock to the upper vnode.
Index: sys/fs/unionfs/union_vnops.c
===================================================================
--- sys/fs/unionfs/union_vnops.c
+++ sys/fs/unionfs/union_vnops.c
@@ -61,6 +61,8 @@
#include <fs/unionfs/union.h>
+#include <machine/atomic.h>
+
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <vm/vm_object.h>
@@ -2523,26 +2525,28 @@
{
struct vnode *tvp, *vp;
struct unionfs_node *unp;
- int error;
+ int error, writerefs;
vp = ap->a_vp;
unp = VTOUNIONFS(vp);
- tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
- VI_LOCK(vp);
+ tvp = unp->un_uppervp;
+ KASSERT(tvp != NULL,
+ ("%s: adding write ref without upper vnode", __func__));
+ error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
+ if (error != 0)
+ return (error);
+ /*
+ * We need to track the write refs we've passed to the underlying
+ * vnodes so that we can undo them in case we are forcibly unmounted.
+ */
+ writerefs = atomic_fetchadd_int(&vp->v_writecount, ap->a_inc);
/* text refs are bypassed to lowervp */
- VNASSERT(vp->v_writecount >= 0, vp, ("wrong null writecount"));
- VNASSERT(vp->v_writecount + ap->a_inc >= 0, vp,
- ("wrong writecount inc %d", ap->a_inc));
- if (tvp != NULL)
- error = VOP_ADD_WRITECOUNT(tvp, ap->a_inc);
- else if (vp->v_writecount < 0)
- error = ETXTBSY;
- else
- error = 0;
- if (error == 0)
- vp->v_writecount += ap->a_inc;
- VI_UNLOCK(vp);
- return (error);
+ VNASSERT(writerefs >= 0, vp,
+ ("%s: invalid write count %d", __func__, writerefs));
+ VNASSERT(writerefs + ap->a_inc >= 0, vp,
+ ("%s: invalid write count inc %d + %d", __func__,
+ writerefs, ap->a_inc));
+ return (0);
}
static int
@@ -2667,6 +2671,38 @@
return (res);
}
+static int
+unionfs_set_text(struct vop_set_text_args *ap)
+{
+ struct vnode *tvp;
+ struct unionfs_node *unp;
+ int error;
+
+ /*
+ * We assume text refs are managed against lvp/uvp through the
+ * executable mapping backed by its VM object. We therefore don't
+ * need to track leased text refs in the case of a forcible unmount.
+ */
+ unp = VTOUNIONFS(ap->a_vp);
+ ASSERT_VOP_LOCKED(ap->a_vp, __func__);
+ tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
+ error = VOP_SET_TEXT(tvp);
+ return (error);
+}
+
+static int
+unionfs_unset_text(struct vop_unset_text_args *ap)
+{
+ struct vnode *tvp;
+ struct unionfs_node *unp;
+
+ ASSERT_VOP_LOCKED(ap->a_vp, __func__);
+ unp = VTOUNIONFS(ap->a_vp);
+ tvp = unp->un_uppervp != NULL ? unp->un_uppervp : unp->un_lowervp;
+ VOP_UNSET_TEXT_CHECKED(tvp);
+ return (0);
+}
+
struct vop_vector unionfs_vnodeops = {
.vop_default = &default_vnodeops,
@@ -2718,5 +2754,7 @@
.vop_vptofh = unionfs_vptofh,
.vop_add_writecount = unionfs_add_writecount,
.vop_vput_pair = unionfs_vput_pair,
+ .vop_set_text = unionfs_set_text,
+ .vop_unset_text = unionfs_unset_text,
};
VFS_VOP_VECTOR_REGISTER(unionfs_vnodeops);

File Metadata

Mime Type
text/plain
Expires
Fri, Jan 24, 6:30 PM (6 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16095968
Default Alt Text
D33611.id100745.diff (4 KB)

Event Timeline