macos disconnected vnode holding fix
authorDerrick Brashear <shadow@dementia.org>
Mon, 2 Aug 2010 18:02:37 +0000 (14:02 -0400)
committerDerrick Brashear <shadow@dementia.org>
Wed, 11 Aug 2010 21:57:34 +0000 (14:57 -0700)
tweak how we hold vcaches to avoid issues with the underlying
vnode having an iocount underrun due to races.

Change-Id: I96526ed52c11aac1124a8cf66458ba3e25e7efb2
Reviewed-on: http://gerrit.openafs.org/2501
Reviewed-by: Derrick Brashear <shadow@dementia.org>
Tested-by: Derrick Brashear <shadow@dementia.org>

src/afs/DARWIN/osi_vnodeops.c
src/afs/afs_dcache.c
src/afs/afs_prototypes.h
src/afs/afs_vcache.c
src/afs/discon.h

index 4190d8b..fb9627b 100644 (file)
@@ -2206,6 +2206,26 @@ afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp, struct component
        }
        avc->v = nvp;
        avc->f.states &=~ CDeadVnode;
+       /* If we were carrying an extra ref for dirty, hold/push it. */
+       if (avc->f.ddirty_flags) {
+           vnode_get(nvp);
+           vnode_ref(nvp);
+       }
+       /* If we were carrying an extra ref for shadow, hold/push it. */
+       if (avc->f.shadow.vnode) {
+           vnode_get(nvp);
+           vnode_ref(nvp);
+       }
+    }
+    /* Drop any extra dirty ref on the old vnode */
+    if (avc->f.ddirty_flags) {
+       vnode_put(ovp);
+       vnode_rele(ovp);
+    }
+    /* Drop any extra shadow ref on the old vnode */
+    if (avc->f.shadow.vnode) {
+       vnode_put(ovp);
+       vnode_rele(ovp);
     }
     vnode_put(ovp);
     vnode_rele(ovp);
index 246acdf..ea708f4 100644 (file)
@@ -3399,7 +3399,7 @@ afs_MakeShadowDir(struct vcache *avc, struct dcache *adc)
        ObtainWriteLock(&afs_xvcache, 763);
        ObtainWriteLock(&afs_disconDirtyLock, 765);
        QAdd(&afs_disconShadow, &avc->shadowq);
-       osi_vnhold(avc, 0);
+       osi_Assert((afs_RefVCache(avc) == 0));
        ReleaseWriteLock(&afs_disconDirtyLock);
        ReleaseWriteLock(&afs_xvcache);
 
index 362bed1..9a877d0 100644 (file)
@@ -1044,6 +1044,7 @@ extern struct vcache *afs_GetVCache(register struct VenusFid *afid,
                                    struct vrequest *areq, afs_int32 * cached,
                                    struct vcache *avc);
 extern void afs_PutVCache(register struct vcache *avc);
+extern int afs_RefVCache(struct vcache *avc);
 extern void afs_ProcessFS(register struct vcache *avc,
                          register struct AFSFetchStatus *astat,
                          struct vrequest *areq);
index 117c919..2d99644 100644 (file)
@@ -2531,6 +2531,45 @@ findvc_sleep(struct vcache *avc, int flag)
        }
     }
 }
+
+/*!
+ * Add a reference on an existing vcache entry.
+ *
+ * \param tvc Pointer to the vcache.
+ *
+ * \note Environment: Must be called with at least one reference from
+ * elsewhere on the vcache, even if that reference will be dropped.
+ * The global lock is required.
+ *
+ * \return 0 on success, -1 on failure.
+ */
+
+int
+afs_RefVCache(struct vcache *tvc)
+{
+#ifdef AFS_DARWIN80_ENV
+    vnode_t tvp;
+#endif
+
+    /* AFS_STATCNT(afs_RefVCache); */
+
+#ifdef  AFS_DARWIN80_ENV
+    tvp = AFSTOV(tvc);
+    if (vnode_get(tvp))
+       return -1;
+    if (vnode_ref(tvp)) {
+       AFS_GUNLOCK();
+       /* AFSTOV(tvc) may be NULL */
+       vnode_put(tvp);
+       AFS_GLOCK();
+       return -1;
+    }
+#else
+       osi_vnhold(tvc, 0);
+#endif
+    return 0;
+}                              /*afs_RefVCache */
+
 /*!
  * Find a vcache entry given a fid.
  *
index dae6612..df342ed 100644 (file)
@@ -56,7 +56,7 @@ static_inline void afs_DisconAddDirty(struct vcache *avc, int operation, int loc
            ObtainWriteLock(&afs_xvcache, 702);
        ObtainWriteLock(&afs_disconDirtyLock, 703);
        QAdd(&afs_disconDirty, &avc->dirtyq);
-       osi_vnhold(avc, 0);
+       osi_Assert((afs_RefVCache(avc) == 0));
        ReleaseWriteLock(&afs_disconDirtyLock);
        if (lock)
            ReleaseWriteLock(&afs_xvcache);