Windows: cm_RemoveSCacheFromHashTable scp not found
[openafs.git] / src / WINNT / afsd / cm_scache.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <windows.h>
17 #include <winsock2.h>
18 #include <nb30.h>
19 #include <malloc.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <osi.h>
23
24 #include "afsd.h"
25 #include "cm_btree.h"
26 #include <afs/unified_afs.h>
27
28 /*extern void afsi_log(char *pattern, ...);*/
29
30 extern osi_hyper_t hzero;
31
32 /* File locks */
33 osi_queue_t *cm_allFileLocks;
34 osi_queue_t *cm_freeFileLocks;
35 unsigned long cm_lockRefreshCycle;
36
37 /* lock for globals */
38 osi_rwlock_t cm_scacheLock;
39
40 /* Dummy scache entry for use with pioctl fids */
41 cm_scache_t cm_fakeSCache;
42
43 osi_queue_t * cm_allFreeWaiters;        /* protected by cm_scacheLock */
44
45 #ifdef AFS_FREELANCE_CLIENT
46 extern osi_mutex_t cm_Freelance_Lock;
47 #endif
48
49 cm_scache_t *
50 cm_RootSCachep(cm_user_t *userp, cm_req_t *reqp)
51 {
52     afs_int32 code;
53
54     lock_ObtainWrite(&cm_data.rootSCachep->rw);
55     code = cm_SyncOp(cm_data.rootSCachep, NULL, userp, reqp, 0,
56                       CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_NEEDCALLBACK);
57     if (!code)
58         cm_SyncOpDone(cm_data.rootSCachep, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
59     lock_ReleaseWrite(&cm_data.rootSCachep->rw);
60
61     return cm_data.rootSCachep;
62 }
63
64
65 /* must be called with cm_scacheLock write-locked! */
66 void cm_AdjustScacheLRU(cm_scache_t *scp)
67 {
68     lock_AssertWrite(&cm_scacheLock);
69     if (!(scp->flags & CM_SCACHEFLAG_DELETED)) {
70         osi_QRemoveHT((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
71         osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **) &cm_data.scacheLRULastp, &scp->q);
72     }
73 }
74
75 static int
76 cm_RemoveSCacheFromHashChain(cm_scache_t *scp, int index)
77 {
78     cm_scache_t **lscpp;
79     cm_scache_t *tscp;
80     int found = 0;
81
82     for (lscpp = &cm_data.scacheHashTablep[index], tscp = cm_data.scacheHashTablep[index];
83           tscp;
84           lscpp = &tscp->nextp, tscp = tscp->nextp) {
85         if (tscp == scp) {
86             *lscpp = scp->nextp;
87             scp->nextp = NULL;
88             found = 1;
89             break;
90         }
91     }
92
93     return found;
94 }
95
96 /* call with cm_scacheLock write-locked and scp rw held */
97 void cm_RemoveSCacheFromHashTable(cm_scache_t *scp)
98 {
99     lock_AssertWrite(&cm_scacheLock);
100     lock_AssertWrite(&scp->rw);
101     if (scp->flags & CM_SCACHEFLAG_INHASH) {
102         int h,i;
103         int found = 0;
104
105         /* hash it out first */
106         h = CM_SCACHE_HASH(&scp->fid);
107         found = cm_RemoveSCacheFromHashChain(scp, h);
108
109         if (!found) {
110             /*
111              * The CM_SCACHEFLAG_INHASH is set on the cm_scache_t but
112              * we didn't find the entry in the expected hash chain.
113              * Did the fid change?
114              * In any case, we will search the entire hashtable for
115              * the object.  If we don't find it, then we know it is
116              * safe to remove the flag.
117              */
118             for (i=0; !found && i<cm_data.scacheHashTableSize; i++) {
119                 if (i != h)
120                     found = cm_RemoveSCacheFromHashChain(scp, i);
121             }
122
123             if (found)
124                 osi_Log1(afsd_logp,"cm_RemoveSCacheFromHashTable scp 0x%p found in wrong hash chain", scp);
125             else
126                 osi_Log1(afsd_logp,"cm_RemoveSCacheFromHashTable scp 0x%p not found in hash table", scp);
127         }
128
129         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_INHASH);
130     }
131 }
132
133 /* called with cm_scacheLock and scp write-locked */
134 void cm_ResetSCacheDirectory(cm_scache_t *scp, afs_int32 dirlock)
135 {
136 #ifdef USE_BPLUS
137     /* destroy directory Bplus Tree */
138     if (scp->dirBplus) {
139         LARGE_INTEGER start, end;
140
141         if (!dirlock && !lock_TryWrite(&scp->dirlock)) {
142             /*
143              * We are not holding the dirlock and obtaining it
144              * requires that we drop the scp->rw.  As a result
145              * we will leave the dirBplus tree intact but
146              * invalidate the version number so that whatever
147              * operation is currently active can safely complete
148              * but the contents will be ignored on the next
149              * directory operation.
150              */
151             scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
152             return;
153         }
154
155         QueryPerformanceCounter(&start);
156         bplus_free_tree++;
157         freeBtree(scp->dirBplus);
158         scp->dirBplus = NULL;
159         scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
160         QueryPerformanceCounter(&end);
161
162         if (!dirlock)
163             lock_ReleaseWrite(&scp->dirlock);
164
165         bplus_free_time += (end.QuadPart - start.QuadPart);
166     }
167 #endif
168 }
169
170 /* called with cm_scacheLock and scp write-locked; recycles an existing scp. */
171 long cm_RecycleSCache(cm_scache_t *scp, afs_int32 flags)
172 {
173     cm_fid_t fid;
174     afs_uint32 fileType;
175     int callback;
176
177     lock_AssertWrite(&cm_scacheLock);
178     lock_AssertWrite(&scp->rw);
179
180     if (scp->refCount != 0) {
181         return -1;
182     }
183
184     if (scp->flags & CM_SCACHEFLAG_SMB_FID) {
185         osi_Log1(afsd_logp,"cm_RecycleSCache CM_SCACHEFLAG_SMB_FID detected scp 0x%p", scp);
186 #ifdef DEBUG
187         osi_panic("cm_RecycleSCache CM_SCACHEFLAG_SMB_FID detected",__FILE__,__LINE__);
188 #endif
189         return -1;
190     }
191
192     if (scp->redirBufCount != 0) {
193         return -1;
194     }
195
196     fid = scp->fid;
197     fileType = scp->fileType;
198     callback = scp->cbExpires ? 1 : 0;
199
200     cm_RemoveSCacheFromHashTable(scp);
201
202     if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
203          !cm_accessPerFileCheck) {
204         cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
205
206         if (volp) {
207             if (!(volp->flags & CM_VOLUMEFLAG_DFS_VOLUME))
208                 cm_EAccesClearParentEntries(&fid);
209
210             cm_PutVolume(volp);
211         }
212     }
213
214     /* invalidate so next merge works fine;
215      * also initialize some flags */
216     scp->fileType = 0;
217     _InterlockedAnd(&scp->flags,
218                     ~( CM_SCACHEFLAG_DELETED
219                      | CM_SCACHEFLAG_RO
220                      | CM_SCACHEFLAG_PURERO
221                      | CM_SCACHEFLAG_OVERQUOTA
222                      | CM_SCACHEFLAG_OUTOFSPACE
223                      | CM_SCACHEFLAG_ASYNCSTORING));
224     scp->serverModTime = 0;
225     scp->dataVersion = CM_SCACHE_VERSION_BAD;
226     scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
227     scp->bulkStatProgress = hzero;
228     scp->waitCount = 0;
229     scp->waitQueueT = NULL;
230
231     if (scp->cbServerp) {
232         cm_PutServer(scp->cbServerp);
233         scp->cbServerp = NULL;
234     }
235     scp->cbExpires = 0;
236     scp->cbIssued = 0;
237     scp->volumeCreationDate = 0;
238
239     scp->fid.vnode = 0;
240     scp->fid.volume = 0;
241     scp->fid.unique = 0;
242     scp->fid.cell = 0;
243     scp->fid.hash = 0;
244
245     /* remove from dnlc */
246     cm_dnlcPurgedp(scp);
247     cm_dnlcPurgevp(scp);
248
249     /* discard cached status; if non-zero, Close
250      * tried to store this to server but failed */
251     scp->mask = 0;
252
253     /* discard symlink info */
254     scp->mpDataVersion = CM_SCACHE_VERSION_BAD;
255     scp->mountPointStringp[0] = '\0';
256     memset(&scp->mountRootFid, 0, sizeof(cm_fid_t));
257     memset(&scp->dotdotFid, 0, sizeof(cm_fid_t));
258
259     /* reset locking info */
260     scp->fileLocksH = NULL;
261     scp->fileLocksT = NULL;
262     scp->serverLock = (-1);
263     scp->exclusiveLocks = 0;
264     scp->sharedLocks = 0;
265     scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
266     scp->fsLockCount = 0;
267
268     /* not locked, but there can be no references to this guy
269      * while we hold the global refcount lock.
270      */
271     cm_FreeAllACLEnts(scp);
272
273     cm_ResetSCacheDirectory(scp, 0);
274
275     if (RDR_Initialized && callback) {
276         /*
277         * We drop the cm_scacheLock because it may be required to
278         * satisfy an ioctl request from the redirector.  It should
279         * be safe to hold the scp->rw lock here because at this
280         * point (a) the object has just been recycled so the fid
281         * is nul and there are no requests that could possibly
282         * be issued by the redirector that would depend upon it.
283         */
284         lock_ReleaseWrite(&cm_scacheLock);
285         RDR_InvalidateObject( fid.cell, fid.volume, fid.vnode,
286                               fid.unique, fid.hash,
287                               fileType, AFS_INVALIDATE_EXPIRED);
288         lock_ObtainWrite(&cm_scacheLock);
289     }
290
291     return 0;
292 }
293
294
295 /*
296  * called with cm_scacheLock write-locked; find a vnode to recycle.
297  * Can allocate a new one if desperate, or if below quota (cm_data.maxSCaches).
298  * returns scp->rw write-locked.
299  */
300 cm_scache_t *
301 cm_GetNewSCache(afs_uint32 locked)
302 {
303     cm_scache_t *scp = NULL;
304     cm_scache_t *scp_prev = NULL;
305     cm_scache_t *scp_next = NULL;
306     int attempt = 0;
307
308     if (locked)
309         lock_AssertWrite(&cm_scacheLock);
310     else
311         lock_ObtainWrite(&cm_scacheLock);
312
313     if (cm_data.currentSCaches >= cm_data.maxSCaches) {
314         /* There were no deleted scache objects that we could use.  Try to find
315          * one that simply hasn't been used in a while.
316          */
317         for (attempt = 0 ; attempt < 128; attempt++) {
318             afs_uint32 count = 0;
319
320             for ( scp = cm_data.scacheLRULastp;
321                   scp;
322                   scp = (cm_scache_t *) osi_QPrev(&scp->q))
323             {
324                 /*
325                  * We save the prev and next pointers in the
326                  * LRU because we are going to drop the cm_scacheLock and
327                  * the order of the list could change out from beneath us.
328                  * If both changed, it means that this entry has been moved
329                  * within the LRU and it should no longer be recycled.
330                  */
331                 scp_prev = (cm_scache_t *) osi_QPrev(&scp->q);
332                 scp_next = (cm_scache_t *) osi_QNext(&scp->q);
333                 count++;
334
335                 /* It is possible for the refCount to be zero and for there still
336                  * to be outstanding dirty buffers.  If there are dirty buffers,
337                  * we must not recycle the scp.
338                  *
339                  * If the object is in use by the redirector, then avoid recycling
340                  * it unless we have to.
341                  */
342                 if (scp->refCount == 0 && scp->bufReadsp == NULL && scp->bufWritesp == NULL) {
343                     afs_uint32 buf_dirty = 0;
344                     afs_uint32 buf_rdr = 0;
345
346                     lock_ReleaseWrite(&cm_scacheLock);
347                     buf_dirty = buf_DirtyBuffersExist(&scp->fid);
348                     if (!buf_dirty)
349                         buf_rdr = buf_RDRBuffersExist(&scp->fid);
350
351                     if (!buf_dirty && !buf_rdr) {
352                         cm_fid_t   fid;
353                         afs_uint32 fileType;
354                         int        success;
355
356                         success = lock_TryWrite(&scp->rw);
357
358                         lock_ObtainWrite(&cm_scacheLock);
359                         if (scp_prev != (cm_scache_t *) osi_QPrev(&scp->q) &&
360                             scp_next != (cm_scache_t *) osi_QNext(&scp->q))
361                         {
362                             osi_Log1(afsd_logp, "GetNewSCache scp 0x%p; LRU order changed", scp);
363                             if (success)
364                                 lock_ReleaseWrite(&scp->rw);
365                             break;
366                         } else if (!success) {
367                                 osi_Log1(afsd_logp, "GetNewSCache failed to obtain lock scp 0x%p", scp);
368                                 continue;
369                         }
370
371                         /* Found a likely candidate.  Save type and fid in case we succeed */
372                         fid = scp->fid;
373                         fileType = scp->fileType;
374
375                         if (!cm_RecycleSCache(scp, 0)) {
376                             /* we found an entry, so return it.
377                              * remove from the LRU queue and put it back at the
378                              * head of the LRU queue.
379                              */
380                             cm_AdjustScacheLRU(scp);
381
382                             /* and we're done - SUCCESS */
383                             osi_assertx(!(scp->flags & CM_SCACHEFLAG_INHASH), "CM_SCACHEFLAG_INHASH set");
384                             goto done;
385                         }
386                         lock_ReleaseWrite(&scp->rw);
387                     } else {
388                         if (buf_rdr)
389                             osi_Log1(afsd_logp,"GetNewSCache redirector is holding extents scp 0x%p", scp);
390                         else
391                             osi_Log1(afsd_logp, "GetNewSCache dirty buffers scp 0x%p", scp);
392
393                         lock_ObtainWrite(&cm_scacheLock);
394                         if (scp_prev != (cm_scache_t *) osi_QPrev(&scp->q) &&
395                             scp_next != (cm_scache_t *) osi_QNext(&scp->q))
396                         {
397                             osi_Log1(afsd_logp, "GetNewSCache scp 0x%p; LRU order changed", scp);
398                             break;
399                         }
400                     }
401                 }
402             } /* for */
403
404             osi_Log2(afsd_logp, "GetNewSCache all scache entries in use (attempt = %d, count = %u)", attempt, count);
405             if (scp == NULL) {
406                 /*
407                 * The entire LRU queue was walked and no available cm_scache_t was
408                 * found.  Drop the cm_scacheLock and sleep for a moment to give a
409                 * chance for cm_scache_t objects to be released.
410                 */
411                 lock_ReleaseWrite(&cm_scacheLock);
412                 Sleep(50);
413                 lock_ObtainWrite(&cm_scacheLock);
414             }
415         }
416         /* FAILURE */
417         scp = NULL;
418         goto done;
419     }
420
421     /* if we get here, we should allocate a new scache entry.  We either are below
422      * quota or we have a leak and need to allocate a new one to avoid panicing.
423      */
424     scp = cm_data.scacheBaseAddress + InterlockedIncrement(&cm_data.currentSCaches) - 1;
425     osi_assertx(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.scacheHashTablep,
426                 "invalid cm_scache_t address");
427     memset(scp, 0, sizeof(cm_scache_t));
428     scp->magic = CM_SCACHE_MAGIC;
429     lock_InitializeRWLock(&scp->rw, "cm_scache_t rw", LOCK_HIERARCHY_SCACHE);
430     osi_assertx(lock_TryWrite(&scp->rw), "cm_scache_t rw held after allocation");
431     lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock", LOCK_HIERARCHY_SCACHE_BUFCREATE);
432 #ifdef USE_BPLUS
433     lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock", LOCK_HIERARCHY_SCACHE_DIRLOCK);
434 #endif
435     lock_InitializeMutex(&scp->redirMx, "cm_scache_t redirMx", LOCK_HIERARCHY_SCACHE_REDIRMX);
436     scp->serverLock = -1;
437     scp->dataVersion = CM_SCACHE_VERSION_BAD;
438     scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
439     scp->lockDataVersion = CM_SCACHE_VERSION_BAD;
440     scp->mpDataVersion = CM_SCACHE_VERSION_BAD;
441
442     /* and put it in the LRU queue */
443     osi_QAddH((osi_queue_t **) &cm_data.scacheLRUFirstp, (osi_queue_t **)&cm_data.scacheLRULastp, &scp->q);
444     cm_dnlcPurgedp(scp); /* make doubly sure that this is not in dnlc */
445     cm_dnlcPurgevp(scp);
446     scp->allNextp = cm_data.allSCachesp;
447     cm_data.allSCachesp = scp;
448
449   done:
450     if (!locked)
451         lock_ReleaseWrite(&cm_scacheLock);
452
453     return scp;
454 }
455
456 void cm_SetFid(cm_fid_t *fidp, afs_uint32 cell, afs_uint32 volume, afs_uint32 vnode, afs_uint32 unique)
457 {
458     fidp->cell = cell;
459     fidp->volume = volume;
460     fidp->vnode = vnode;
461     fidp->unique = unique;
462     CM_FID_GEN_HASH(fidp);
463 }
464
465 /* like strcmp, only for fids */
466 __inline int cm_FidCmp(cm_fid_t *ap, cm_fid_t *bp)
467 {
468     if (ap->hash != bp->hash)
469         return 1;
470     if (ap->vnode != bp->vnode)
471         return 1;
472     if (ap->volume != bp->volume)
473         return 1;
474     if (ap->unique != bp->unique)
475         return 1;
476     if (ap->cell != bp->cell)
477         return 1;
478     return 0;
479 }
480
481 void cm_fakeSCacheInit(int newFile)
482 {
483     if ( newFile ) {
484         memset(&cm_data.fakeSCache, 0, sizeof(cm_scache_t));
485         cm_data.fakeSCache.magic = CM_SCACHE_MAGIC;
486         cm_data.fakeSCache.cbServerp = (struct cm_server *)(-1);
487         cm_data.fakeSCache.cbExpires = (time_t)-1;
488         cm_data.fakeSCache.cbExpires = time(NULL);
489         /* can leave clientModTime at 0 */
490         cm_data.fakeSCache.fileType = CM_SCACHETYPE_FILE;
491         cm_data.fakeSCache.unixModeBits = 0777;
492         cm_data.fakeSCache.length.LowPart = 1000;
493         cm_data.fakeSCache.linkCount = 1;
494         cm_data.fakeSCache.refCount = 1;
495         cm_data.fakeSCache.serverLock = -1;
496         cm_data.fakeSCache.dataVersion = CM_SCACHE_VERSION_BAD;
497     }
498     lock_InitializeRWLock(&cm_data.fakeSCache.rw, "cm_scache_t rw", LOCK_HIERARCHY_SCACHE);
499     lock_InitializeRWLock(&cm_data.fakeSCache.bufCreateLock, "cm_scache_t bufCreateLock", LOCK_HIERARCHY_SCACHE_BUFCREATE);
500     lock_InitializeRWLock(&cm_data.fakeSCache.dirlock, "cm_scache_t dirlock", LOCK_HIERARCHY_SCACHE_DIRLOCK);
501     lock_InitializeMutex(&cm_data.fakeSCache.redirMx, "cm_scache_t redirMx", LOCK_HIERARCHY_SCACHE_REDIRMX);
502 }
503
504 long
505 cm_ValidateSCache(void)
506 {
507     cm_scache_t * scp, *lscp;
508     long i;
509
510     if ( cm_data.scacheLRUFirstp == NULL && cm_data.scacheLRULastp != NULL ||
511          cm_data.scacheLRUFirstp != NULL && cm_data.scacheLRULastp == NULL) {
512         afsi_log("cm_ValidateSCache failure: inconsistent LRU pointers");
513         fprintf(stderr, "cm_ValidateSCache failure: inconsistent LRU pointers\n");
514         return -17;
515     }
516
517     for ( scp = cm_data.scacheLRUFirstp, lscp = NULL, i = 0;
518           scp;
519           lscp = scp, scp = (cm_scache_t *) osi_QNext(&scp->q), i++ ) {
520
521         if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
522              scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
523             afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
524             fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
525             return -18;
526         }
527
528         if (scp->magic != CM_SCACHE_MAGIC) {
529             afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
530             fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
531             return -1;
532         }
533
534         if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
535              scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
536             afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
537             fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
538             return -21;
539         }
540
541         if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
542             afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
543             fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
544             return -2;
545         }
546
547         if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
548              scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
549             afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
550             fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
551             return -32;
552         }
553
554         if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
555             afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
556             fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
557             return -3;
558         }
559         if (i > cm_data.currentSCaches ) {
560             afsi_log("cm_ValidateSCache failure: LRU First queue loops");
561             fprintf(stderr, "cm_ValidateSCache failure: LUR First queue loops\n");
562             return -13;
563         }
564         if (lscp != (cm_scache_t *) osi_QPrev(&scp->q)) {
565             afsi_log("cm_ValidateSCache failure: QPrev(scp) != previous");
566             fprintf(stderr, "cm_ValidateSCache failure: QPrev(scp) != previous\n");
567             return -15;
568         }
569     }
570
571     for ( scp = cm_data.scacheLRULastp, lscp = NULL, i = 0; scp;
572           lscp = scp, scp = (cm_scache_t *) osi_QPrev(&scp->q), i++ ) {
573
574         if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
575              scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
576             afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
577             fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
578             return -19;
579         }
580
581         if (scp->magic != CM_SCACHE_MAGIC) {
582             afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
583             fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
584             return -5;
585         }
586
587         if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
588              scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
589             afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
590             fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
591             return -22;
592         }
593
594         if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
595             afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
596             fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
597             return -6;
598         }
599
600         if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
601              scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
602             afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
603             fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
604             return -31;
605         }
606
607         if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
608             afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
609             fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
610             return -7;
611         }
612         if (i > cm_data.currentSCaches ) {
613             afsi_log("cm_ValidateSCache failure: LRU Last queue loops");
614             fprintf(stderr, "cm_ValidateSCache failure: LUR Last queue loops\n");
615             return -14;
616         }
617         if (lscp != (cm_scache_t *) osi_QNext(&scp->q)) {
618             afsi_log("cm_ValidateSCache failure: QNext(scp) != next");
619             fprintf(stderr, "cm_ValidateSCache failure: QNext(scp) != next\n");
620             return -16;
621         }
622     }
623
624     for ( i=0; i < cm_data.scacheHashTableSize; i++ ) {
625         for ( scp = cm_data.scacheHashTablep[i]; scp; scp = scp->nextp ) {
626             afs_uint32 hash;
627
628             if ( scp < (cm_scache_t *)cm_data.scacheBaseAddress ||
629                  scp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
630                 afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
631                 fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
632                 return -20;
633             }
634
635             hash = CM_SCACHE_HASH(&scp->fid);
636
637             if (scp->magic != CM_SCACHE_MAGIC) {
638                 afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
639                 fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
640                 return -9;
641             }
642
643             if ( scp->nextp < (cm_scache_t *)cm_data.scacheBaseAddress ||
644                  scp->nextp >= (cm_scache_t *)cm_data.dnlcBaseAddress) {
645                 afsi_log("cm_ValidateSCache failure: out of range cm_scache_t pointers");
646                 fprintf(stderr, "cm_ValidateSCache failure: out of range cm_scache_t pointers\n");
647                 return -23;
648             }
649
650             if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
651                 afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
652                 fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
653                 return -10;
654             }
655
656             if ( scp->randomACLp < (cm_aclent_t *)cm_data.aclBaseAddress ||
657                  scp->randomACLp >= (cm_aclent_t *)cm_data.scacheBaseAddress) {
658                 afsi_log("cm_ValidateSCache failure: out of range cm_aclent_t pointers");
659                 fprintf(stderr, "cm_ValidateSCache failure: out of range cm_aclent_t pointers\n");
660                 return -30;
661             }
662
663             if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
664                 afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
665                 fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
666                 return -11;
667             }
668             if (hash != i) {
669                 afsi_log("cm_ValidateSCache failure: scp hash != hash index");
670                 fprintf(stderr, "cm_ValidateSCache failure: scp hash != hash index\n");
671                 return -13;
672             }
673         }
674     }
675
676     return cm_dnlcValidate();
677 }
678
679 void
680 cm_SuspendSCache(void)
681 {
682     cm_scache_t * scp;
683     time_t now;
684
685     cm_GiveUpAllCallbacksAllServersMulti(TRUE);
686
687     /*
688      * After this call all servers are marked down.
689      * Do not clear the callbacks, instead change the
690      * expiration time so that the callbacks will be expired
691      * when the servers are marked back up.  However, we
692      * want the callbacks to be preserved as long as the
693      * servers are down.  That way if the machine resumes
694      * without network, the stat cache item will still be
695      * considered valid.
696      */
697     now = time(NULL);
698
699     lock_ObtainWrite(&cm_scacheLock);
700     for ( scp = cm_data.allSCachesp; scp; scp = scp->allNextp ) {
701         if (scp->cbServerp) {
702             if (scp->flags & CM_SCACHEFLAG_PURERO) {
703                 cm_volume_t *volp = cm_GetVolumeByFID(&scp->fid);
704                 if (volp) {
705                     if (volp->cbExpiresRO == scp->cbExpires)
706                         volp->cbExpiresRO = now+1;
707                     cm_PutVolume(volp);
708                 }
709             }
710             scp->cbExpires = now+1;
711         }
712     }
713     lock_ReleaseWrite(&cm_scacheLock);
714 }
715
716 long
717 cm_ShutdownSCache(void)
718 {
719     cm_scache_t * scp, * nextp;
720
721     cm_GiveUpAllCallbacksAllServersMulti(FALSE);
722
723     lock_ObtainWrite(&cm_scacheLock);
724
725     for ( scp = cm_data.allSCachesp; scp;
726           scp = nextp ) {
727         nextp = scp->allNextp;
728         lock_ReleaseWrite(&cm_scacheLock);
729 #ifdef USE_BPLUS
730         lock_ObtainWrite(&scp->dirlock);
731 #endif
732         lock_ObtainWrite(&scp->rw);
733         lock_ObtainWrite(&cm_scacheLock);
734
735         if (scp->randomACLp) {
736             cm_FreeAllACLEnts(scp);
737         }
738
739         if (scp->cbServerp) {
740             cm_PutServer(scp->cbServerp);
741             scp->cbServerp = NULL;
742         }
743         scp->cbExpires = 0;
744         scp->cbIssued = 0;
745         lock_ReleaseWrite(&scp->rw);
746
747 #ifdef USE_BPLUS
748         if (scp->dirBplus)
749             freeBtree(scp->dirBplus);
750         scp->dirBplus = NULL;
751         scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
752         lock_ReleaseWrite(&scp->dirlock);
753         lock_FinalizeRWLock(&scp->dirlock);
754 #endif
755         lock_FinalizeRWLock(&scp->rw);
756         lock_FinalizeRWLock(&scp->bufCreateLock);
757         lock_FinalizeMutex(&scp->redirMx);
758     }
759     lock_ReleaseWrite(&cm_scacheLock);
760
761     return cm_dnlcShutdown();
762 }
763
764 void cm_InitSCache(int newFile, long maxSCaches)
765 {
766     static osi_once_t once;
767
768     if (osi_Once(&once)) {
769         lock_InitializeRWLock(&cm_scacheLock, "cm_scacheLock", LOCK_HIERARCHY_SCACHE_GLOBAL);
770         if ( newFile ) {
771             memset(cm_data.scacheHashTablep, 0, sizeof(cm_scache_t *) * cm_data.scacheHashTableSize);
772             cm_data.allSCachesp = NULL;
773             cm_data.currentSCaches = 0;
774             cm_data.maxSCaches = maxSCaches;
775             cm_data.scacheLRUFirstp = cm_data.scacheLRULastp = NULL;
776         } else {
777             cm_scache_t * scp;
778
779             for ( scp = cm_data.allSCachesp; scp;
780                   scp = scp->allNextp ) {
781                 lock_InitializeRWLock(&scp->rw, "cm_scache_t rw", LOCK_HIERARCHY_SCACHE);
782                 lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock", LOCK_HIERARCHY_SCACHE_BUFCREATE);
783 #ifdef USE_BPLUS
784                 lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock", LOCK_HIERARCHY_SCACHE_DIRLOCK);
785 #endif
786                 scp->cbServerp = NULL;
787                 scp->cbExpires = 0;
788                 scp->cbIssued = 0;
789                 scp->volumeCreationDate = 0;
790                 scp->fileLocksH = NULL;
791                 scp->fileLocksT = NULL;
792                 scp->serverLock = (-1);
793                 scp->lastRefreshCycle = 0;
794                 scp->exclusiveLocks = 0;
795                 scp->sharedLocks = 0;
796                 scp->openReads = 0;
797                 scp->openWrites = 0;
798                 scp->openShares = 0;
799                 scp->openExcls = 0;
800                 scp->waitCount = 0;
801                 scp->activeRPCs = 0;
802 #ifdef USE_BPLUS
803                 scp->dirBplus = NULL;
804                 scp->dirDataVersion = CM_SCACHE_VERSION_BAD;
805 #endif
806                 scp->waitQueueT = NULL;
807                 _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_WAITING | CM_SCACHEFLAG_RDR_IN_USE));
808
809                 scp->redirBufCount = 0;
810                 scp->redirQueueT = NULL;
811                 scp->redirQueueH = NULL;
812                 lock_InitializeMutex(&scp->redirMx, "cm_scache_t redirMx", LOCK_HIERARCHY_SCACHE_REDIRMX);
813             }
814         }
815         cm_allFileLocks = NULL;
816         cm_freeFileLocks = NULL;
817         cm_lockRefreshCycle = 0;
818         cm_fakeSCacheInit(newFile);
819         cm_allFreeWaiters = NULL;
820         cm_dnlcInit(newFile);
821         osi_EndOnce(&once);
822     }
823 }
824
825 /* version that doesn't bother creating the entry if we don't find it */
826 cm_scache_t *cm_FindSCache(cm_fid_t *fidp)
827 {
828     long hash;
829     cm_scache_t *scp;
830
831     hash = CM_SCACHE_HASH(fidp);
832
833     if (fidp->cell == 0) {
834         return NULL;
835     }
836
837     lock_ObtainRead(&cm_scacheLock);
838     for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
839         if (cm_FidCmp(fidp, &scp->fid) == 0) {
840             cm_HoldSCacheNoLock(scp);
841             lock_ConvertRToW(&cm_scacheLock);
842             cm_AdjustScacheLRU(scp);
843             lock_ReleaseWrite(&cm_scacheLock);
844             return scp;
845         }
846     }
847     lock_ReleaseRead(&cm_scacheLock);
848     return NULL;
849 }
850
851 #ifdef DEBUG_REFCOUNT
852 long cm_GetSCacheDbg(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, cm_user_t *userp,
853                   cm_req_t *reqp, char * file, long line)
854 #else
855 long cm_GetSCache(cm_fid_t *fidp, cm_fid_t *parentFidp, cm_scache_t **outScpp, cm_user_t *userp,
856                   cm_req_t *reqp)
857 #endif
858 {
859     long hash;
860     cm_scache_t *scp = NULL;
861     cm_scache_t *newScp = NULL;
862     long code;
863     cm_volume_t *volp = NULL;
864     cm_cell_t *cellp;
865     int special = 0; // yj: boolean variable to test if file is on root.afs
866     int isRoot = 0;
867     extern cm_fid_t cm_rootFid;
868     afs_int32 refCount;
869
870     hash = CM_SCACHE_HASH(fidp);
871
872     if (fidp->cell == 0)
873         return CM_ERROR_INVAL;
874
875 #ifdef AFS_FREELANCE_CLIENT
876     special = (fidp->cell==AFS_FAKE_ROOT_CELL_ID &&
877                fidp->volume==AFS_FAKE_ROOT_VOL_ID &&
878                !(fidp->vnode==0x1 && fidp->unique==0x1));
879     isRoot = (fidp->cell==AFS_FAKE_ROOT_CELL_ID &&
880               fidp->volume==AFS_FAKE_ROOT_VOL_ID &&
881               fidp->vnode==0x1 && fidp->unique==0x1);
882 #endif
883
884     // yj: check if we have the scp, if so, we don't need
885     // to do anything else
886     lock_ObtainRead(&cm_scacheLock);
887     for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
888         if (cm_FidCmp(fidp, &scp->fid) == 0) {
889 #ifdef DEBUG_REFCOUNT
890             afsi_log("%s:%d cm_GetSCache (1) scp 0x%p ref %d", file, line, scp, scp->refCount);
891             osi_Log1(afsd_logp,"cm_GetSCache (1) scp 0x%p", scp);
892 #endif
893 #ifdef AFS_FREELANCE_CLIENT
894             if (cm_freelanceEnabled && special &&
895                 cm_data.fakeDirVersion != scp->dataVersion)
896                 break;
897 #endif
898             if (parentFidp && scp->parentVnode == 0) {
899                 scp->parentVnode = parentFidp->vnode;
900                 scp->parentUnique = parentFidp->unique;
901             }
902             cm_HoldSCacheNoLock(scp);
903             *outScpp = scp;
904             lock_ConvertRToW(&cm_scacheLock);
905             cm_AdjustScacheLRU(scp);
906             lock_ReleaseWrite(&cm_scacheLock);
907             return 0;
908         }
909     }
910     lock_ReleaseRead(&cm_scacheLock);
911
912     // yj: when we get here, it means we don't have an scp
913     // so we need to either load it or fake it, depending
914     // on whether the file is "special", see below.
915
916     // yj: if we're trying to get an scp for a file that's
917     // on root.afs of homecell, we want to handle it specially
918     // because we have to fill in the status stuff 'coz we
919     // don't want trybulkstat to fill it in for us
920 #ifdef AFS_FREELANCE_CLIENT
921     if (cm_freelanceEnabled && isRoot) {
922         osi_Log0(afsd_logp,"cm_GetSCache Freelance and isRoot");
923         /* freelance: if we are trying to get the root scp for the first
924          * time, we will just put in a place holder entry.
925          */
926         volp = NULL;
927     }
928
929     if (cm_freelanceEnabled && special) {
930         osi_Log0(afsd_logp,"cm_GetSCache Freelance and special");
931
932         if (cm_getLocalMountPointChange()) {
933             cm_clearLocalMountPointChange();
934             cm_reInitLocalMountPoints();
935         }
936
937         if (scp == NULL) {
938             scp = cm_GetNewSCache(FALSE);    /* returns scp->rw held */
939             if (scp == NULL) {
940                 osi_Log0(afsd_logp,"cm_GetSCache unable to obtain *new* scache entry");
941                 return CM_ERROR_WOULDBLOCK;
942             }
943         } else {
944             lock_ObtainWrite(&scp->rw);
945         }
946         scp->fid = *fidp;
947         cm_SetFid(&scp->dotdotFid,AFS_FAKE_ROOT_CELL_ID,AFS_FAKE_ROOT_VOL_ID,1,1);
948         if (parentFidp) {
949             scp->parentVnode = parentFidp->vnode;
950             scp->parentUnique = parentFidp->unique;
951         }
952         _InterlockedOr(&scp->flags, (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO));
953         lock_ObtainWrite(&cm_scacheLock);
954         if (!(scp->flags & CM_SCACHEFLAG_INHASH)) {
955             scp->nextp = cm_data.scacheHashTablep[hash];
956             cm_data.scacheHashTablep[hash] = scp;
957             _InterlockedOr(&scp->flags, CM_SCACHEFLAG_INHASH);
958         }
959         refCount = InterlockedIncrement(&scp->refCount);
960         osi_Log2(afsd_logp,"cm_GetSCache (freelance) sets refCount to 1 scp 0x%p refCount %d", scp, refCount);
961         lock_ReleaseWrite(&cm_scacheLock);
962
963         /* must be called after the scp->fid is set */
964         cm_FreelanceFetchMountPointString(scp);
965         cm_FreelanceFetchFileType(scp);
966
967         scp->length.LowPart = (DWORD)strlen(scp->mountPointStringp)+4;
968         scp->length.HighPart = 0;
969         scp->owner=0x0;
970         scp->unixModeBits=0777;
971         scp->clientModTime=FakeFreelanceModTime;
972         scp->serverModTime=FakeFreelanceModTime;
973         scp->parentUnique = 0x1;
974         scp->parentVnode=0x1;
975         scp->group=0;
976         scp->dataVersion=cm_data.fakeDirVersion;
977         scp->bufDataVersionLow=cm_data.fakeDirVersion;
978         scp->lockDataVersion=CM_SCACHE_VERSION_BAD; /* no lock yet */
979         scp->fsLockCount=0;
980         lock_ReleaseWrite(&scp->rw);
981         *outScpp = scp;
982 #ifdef DEBUG_REFCOUNT
983         afsi_log("%s:%d cm_GetSCache (2) scp 0x%p ref %d", file, line, scp, scp->refCount);
984         osi_Log1(afsd_logp,"cm_GetSCache (2) scp 0x%p", scp);
985 #endif
986         return 0;
987     }
988     // end of yj code
989 #endif /* AFS_FREELANCE_CLIENT */
990
991     /* we don't have the fid, recycle something */
992     newScp = cm_GetNewSCache(FALSE);    /* returns scp->rw held */
993     if (newScp == NULL) {
994         osi_Log0(afsd_logp,"cm_GetNewSCache unable to obtain *new* scache entry");
995         return CM_ERROR_WOULDBLOCK;
996     }
997 #ifdef DEBUG_REFCOUNT
998     afsi_log("%s:%d cm_GetNewSCache returns scp 0x%p flags 0x%x", file, line, newScp, newScp->flags);
999 #endif
1000     osi_Log2(afsd_logp,"cm_GetNewSCache returns scp 0x%p flags 0x%x", newScp, newScp->flags);
1001
1002     /* otherwise, we need to find the volume */
1003     if (!cm_freelanceEnabled || !isRoot) {
1004         cellp = cm_FindCellByID(fidp->cell, 0);
1005         if (!cellp) {
1006             /* put back newScp so it can be reused */
1007             lock_ObtainWrite(&cm_scacheLock);
1008             _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
1009             cm_AdjustScacheLRU(newScp);
1010             lock_ReleaseWrite(&newScp->rw);
1011             lock_ReleaseWrite(&cm_scacheLock);
1012             return CM_ERROR_NOSUCHCELL;
1013         }
1014
1015         code = cm_FindVolumeByID(cellp, fidp->volume, userp, reqp, CM_GETVOL_FLAG_CREATE, &volp);
1016         if (code) {
1017             /* put back newScp so it can be reused */
1018             lock_ObtainWrite(&cm_scacheLock);
1019             _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
1020             cm_AdjustScacheLRU(newScp);
1021             lock_ReleaseWrite(&newScp->rw);
1022             lock_ReleaseWrite(&cm_scacheLock);
1023             return code;
1024         }
1025     }
1026
1027     /*
1028      * otherwise, we have the volume, now reverify that the scp doesn't
1029      * exist, and proceed.  make sure that we hold the cm_scacheLock
1030      * write-locked until the scp is put into the hash table in order
1031      * to avoid a race.
1032      */
1033     lock_ObtainWrite(&cm_scacheLock);
1034     for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
1035         if (cm_FidCmp(fidp, &scp->fid) == 0) {
1036 #ifdef DEBUG_REFCOUNT
1037             afsi_log("%s:%d cm_GetSCache (3) scp 0x%p ref %d", file, line, scp, scp->refCount);
1038             osi_Log1(afsd_logp,"cm_GetSCache (3) scp 0x%p", scp);
1039 #endif
1040             if (parentFidp && scp->parentVnode == 0) {
1041                 scp->parentVnode = parentFidp->vnode;
1042                 scp->parentUnique = parentFidp->unique;
1043             }
1044             if (volp)
1045                 cm_PutVolume(volp);
1046             cm_HoldSCacheNoLock(scp);
1047             cm_AdjustScacheLRU(scp);
1048
1049             /* put back newScp so it can be reused */
1050             _InterlockedOr(&newScp->flags, CM_SCACHEFLAG_DELETED);
1051             cm_AdjustScacheLRU(newScp);
1052             lock_ReleaseWrite(&newScp->rw);
1053             lock_ReleaseWrite(&cm_scacheLock);
1054
1055             *outScpp = scp;
1056             return 0;
1057         }
1058     }
1059
1060     scp = newScp;
1061     scp->fid = *fidp;
1062     if (!cm_freelanceEnabled || !isRoot) {
1063         /* if this scache entry represents a volume root then we need
1064          * to copy the dotdotFid from the volume structure where the
1065          * "master" copy is stored (defect 11489)
1066          */
1067         if (volp->vol[ROVOL].ID == fidp->volume) {
1068             _InterlockedOr(&scp->flags, (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO));
1069             if (scp->fid.vnode == 1 && scp->fid.unique == 1)
1070                 scp->dotdotFid = cm_VolumeStateByType(volp, ROVOL)->dotdotFid;
1071         } else if (volp->vol[BACKVOL].ID == fidp->volume) {
1072             _InterlockedOr(&scp->flags, CM_SCACHEFLAG_RO);
1073             if (scp->fid.vnode == 1 && scp->fid.unique == 1)
1074                 scp->dotdotFid = cm_VolumeStateByType(volp, BACKVOL)->dotdotFid;
1075         } else {
1076             if (scp->fid.vnode == 1 && scp->fid.unique == 1)
1077                 scp->dotdotFid = cm_VolumeStateByType(volp, RWVOL)->dotdotFid;
1078         }
1079     }
1080     if (parentFidp) {
1081         scp->parentVnode = parentFidp->vnode;
1082         scp->parentUnique = parentFidp->unique;
1083     }
1084     if (volp)
1085         cm_PutVolume(volp);
1086
1087     scp->nextp = cm_data.scacheHashTablep[hash];
1088     cm_data.scacheHashTablep[hash] = scp;
1089     _InterlockedOr(&scp->flags, CM_SCACHEFLAG_INHASH);
1090     refCount = InterlockedIncrement(&scp->refCount);
1091     lock_ReleaseWrite(&cm_scacheLock);
1092     lock_ReleaseWrite(&scp->rw);
1093 #ifdef DEBUG_REFCOUNT
1094     afsi_log("%s:%d cm_GetSCache sets refCount to 1 scp 0x%p refCount %d", file, line, scp, refCount);
1095 #endif
1096     osi_Log2(afsd_logp,"cm_GetSCache sets refCount to 1 scp 0x%p refCount %d", scp, refCount);
1097
1098     /* XXX - The following fields in the cm_scache are
1099      * uninitialized:
1100      *   fileType
1101      *   parentVnode
1102      *   parentUnique
1103      */
1104
1105     /* now we have a held scache entry; just return it */
1106     *outScpp = scp;
1107 #ifdef DEBUG_REFCOUNT
1108     afsi_log("%s:%d cm_GetSCache (4) scp 0x%p ref %d", file, line, scp, scp->refCount);
1109     osi_Log1(afsd_logp,"cm_GetSCache (4) scp 0x%p", scp);
1110 #endif
1111     return 0;
1112 }
1113
1114 /* Returns a held reference to the scache's parent
1115  * if it exists */
1116 cm_scache_t * cm_FindSCacheParent(cm_scache_t * scp)
1117 {
1118     long code = 0;
1119     int i;
1120     cm_fid_t    parent_fid;
1121     cm_scache_t * pscp = NULL;
1122
1123     if (scp->parentVnode == 0)
1124         return NULL;
1125
1126     lock_ObtainWrite(&cm_scacheLock);
1127     cm_SetFid(&parent_fid, scp->fid.cell, scp->fid.volume, scp->parentVnode, scp->parentUnique);
1128
1129     if (cm_FidCmp(&scp->fid, &parent_fid)) {
1130         i = CM_SCACHE_HASH(&parent_fid);
1131         for (pscp = cm_data.scacheHashTablep[i]; pscp; pscp = pscp->nextp) {
1132             if (!cm_FidCmp(&pscp->fid, &parent_fid)) {
1133                 cm_HoldSCacheNoLock(pscp);
1134                 break;
1135             }
1136         }
1137     }
1138
1139     lock_ReleaseWrite(&cm_scacheLock);
1140
1141     return pscp;
1142 }
1143
1144 void cm_SyncOpAddToWaitQueue(cm_scache_t * scp, afs_int32 flags, cm_buf_t * bufp)
1145 {
1146     cm_scache_waiter_t * w;
1147
1148     lock_ObtainWrite(&cm_scacheLock);
1149     if (cm_allFreeWaiters == NULL) {
1150         w = malloc(sizeof(*w));
1151         memset(w, 0, sizeof(*w));
1152     } else {
1153         w = (cm_scache_waiter_t *) cm_allFreeWaiters;
1154         osi_QRemove(&cm_allFreeWaiters, (osi_queue_t *) w);
1155     }
1156
1157     w->threadId = thrd_Current();
1158     w->scp = scp;
1159     cm_HoldSCacheNoLock(scp);
1160     w->flags = flags;
1161     w->bufp = bufp;
1162
1163     osi_QAddT(&scp->waitQueueH, &scp->waitQueueT, (osi_queue_t *) w);
1164     lock_ReleaseWrite(&cm_scacheLock);
1165
1166     osi_Log2(afsd_logp, "cm_SyncOpAddToWaitQueue : Adding thread to wait queue scp 0x%p w 0x%p", scp, w);
1167 }
1168
1169 int cm_SyncOpCheckContinue(cm_scache_t * scp, afs_int32 flags, cm_buf_t * bufp)
1170 {
1171     cm_scache_waiter_t * w;
1172     int this_is_me;
1173
1174     osi_Log0(afsd_logp, "cm_SyncOpCheckContinue checking for continuation");
1175
1176     lock_ObtainRead(&cm_scacheLock);
1177     for (w = (cm_scache_waiter_t *)scp->waitQueueH;
1178          w;
1179          w = (cm_scache_waiter_t *)osi_QNext((osi_queue_t *) w)) {
1180         if (w->flags == flags && w->bufp == bufp) {
1181             break;
1182         }
1183     }
1184
1185     osi_assertx(w != NULL, "null cm_scache_waiter_t");
1186     this_is_me = (w->threadId == thrd_Current());
1187     lock_ReleaseRead(&cm_scacheLock);
1188
1189     if (!this_is_me) {
1190         osi_Log1(afsd_logp, "cm_SyncOpCheckContinue MISS: Waiter 0x%p", w);
1191         return 0;
1192     }
1193
1194     osi_Log1(afsd_logp, "cm_SyncOpCheckContinue HIT: Waiter 0x%p", w);
1195
1196     lock_ObtainWrite(&cm_scacheLock);
1197     osi_QRemoveHT(&scp->waitQueueH, &scp->waitQueueT, (osi_queue_t *) w);
1198     cm_ReleaseSCacheNoLock(scp);
1199     memset(w, 0, sizeof(*w));
1200     osi_QAdd(&cm_allFreeWaiters, (osi_queue_t *) w);
1201     lock_ReleaseWrite(&cm_scacheLock);
1202
1203     return 1;
1204 }
1205
1206
1207 /* synchronize a fetch, store, read, write, fetch status or store status.
1208  * Called with scache mutex held, and returns with it held, but temporarily
1209  * drops it during the fetch.
1210  *
1211  * At most one flag can be on in flags, if this is an RPC request.
1212  *
1213  * Also, if we're fetching or storing data, we must ensure that we have a buffer.
1214  *
1215  * There are a lot of weird restrictions here; here's an attempt to explain the
1216  * rationale for the concurrency restrictions implemented in this function.
1217  *
1218  * First, although the file server will break callbacks when *another* machine
1219  * modifies a file or status block, the client itself is responsible for
1220  * concurrency control on its own requests.  Callback breaking events are rare,
1221  * and simply invalidate any concurrent new status info.
1222  *
1223  * In the absence of callback breaking messages, we need to know how to
1224  * synchronize incoming responses describing updates to files.  We synchronize
1225  * operations that update the data version by comparing the data versions.
1226  * However, updates that do not update the data, but only the status, can't be
1227  * synchronized with fetches or stores, since there's nothing to compare
1228  * to tell which operation executed first at the server.
1229  *
1230  * Thus, we can allow multiple ops that change file data, or dir data, and
1231  * fetches.  However, status storing ops have to be done serially.
1232  *
1233  * Furthermore, certain data-changing ops are incompatible: we can't read or
1234  * write a buffer while doing a truncate.  We can't read and write the same
1235  * buffer at the same time, or write while fetching or storing, or read while
1236  * fetching a buffer (this may change).  We can't fetch and store at the same
1237  * time, either.
1238  *
1239  * With respect to status, we can't read and write at the same time, read while
1240  * fetching, write while fetching or storing, or fetch and store at the same time.
1241  *
1242  * We can't allow a get callback RPC to run in concurrently with something that
1243  * will return updated status, since we could start a call, have the server
1244  * return status, have another machine make an update to the status (which
1245  * doesn't change serverModTime), have the original machine get a new callback,
1246  * and then have the original machine merge in the early, old info from the
1247  * first call.  At this point, the easiest way to avoid this problem is to have
1248  * getcallback calls conflict with all others for the same vnode.  Other calls
1249  * to cm_MergeStatus that aren't associated with calls to cm_SyncOp on the same
1250  * vnode must be careful not to merge in their status unless they have obtained
1251  * a callback from the start of their call.
1252  *
1253  * Note added 1/23/96
1254  * Concurrent StoreData RPC's can cause trouble if the file is being extended.
1255  * Each such RPC passes a FileLength parameter, which the server uses to do
1256  * pre-truncation if necessary.  So if two RPC's are processed out of order at
1257  * the server, the one with the smaller FileLength will be processed last,
1258  * possibly resulting in a bogus truncation.  The simplest way to avoid this
1259  * is to serialize all StoreData RPC's.  This is the reason we defined
1260  * CM_SCACHESYNC_STOREDATA_EXCL and CM_SCACHEFLAG_DATASTORING.
1261  *
1262  * CM_SCACHESYNC_BULKREAD is used to permit synchronization of multiple bulk
1263  * readers which may be requesting overlapping ranges.
1264  */
1265 long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *userp, cm_req_t *reqp,
1266                afs_uint32 rights, afs_uint32 flags)
1267 {
1268     osi_queueData_t *qdp;
1269     long code;
1270     cm_buf_t *tbufp;
1271     afs_uint32 outRights;
1272     int bufLocked;
1273     afs_uint32 sleep_scp_flags = 0;
1274     afs_uint32 sleep_buf_cmflags = 0;
1275     afs_uint32 sleep_scp_bufs = 0;
1276     int wakeupCycle;
1277     afs_int32 waitCount;
1278     afs_int32 waitRequests;
1279
1280     lock_AssertWrite(&scp->rw);
1281
1282     /* lookup this first */
1283     bufLocked = flags & CM_SCACHESYNC_BUFLOCKED;
1284
1285     if (bufp)
1286         osi_assertx(bufp->refCount > 0, "cm_buf_t refCount 0");
1287
1288
1289     /* Do the access check.  Now we don't really do the access check
1290      * atomically, since the caller doesn't expect the parent dir to be
1291      * returned locked, and that is what we'd have to do to prevent a
1292      * callback breaking message on the parent due to a setacl call from
1293      * being processed while we're running.  So, instead, we check things
1294      * here, and if things look fine with the access, we proceed to finish
1295      * the rest of this check.  Sort of a hack, but probably good enough.
1296      */
1297
1298     while (1) {
1299         if (flags & CM_SCACHESYNC_FETCHSTATUS) {
1300             /* if we're bringing in a new status block, ensure that
1301              * we aren't already doing so, and that no one is
1302              * changing the status concurrently, either.  We need
1303              * to do this, even if the status is of a different
1304              * type, since we don't have the ability to figure out,
1305              * in the AFS 3 protocols, which status-changing
1306              * operation ran first, or even which order a read and
1307              * a write occurred in.
1308              */
1309             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESETTING |
1310                               CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
1311                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESETTING|SIZESTORING|GETCALLBACK want FETCHSTATUS", scp);
1312                 goto sleep;
1313             }
1314         }
1315         if (flags & (CM_SCACHESYNC_STORESIZE | CM_SCACHESYNC_STORESTATUS
1316                       | CM_SCACHESYNC_SETSIZE | CM_SCACHESYNC_GETCALLBACK)) {
1317             /* if we're going to make an RPC to change the status, make sure
1318              * that no one is bringing in or sending out the status.
1319              */
1320             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESETTING |
1321                               CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
1322                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESETTING|SIZESTORING|GETCALLBACK want STORESIZE|STORESTATUS|SETSIZE|GETCALLBACK", scp);
1323                 goto sleep;
1324             }
1325             if ((!bufp || bufp && scp->fileType == CM_SCACHETYPE_FILE) &&
1326                 (scp->bufReadsp || scp->bufWritesp)) {
1327                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is bufRead|bufWrite want STORESIZE|STORESTATUS|SETSIZE|GETCALLBACK", scp);
1328                 goto sleep;
1329             }
1330         }
1331         if (flags & CM_SCACHESYNC_FETCHDATA) {
1332             /* if we're bringing in a new chunk of data, make sure that
1333              * nothing is happening to that chunk, and that we aren't
1334              * changing the basic file status info, either.
1335              */
1336             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESETTING |
1337                               CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
1338                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESETTING|SIZESTORING|GETCALLBACK want FETCHDATA", scp);
1339                 goto sleep;
1340             }
1341             if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING | CM_BUF_CMWRITING))) {
1342                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING|BUF_CMWRITING want FETCHDATA", scp, bufp);
1343                 goto sleep;
1344             }
1345         }
1346         if (flags & CM_SCACHESYNC_STOREDATA) {
1347             /* same as fetch data */
1348             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
1349                                | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
1350                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESTORING|GETCALLBACK want STOREDATA", scp);
1351                 goto sleep;
1352             }
1353             if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING | CM_BUF_CMWRITING))) {
1354                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING|BUF_CMSTORING|BUF_CMWRITING want STOREDATA", scp, bufp);
1355                 goto sleep;
1356             }
1357         }
1358
1359         if (flags & CM_SCACHESYNC_STOREDATA_EXCL) {
1360             /* Don't allow concurrent StoreData RPC's */
1361             if (scp->flags & CM_SCACHEFLAG_DATASTORING) {
1362                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is DATASTORING want STOREDATA_EXCL", scp);
1363                 goto sleep;
1364             }
1365         }
1366
1367         if (flags & CM_SCACHESYNC_ASYNCSTORE) {
1368             /* Don't allow more than one BKG store request */
1369             if (scp->flags & CM_SCACHEFLAG_ASYNCSTORING) {
1370                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is ASYNCSTORING want ASYNCSTORE", scp);
1371                 goto sleep;
1372             }
1373         }
1374
1375         if (flags & CM_SCACHESYNC_LOCK) {
1376             /* Don't allow concurrent fiddling with lock lists */
1377             if (scp->flags & CM_SCACHEFLAG_LOCKING) {
1378                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is LOCKING want LOCK", scp);
1379                 goto sleep;
1380             }
1381         }
1382
1383         /* now the operations that don't correspond to making RPCs */
1384         if (flags & CM_SCACHESYNC_GETSTATUS) {
1385             /* we can use the status that's here, if we're not
1386              * bringing in new status.
1387              */
1388             if (scp->flags & (CM_SCACHEFLAG_FETCHING)) {
1389                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING want GETSTATUS", scp);
1390                 goto sleep;
1391             }
1392         }
1393         if (flags & CM_SCACHESYNC_SETSTATUS) {
1394             /* we can make a change to the local status, as long as
1395              * the status isn't changing now.
1396              *
1397              * If we're fetching or storing a chunk of data, we can
1398              * change the status locally, since the fetch/store
1399              * operations don't change any of the data that we're
1400              * changing here.
1401              */
1402             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING |
1403                               CM_SCACHEFLAG_SIZESETTING | CM_SCACHEFLAG_SIZESTORING)) {
1404                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESETTING|SIZESTORING want SETSTATUS", scp);
1405                 goto sleep;
1406             }
1407         }
1408         if (flags & CM_SCACHESYNC_READ) {
1409             /* we're going to read the data, make sure that the
1410              * status is available, and that the data is here.  It
1411              * is OK to read while storing the data back.
1412              */
1413             if (scp->flags & CM_SCACHEFLAG_FETCHING) {
1414                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING want READ", scp);
1415                 goto sleep;
1416             }
1417             if (bufp && ((bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED)) == CM_BUF_CMFETCHING)) {
1418                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMFETCHING want READ", scp, bufp);
1419                 goto sleep;
1420             }
1421             if (bufp && (bufp->cmFlags & CM_BUF_CMWRITING)) {
1422                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is BUF_CMWRITING want READ", scp, bufp);
1423                 goto sleep;
1424             }
1425         }
1426         if (flags & CM_SCACHESYNC_WRITE) {
1427             /* don't write unless the status is stable and the chunk
1428              * is stable.
1429              */
1430             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESETTING |
1431                               CM_SCACHEFLAG_SIZESTORING)) {
1432                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is FETCHING|STORING|SIZESETTING|SIZESTORING want WRITE", scp);
1433                 goto sleep;
1434             }
1435             if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING |
1436                                           CM_BUF_CMSTORING |
1437                                           CM_BUF_CMWRITING))) {
1438                 osi_Log3(afsd_logp, "CM SyncOp scp 0x%p bufp 0x%p is %s want WRITE",
1439                          scp, bufp,
1440                          ((bufp->cmFlags & CM_BUF_CMFETCHING) ? "CM_BUF_CMFETCHING":
1441                           ((bufp->cmFlags & CM_BUF_CMSTORING) ? "CM_BUF_CMSTORING" :
1442                            ((bufp->cmFlags & CM_BUF_CMWRITING) ? "CM_BUF_CMWRITING" :
1443                             "UNKNOWN!!!"))));
1444                 goto sleep;
1445             }
1446         }
1447
1448         if ((flags & CM_SCACHESYNC_NEEDCALLBACK)) {
1449             if ((flags & CM_SCACHESYNC_FORCECB) || !cm_HaveCallback(scp)) {
1450                 osi_Log1(afsd_logp, "CM SyncOp getting callback on scp 0x%p",
1451                           scp);
1452
1453                 if (cm_EAccesFindEntry(userp, &scp->fid)) {
1454                     code = CM_ERROR_NOACCESS;
1455                     goto on_error;
1456                 }
1457
1458                 if (bufLocked)
1459                     lock_ReleaseMutex(&bufp->mx);
1460                 code = cm_GetCallback(scp, userp, reqp, (flags & CM_SCACHESYNC_FORCECB)?1:0);
1461                 if (bufLocked) {
1462                     lock_ReleaseWrite(&scp->rw);
1463                     lock_ObtainMutex(&bufp->mx);
1464                     lock_ObtainWrite(&scp->rw);
1465                 }
1466                 if (code)
1467                     goto on_error;
1468
1469                 flags &= ~CM_SCACHESYNC_FORCECB;        /* only force once */
1470                 continue;
1471             }
1472         }
1473
1474         if (rights) {
1475             /* can't check access rights without a callback */
1476             osi_assertx(flags & CM_SCACHESYNC_NEEDCALLBACK, "!CM_SCACHESYNC_NEEDCALLBACK");
1477
1478             if ((rights & (PRSFS_WRITE|PRSFS_DELETE)) && (scp->flags & CM_SCACHEFLAG_RO)) {
1479                 code = CM_ERROR_READONLY;
1480                 goto on_error;
1481             }
1482
1483             if (cm_HaveAccessRights(scp, userp, reqp, rights, &outRights)) {
1484                 if (~outRights & rights) {
1485                     code = CM_ERROR_NOACCESS;
1486                     goto on_error;
1487                 }
1488             }
1489             else {
1490                 /* we don't know the required access rights */
1491                 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
1492                 code = cm_GetAccessRights(scp, userp, reqp);
1493                 if (bufLocked) {
1494                     lock_ReleaseWrite(&scp->rw);
1495                     lock_ObtainMutex(&bufp->mx);
1496                     lock_ObtainWrite(&scp->rw);
1497                 }
1498                 if (code)
1499                     goto on_error;
1500                 continue;
1501             }
1502         }
1503
1504         if (flags & CM_SCACHESYNC_BULKREAD) {
1505             /* Don't allow concurrent fiddling with lock lists */
1506             if (scp->flags & CM_SCACHEFLAG_BULKREADING) {
1507                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%p is BULKREADING want BULKREAD", scp);
1508                 goto sleep;
1509             }
1510         }
1511
1512         /* if we get here, we're happy */
1513         break;
1514
1515       sleep:
1516         /* first check if we're not supposed to wait: fail
1517          * in this case, returning with everything still locked.
1518          */
1519         if (flags & CM_SCACHESYNC_NOWAIT) {
1520             code = CM_ERROR_WOULDBLOCK;
1521             goto on_error;
1522         }
1523
1524         /* These are used for minidump debugging */
1525         sleep_scp_flags = scp->flags;           /* so we know why we slept */
1526         sleep_buf_cmflags = bufp ? bufp->cmFlags : 0;
1527         sleep_scp_bufs = (scp->bufReadsp ? 1 : 0) | (scp->bufWritesp ? 2 : 0);
1528
1529         /* wait here, then try again */
1530         osi_Log1(afsd_logp, "CM SyncOp sleeping scp 0x%p", scp);
1531
1532         waitCount = InterlockedIncrement(&scp->waitCount);
1533         waitRequests = InterlockedIncrement(&scp->waitRequests);
1534         if (waitCount > 1) {
1535             osi_Log3(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING already set for 0x%p; %d threads; %d requests",
1536                      scp, waitCount, waitRequests);
1537         } else {
1538             osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING set for 0x%p", scp);
1539             _InterlockedOr(&scp->flags, CM_SCACHEFLAG_WAITING);
1540         }
1541
1542         cm_SyncOpAddToWaitQueue(scp, flags, bufp);
1543         wakeupCycle = 0;
1544         do {
1545             if (bufLocked)
1546                 lock_ReleaseMutex(&bufp->mx);
1547             osi_SleepW((LONG_PTR) &scp->flags, &scp->rw);
1548             if (bufLocked)
1549                 lock_ObtainMutex(&bufp->mx);
1550             lock_ObtainWrite(&scp->rw);
1551         } while (!cm_SyncOpCheckContinue(scp, flags, bufp));
1552
1553         cm_UpdateServerPriority();
1554
1555         waitCount = InterlockedDecrement(&scp->waitCount);
1556         osi_Log3(afsd_logp, "CM SyncOp woke! scp 0x%p; still waiting %d threads of %d requests",
1557                  scp, waitCount, scp->waitRequests);
1558         if (waitCount == 0) {
1559             osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING reset for 0x%p", scp);
1560             _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_WAITING);
1561             scp->waitRequests = 0;
1562         }
1563     } /* big while loop */
1564
1565     /* now, update the recorded state for RPC-type calls */
1566     if (flags & CM_SCACHESYNC_FETCHSTATUS)
1567         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_FETCHING);
1568     if (flags & CM_SCACHESYNC_STORESTATUS)
1569         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_STORING);
1570     if (flags & CM_SCACHESYNC_SETSIZE)
1571         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_SIZESETTING);
1572     if (flags & CM_SCACHESYNC_STORESIZE)
1573         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_SIZESTORING);
1574     if (flags & CM_SCACHESYNC_GETCALLBACK)
1575         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_GETCALLBACK);
1576     if (flags & CM_SCACHESYNC_STOREDATA_EXCL)
1577         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_DATASTORING);
1578     if (flags & CM_SCACHESYNC_ASYNCSTORE)
1579         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_ASYNCSTORING);
1580     if (flags & CM_SCACHESYNC_LOCK)
1581         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_LOCKING);
1582     if (flags & CM_SCACHESYNC_BULKREAD)
1583         _InterlockedOr(&scp->flags, CM_SCACHEFLAG_BULKREADING);
1584
1585     /* now update the buffer pointer */
1586     if (bufp && (flags & CM_SCACHESYNC_FETCHDATA)) {
1587         /* ensure that the buffer isn't already in the I/O list */
1588         for (qdp = scp->bufReadsp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
1589             tbufp = osi_GetQData(qdp);
1590             osi_assertx(tbufp != bufp, "unexpected cm_buf_t value");
1591         }
1592
1593         /* queue a held reference to the buffer in the "reading" I/O list */
1594         qdp = osi_QDAlloc();
1595         osi_SetQData(qdp, bufp);
1596
1597         buf_Hold(bufp);
1598         _InterlockedOr(&bufp->cmFlags, CM_BUF_CMFETCHING);
1599         osi_QAdd((osi_queue_t **) &scp->bufReadsp, &qdp->q);
1600     }
1601
1602     if (bufp && (flags & CM_SCACHESYNC_STOREDATA)) {
1603         osi_assertx(scp->fileType == CM_SCACHETYPE_FILE,
1604             "attempting to store extents on a non-file object");
1605
1606         /* ensure that the buffer isn't already in the I/O list */
1607         for (qdp = scp->bufWritesp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
1608             tbufp = osi_GetQData(qdp);
1609             osi_assertx(tbufp != bufp, "unexpected cm_buf_t value");
1610         }
1611
1612         /* queue a held reference to the buffer in the "writing" I/O list */
1613         qdp = osi_QDAlloc();
1614         osi_SetQData(qdp, bufp);
1615         buf_Hold(bufp);
1616         _InterlockedOr(&bufp->cmFlags, CM_BUF_CMSTORING);
1617         osi_QAdd((osi_queue_t **) &scp->bufWritesp, &qdp->q);
1618     }
1619
1620     if (bufp && (flags & CM_SCACHESYNC_WRITE)) {
1621         /* mark the buffer as being written to. */
1622         _InterlockedOr(&bufp->cmFlags, CM_BUF_CMWRITING);
1623     }
1624
1625     return 0;   /* Success */
1626
1627   on_error:
1628     /*
1629      * This thread may have been a waiter that was woken up.
1630      * If cm_SyncOp completes due to an error, cm_SyncOpDone() will
1631      * never be called.  If there are additional threads waiting on
1632      * scp those threads will never be woken.  Make sure we wake the
1633      * next waiting thread before we leave.
1634      */
1635     if ((scp->flags & CM_SCACHEFLAG_WAITING) ||
1636          !osi_QIsEmpty(&scp->waitQueueH)) {
1637         osi_Log3(afsd_logp, "CM SyncOp 0x%x Waking scp 0x%p bufp 0x%p",
1638                  flags, scp, bufp);
1639         osi_Wakeup((LONG_PTR) &scp->flags);
1640     }
1641     return code;
1642 }
1643
1644 /* for those syncops that setup for RPCs.
1645  * Called with scache locked.
1646  */
1647 void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, afs_uint32 flags)
1648 {
1649     osi_queueData_t *qdp;
1650     cm_buf_t *tbufp;
1651
1652     lock_AssertWrite(&scp->rw);
1653
1654     /* now, update the recorded state for RPC-type calls */
1655     if (flags & CM_SCACHESYNC_FETCHSTATUS)
1656         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_FETCHING);
1657     if (flags & CM_SCACHESYNC_STORESTATUS)
1658         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_STORING);
1659     if (flags & CM_SCACHESYNC_SETSIZE)
1660         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_SIZESETTING);
1661     if (flags & CM_SCACHESYNC_STORESIZE)
1662         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_SIZESTORING);
1663     if (flags & CM_SCACHESYNC_GETCALLBACK)
1664         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_GETCALLBACK);
1665     if (flags & CM_SCACHESYNC_STOREDATA_EXCL)
1666         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_DATASTORING);
1667     if (flags & CM_SCACHESYNC_ASYNCSTORE)
1668         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_ASYNCSTORING);
1669     if (flags & CM_SCACHESYNC_LOCK)
1670         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_LOCKING);
1671     if (flags & CM_SCACHESYNC_BULKREAD)
1672         _InterlockedAnd(&scp->flags, ~CM_SCACHEFLAG_BULKREADING);
1673
1674     /* now update the buffer pointer */
1675     if (bufp && (flags & CM_SCACHESYNC_FETCHDATA)) {
1676         int release = 0;
1677
1678         /* ensure that the buffer is in the I/O list */
1679         for (qdp = scp->bufReadsp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
1680             tbufp = osi_GetQData(qdp);
1681             if (tbufp == bufp)
1682                 break;
1683         }
1684         if (qdp) {
1685             osi_QRemove((osi_queue_t **) &scp->bufReadsp, &qdp->q);
1686             osi_QDFree(qdp);
1687             release = 1;
1688         }
1689         _InterlockedAnd(&bufp->cmFlags, ~(CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED));
1690         if (bufp->flags & CM_BUF_WAITING) {
1691             osi_Log2(afsd_logp, "CM SyncOpDone FetchData Waking [scp 0x%p] bufp 0x%p", scp, bufp);
1692             osi_Wakeup((LONG_PTR) &bufp);
1693         }
1694         if (release)
1695             buf_Release(bufp);
1696     }
1697
1698     /* now update the buffer pointer */
1699     if (bufp && (flags & CM_SCACHESYNC_STOREDATA)) {
1700         int release = 0;
1701         /* ensure that the buffer is in the I/O list */
1702         for (qdp = scp->bufWritesp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
1703             tbufp = osi_GetQData(qdp);
1704             if (tbufp == bufp)
1705                 break;
1706         }
1707         if (qdp) {
1708             osi_QRemove((osi_queue_t **) &scp->bufWritesp, &qdp->q);
1709             osi_QDFree(qdp);
1710             release = 1;
1711         }
1712         _InterlockedAnd(&bufp->cmFlags, ~CM_BUF_CMSTORING);
1713         if (bufp->flags & CM_BUF_WAITING) {
1714             osi_Log2(afsd_logp, "CM SyncOpDone StoreData Waking [scp 0x%p] bufp 0x%p", scp, bufp);
1715             osi_Wakeup((LONG_PTR) &bufp);
1716         }
1717         if (release)
1718             buf_Release(bufp);
1719     }
1720
1721     if (bufp && (flags & CM_SCACHESYNC_WRITE)) {
1722         osi_assertx(bufp->cmFlags & CM_BUF_CMWRITING, "!CM_BUF_CMWRITING");
1723         _InterlockedAnd(&bufp->cmFlags, ~CM_BUF_CMWRITING);
1724     }
1725
1726     /* and wakeup anyone who is waiting */
1727     if ((scp->flags & CM_SCACHEFLAG_WAITING) ||
1728         !osi_QIsEmpty(&scp->waitQueueH)) {
1729         osi_Log3(afsd_logp, "CM SyncOpDone 0x%x Waking scp 0x%p bufp 0x%p", flags, scp, bufp);
1730         osi_Wakeup((LONG_PTR) &scp->flags);
1731     }
1732 }
1733
1734 static afs_uint32
1735 dv_diff(afs_uint64 dv1, afs_uint64 dv2)
1736 {
1737     if ( dv1 - dv2 > 0x7FFFFFFF )
1738         return (afs_uint32)(dv2 - dv1);
1739     else
1740         return (afs_uint32)(dv1 - dv2);
1741 }
1742
1743 long
1744 cm_IsStatusValid(AFSFetchStatus *statusp)
1745 {
1746     if (statusp->InterfaceVersion != 0x1 ||
1747         !(statusp->FileType > 0 && statusp->FileType <= SymbolicLink)) {
1748         return 0;
1749     }
1750
1751     return 1;
1752 }
1753
1754 /* merge in a response from an RPC.  The scp must be locked, and the callback
1755  * is optional.
1756  *
1757  * Don't overwrite any status info that is dirty, since we could have a store
1758  * operation (such as store data) that merges some info in, and we don't want
1759  * to lose the local updates.  Typically, there aren't many updates we do
1760  * locally, anyway, probably only mtime.
1761  *
1762  * There is probably a bug in here where a chmod (which doesn't change
1763  * serverModTime) that occurs between two fetches, both of whose responses are
1764  * handled after the callback breaking is done, but only one of whose calls
1765  * started before that, can cause old info to be merged from the first call.
1766  */
1767 long cm_MergeStatus(cm_scache_t *dscp,
1768                     cm_scache_t *scp, AFSFetchStatus *statusp,
1769                     AFSVolSync *volsyncp,
1770                     cm_user_t *userp, cm_req_t *reqp, afs_uint32 flags)
1771 {
1772     afs_uint64 dataVersion;
1773     struct cm_volume *volp = NULL;
1774     struct cm_cell *cellp = NULL;
1775     int rdr_invalidate = 0;
1776     afs_uint32 activeRPCs;
1777
1778     lock_AssertWrite(&scp->rw);
1779
1780     activeRPCs = 1 + InterlockedDecrement(&scp->activeRPCs);
1781
1782     // yj: i want to create some fake status for the /afs directory and the
1783     // entries under that directory
1784 #ifdef AFS_FREELANCE_CLIENT
1785     if (cm_freelanceEnabled && scp->fid.cell==AFS_FAKE_ROOT_CELL_ID &&
1786          scp->fid.volume==AFS_FAKE_ROOT_VOL_ID) {
1787         if (scp == cm_data.rootSCachep) {
1788             osi_Log0(afsd_logp,"cm_MergeStatus Freelance cm_data.rootSCachep");
1789             statusp->FileType = CM_SCACHETYPE_DIRECTORY;
1790             statusp->Length = cm_fakeDirSize;
1791             statusp->Length_hi = 0;
1792         } else {
1793             statusp->FileType = scp->fileType;
1794             statusp->Length = scp->length.LowPart;
1795             statusp->Length_hi = scp->length.HighPart;
1796         }
1797         statusp->InterfaceVersion = 0x1;
1798         statusp->LinkCount = scp->linkCount;
1799         statusp->DataVersion = (afs_uint32)(cm_data.fakeDirVersion & 0xFFFFFFFF);
1800         statusp->Author = 0x1;
1801         statusp->Owner = 0x0;
1802         statusp->CallerAccess = 0x9;
1803         statusp->AnonymousAccess = 0x9;
1804         statusp->UnixModeBits = 0777;
1805         statusp->ParentVnode = 0x1;
1806         statusp->ParentUnique = 0x1;
1807         statusp->ResidencyMask = 0;
1808         statusp->ClientModTime = FakeFreelanceModTime;
1809         statusp->ServerModTime = FakeFreelanceModTime;
1810         statusp->Group = 0;
1811         statusp->SyncCounter = 0;
1812         statusp->dataVersionHigh = (afs_uint32)(cm_data.fakeDirVersion >> 32);
1813         statusp->lockCount = 0;
1814         statusp->errorCode = 0;
1815     }
1816 #endif /* AFS_FREELANCE_CLIENT */
1817
1818     if (!cm_IsStatusValid(statusp)) {
1819         osi_Log3(afsd_logp, "Merge: Bad Status scp 0x%p Invalid InterfaceVersion %d FileType %d",
1820                  scp, statusp->InterfaceVersion, statusp->FileType);
1821         return CM_ERROR_INVAL;
1822     }
1823
1824     if (statusp->errorCode != 0) {
1825         switch (statusp->errorCode) {
1826         case EACCES:
1827         case UAEACCES:
1828         case EPERM:
1829         case UAEPERM:
1830             cm_EAccesAddEntry(userp, &scp->fid, &dscp->fid);
1831         }
1832         osi_Log2(afsd_logp, "Merge, Failure scp 0x%p code 0x%x", scp, statusp->errorCode);
1833
1834         if (scp->fid.vnode & 0x1)
1835             scp->fileType = CM_SCACHETYPE_DIRECTORY;
1836         else
1837             scp->fileType = CM_SCACHETYPE_UNKNOWN;
1838
1839         scp->serverModTime = 0;
1840         scp->clientModTime = 0;
1841         scp->length.LowPart = 0;
1842         scp->length.HighPart = 0;
1843         scp->serverLength.LowPart = 0;
1844         scp->serverLength.HighPart = 0;
1845         scp->linkCount = 0;
1846         scp->owner = 0;
1847         scp->group = 0;
1848         scp->unixModeBits = 0;
1849         scp->anyAccess = 0;
1850         scp->dataVersion = CM_SCACHE_VERSION_BAD;
1851         scp->bufDataVersionLow = CM_SCACHE_VERSION_BAD;
1852         scp->fsLockCount = 0;
1853
1854         if (dscp && dscp != scp) {
1855             scp->parentVnode = dscp->fid.vnode;
1856             scp->parentUnique = dscp->fid.unique;
1857         } else {
1858             scp->parentVnode = 0;
1859             scp->parentUnique = 0;
1860         }
1861
1862         if (RDR_Initialized)
1863             rdr_invalidate = 1;
1864     }
1865
1866     dataVersion = statusp->dataVersionHigh;
1867     dataVersion <<= 32;
1868     dataVersion |= statusp->DataVersion;
1869
1870     if (!(flags & CM_MERGEFLAG_FORCE) &&
1871         dataVersion < scp->dataVersion &&
1872         scp->dataVersion != CM_SCACHE_VERSION_BAD) {
1873
1874         cellp = cm_FindCellByID(scp->fid.cell, 0);
1875         if (scp->cbServerp) {
1876             cm_FindVolumeByID(cellp, scp->fid.volume, userp,
1877                               reqp, CM_GETVOL_FLAG_CREATE, &volp);
1878             osi_Log2(afsd_logp, "old data from server %x volume %s",
1879                       scp->cbServerp->addr.sin_addr.s_addr,
1880                       volp ? volp->namep : "(unknown)");
1881         }
1882
1883         osi_Log3(afsd_logp, "Bad merge, scp 0x%p, scp dv %d, RPC dv %d",
1884                   scp, scp->dataVersion, dataVersion);
1885         /* we have a number of data fetch/store operations running
1886          * concurrently, and we can tell which one executed last at the
1887          * server by its mtime.
1888          * Choose the one with the largest mtime, and ignore the rest.
1889          *
1890          * These concurrent calls are incompatible with setting the
1891          * mtime, so we won't have a locally changed mtime here.
1892          *
1893          * We could also have ACL info for a different user than usual,
1894          * in which case we have to do that part of the merge, anyway.
1895          * We won't have to worry about the info being old, since we
1896          * won't have concurrent calls
1897          * that change file status running from this machine.
1898          *
1899          * Added 3/17/98:  if we see data version regression on an RO
1900          * file, it's probably due to a server holding an out-of-date
1901          * replica, rather than to concurrent RPC's.  Failures to
1902          * release replicas are now flagged by the volserver, but only
1903          * since AFS 3.4 5.22, so there are plenty of clients getting
1904          * out-of-date replicas out there.
1905          *
1906          * If we discover an out-of-date replica, by this time it's too
1907          * late to go to another server and retry.  Also, we can't
1908          * reject the merge, because then there is no way for
1909          * GetAccess to do its work, and the caller gets into an
1910          * infinite loop.  So we just grin and bear it.
1911          */
1912         if (!(scp->flags & CM_SCACHEFLAG_RO))
1913             goto done;
1914     }
1915
1916     /*
1917      * The first field of the volsync parameter is supposed to be the
1918      * volume creation date.  Unfortunately, pre-OpenAFS 1.4.11 and 1.6.0
1919      * file servers do not populate the VolSync structure for BulkStat and
1920      * InlineBulkStat RPCs.  As a result, the volume creation date is not
1921      * trustworthy when status is obtained via [Inline]BulkStatus RPCs.
1922      * If cm_readonlyVolumeVersioning is set, it is assumed that all file
1923      * servers populate the VolSync structure at all times.
1924      */
1925     if (cm_readonlyVolumeVersioning || !(flags & CM_MERGEFLAG_BULKSTAT))
1926         scp->volumeCreationDate = volsyncp->spare1;       /* volume creation date */
1927     else
1928         scp->volumeCreationDate = 0;
1929
1930     scp->serverModTime = statusp->ServerModTime;
1931
1932     if (!(scp->mask & CM_SCACHEMASK_CLIENTMODTIME)) {
1933         scp->clientModTime = statusp->ClientModTime;
1934     }
1935     if (!(scp->mask & CM_SCACHEMASK_LENGTH)) {
1936         scp->length.LowPart = statusp->Length;
1937         scp->length.HighPart = statusp->Length_hi;
1938     }
1939
1940     scp->serverLength.LowPart = statusp->Length;
1941     scp->serverLength.HighPart = statusp->Length_hi;
1942
1943     scp->linkCount = statusp->LinkCount;
1944     scp->owner = statusp->Owner;
1945     scp->group = statusp->Group;
1946     scp->unixModeBits = statusp->UnixModeBits & 07777;
1947
1948     if (statusp->FileType == File)
1949         scp->fileType = CM_SCACHETYPE_FILE;
1950     else if (statusp->FileType == Directory)
1951         scp->fileType = CM_SCACHETYPE_DIRECTORY;
1952     else if (statusp->FileType == SymbolicLink) {
1953         if ((scp->unixModeBits & 0111) == 0)
1954             scp->fileType = CM_SCACHETYPE_MOUNTPOINT;
1955         else
1956             scp->fileType = CM_SCACHETYPE_SYMLINK;
1957     }
1958     else {
1959         osi_Log2(afsd_logp, "Merge, Invalid File Type (%d), scp 0x%p", statusp->FileType, scp);
1960         scp->fileType = CM_SCACHETYPE_INVALID;  /* invalid */
1961     }
1962     /* and other stuff */
1963     scp->parentVnode = statusp->ParentVnode;
1964     scp->parentUnique = statusp->ParentUnique;
1965
1966     /* -1 is a write lock; any positive values are read locks */
1967     scp->fsLockCount = (afs_int32)statusp->lockCount;
1968
1969     /* and merge in the private acl cache info, if this is more than the public
1970      * info; merge in the public stuff in any case.
1971      */
1972     scp->anyAccess = statusp->AnonymousAccess;
1973
1974     if (userp != NULL) {
1975         cm_AddACLCache(scp, userp, statusp->CallerAccess);
1976     }
1977
1978     if (dataVersion != 0 && scp->dataVersion != CM_SCACHE_VERSION_BAD &&
1979         (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) && (dataVersion != scp->dataVersion) ||
1980          (flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
1981          (dv_diff(dataVersion, scp->dataVersion) > activeRPCs))) {
1982         /*
1983          * We now know that all of the data buffers that we have associated
1984          * with this scp are invalid.  Subsequent operations will go faster
1985          * if the buffers are removed from the hash tables.
1986          *
1987          * We do not remove directory buffers if the dataVersion delta is 'activeRPCs' because
1988          * those version numbers will be updated as part of the directory operation.
1989          *
1990          * We do not remove storedata buffers because they will still be valid.
1991          */
1992         int i, j;
1993         cm_buf_t **lbpp;
1994         cm_buf_t *tbp;
1995         cm_buf_t *bp, *prevBp, *nextBp;
1996
1997         lock_ObtainWrite(&buf_globalLock);
1998         i = BUF_FILEHASH(&scp->fid);
1999         for (bp = cm_data.buf_fileHashTablepp[i]; bp; bp=nextBp)
2000         {
2001             nextBp = bp->fileHashp;
2002             /*
2003              * if the buffer belongs to this stat cache entry
2004              * and the buffer mutex can be obtained, check the
2005              * reference count and if it is zero, remove the buffer
2006              * from the hash tables.  If there are references,
2007              * the buffer might be updated to the current version
2008              * so leave it in place.
2009              */
2010             if (cm_FidCmp(&scp->fid, &bp->fid) == 0 &&
2011                 bp->refCount == 0 &&
2012                 lock_TryMutex(&bp->mx)) {
2013                 if (bp->refCount == 0 &&
2014                     !(bp->flags & (CM_BUF_READING | CM_BUF_WRITING | CM_BUF_DIRTY)) &&
2015                     !(bp->qFlags & CM_BUF_QREDIR)) {
2016                     prevBp = bp->fileHashBackp;
2017                     bp->fileHashBackp = bp->fileHashp = NULL;
2018                     if (prevBp)
2019                         prevBp->fileHashp = nextBp;
2020                     else
2021                         cm_data.buf_fileHashTablepp[i] = nextBp;
2022                     if (nextBp)
2023                         nextBp->fileHashBackp = prevBp;
2024
2025                     j = BUF_HASH(&bp->fid, &bp->offset);
2026                     lbpp = &(cm_data.buf_scacheHashTablepp[j]);
2027                     for(tbp = *lbpp; tbp; lbpp = &tbp->hashp, tbp = tbp->hashp) {
2028                         if (tbp == bp)
2029                             break;
2030                     }
2031
2032                     /* we better find it */
2033                     osi_assertx(tbp != NULL, "cm_MergeStatus: buf_scacheHashTablepp table screwup");
2034
2035                     *lbpp = bp->hashp;  /* hash out */
2036                     bp->hashp = NULL;
2037
2038                     _InterlockedAnd(&bp->qFlags, ~CM_BUF_QINHASH);
2039                 }
2040                 lock_ReleaseMutex(&bp->mx);
2041             }
2042         }
2043         lock_ReleaseWrite(&buf_globalLock);
2044     }
2045
2046     if (scp->dataVersion != dataVersion && !(flags & CM_MERGEFLAG_FETCHDATA)) {
2047         osi_Log5(afsd_logp, "cm_MergeStatus data version change scp 0x%p cell %u vol %u vn %u uniq %u",
2048                  scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
2049
2050         osi_Log4(afsd_logp, ".... oldDV 0x%x:%x -> newDV 0x%x:%x",
2051                  (afs_uint32)((scp->dataVersion >> 32) & 0xFFFFFFFF),
2052                  (afs_uint32)(scp->dataVersion & 0xFFFFFFFF),
2053                  (afs_uint32)((dataVersion >> 32) & 0xFFFFFFFF),
2054                  (afs_uint32)(dataVersion & 0xFFFFFFFF));
2055     }
2056
2057     /* We maintain a range of buffer dataVersion values which are considered
2058      * valid.  This avoids the need to update the dataVersion on each buffer
2059      * object during an uncontested storeData operation.  As a result this
2060      * merge status no longer has performance characteristics derived from
2061      * the size of the file.
2062      *
2063      * For directory buffers, only current dataVersion values are up to date.
2064      */
2065     if (((flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (dv_diff(dataVersion, scp->dataVersion) > activeRPCs)) ||
2066          (!(flags & (CM_MERGEFLAG_STOREDATA|CM_MERGEFLAG_DIROP)) && (scp->dataVersion != dataVersion)) ||
2067          scp->bufDataVersionLow == CM_SCACHE_VERSION_BAD ||
2068          scp->fileType == CM_SCACHETYPE_DIRECTORY ||
2069          flags & CM_MERGEFLAG_CACHE_BYPASS) {
2070         scp->bufDataVersionLow = dataVersion;
2071     }
2072
2073     if (RDR_Initialized) {
2074         /*
2075          * The redirector maintains its own cached status information which
2076          * must be updated when a DV change occurs that is not the result
2077          * of a redirector initiated data change.
2078          *
2079          * If the current old DV is BAD, send a DV change notification.
2080          *
2081          * If the DV has changed and request was not initiated by the
2082          * redirector, send a DV change notification.
2083          *
2084          * If the request was initiated by the redirector, send a notification
2085          * for store and directory operations that result in a DV change greater
2086          * than the number of active RPCs or any other operation that results
2087          * in an unexpected DV change such as FetchStatus.
2088          */
2089
2090         if (scp->dataVersion == CM_SCACHE_VERSION_BAD && dataVersion != 0) {
2091             rdr_invalidate = 1;
2092         } else if (!(reqp->flags & CM_REQ_SOURCE_REDIR) && scp->dataVersion != dataVersion) {
2093             rdr_invalidate = 1;
2094         } else if (reqp->flags & CM_REQ_SOURCE_REDIR) {
2095             if (!(flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
2096                 (dv_diff(dataVersion, scp->dataVersion) > activeRPCs - 1)) {
2097                 rdr_invalidate = 1;
2098             } else if ((flags & (CM_MERGEFLAG_DIROP|CM_MERGEFLAG_STOREDATA)) &&
2099                        dv_diff(dataVersion, scp->dataVersion) > activeRPCs) {
2100                 rdr_invalidate = 1;
2101             }
2102         }
2103     }
2104     scp->dataVersion = dataVersion;
2105
2106     /*
2107      * If someone is waiting for status information, we can wake them up
2108      * now even though the entity that issued the FetchStatus may not
2109      * have completed yet.
2110      */
2111     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_FETCHSTATUS);
2112
2113     /*
2114      * We just successfully merged status on the stat cache object.
2115      * This means that the associated volume must be online.
2116      */
2117     if (!volp) {
2118         if (!cellp)
2119             cellp = cm_FindCellByID(scp->fid.cell, 0);
2120         cm_FindVolumeByID(cellp, scp->fid.volume, userp, reqp, 0, &volp);
2121     }
2122     if (volp) {
2123         cm_vol_state_t *statep = cm_VolumeStateByID(volp, scp->fid.volume);
2124         if (statep->state != vl_online) {
2125             lock_ObtainWrite(&volp->rw);
2126             cm_VolumeStatusNotification(volp, statep->ID, statep->state, vl_online);
2127             statep->state = vl_online;
2128             lock_ReleaseWrite(&volp->rw);
2129         }
2130     }
2131
2132     /* Remove cached EACCES / EPERM errors if the file is a directory */
2133     if (scp->fileType == CM_SCACHETYPE_DIRECTORY &&
2134         !(volp && (volp->flags & CM_VOLUMEFLAG_DFS_VOLUME)) &&
2135         !cm_accessPerFileCheck)
2136     {
2137         cm_EAccesClearParentEntries(&scp->fid);
2138     }
2139
2140   done:
2141     if (volp)
2142         cm_PutVolume(volp);
2143
2144     /*
2145      * The scache rw lock cannot be held across the invalidation.
2146      * Doing so can result in deadlocks with other threads processing
2147      * requests initiated by the afs redirector.
2148      */
2149     if (rdr_invalidate) {
2150         lock_ReleaseWrite(&scp->rw);
2151         RDR_InvalidateObject(scp->fid.cell, scp->fid.volume, scp->fid.vnode,
2152                              scp->fid.unique, scp->fid.hash,
2153                              scp->fileType, AFS_INVALIDATE_DATA_VERSION);
2154         lock_ObtainWrite(&scp->rw);
2155     }
2156
2157     return 0;
2158 }
2159
2160 /* note that our stat cache info is incorrect, so force us eventually
2161  * to stat the file again.  There may be dirty data associated with
2162  * this vnode, and we want to preserve that information.
2163  *
2164  * This function works by simply simulating a loss of the callback.
2165  *
2166  * This function must be called with the scache locked.
2167  */
2168 void cm_DiscardSCache(cm_scache_t *scp)
2169 {
2170     lock_AssertWrite(&scp->rw);
2171     if (scp->cbServerp) {
2172         cm_PutServer(scp->cbServerp);
2173         scp->cbServerp = NULL;
2174     }
2175     scp->cbExpires = 0;
2176     scp->cbIssued = 0;
2177     _InterlockedAnd(&scp->flags, ~(CM_SCACHEFLAG_LOCAL | CM_SCACHEFLAG_RDR_IN_USE));
2178     cm_dnlcPurgedp(scp);
2179     cm_dnlcPurgevp(scp);
2180     cm_FreeAllACLEnts(scp);
2181
2182     if (scp->fileType == CM_SCACHETYPE_DFSLINK)
2183         cm_VolStatus_Invalidate_DFS_Mapping(scp);
2184 }
2185
2186 void cm_AFSFidFromFid(AFSFid *afsFidp, cm_fid_t *fidp)
2187 {
2188     afsFidp->Volume = fidp->volume;
2189     afsFidp->Vnode = fidp->vnode;
2190     afsFidp->Unique = fidp->unique;
2191 }
2192
2193 #ifdef DEBUG_REFCOUNT
2194 void cm_HoldSCacheNoLockDbg(cm_scache_t *scp, char * file, long line)
2195 #else
2196 void cm_HoldSCacheNoLock(cm_scache_t *scp)
2197 #endif
2198 {
2199     afs_int32 refCount;
2200
2201     osi_assertx(scp != NULL, "null cm_scache_t");
2202     lock_AssertAny(&cm_scacheLock);
2203     refCount = InterlockedIncrement(&scp->refCount);
2204 #ifdef DEBUG_REFCOUNT
2205     osi_Log2(afsd_logp,"cm_HoldSCacheNoLock scp 0x%p ref %d",scp, refCount);
2206     afsi_log("%s:%d cm_HoldSCacheNoLock scp 0x%p, ref %d", file, line, scp, refCount);
2207 #endif
2208 }
2209
2210 #ifdef DEBUG_REFCOUNT
2211 void cm_HoldSCacheDbg(cm_scache_t *scp, char * file, long line)
2212 #else
2213 void cm_HoldSCache(cm_scache_t *scp)
2214 #endif
2215 {
2216     afs_int32 refCount;
2217
2218     osi_assertx(scp != NULL, "null cm_scache_t");
2219     lock_ObtainRead(&cm_scacheLock);
2220     refCount = InterlockedIncrement(&scp->refCount);
2221 #ifdef DEBUG_REFCOUNT
2222     osi_Log2(afsd_logp,"cm_HoldSCache scp 0x%p ref %d",scp, refCount);
2223     afsi_log("%s:%d cm_HoldSCache scp 0x%p ref %d", file, line, scp, refCount);
2224 #endif
2225     lock_ReleaseRead(&cm_scacheLock);
2226 }
2227
2228 #ifdef DEBUG_REFCOUNT
2229 void cm_ReleaseSCacheNoLockDbg(cm_scache_t *scp, char * file, long line)
2230 #else
2231 void cm_ReleaseSCacheNoLock(cm_scache_t *scp)
2232 #endif
2233 {
2234     afs_int32 refCount;
2235
2236     osi_assertx(scp != NULL, "null cm_scache_t");
2237     lock_AssertAny(&cm_scacheLock);
2238
2239     refCount = InterlockedDecrement(&scp->refCount);
2240 #ifdef DEBUG_REFCOUNT
2241     if (refCount < 0)
2242         osi_Log1(afsd_logp,"cm_ReleaseSCacheNoLock about to panic scp 0x%x",scp);
2243 #endif
2244     osi_assertx(refCount >= 0, "cm_scache_t refCount 0");
2245 #ifdef DEBUG_REFCOUNT
2246     osi_Log2(afsd_logp,"cm_ReleaseSCacheNoLock scp 0x%p ref %d",scp, refCount);
2247     afsi_log("%s:%d cm_ReleaseSCacheNoLock scp 0x%p ref %d", file, line, scp, refCount);
2248 #endif
2249 }
2250
2251 #ifdef DEBUG_REFCOUNT
2252 void cm_ReleaseSCacheDbg(cm_scache_t *scp, char * file, long line)
2253 #else
2254 void cm_ReleaseSCache(cm_scache_t *scp)
2255 #endif
2256 {
2257     afs_int32 refCount;
2258
2259     osi_assertx(scp != NULL, "null cm_scache_t");
2260     lock_ObtainRead(&cm_scacheLock);
2261     refCount = InterlockedDecrement(&scp->refCount);
2262 #ifdef DEBUG_REFCOUNT
2263     if (refCount < 0)
2264         osi_Log1(afsd_logp,"cm_ReleaseSCache about to panic scp 0x%x",scp);
2265 #endif
2266     osi_assertx(refCount >= 0, "cm_scache_t refCount 0");
2267 #ifdef DEBUG_REFCOUNT
2268     osi_Log2(afsd_logp,"cm_ReleaseSCache scp 0x%p ref %d",scp, refCount);
2269     afsi_log("%s:%d cm_ReleaseSCache scp 0x%p ref %d", file, line, scp, refCount);
2270 #endif
2271     lock_ReleaseRead(&cm_scacheLock);
2272 }
2273
2274 /* just look for the scp entry to get filetype */
2275 /* doesn't need to be perfectly accurate, so locking doesn't matter too much */
2276 int cm_FindFileType(cm_fid_t *fidp)
2277 {
2278     long hash;
2279     cm_scache_t *scp;
2280
2281     hash = CM_SCACHE_HASH(fidp);
2282
2283     osi_assertx(fidp->cell != 0, "unassigned cell value");
2284
2285     lock_ObtainWrite(&cm_scacheLock);
2286     for (scp=cm_data.scacheHashTablep[hash]; scp; scp=scp->nextp) {
2287         if (cm_FidCmp(fidp, &scp->fid) == 0) {
2288             lock_ReleaseWrite(&cm_scacheLock);
2289             return scp->fileType;
2290         }
2291     }
2292     lock_ReleaseWrite(&cm_scacheLock);
2293     return 0;
2294 }
2295
2296 /* dump all scp's that have reference count > 0 to a file.
2297  * cookie is used to identify this batch for easy parsing,
2298  * and it a string provided by a caller
2299  */
2300 int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
2301 {
2302     int zilch;
2303     cm_scache_t *scp;
2304     osi_queue_t *q;
2305     char output[2048];
2306     int i;
2307
2308     if (lock)
2309         lock_ObtainRead(&cm_scacheLock);
2310
2311     sprintf(output, "%s - dumping all scache - cm_data.currentSCaches=%d, cm_data.maxSCaches=%d\r\n", cookie, cm_data.currentSCaches, cm_data.maxSCaches);
2312     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2313
2314     for (scp = cm_data.allSCachesp; scp; scp = scp->allNextp)
2315     {
2316         time_t t;
2317         char *srvStr = NULL;
2318         afs_uint32 srvStrRpc = TRUE;
2319         char *cbt = NULL;
2320         char *cdrot = NULL;
2321
2322         if (scp->cbServerp) {
2323             if (!((scp->cbServerp->flags & CM_SERVERFLAG_UUID) &&
2324                 UuidToString((UUID *)&scp->cbServerp->uuid, &srvStr) == RPC_S_OK)) {
2325                 srvStr = malloc(16); /* enough for 255.255.255.255 */
2326                 if (srvStr != NULL)
2327                     afs_inet_ntoa_r(scp->cbServerp->addr.sin_addr.s_addr, srvStr);
2328                 srvStrRpc = FALSE;
2329             }
2330         }
2331         if (scp->cbExpires) {
2332             t = scp->cbExpires;
2333             cbt = ctime(&t);
2334             if (cbt) {
2335                 cbt = strdup(cbt);
2336                 cbt[strlen(cbt)-1] = '\0';
2337             }
2338         }
2339         if (scp->volumeCreationDate) {
2340             t = scp->volumeCreationDate;
2341             cdrot = ctime(&t);
2342             if (cdrot) {
2343                 cdrot = strdup(cdrot);
2344                 cdrot[strlen(cdrot)-1] = '\0';
2345             }
2346         }
2347         sprintf(output,
2348                 "%s scp=0x%p, fid (cell=%d, volume=%d, vnode=%d, unique=%d) type=%d dv=%I64d len=0x%I64x "
2349                 "mpDV=%I64d mp='%s' Locks (server=0x%x shared=%d excl=%d clnt=%d) fsLockCount=%d linkCount=%d anyAccess=0x%x "
2350                 "flags=0x%x cbServer='%s' cbExpires='%s' volumeCreationDate='%s' refCount=%u\r\n",
2351                 cookie, scp, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
2352                 scp->fileType, scp->dataVersion, scp->length.QuadPart, scp->mpDataVersion, scp->mountPointStringp,
2353                 scp->serverLock, scp->sharedLocks, scp->exclusiveLocks, scp->clientLocks, scp->fsLockCount,
2354                 scp->linkCount, scp->anyAccess, scp->flags, srvStr ? srvStr : "<none>", cbt ? cbt : "<none>",
2355                 cdrot ? cdrot : "<none>", scp->refCount);
2356         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2357
2358         if (scp->fileLocksH) {
2359             sprintf(output, "  %s - begin dumping scp locks\r\n", cookie);
2360             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2361
2362             for (q = scp->fileLocksH; q; q = osi_QNext(q)) {
2363                 cm_file_lock_t * lockp = fileq_to_cm_file_lock_t(q);
2364                 sprintf(output, "  %s lockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x "
2365                         "key=0x%I64x flags=0x%x update=0x%I64u\r\n",
2366                         cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length,
2367                         lockp->lockType, lockp->key, lockp->flags, (afs_uint64)lockp->lastUpdate);
2368                 WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2369             }
2370
2371             sprintf(output, "  %s - done dumping scp locks\r\n", cookie);
2372             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2373         }
2374
2375         if (srvStr) {
2376             if (srvStrRpc)
2377                 RpcStringFree(&srvStr);
2378             else
2379                 free(srvStr);
2380         }
2381         if (cbt)
2382             free(cbt);
2383         if (cdrot)
2384             free(cdrot);
2385     }
2386
2387     sprintf(output, "%s - Done dumping all scache.\r\n", cookie);
2388     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2389     sprintf(output, "%s - dumping cm_data.scacheHashTable - cm_data.scacheHashTableSize=%d\r\n",
2390             cookie, cm_data.scacheHashTableSize);
2391     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2392
2393     for (i = 0; i < cm_data.scacheHashTableSize; i++)
2394     {
2395         for(scp = cm_data.scacheHashTablep[i]; scp; scp=scp->nextp)
2396         {
2397             sprintf(output, "%s scp=0x%p, hash=%d, fid (cell=%d, volume=%d, vnode=%d, unique=%d)\r\n",
2398                     cookie, scp, i, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique);
2399             WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2400         }
2401     }
2402
2403     sprintf(output, "%s - Done dumping cm_data.scacheHashTable\r\n", cookie);
2404     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2405
2406     sprintf(output, "%s - begin dumping all file locks\r\n", cookie);
2407     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2408
2409     for (q = cm_allFileLocks; q; q = osi_QNext(q)) {
2410         cm_file_lock_t * lockp = (cm_file_lock_t *)q;
2411         sprintf(output, "%s filelockp=0x%p scp=0x%p, cm_userp=0x%p offset=0x%I64x len=0x%08I64x type=0x%x key=0x%I64x flags=0x%x update=0x%I64u\r\n",
2412                  cookie, lockp, lockp->scp, lockp->userp, lockp->range.offset, lockp->range.length,
2413                  lockp->lockType, lockp->key, lockp->flags, (afs_uint64)lockp->lastUpdate);
2414         WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2415     }
2416
2417     sprintf(output, "%s - done dumping all file locks\r\n", cookie);
2418     WriteFile(outputFile, output, (DWORD)strlen(output), &zilch, NULL);
2419
2420     if (lock)
2421         lock_ReleaseRead(&cm_scacheLock);
2422     return (0);
2423 }
2424