windows-byte-range-locks-20050816
[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 <afs/param.h>
11 #include <afs/stds.h>
12
13 #ifndef DJGPP
14 #include <windows.h>
15 #include <winsock2.h>
16 #include <nb30.h>
17 #endif /* !DJGPP */
18 #include <malloc.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <osi.h>
22
23 #include "afsd.h"
24
25 /*extern void afsi_log(char *pattern, ...);*/
26
27 extern osi_hyper_t hzero;
28
29 /* File locks */
30 osi_queue_t *cm_allFileLocks;
31 osi_queue_t *cm_freeFileLocks;
32 unsigned long cm_lockRefreshCycle;
33
34 /* lock for globals */
35 osi_rwlock_t cm_scacheLock;
36
37 /* Dummy scache entry for use with pioctl fids */
38 cm_scache_t cm_fakeSCache;
39
40 #ifdef AFS_FREELANCE_CLIENT
41 extern osi_mutex_t cm_Freelance_Lock;
42 #endif
43
44 /* must be called with cm_scacheLock write-locked! */
45 void cm_AdjustLRU(cm_scache_t *scp)
46 {
47     if (scp == cm_data.scacheLRULastp)
48         cm_data.scacheLRULastp = (cm_scache_t *) osi_QPrev(&scp->q);
49     osi_QRemove((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
50     osi_QAdd((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
51     if (!cm_data.scacheLRULastp) 
52         cm_data.scacheLRULastp = scp;
53 }
54
55 /* called with cm_scacheLock write-locked; find a vnode to recycle.
56  * Can allocate a new one if desperate, or if below quota (cm_data.maxSCaches).
57  */
58 cm_scache_t *cm_GetNewSCache(void)
59 {
60     cm_scache_t *scp;
61     int i;
62     cm_scache_t **lscpp;
63     cm_scache_t *tscp;
64
65     if (cm_data.currentSCaches >= cm_data.maxSCaches) {
66         for (scp = cm_data.scacheLRULastp;
67               scp;
68               scp = (cm_scache_t *) osi_QPrev(&scp->q)) {
69             if (scp->refCount == 0) 
70                 break;
71         }
72                 
73         if (scp) {
74             osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
75             /* we found an entry, so return it */
76             if (scp->flags & CM_SCACHEFLAG_INHASH) {
77                 /* hash it out first */
78                 i = CM_SCACHE_HASH(&scp->fid);
79                 for (lscpp = &cm_data.hashTablep[i], tscp = cm_data.hashTablep[i];
80                       tscp;
81                       lscpp = &tscp->nextp, tscp = tscp->nextp) {
82                     if (tscp == scp) {
83                         *lscpp = scp->nextp;
84                         scp->flags &= ~CM_SCACHEFLAG_INHASH;
85                         break;
86                     }
87                 }
88                 osi_assertx(tscp, "afsd: scache hash screwup");
89             }
90
91             /* look for things that shouldn't still be set */
92             osi_assert(scp->bufWritesp == NULL);
93             osi_assert(scp->bufReadsp == NULL);
94
95             /* invalidate so next merge works fine;
96             * also initialize some flags */
97             scp->flags &= ~(CM_SCACHEFLAG_STATD
98                              | CM_SCACHEFLAG_RO
99                              | CM_SCACHEFLAG_PURERO
100                              | CM_SCACHEFLAG_OVERQUOTA
101                              | CM_SCACHEFLAG_OUTOFSPACE);
102             scp->serverModTime = 0;
103             scp->dataVersion = 0;
104             scp->bulkStatProgress = hzero;
105             scp->waitCount = 0;
106
107             scp->fid.vnode = 0;
108             scp->fid.volume = 0;
109             scp->fid.unique = 0;
110             scp->fid.cell = 0;
111
112             /* discard callback */
113             if (scp->cbServerp) {
114                 cm_PutServer(scp->cbServerp);
115                 scp->cbServerp = NULL;
116             }
117             scp->cbExpires = 0;
118
119             /* remove from dnlc */
120             cm_dnlcPurgedp(scp);
121             cm_dnlcPurgevp(scp);
122
123             /* discard cached status; if non-zero, Close
124              * tried to store this to server but failed */
125             scp->mask = 0;
126
127             /* drop held volume ref */
128             if (scp->volp) {
129                 cm_PutVolume(scp->volp);
130                 scp->volp = NULL;
131             }
132
133             /* discard symlink info */
134             scp->mountPointStringp[0] = 0;
135             memset(&scp->mountRootFid, 0, sizeof(cm_fid_t));
136             memset(&scp->dotdotFid, 0, sizeof(cm_fid_t));
137
138             /* reset locking info */
139             scp->fileLocksH = NULL;
140             scp->fileLocksT = NULL;
141             scp->serverLock = (-1);
142             scp->exclusiveLocks = 0;
143             scp->sharedLocks = 0;
144
145             /* not locked, but there can be no references to this guy
146              * while we hold the global refcount lock.
147              */
148             cm_FreeAllACLEnts(scp);
149
150             /* now remove from the LRU queue and put it back at the
151              * head of the LRU queue.
152              */
153             cm_AdjustLRU(scp);
154
155             /* and we're done */
156             return scp;
157         }
158     }
159         
160     /* if we get here, we should allocate a new scache entry.  We either are below
161      * quota or we have a leak and need to allocate a new one to avoid panicing.
162      */
163     scp = cm_data.scacheBaseAddress + cm_data.currentSCaches;
164     osi_assert(scp >= cm_data.scacheBaseAddress && scp < (cm_scache_t *)cm_data.hashTablep);
165     memset(scp, 0, sizeof(cm_scache_t));
166     scp->magic = CM_SCACHE_MAGIC;
167     lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
168     lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
169     scp->serverLock = -1;
170
171     /* and put it in the LRU queue */
172     osi_QAdd((osi_queue_t **) &cm_data.scacheLRUFirstp, &scp->q);
173     if (!cm_data.scacheLRULastp) 
174         cm_data.scacheLRULastp = scp;
175     cm_data.currentSCaches++;
176     cm_dnlcPurgedp(scp); /* make doubly sure that this is not in dnlc */
177     cm_dnlcPurgevp(scp); 
178     return scp;
179 }       
180
181 /* like strcmp, only for fids */
182 int cm_FidCmp(cm_fid_t *ap, cm_fid_t *bp)
183 {
184     if (ap->vnode != bp->vnode) 
185         return 1;
186     if (ap->volume != bp->volume) 
187         return 1;
188     if (ap->unique != bp->unique) 
189         return 1;
190     if (ap->cell != bp->cell) 
191         return 1;
192     return 0;
193 }
194
195 void cm_fakeSCacheInit(int newFile)
196 {
197     if ( newFile ) {
198         memset(&cm_data.fakeSCache, 0, sizeof(cm_scache_t));
199         cm_data.fakeSCache.cbServerp = (struct cm_server *)(-1);
200         /* can leave clientModTime at 0 */
201         cm_data.fakeSCache.fileType = CM_SCACHETYPE_FILE;
202         cm_data.fakeSCache.unixModeBits = 0777;
203         cm_data.fakeSCache.length.LowPart = 1000;
204         cm_data.fakeSCache.linkCount = 1;
205         cm_data.fakeSCache.refCount = 1;
206     }
207     lock_InitializeMutex(&cm_data.fakeSCache.mx, "cm_scache_t mutex");
208 }
209
210 long
211 cm_ValidateSCache(void)
212 {
213     cm_scache_t * scp, *lscp;
214     long i;
215
216     if ( cm_data.scacheLRUFirstp == NULL && cm_data.scacheLRULastp != NULL ||
217          cm_data.scacheLRUFirstp != NULL && cm_data.scacheLRULastp == NULL) {
218         afsi_log("cm_ValidateSCache failure: inconsistent LRU pointers");
219         fprintf(stderr, "cm_ValidateSCache failure: inconsistent LRU pointers\n");
220         return -17;
221     }
222
223     for ( scp = cm_data.scacheLRUFirstp, lscp = NULL, i = 0; 
224           scp;
225           lscp = scp, scp = (cm_scache_t *) osi_QNext(&scp->q), i++ ) {
226         if (scp->magic != CM_SCACHE_MAGIC) {
227             afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
228             fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
229             return -1;
230         }
231         if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
232             afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
233             fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
234             return -2;
235         }
236         if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
237             afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
238             fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
239             return -3;
240         }
241         if (scp->volp && scp->volp->magic != CM_VOLUME_MAGIC) {
242             afsi_log("cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC");
243             fprintf(stderr, "cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC\n");
244             return -4;
245         }
246         if (i > cm_data.currentSCaches ) {
247             afsi_log("cm_ValidateSCache failure: LRU First queue loops");
248             fprintf(stderr, "cm_ValidateSCache failure: LUR First queue loops\n");
249             return -13;
250         }
251         if (lscp != (cm_scache_t *) osi_QPrev(&scp->q)) {
252             afsi_log("cm_ValidateSCache failure: QPrev(scp) != previous");
253             fprintf(stderr, "cm_ValidateSCache failure: QPrev(scp) != previous\n");
254             return -15;
255         }
256     }
257
258     for ( scp = cm_data.scacheLRULastp, lscp = NULL, i = 0; scp;
259           lscp = scp, scp = (cm_scache_t *) osi_QPrev(&scp->q), i++ ) {
260         if (scp->magic != CM_SCACHE_MAGIC) {
261             afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
262             fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
263             return -5;
264         }
265         if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
266             afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
267             fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
268             return -6;
269         }
270         if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
271             afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
272             fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
273             return -7;
274         }
275         if (scp->volp && scp->volp->magic != CM_VOLUME_MAGIC) {
276             afsi_log("cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC");
277             fprintf(stderr, "cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC\n");
278             return -8;
279         }
280         if (i > cm_data.currentSCaches ) {
281             afsi_log("cm_ValidateSCache failure: LRU Last queue loops");
282             fprintf(stderr, "cm_ValidateSCache failure: LUR Last queue loops\n");
283             return -14;
284         }
285         if (lscp != (cm_scache_t *) osi_QNext(&scp->q)) {
286             afsi_log("cm_ValidateSCache failure: QNext(scp) != next");
287             fprintf(stderr, "cm_ValidateSCache failure: QNext(scp) != next\n");
288             return -16;
289         }
290     }
291
292     for ( i=0; i < cm_data.hashTableSize; i++ ) {
293         for ( scp = cm_data.hashTablep[i]; scp; scp = scp->nextp ) {
294             if (scp->magic != CM_SCACHE_MAGIC) {
295                 afsi_log("cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC");
296                 fprintf(stderr, "cm_ValidateSCache failure: scp->magic != CM_SCACHE_MAGIC\n");
297                 return -9;
298             }
299             if (scp->nextp && scp->nextp->magic != CM_SCACHE_MAGIC) {
300                 afsi_log("cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC");
301                 fprintf(stderr, "cm_ValidateSCache failure: scp->nextp->magic != CM_SCACHE_MAGIC\n");
302                 return -10;
303             }
304             if (scp->randomACLp && scp->randomACLp->magic != CM_ACLENT_MAGIC) {
305                 afsi_log("cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC");
306                 fprintf(stderr, "cm_ValidateSCache failure: scp->randomACLp->magic != CM_ACLENT_MAGIC\n");
307                 return -11;
308             }
309             if (scp->volp && scp->volp->magic != CM_VOLUME_MAGIC) {
310                 afsi_log("cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC");
311                 fprintf(stderr, "cm_ValidateSCache failure: scp->volp->magic != CM_VOLUME_MAGIC\n");
312                 return -12;
313             }
314         }
315     }
316
317     return cm_dnlcValidate();
318 }
319
320 long
321 cm_ShutdownSCache(void)
322 {
323     cm_scache_t * scp;
324
325     for ( scp = cm_data.scacheLRULastp; scp;
326           scp = (cm_scache_t *) osi_QPrev(&scp->q) ) {
327         if (scp->randomACLp) {
328             lock_ObtainMutex(&scp->mx);
329             cm_FreeAllACLEnts(scp);
330             lock_ReleaseMutex(&scp->mx);
331         }
332         lock_FinalizeMutex(&scp->mx);
333         lock_FinalizeRWLock(&scp->bufCreateLock);
334     }
335
336     return cm_dnlcShutdown();
337 }
338
339 void cm_InitSCache(int newFile, long maxSCaches)
340 {
341     static osi_once_t once;
342         
343     if (osi_Once(&once)) {
344         lock_InitializeRWLock(&cm_scacheLock, "cm_scacheLock");
345         if ( newFile ) {
346             memset(cm_data.hashTablep, 0, sizeof(cm_scache_t *) * cm_data.hashTableSize);
347             cm_data.currentSCaches = 0;
348             cm_data.maxSCaches = maxSCaches;
349             cm_data.scacheLRUFirstp = cm_data.scacheLRULastp = NULL;
350         } else {
351             cm_scache_t * scp;
352
353             for ( scp = cm_data.scacheLRULastp; scp;
354                   scp = (cm_scache_t *) osi_QPrev(&scp->q) ) {
355                 lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
356                 lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
357
358                 scp->cbServerp = NULL;
359                 scp->cbExpires = 0;
360                 scp->fileLocksH = NULL;
361                 scp->fileLocksT = NULL;
362                 scp->serverLock = (-1);
363                 scp->lastRefreshCycle = 0;
364                 scp->exclusiveLocks = 0;
365                 scp->sharedLocks = 0;
366                 scp->openReads = 0;
367                 scp->openWrites = 0;
368                 scp->openShares = 0;
369                 scp->openExcls = 0;
370                 scp->waitCount = 0;
371                 scp->flags &= ~CM_SCACHEFLAG_WAITING;
372             }
373         }
374         cm_allFileLocks = NULL;
375         cm_freeFileLocks = NULL;
376         cm_lockRefreshCycle = 0;
377         cm_fakeSCacheInit(newFile);
378         cm_dnlcInit(newFile);
379         osi_EndOnce(&once);
380     }
381 }
382
383 /* version that doesn't bother creating the entry if we don't find it */
384 cm_scache_t *cm_FindSCache(cm_fid_t *fidp)
385 {
386     long hash;
387     cm_scache_t *scp;
388
389     hash = CM_SCACHE_HASH(fidp);
390         
391     osi_assert(fidp->cell != 0);
392
393     lock_ObtainWrite(&cm_scacheLock);
394     for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
395         if (cm_FidCmp(fidp, &scp->fid) == 0) {
396             cm_HoldSCacheNoLock(scp);
397             cm_AdjustLRU(scp);
398             lock_ReleaseWrite(&cm_scacheLock);
399             return scp;
400         }
401     }
402     lock_ReleaseWrite(&cm_scacheLock);
403     return NULL;
404 }
405
406 long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
407                   cm_req_t *reqp)
408 {
409     long hash;
410     cm_scache_t *scp;
411     long code;
412     cm_volume_t *volp = 0;
413     cm_cell_t *cellp;
414     char* mp = 0;
415     int special; // yj: boolean variable to test if file is on root.afs
416     int isRoot;
417     extern cm_fid_t cm_rootFid;
418         
419     hash = CM_SCACHE_HASH(fidp);
420         
421     osi_assert(fidp->cell != 0);
422
423     if (fidp->cell== cm_data.rootFid.cell && 
424          fidp->volume==cm_data.rootFid.volume &&
425          fidp->vnode==0x0 && fidp->unique==0x0)
426     {
427         osi_Log0(afsd_logp,"cm_getSCache called with root cell/volume and vnode=0 and unique=0");
428     }
429
430     // yj: check if we have the scp, if so, we don't need
431     // to do anything else
432     lock_ObtainWrite(&cm_scacheLock);
433     for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
434         if (cm_FidCmp(fidp, &scp->fid) == 0) {
435             cm_HoldSCacheNoLock(scp);
436             *outScpp = scp;
437             cm_AdjustLRU(scp);
438             lock_ReleaseWrite(&cm_scacheLock);
439             return 0;
440         }
441     }
442         
443     // yj: when we get here, it means we don't have an scp
444     // so we need to either load it or fake it, depending
445     // on whether the file is "special", see below.
446
447     // yj: if we're trying to get an scp for a file that's
448     // on root.afs of homecell, we want to handle it specially
449     // because we have to fill in the status stuff 'coz we
450     // don't want trybulkstat to fill it in for us
451 #ifdef AFS_FREELANCE_CLIENT
452     special = (fidp->cell==AFS_FAKE_ROOT_CELL_ID && 
453                fidp->volume==AFS_FAKE_ROOT_VOL_ID &&
454                !(fidp->vnode==0x1 && fidp->unique==0x1));
455     isRoot = (fidp->cell==AFS_FAKE_ROOT_CELL_ID && 
456               fidp->volume==AFS_FAKE_ROOT_VOL_ID &&
457               fidp->vnode==0x1 && fidp->unique==0x1);
458     if (cm_freelanceEnabled && isRoot) {
459         osi_Log0(afsd_logp,"cm_getSCache Freelance and isRoot");
460         /* freelance: if we are trying to get the root scp for the first
461          * time, we will just put in a place holder entry. 
462          */
463         volp = NULL;
464     }
465           
466     if (cm_freelanceEnabled && special) {
467         osi_Log0(afsd_logp,"cm_getSCache Freelance and special");
468         if (fidp->vnode > 1 && fidp->vnode <= cm_noLocalMountPoints + 2) {
469             lock_ObtainMutex(&cm_Freelance_Lock);
470             mp =(cm_localMountPoints+fidp->vnode-2)->mountPointStringp;
471             lock_ReleaseMutex(&cm_Freelance_Lock);
472         } else {
473             mp = "";
474         }
475         scp = cm_GetNewSCache();
476                 
477         scp->fid = *fidp;
478         scp->volp = cm_data.rootSCachep->volp;
479         scp->dotdotFid.cell=AFS_FAKE_ROOT_CELL_ID;
480         scp->dotdotFid.volume=AFS_FAKE_ROOT_VOL_ID;
481         scp->dotdotFid.unique=1;
482         scp->dotdotFid.vnode=1;
483         scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
484         scp->nextp=cm_data.hashTablep[hash];
485         cm_data.hashTablep[hash]=scp;
486         scp->flags |= CM_SCACHEFLAG_INHASH;
487         scp->refCount = 1;
488         if (fidp->vnode > 1 && fidp->vnode <= cm_noLocalMountPoints + 2)
489             scp->fileType = (cm_localMountPoints+fidp->vnode-2)->fileType;
490         else 
491             scp->fileType = CM_SCACHETYPE_INVALID;
492
493         lock_ObtainMutex(&cm_Freelance_Lock);
494         scp->length.LowPart = strlen(mp)+4;
495         strncpy(scp->mountPointStringp,mp,MOUNTPOINTLEN);
496         scp->mountPointStringp[MOUNTPOINTLEN-1] = '\0';
497         lock_ReleaseMutex(&cm_Freelance_Lock);
498
499         scp->owner=0x0;
500         scp->unixModeBits=0x1ff;
501         scp->clientModTime=FakeFreelanceModTime;
502         scp->serverModTime=FakeFreelanceModTime;
503         scp->parentUnique = 0x1;
504         scp->parentVnode=0x1;
505         scp->group=0;
506         scp->dataVersion=cm_data.fakeDirVersion;
507         *outScpp = scp;
508         lock_ReleaseWrite(&cm_scacheLock);
509         /*afsi_log("   getscache done");*/
510         return 0;
511     }
512     // end of yj code
513 #endif /* AFS_FREELANCE_CLIENT */
514
515     /* otherwise, we need to find the volume */
516     if (!cm_freelanceEnabled || !isRoot) {
517         lock_ReleaseWrite(&cm_scacheLock);      /* for perf. reasons */
518         cellp = cm_FindCellByID(fidp->cell);
519         if (!cellp) 
520             return CM_ERROR_NOSUCHCELL;
521
522         code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, &volp);
523         if (code) 
524             return code;
525         lock_ObtainWrite(&cm_scacheLock);
526     }
527         
528     /* otherwise, we have the volume, now reverify that the scp doesn't
529      * exist, and proceed.
530      */
531     for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
532         if (cm_FidCmp(fidp, &scp->fid) == 0) {
533             cm_HoldSCacheNoLock(scp);
534             osi_assert(scp->volp == volp);
535             cm_AdjustLRU(scp);
536             lock_ReleaseWrite(&cm_scacheLock);
537             if (volp)
538                 cm_PutVolume(volp);
539             *outScpp = scp;
540             return 0;
541         }
542     }
543         
544     /* now, if we don't have the fid, recycle something */
545     scp = cm_GetNewSCache();
546     osi_assert(!(scp->flags & CM_SCACHEFLAG_INHASH));
547     scp->fid = *fidp;
548     scp->volp = volp;   /* a held reference */
549
550     if (!cm_freelanceEnabled || !isRoot) {
551         /* if this scache entry represents a volume root then we need 
552          * to copy the dotdotFipd from the volume structure where the 
553          * "master" copy is stored (defect 11489)
554          */
555         if (scp->fid.vnode == 1 && scp->fid.unique == 1) {
556             scp->dotdotFid = volp->dotdotFid;
557         }
558           
559         if (volp->roID == fidp->volume)
560             scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
561         else if (volp->bkID == fidp->volume)
562             scp->flags |= CM_SCACHEFLAG_RO;
563     }
564     scp->nextp = cm_data.hashTablep[hash];
565     cm_data.hashTablep[hash] = scp;
566     scp->flags |= CM_SCACHEFLAG_INHASH;
567     scp->refCount = 1;
568
569     /* XXX - The following fields in the cm_scache are 
570      * uninitialized:
571      *   fileType
572      *   parentVnode
573      *   parentUnique
574      */
575     lock_ReleaseWrite(&cm_scacheLock);
576         
577     /* now we have a held scache entry; just return it */
578     *outScpp = scp;
579     return 0;
580 }
581
582 /* synchronize a fetch, store, read, write, fetch status or store status.
583  * Called with scache mutex held, and returns with it held, but temporarily
584  * drops it during the fetch.
585  * 
586  * At most one flag can be on in flags, if this is an RPC request.
587  *
588  * Also, if we're fetching or storing data, we must ensure that we have a buffer.
589  *
590  * There are a lot of weird restrictions here; here's an attempt to explain the
591  * rationale for the concurrency restrictions implemented in this function.
592  *
593  * First, although the file server will break callbacks when *another* machine
594  * modifies a file or status block, the client itself is responsible for
595  * concurrency control on its own requests.  Callback breaking events are rare,
596  * and simply invalidate any concurrent new status info.
597  *
598  * In the absence of callback breaking messages, we need to know how to
599  * synchronize incoming responses describing updates to files.  We synchronize
600  * operations that update the data version by comparing the data versions.
601  * However, updates that do not update the data, but only the status, can't be
602  * synchronized with fetches or stores, since there's nothing to compare
603  * to tell which operation executed first at the server.
604  *
605  * Thus, we can allow multiple ops that change file data, or dir data, and
606  * fetches.  However, status storing ops have to be done serially.
607  *
608  * Furthermore, certain data-changing ops are incompatible: we can't read or
609  * write a buffer while doing a truncate.  We can't read and write the same
610  * buffer at the same time, or write while fetching or storing, or read while
611  * fetching a buffer (this may change).  We can't fetch and store at the same
612  * time, either.
613  *
614  * With respect to status, we can't read and write at the same time, read while
615  * fetching, write while fetching or storing, or fetch and store at the same time.
616  *
617  * We can't allow a get callback RPC to run in concurrently with something that
618  * will return updated status, since we could start a call, have the server
619  * return status, have another machine make an update to the status (which
620  * doesn't change serverModTime), have the original machine get a new callback,
621  * and then have the original machine merge in the early, old info from the
622  * first call.  At this point, the easiest way to avoid this problem is to have
623  * getcallback calls conflict with all others for the same vnode.  Other calls
624  * to cm_MergeStatus that aren't associated with calls to cm_SyncOp on the same
625  * vnode must be careful not to merge in their status unless they have obtained
626  * a callback from the start of their call.
627  *
628  * Note added 1/23/96
629  * Concurrent StoreData RPC's can cause trouble if the file is being extended.
630  * Each such RPC passes a FileLength parameter, which the server uses to do
631  * pre-truncation if necessary.  So if two RPC's are processed out of order at
632  * the server, the one with the smaller FileLength will be processed last,
633  * possibly resulting in a bogus truncation.  The simplest way to avoid this
634  * is to serialize all StoreData RPC's.  This is the reason we defined
635  * CM_SCACHESYNC_STOREDATA_EXCL and CM_SCACHEFLAG_DATASTORING.
636  */
637 long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *up, cm_req_t *reqp,
638                long rights, long flags)
639 {
640     osi_queueData_t *qdp;
641     long code;
642     cm_buf_t *tbufp;
643     long outRights;
644     int bufLocked;
645
646     /* lookup this first */
647     bufLocked = flags & CM_SCACHESYNC_BUFLOCKED;
648
649     /* some minor assertions */
650     if (flags & (CM_SCACHESYNC_STOREDATA | CM_SCACHESYNC_FETCHDATA
651                   | CM_SCACHESYNC_READ | CM_SCACHESYNC_WRITE
652                   | CM_SCACHESYNC_SETSIZE)) {
653         if (bufp) {
654             osi_assert(bufp->refCount > 0);
655             /*
656                osi_assert(cm_FidCmp(&bufp->fid, &scp->fid) == 0);
657              */
658         }
659     }
660     else osi_assert(bufp == NULL);
661
662     /* Do the access check.  Now we don't really do the access check
663      * atomically, since the caller doesn't expect the parent dir to be
664      * returned locked, and that is what we'd have to do to prevent a
665      * callback breaking message on the parent due to a setacl call from
666      * being processed while we're running.  So, instead, we check things
667      * here, and if things look fine with the access, we proceed to finish
668      * the rest of this check.  Sort of a hack, but probably good enough.
669      */
670
671     while (1) {
672         if (flags & CM_SCACHESYNC_FETCHSTATUS) {
673             /* if we're bringing in a new status block, ensure that
674              * we aren't already doing so, and that no one is
675              * changing the status concurrently, either.  We need
676              * to do this, even if the status is of a different
677              * type, since we don't have the ability to figure out,
678              * in the AFS 3 protocols, which status-changing
679              * operation ran first, or even which order a read and
680              * a write occurred in.
681              */
682             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
683                                | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
684                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING|STORING|SIZESTORING|GETCALLBACK want FETCHSTATUS", scp);
685                 goto sleep;
686             }
687         }
688         if (flags & (CM_SCACHESYNC_STORESIZE | CM_SCACHESYNC_STORESTATUS
689                       | CM_SCACHESYNC_SETSIZE | CM_SCACHESYNC_GETCALLBACK)) {
690             /* if we're going to make an RPC to change the status, make sure
691              * that no one is bringing in or sending out the status.
692              */
693             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING |
694                               CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
695                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING|STORING|SIZESTORING|GETCALLBACK want STORESIZE|STORESTATUS|SETSIZE|GETCALLBACK", scp);
696                 goto sleep;
697             }
698             if (scp->bufReadsp || scp->bufWritesp) {
699                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is bufRead|bufWrite want STORESIZE|STORESTATUS|SETSIZE|GETCALLBACK", scp);
700                 goto sleep;
701             }
702         }
703         if (flags & CM_SCACHESYNC_FETCHDATA) {
704             /* if we're bringing in a new chunk of data, make sure that
705              * nothing is happening to that chunk, and that we aren't
706              * changing the basic file status info, either.
707              */
708             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
709                                | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
710                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING|STORING|SIZESTORING|GETCALLBACK want FETCHDATA", scp);
711                 goto sleep;
712             }
713             if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING))) {
714                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%x bufp 0x%x is BUF_CMFETCHING|BUF_CMSTORING want FETCHDATA", scp, bufp);
715                 goto sleep;
716             }
717         }
718         if (flags & CM_SCACHESYNC_STOREDATA) {
719             /* same as fetch data */
720             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
721                                | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK)) {
722                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING|STORING|SIZESTORING|GETCALLBACK want STOREDATA", scp);
723                 goto sleep;
724             }
725             if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING))) {
726                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%x bufp 0x%x is BUF_CMFETCHING|BUF_CMSTORING want STOREDATA", scp, bufp);
727                 goto sleep;
728             }
729         }
730
731         if (flags & CM_SCACHESYNC_STOREDATA_EXCL) {
732             /* Don't allow concurrent StoreData RPC's */
733             if (scp->flags & CM_SCACHEFLAG_DATASTORING) {
734                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is DATASTORING want STOREDATA_EXCL", scp);
735                 goto sleep;
736             }
737         }
738
739         if (flags & CM_SCACHESYNC_ASYNCSTORE) {
740             /* Don't allow more than one BKG store request */
741             if (scp->flags & CM_SCACHEFLAG_ASYNCSTORING) {
742                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is ASYNCSTORING want ASYNCSTORE", scp);
743                 goto sleep;
744             }
745         }
746
747         if (flags & CM_SCACHESYNC_LOCK) {
748             /* Don't allow concurrent fiddling with lock lists */
749             if (scp->flags & CM_SCACHEFLAG_LOCKING) {
750                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is LOCKING want LOCK", scp);
751                 goto sleep;
752             }
753         }
754
755         /* now the operations that don't correspond to making RPCs */
756         if (flags & CM_SCACHESYNC_GETSTATUS) {
757             /* we can use the status that's here, if we're not
758              * bringing in new status.
759              */
760             if (scp->flags & (CM_SCACHEFLAG_FETCHING)) {
761                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING want GETSTATUS", scp);
762                 goto sleep;
763             }
764         }
765         if (flags & CM_SCACHESYNC_SETSTATUS) {
766             /* we can make a change to the local status, as long as
767              * the status isn't changing now.
768              *
769              * If we're fetching or storing a chunk of data, we can
770              * change the status locally, since the fetch/store
771              * operations don't change any of the data that we're
772              * changing here.
773              */
774             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING | CM_SCACHEFLAG_SIZESTORING)) {
775                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING|STORING|SIZESTORING want SETSTATUS", scp);
776                 goto sleep;
777             }
778         }
779         if (flags & CM_SCACHESYNC_READ) {
780             /* we're going to read the data, make sure that the
781              * status is available, and that the data is here.  It
782              * is OK to read while storing the data back.
783              */
784             if (scp->flags & CM_SCACHEFLAG_FETCHING) {
785                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING want READ", scp);
786                 goto sleep;
787             }
788             if (bufp && ((bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED)) == CM_BUF_CMFETCHING)) {
789                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%x bufp 0x%x is BUF_CMFETCHING want READ", scp, bufp);
790                 goto sleep;
791             }
792         }
793         if (flags & CM_SCACHESYNC_WRITE) {
794             /* don't write unless the status is stable and the chunk
795              * is stable.
796              */
797             if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
798                                | CM_SCACHEFLAG_SIZESTORING)) {
799                 osi_Log1(afsd_logp, "CM SyncOp scp 0x%x is FETCHING|STORING|SIZESTORING want WRITE", scp);
800                 goto sleep;
801             }
802             if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING))) {
803                 osi_Log2(afsd_logp, "CM SyncOp scp 0x%x bufp 0x%x is BUF_CMFETCHING|BUF_CMSTORING want WRITE", scp, bufp);
804                 goto sleep;
805             }
806         }
807
808         // yj: modified this so that callback only checked if we're
809         // not checking something on /afs
810         /* fix the conditional to match the one in cm_HaveCallback */
811         if (  (flags & CM_SCACHESYNC_NEEDCALLBACK)
812 #ifdef AFS_FREELANCE_CLIENT
813              && (!cm_freelanceEnabled || 
814                   !(scp->fid.vnode==0x1 && scp->fid.unique==0x1) ||
815                   scp->fid.cell!=AFS_FAKE_ROOT_CELL_ID ||
816                   scp->fid.volume!=AFS_FAKE_ROOT_VOL_ID ||
817                   cm_fakeDirCallback < 2)
818 #endif /* AFS_FREELANCE_CLIENT */
819              ) {
820             if (!cm_HaveCallback(scp)) {
821                 osi_Log1(afsd_logp, "CM SyncOp getting callback on scp %x",
822                           (long) scp);
823                 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
824                 code = cm_GetCallback(scp, up, reqp, 0);
825                 if (bufLocked) {
826                     lock_ReleaseMutex(&scp->mx);
827                     lock_ObtainMutex(&bufp->mx);
828                     lock_ObtainMutex(&scp->mx);
829                 }
830                 if (code) 
831                     return code;
832                 continue;
833             }
834         }
835
836         if (rights) {
837             /* can't check access rights without a callback */
838             osi_assert(flags & CM_SCACHESYNC_NEEDCALLBACK);
839
840             if ((rights & PRSFS_WRITE) && (scp->flags & CM_SCACHEFLAG_RO))
841                 return CM_ERROR_READONLY;
842
843             if (cm_HaveAccessRights(scp, up, rights, &outRights)) {
844                 if (~outRights & rights) return CM_ERROR_NOACCESS;
845             }
846             else {
847                 /* we don't know the required access rights */
848                 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
849                 code = cm_GetAccessRights(scp, up, reqp);
850                 if (code) 
851                     return code;
852                 if (bufLocked) {
853                     lock_ReleaseMutex(&scp->mx);
854                     lock_ObtainMutex(&bufp->mx);
855                     lock_ObtainMutex(&scp->mx);
856                 }
857                 continue;
858             }
859         }
860
861         /* if we get here, we're happy */
862         break;
863
864       sleep:
865         /* first check if we're not supposed to wait: fail 
866          * in this case, returning with everything still locked.
867          */
868         if (flags & CM_SCACHESYNC_NOWAIT) 
869             return CM_ERROR_WOULDBLOCK;
870
871         /* wait here, then try again */
872         osi_Log1(afsd_logp, "CM SyncOp sleeping scp 0x%x", scp);
873         if ( scp->flags & CM_SCACHEFLAG_WAITING ) {
874             scp->waitCount++;
875             scp->waitRequests++;
876             osi_Log3(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING already set for 0x%x; %d threads; %d requests", 
877                      scp, scp->waitCount, scp->waitRequests);
878         } else {
879             osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING set for 0x%x", scp);
880             scp->flags |= CM_SCACHEFLAG_WAITING;
881             scp->waitCount = scp->waitRequests = 1;
882         }
883         if (bufLocked) 
884             lock_ReleaseMutex(&bufp->mx);
885         osi_SleepM((long) &scp->flags, &scp->mx);
886         if (bufLocked) 
887             lock_ObtainMutex(&bufp->mx);
888         lock_ObtainMutex(&scp->mx);
889         scp->waitCount--;
890         osi_Log3(afsd_logp, "CM SyncOp woke! scp 0x%x; still waiting %d threads of %d requests", 
891                  scp, scp->waitCount, scp->waitRequests);
892         if (scp->waitCount == 0) {
893             osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING reset for 0x%x", scp);
894             scp->flags &= ~CM_SCACHEFLAG_WAITING;
895             scp->waitRequests = 0;
896         }
897     } /* big while loop */
898         
899     /* now, update the recorded state for RPC-type calls */
900     if (flags & CM_SCACHESYNC_FETCHSTATUS)
901         scp->flags |= CM_SCACHEFLAG_FETCHING;
902     if (flags & CM_SCACHESYNC_STORESTATUS)
903         scp->flags |= CM_SCACHEFLAG_STORING;
904     if (flags & CM_SCACHESYNC_STORESIZE)
905         scp->flags |= CM_SCACHEFLAG_SIZESTORING;
906     if (flags & CM_SCACHESYNC_GETCALLBACK)
907         scp->flags |= CM_SCACHEFLAG_GETCALLBACK;
908     if (flags & CM_SCACHESYNC_STOREDATA_EXCL)
909         scp->flags |= CM_SCACHEFLAG_DATASTORING;
910     if (flags & CM_SCACHESYNC_ASYNCSTORE)
911         scp->flags |= CM_SCACHEFLAG_ASYNCSTORING;
912     if (flags & CM_SCACHESYNC_LOCK)
913         scp->flags |= CM_SCACHEFLAG_LOCKING;
914
915     /* now update the buffer pointer */
916     if (flags & CM_SCACHESYNC_FETCHDATA) {
917         /* ensure that the buffer isn't already in the I/O list */
918         if (bufp) {
919             for(qdp = scp->bufReadsp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
920                 tbufp = osi_GetQData(qdp);
921                 osi_assert(tbufp != bufp);
922             }
923         }
924
925         /* queue a held reference to the buffer in the "reading" I/O list */
926         qdp = osi_QDAlloc();
927         osi_SetQData(qdp, bufp);
928         if (bufp) {
929             buf_Hold(bufp);
930             bufp->cmFlags |= CM_BUF_CMFETCHING;
931         }
932         osi_QAdd((osi_queue_t **) &scp->bufReadsp, &qdp->q);
933     }
934
935     if (flags & CM_SCACHESYNC_STOREDATA) {
936         /* ensure that the buffer isn't already in the I/O list */
937         if (bufp) {
938             for(qdp = scp->bufWritesp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
939                 tbufp = osi_GetQData(qdp);
940                 osi_assert(tbufp != bufp);
941             }
942         }
943
944         /* queue a held reference to the buffer in the "writing" I/O list */
945         qdp = osi_QDAlloc();
946         osi_SetQData(qdp, bufp);
947         if (bufp) {
948             buf_Hold(bufp);
949             bufp->cmFlags |= CM_BUF_CMSTORING;
950         }
951         osi_QAdd((osi_queue_t **) &scp->bufWritesp, &qdp->q);
952     }
953
954     return 0;
955 }
956
957 /* for those syncops that setup for RPCs.
958  * Called with scache locked.
959  */
960 void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, long flags)
961 {
962     osi_queueData_t *qdp;
963     cm_buf_t *tbufp;
964
965     /* now, update the recorded state for RPC-type calls */
966     if (flags & CM_SCACHESYNC_FETCHSTATUS)
967         scp->flags &= ~CM_SCACHEFLAG_FETCHING;
968     if (flags & CM_SCACHESYNC_STORESTATUS)
969         scp->flags &= ~CM_SCACHEFLAG_STORING;
970     if (flags & CM_SCACHESYNC_STORESIZE)
971         scp->flags &= ~CM_SCACHEFLAG_SIZESTORING;
972     if (flags & CM_SCACHESYNC_GETCALLBACK)
973         scp->flags &= ~CM_SCACHEFLAG_GETCALLBACK;
974     if (flags & CM_SCACHESYNC_STOREDATA_EXCL)
975         scp->flags &= ~CM_SCACHEFLAG_DATASTORING;
976     if (flags & CM_SCACHESYNC_ASYNCSTORE)
977         scp->flags &= ~CM_SCACHEFLAG_ASYNCSTORING;
978     if (flags & CM_SCACHESYNC_LOCK)
979         scp->flags &= ~CM_SCACHEFLAG_LOCKING;
980
981     /* now update the buffer pointer */
982     if (flags & CM_SCACHESYNC_FETCHDATA) {
983         /* ensure that the buffer isn't already in the I/O list */
984         for(qdp = scp->bufReadsp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
985             tbufp = osi_GetQData(qdp);
986             if (tbufp == bufp) break;
987         }
988         osi_assert(qdp != NULL);
989         osi_assert(osi_GetQData(qdp) == bufp);
990         osi_QRemove((osi_queue_t **) &scp->bufReadsp, &qdp->q);
991         osi_QDFree(qdp);
992         if (bufp) {
993             bufp->cmFlags &= ~(CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED);
994             if (bufp->flags & CM_BUF_WAITING) {
995                 osi_Log2(afsd_logp, "CM SyncOpDone Waking [scp 0x%x] bufp 0x%x", scp, bufp);
996                 osi_Wakeup((long) &bufp);
997             }
998             buf_Release(bufp);
999         }
1000     }
1001
1002     /* now update the buffer pointer */
1003     if (flags & CM_SCACHESYNC_STOREDATA) {
1004         /* ensure that the buffer isn't already in the I/O list */
1005         for(qdp = scp->bufWritesp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
1006             tbufp = osi_GetQData(qdp);
1007             if (tbufp == bufp) break;
1008         }
1009         osi_assert(qdp != NULL);
1010         osi_assert(osi_GetQData(qdp) == bufp);
1011         osi_QRemove((osi_queue_t **) &scp->bufWritesp, &qdp->q);
1012         osi_QDFree(qdp);
1013         if (bufp) {
1014             bufp->cmFlags &= ~CM_BUF_CMSTORING;
1015             if (bufp->flags & CM_BUF_WAITING) {
1016                 osi_Log2(afsd_logp, "CM SyncOpDone Waking [scp 0x%x] bufp 0x%x", scp, bufp);
1017                 osi_Wakeup((long) &bufp);
1018             }
1019             buf_Release(bufp);
1020         }
1021     }
1022
1023     /* and wakeup anyone who is waiting */
1024     if (scp->flags & CM_SCACHEFLAG_WAITING) {
1025         osi_Log1(afsd_logp, "CM SyncOpDone Waking scp 0x%x", scp);
1026         osi_Wakeup((long) &scp->flags);
1027     }
1028 }       
1029
1030 /* merge in a response from an RPC.  The scp must be locked, and the callback
1031  * is optional.
1032  *
1033  * Don't overwrite any status info that is dirty, since we could have a store
1034  * operation (such as store data) that merges some info in, and we don't want
1035  * to lose the local updates.  Typically, there aren't many updates we do
1036  * locally, anyway, probably only mtime.
1037  *
1038  * There is probably a bug in here where a chmod (which doesn't change
1039  * serverModTime) that occurs between two fetches, both of whose responses are
1040  * handled after the callback breaking is done, but only one of whose calls
1041  * started before that, can cause old info to be merged from the first call.
1042  */
1043 void cm_MergeStatus(cm_scache_t *scp, AFSFetchStatus *statusp, AFSVolSync *volp,
1044                     cm_user_t *userp, int flags)
1045 {
1046     // yj: i want to create some fake status for the /afs directory and the
1047     // entries under that directory
1048 #ifdef AFS_FREELANCE_CLIENT
1049     if (cm_freelanceEnabled && scp == cm_data.rootSCachep) {
1050         osi_Log0(afsd_logp,"cm_MergeStatus Freelance cm_data.rootSCachep");
1051         statusp->InterfaceVersion = 0x1;
1052         statusp->FileType = CM_SCACHETYPE_DIRECTORY;
1053         statusp->LinkCount = scp->linkCount;
1054         statusp->Length = cm_fakeDirSize;
1055         statusp->DataVersion = cm_data.fakeDirVersion;
1056         statusp->Author = 0x1;
1057         statusp->Owner = 0x0;
1058         statusp->CallerAccess = 0x9;
1059         statusp->AnonymousAccess = 0x9;
1060         statusp->UnixModeBits = 0x1ff;
1061         statusp->ParentVnode = 0x1;
1062         statusp->ParentUnique = 0x1;
1063         statusp->ResidencyMask = 0;
1064         statusp->ClientModTime = FakeFreelanceModTime;
1065         statusp->ServerModTime = FakeFreelanceModTime;
1066         statusp->Group = 0;
1067         statusp->SyncCounter = 0;
1068         statusp->dataVersionHigh = 0;
1069     }
1070 #endif /* AFS_FREELANCE_CLIENT */
1071
1072     if (!(flags & CM_MERGEFLAG_FORCE)
1073          && statusp->DataVersion < (unsigned long) scp->dataVersion) {
1074         struct cm_cell *cellp;
1075
1076         cellp = cm_FindCellByID(scp->fid.cell);
1077         if (scp->cbServerp) {
1078             struct cm_volume *volp = NULL;
1079
1080             cm_GetVolumeByID(cellp, scp->fid.volume, userp,
1081                               (cm_req_t *) NULL, &volp);
1082             osi_Log2(afsd_logp, "old data from server %x volume %s",
1083                       scp->cbServerp->addr.sin_addr.s_addr,
1084                       volp ? volp->namep : "(unknown)");
1085             if (volp)
1086                 cm_PutVolume(volp);
1087         }
1088         osi_Log3(afsd_logp, "Bad merge, scp %x, scp dv %d, RPC dv %d",
1089                   scp, scp->dataVersion, statusp->DataVersion);
1090         /* we have a number of data fetch/store operations running
1091          * concurrently, and we can tell which one executed last at the
1092          * server by its mtime.
1093          * Choose the one with the largest mtime, and ignore the rest.
1094          *
1095          * These concurrent calls are incompatible with setting the
1096          * mtime, so we won't have a locally changed mtime here.
1097          *
1098          * We could also have ACL info for a different user than usual,
1099          * in which case we have to do that part of the merge, anyway.
1100          * We won't have to worry about the info being old, since we
1101          * won't have concurrent calls
1102          * that change file status running from this machine.
1103          *
1104          * Added 3/17/98:  if we see data version regression on an RO
1105          * file, it's probably due to a server holding an out-of-date
1106          * replica, rather than to concurrent RPC's.  Failures to
1107          * release replicas are now flagged by the volserver, but only
1108          * since AFS 3.4 5.22, so there are plenty of clients getting
1109          * out-of-date replicas out there.
1110          *
1111          * If we discover an out-of-date replica, by this time it's too
1112          * late to go to another server and retry.  Also, we can't
1113          * reject the merge, because then there is no way for
1114          * GetAccess to do its work, and the caller gets into an
1115          * infinite loop.  So we just grin and bear it.
1116          */
1117         if (!(scp->flags & CM_SCACHEFLAG_RO))
1118             return;
1119     }       
1120     scp->serverModTime = statusp->ServerModTime;
1121
1122     if (!(scp->mask & CM_SCACHEMASK_CLIENTMODTIME)) {
1123         scp->clientModTime = statusp->ClientModTime;
1124     }
1125     if (!(scp->mask & CM_SCACHEMASK_LENGTH)) {
1126         scp->length.LowPart = statusp->Length;
1127         scp->length.HighPart = 0;
1128     }
1129
1130     scp->serverLength.LowPart = statusp->Length;
1131     scp->serverLength.HighPart = 0;
1132
1133     scp->linkCount = statusp->LinkCount;
1134     scp->dataVersion = statusp->DataVersion;
1135     scp->owner = statusp->Owner;
1136     scp->group = statusp->Group;
1137     scp->unixModeBits = statusp->UnixModeBits & 07777;
1138
1139     if (statusp->FileType == File)
1140         scp->fileType = CM_SCACHETYPE_FILE;
1141     else if (statusp->FileType == Directory)
1142         scp->fileType = CM_SCACHETYPE_DIRECTORY;
1143     else if (statusp->FileType == SymbolicLink) {
1144         if ((scp->unixModeBits & 0111) == 0)
1145             scp->fileType = CM_SCACHETYPE_MOUNTPOINT;
1146         else
1147             scp->fileType = CM_SCACHETYPE_SYMLINK;
1148     }       
1149     else {
1150         osi_Log1(afsd_logp, "Merge, Invalid File Type, scp %x", scp);
1151         scp->fileType = 0;      /* invalid */
1152     }
1153     /* and other stuff */
1154     scp->parentVnode = statusp->ParentVnode;
1155     scp->parentUnique = statusp->ParentUnique;
1156         
1157     /* and merge in the private acl cache info, if this is more than the public
1158      * info; merge in the public stuff in any case.
1159      */
1160     scp->anyAccess = statusp->AnonymousAccess;
1161
1162     if (userp != NULL) {
1163         cm_AddACLCache(scp, userp, statusp->CallerAccess);
1164     }
1165 }
1166
1167 /* note that our stat cache info is incorrect, so force us eventually
1168  * to stat the file again.  There may be dirty data associated with
1169  * this vnode, and we want to preserve that information.
1170  *
1171  * This function works by simply simulating a loss of the callback.
1172  *
1173  * This function must be called with the scache locked.
1174  */
1175 void cm_DiscardSCache(cm_scache_t *scp)
1176 {
1177     lock_AssertMutex(&scp->mx);
1178     if (scp->cbServerp) {
1179         cm_PutServer(scp->cbServerp);
1180         scp->cbServerp = NULL;
1181     }
1182     scp->cbExpires = 0;
1183     cm_dnlcPurgedp(scp);
1184     cm_dnlcPurgevp(scp);
1185     cm_FreeAllACLEnts(scp);
1186 }
1187
1188 void cm_AFSFidFromFid(AFSFid *afsFidp, cm_fid_t *fidp)
1189 {
1190     afsFidp->Volume = fidp->volume;
1191     afsFidp->Vnode = fidp->vnode;
1192     afsFidp->Unique = fidp->unique;
1193 }       
1194
1195 void cm_HoldSCacheNoLock(cm_scache_t *scp)
1196 {
1197     osi_assert(scp != 0);
1198     osi_assert(scp->refCount >= 0);
1199     scp->refCount++;
1200 }
1201
1202 void cm_HoldSCache(cm_scache_t *scp)
1203 {
1204     osi_assert(scp != 0);
1205     lock_ObtainWrite(&cm_scacheLock);
1206     osi_assert(scp->refCount >= 0);
1207     scp->refCount++;
1208     lock_ReleaseWrite(&cm_scacheLock);
1209 }
1210
1211 void cm_ReleaseSCacheNoLock(cm_scache_t *scp)
1212 {
1213     osi_assert(scp != 0);
1214     osi_assert(scp->refCount-- >= 0);
1215 }
1216
1217 void cm_ReleaseSCache(cm_scache_t *scp)
1218 {
1219     osi_assert(scp != 0);
1220     lock_ObtainWrite(&cm_scacheLock);
1221     osi_assert(scp->refCount != 0);
1222     scp->refCount--;
1223     lock_ReleaseWrite(&cm_scacheLock);
1224 }
1225
1226 /* just look for the scp entry to get filetype */
1227 /* doesn't need to be perfectly accurate, so locking doesn't matter too much */
1228 int cm_FindFileType(cm_fid_t *fidp)
1229 {
1230     long hash;
1231     cm_scache_t *scp;
1232         
1233     hash = CM_SCACHE_HASH(fidp);
1234         
1235     osi_assert(fidp->cell != 0);
1236
1237     lock_ObtainWrite(&cm_scacheLock);
1238     for (scp=cm_data.hashTablep[hash]; scp; scp=scp->nextp) {
1239         if (cm_FidCmp(fidp, &scp->fid) == 0) {
1240             lock_ReleaseWrite(&cm_scacheLock);
1241             return scp->fileType;
1242         }
1243     }
1244     lock_ReleaseWrite(&cm_scacheLock);
1245     return 0;
1246 }
1247
1248 /* dump all scp's that have reference count > 0 to a file. 
1249  * cookie is used to identify this batch for easy parsing, 
1250  * and it a string provided by a caller 
1251  */
1252 int cm_DumpSCache(FILE *outputFile, char *cookie, int lock)
1253 {
1254     int zilch;
1255     cm_scache_t *scp;
1256     char output[1024];
1257     int i;
1258   
1259     if (lock)
1260         lock_ObtainRead(&cm_scacheLock);
1261   
1262     sprintf(output, "%s - dumping scache - cm_data.currentSCaches=%d, cm_data.maxSCaches=%d\n", cookie, cm_data.currentSCaches, cm_data.maxSCaches);
1263     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1264   
1265     for (scp = cm_data.scacheLRULastp; scp; scp = (cm_scache_t *) osi_QPrev(&scp->q)) 
1266     {
1267         if (scp->refCount != 0)
1268         {
1269             sprintf(output, "%s fid (cell=%d, volume=%d, vnode=%d, unique=%d) refCount=%u\n", 
1270                     cookie, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique, 
1271                     scp->refCount);
1272             WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1273         }
1274     }
1275   
1276     sprintf(output, "%s - dumping cm_data.hashTable - cm_data.hashTableSize=%d\n", cookie, cm_data.hashTableSize);
1277     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1278   
1279     for (i = 0; i < cm_data.hashTableSize; i++)
1280     {
1281         for(scp = cm_data.hashTablep[i]; scp; scp=scp->nextp) 
1282         {
1283             if (scp->refCount != 0)
1284             {
1285                 sprintf(output, "%s scp=0x%08X, hash=%d, fid (cell=%d, volume=%d, vnode=%d, unique=%d) refCount=%u\n", 
1286                          cookie, (void *)scp, i, scp->fid.cell, scp->fid.volume, scp->fid.vnode, 
1287                          scp->fid.unique, scp->refCount);
1288                 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1289             }
1290         }
1291     }
1292
1293     sprintf(output, "%s - Done dumping scache.\n", cookie);
1294     WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1295   
1296     if (lock)
1297         lock_ReleaseRead(&cm_scacheLock);       
1298     return (0);     
1299 }
1300