libafs: Set tvcp->callback before BulkStatus
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index bd415f2..759abfe 100644 (file)
@@ -928,21 +928,54 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
 
        tcp = afs_Conn(&adp->f.fid, areqp, SHARED_LOCK);
        if (tcp) {
-           hostp = tcp->srvr->server;
+           hostp = tcp->parent->srvr->server;
+
+           for (i = 0; i < fidIndex; i++) {
+               /* we must set tvcp->callback before the BulkStatus call, so
+                * we can detect concurrent InitCallBackState's */
+
+               afid.Cell = adp->f.fid.Cell;
+               afid.Fid.Volume = adp->f.fid.Fid.Volume;
+               afid.Fid.Vnode = fidsp[i].Vnode;
+               afid.Fid.Unique = fidsp[i].Unique;
+
+               do {
+                   retry = 0;
+                   ObtainReadLock(&afs_xvcache);
+                   tvcp = afs_FindVCache(&afid, &retry, 0 /* !stats&!lru */);
+                   ReleaseReadLock(&afs_xvcache);
+               } while (tvcp && retry);
+
+               if (!tvcp) {
+                   continue;
+               }
+
+               if ((tvcp->f.states & CBulkFetching) &&
+                    (tvcp->f.m.Length == statSeqNo)) {
+                   tvcp->callback = hostp;
+               }
+
+               afs_PutVCache(tvcp);
+               tvcp = NULL;
+           }
+
            XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
-           RX_AFS_GUNLOCK();
 
-           if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
+           if (!(tcp->parent->srvr->server->flags & SNO_INLINEBULK)) {
            retryonce:
+               RX_AFS_GUNLOCK();
                code =
                    RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
                                           &cbParm, &volSync);
+               RX_AFS_GLOCK();
                if (code == RXGEN_OPCODE) {
-                   tcp->srvr->server->flags |= SNO_INLINEBULK;
+                   tcp->parent->srvr->server->flags |= SNO_INLINEBULK;
                    inlinebulk = 0;
+                   RX_AFS_GUNLOCK();
                    code =
                        RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
                                         &cbParm, &volSync);
+                   RX_AFS_GLOCK();
                } else {
                    inlinebulk = 1;
                    if (!code && ((&statsp[0])->errorCode)) {
@@ -960,11 +993,12 @@ afs_DoBulkStat(struct vcache *adp, long dirCookie, struct vrequest *areqp)
                }
            } else {
                inlinebulk = 0;
+               RX_AFS_GUNLOCK();
                code =
                    RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
                                     &volSync);
+               RX_AFS_GLOCK();
            }
-           RX_AFS_GLOCK();
            XSTATS_END_TIME;
        } else
            code = -1;