macos: bulkstat caller reference handling
authorDerrick Brashear <shadow@dementia.org>
Thu, 26 May 2011 05:39:18 +0000 (01:39 -0400)
committerDerrick Brashear <shadow@dementia.org>
Thu, 26 May 2011 15:29:46 +0000 (08:29 -0700)
if bulkstat is called and fakes up vnodes for non-dir cases, it can
guess wrong, and we end up needing to fix up the type by swapping
in a new vnode under the vcache. however, references are tracked on
the vnode, and more importantly, callers can know about the vnode;
unlinking a vcache from a vnode leaves null pointers to blow up on.

thing is, we shouldn't end up with a un-fixed-up vcache in use:
any caller of ProcessFS will notice if the vnode is the wrong type,
and fix it. so in order to reach CStatd, we have to fix it.
the only places where we can get a vcache in use not CStatd are:
FindVCache, LookupVCache, GetVCache where InReadDir. The last happens
only on Linux. LookupVCache doesn't happen anywhere that matters
(CForeign, or we immediately dispose...). FindVCache is only called
somewhere which won't lead to us fixing up during create, but that
vnode isn't returned to callers; we finalize in the result of create
and return the vnode that's linked to the vcache, which will be correct.

so, the only other place we can have a reference which won't immediately
get fixed up is in lookup, across the bulkstat call. if that's true,
and we return from bulkstat a non-CStatd vcache, lookup will fill in the
entry manually. so, if there are references remaining after we do a fixup,
unmark CStatd so the caller (presumably lookup, given the above) will give
back the vcache and retry, getting a corrected vnode as a result, with
the reference on the vnode we want it on.

Change-Id: I3b225c8d48067624f3cbac7b1f897e52193a8d55
Reviewed-on: http://gerrit.openafs.org/4722
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>

src/afs/DARWIN/osi_vnodeops.c

index 3380e8e..0d096fd 100644 (file)
@@ -2237,6 +2237,10 @@ afs_darwin_finalizevnode(struct vcache *avc, struct vnode *dvp,
        vnode_put(ovp);
        vnode_rele(ovp);
     }
+    /* If it's ref'd still, unmark stat'd to force new lookup */
+    if ((vnode_vtype(ovp) != avc->f.m.Type) && VREFCOUNT_GT(avc, 1))
+       avc->f.states &= ~CStatd;
+
     vnode_put(ovp);
     vnode_rele(ovp);
     AFS_GLOCK();