2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
25 /*extern void afsi_log(char *pattern, ...);*/
27 extern osi_hyper_t hzero;
29 /* hash table stuff */
30 cm_scache_t **cm_hashTablep;
31 long cm_hashTableSize;
33 long cm_currentSCaches;
36 cm_scache_t *cm_scacheLRUFirstp;
37 cm_scache_t *cm_scacheLRULastp;
40 osi_queue_t *cm_allFileLocks;
42 /* lock for globals */
43 osi_rwlock_t cm_scacheLock;
45 /* Dummy scache entry for use with pioctl fids */
46 cm_scache_t cm_fakeSCache;
48 #ifdef AFS_FREELANCE_CLIENT
49 extern osi_mutex_t cm_Freelance_Lock;
52 /* must be called with cm_scacheLock write-locked! */
53 void cm_AdjustLRU(cm_scache_t *scp)
55 if (scp == cm_scacheLRULastp)
56 cm_scacheLRULastp = (cm_scache_t *) osi_QPrev(&scp->q);
57 osi_QRemove((osi_queue_t **) &cm_scacheLRUFirstp, &scp->q);
58 osi_QAdd((osi_queue_t **) &cm_scacheLRUFirstp, &scp->q);
59 if (!cm_scacheLRULastp)
60 cm_scacheLRULastp = scp;
63 /* called with cm_scacheLock write-locked; find a vnode to recycle.
64 * Can allocate a new one if desperate, or if below quota (cm_maxSCaches).
66 cm_scache_t *cm_GetNewSCache(void)
73 if (cm_currentSCaches >= cm_maxSCaches) {
74 for (scp = cm_scacheLRULastp;
76 scp = (cm_scache_t *) osi_QPrev(&scp->q)) {
77 if (scp->refCount == 0)
82 /* we found an entry, so return it */
83 if (scp->flags & CM_SCACHEFLAG_INHASH) {
84 /* hash it out first */
85 i = CM_SCACHE_HASH(&scp->fid);
86 lscpp = &cm_hashTablep[i];
89 lscpp = &tscp->nextp, tscp = *lscpp) {
93 osi_assertx(tscp, "afsd: scache hash screwup");
95 scp->flags &= ~CM_SCACHEFLAG_INHASH;
98 /* look for things that shouldn't still be set */
99 osi_assert(scp->bufWritesp == NULL);
100 osi_assert(scp->bufReadsp == NULL);
102 /* invalidate so next merge works fine;
103 * also initialize some flags */
104 scp->flags &= ~(CM_SCACHEFLAG_STATD
106 | CM_SCACHEFLAG_PURERO
107 | CM_SCACHEFLAG_OVERQUOTA
108 | CM_SCACHEFLAG_OUTOFSPACE);
109 scp->serverModTime = 0;
110 scp->dataVersion = 0;
111 scp->bulkStatProgress = hzero;
113 /* discard callback */
114 if (scp->cbServerp) {
115 cm_PutServer(scp->cbServerp);
116 scp->cbServerp = NULL;
120 /* remove from dnlc */
124 /* discard cached status; if non-zero, Close
125 * tried to store this to server but failed */
128 /* drop held volume ref */
130 cm_PutVolume(scp->volp);
134 /* discard symlink info */
135 if (scp->mountPointStringp) {
136 free(scp->mountPointStringp);
137 scp->mountPointStringp = NULL;
139 if (scp->mountRootFidp) {
140 free(scp->mountRootFidp);
141 scp->mountRootFidp = NULL;
143 if (scp->dotdotFidp) {
144 free(scp->dotdotFidp);
145 scp->dotdotFidp = NULL;
148 /* not locked, but there can be no references to this guy
149 * while we hold the global refcount lock.
151 cm_FreeAllACLEnts(scp);
153 /* now remove from the LRU queue and put it back at the
154 * head of the LRU queue.
163 /* if we get here, we should allocate a new scache entry. We either are below
164 * quota or we have a leak and need to allocate a new one to avoid panicing.
166 scp = malloc(sizeof(*scp));
167 memset(scp, 0, sizeof(*scp));
168 lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
169 lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
171 /* and put it in the LRU queue */
172 osi_QAdd((osi_queue_t **) &cm_scacheLRUFirstp, &scp->q);
173 if (!cm_scacheLRULastp)
174 cm_scacheLRULastp = scp;
176 cm_dnlcPurgedp(scp); /* make doubly sure that this is not in dnlc */
181 /* like strcmp, only for fids */
182 int cm_FidCmp(cm_fid_t *ap, cm_fid_t *bp)
184 if (ap->vnode != bp->vnode)
186 if (ap->volume != bp->volume)
188 if (ap->unique != bp->unique)
190 if (ap->cell != bp->cell)
195 void cm_fakeSCacheInit()
197 memset(&cm_fakeSCache, 0, sizeof(cm_fakeSCache));
198 lock_InitializeMutex(&cm_fakeSCache.mx, "cm_scache_t mutex");
199 cm_fakeSCache.cbServerp = (struct cm_server *)(-1);
200 /* can leave clientModTime at 0 */
201 cm_fakeSCache.fileType = CM_SCACHETYPE_FILE;
202 cm_fakeSCache.unixModeBits = 0777;
203 cm_fakeSCache.length.LowPart = 1000;
204 cm_fakeSCache.linkCount = 1;
207 void cm_InitSCache(long maxSCaches)
209 static osi_once_t once;
211 if (osi_Once(&once)) {
212 lock_InitializeRWLock(&cm_scacheLock, "cm_scacheLock");
213 cm_hashTableSize = maxSCaches / 2;
214 cm_hashTablep = malloc(sizeof(cm_scache_t *) * cm_hashTableSize);
215 memset(cm_hashTablep, 0, sizeof(cm_scache_t *) * cm_hashTableSize);
216 cm_allFileLocks = NULL;
217 cm_currentSCaches = 0;
218 cm_maxSCaches = maxSCaches;
225 /* version that doesn't bother creating the entry if we don't find it */
226 cm_scache_t *cm_FindSCache(cm_fid_t *fidp)
231 hash = CM_SCACHE_HASH(fidp);
233 osi_assert(fidp->cell != 0);
235 lock_ObtainWrite(&cm_scacheLock);
236 for(scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
237 if (cm_FidCmp(fidp, &scp->fid) == 0) {
238 cm_HoldSCacheNoLock(scp);
240 lock_ReleaseWrite(&cm_scacheLock);
244 lock_ReleaseWrite(&cm_scacheLock);
248 long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp,
254 cm_volume_t *volp = 0;
257 int special; // yj: boolean variable to test if file is on root.afs
259 extern cm_fid_t cm_rootFid;
261 hash = CM_SCACHE_HASH(fidp);
263 osi_assert(fidp->cell != 0);
265 if (fidp->cell== cm_rootFid.cell &&
266 fidp->volume==cm_rootFid.volume &&
267 fidp->vnode==0x0 && fidp->unique==0x0)
269 osi_Log0(afsd_logp,"cm_getSCache called with root cell/volume and vnode=0 and unique=0");
272 // yj: check if we have the scp, if so, we don't need
273 // to do anything else
274 lock_ObtainWrite(&cm_scacheLock);
275 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
276 if (cm_FidCmp(fidp, &scp->fid) == 0) {
277 cm_HoldSCacheNoLock(scp);
280 lock_ReleaseWrite(&cm_scacheLock);
285 // yj: when we get here, it means we don't have an scp
286 // so we need to either load it or fake it, depending
287 // on whether the file is "special", see below.
289 // yj: if we're trying to get an scp for a file that's
290 // on root.afs of homecell, we want to handle it specially
291 // because we have to fill in the status stuff 'coz we
292 // don't want trybulkstat to fill it in for us
293 #ifdef AFS_FREELANCE_CLIENT
294 special = (fidp->cell==AFS_FAKE_ROOT_CELL_ID &&
295 fidp->volume==AFS_FAKE_ROOT_VOL_ID &&
296 !(fidp->vnode==0x1 && fidp->unique==0x1));
297 isRoot = (fidp->cell==AFS_FAKE_ROOT_CELL_ID &&
298 fidp->volume==AFS_FAKE_ROOT_VOL_ID &&
299 fidp->vnode==0x1 && fidp->unique==0x1);
300 if (cm_freelanceEnabled && isRoot) {
301 osi_Log0(afsd_logp,"cm_getSCache Freelance and isRoot");
302 /* freelance: if we are trying to get the root scp for the first
303 * time, we will just put in a place holder entry.
308 if (cm_freelanceEnabled && special) {
309 osi_Log0(afsd_logp,"cm_getSCache Freelance and special");
310 if (fidp->vnode > 1) {
311 lock_ObtainMutex(&cm_Freelance_Lock);
312 mp =(cm_localMountPoints+fidp->vnode-2)->mountPointStringp;
313 lock_ReleaseMutex(&cm_Freelance_Lock);
317 scp = cm_GetNewSCache();
320 scp->volp = cm_rootSCachep->volp;
321 if (scp->dotdotFidp == (cm_fid_t *) NULL)
322 scp->dotdotFidp = (cm_fid_t *) malloc (sizeof(cm_fid_t));
323 scp->dotdotFidp->cell=AFS_FAKE_ROOT_CELL_ID;
324 scp->dotdotFidp->volume=AFS_FAKE_ROOT_VOL_ID;
325 scp->dotdotFidp->unique=1;
326 scp->dotdotFidp->vnode=1;
327 scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
328 scp->nextp=cm_hashTablep[hash];
329 cm_hashTablep[hash]=scp;
330 scp->flags |= CM_SCACHEFLAG_INHASH;
332 scp->fileType = (cm_localMountPoints+fidp->vnode-2)->fileType;
334 lock_ObtainMutex(&cm_Freelance_Lock);
335 scp->length.LowPart = strlen(mp)+4;
336 scp->mountPointStringp=malloc(strlen(mp)+1);
337 strcpy(scp->mountPointStringp,mp);
338 lock_ReleaseMutex(&cm_Freelance_Lock);
341 scp->unixModeBits=0x1ff;
342 scp->clientModTime=FakeFreelanceModTime;
343 scp->serverModTime=FakeFreelanceModTime;
344 scp->parentUnique = 0x1;
345 scp->parentVnode=0x1;
347 scp->dataVersion=0x8;
349 lock_ReleaseWrite(&cm_scacheLock);
350 /*afsi_log(" getscache done");*/
354 #endif /* AFS_FREELANCE_CLIENT */
356 /* otherwise, we need to find the volume */
357 if (!cm_freelanceEnabled || !isRoot) {
358 lock_ReleaseWrite(&cm_scacheLock); /* for perf. reasons */
359 cellp = cm_FindCellByID(fidp->cell);
361 return CM_ERROR_NOSUCHCELL;
363 code = cm_GetVolumeByID(cellp, fidp->volume, userp, reqp, &volp);
366 lock_ObtainWrite(&cm_scacheLock);
369 /* otherwise, we have the volume, now reverify that the scp doesn't
370 * exist, and proceed.
372 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
373 if (cm_FidCmp(fidp, &scp->fid) == 0) {
374 osi_assert(scp->volp == volp);
375 cm_HoldSCacheNoLock(scp);
377 lock_ReleaseWrite(&cm_scacheLock);
385 /* now, if we don't have the fid, recycle something */
386 scp = cm_GetNewSCache();
387 osi_assert(!(scp->flags & CM_SCACHEFLAG_INHASH));
389 scp->volp = volp; /* a held reference */
391 if (!cm_freelanceEnabled || !isRoot) {
392 /* if this scache entry represents a volume root then we need
393 * to copy the dotdotFipd from the volume structure where the
394 * "master" copy is stored (defect 11489)
396 if (scp->fid.vnode == 1 && scp->fid.unique == 1 && volp->dotdotFidp) {
397 if (scp->dotdotFidp == (cm_fid_t *) NULL)
398 scp->dotdotFidp = (cm_fid_t *) malloc(sizeof(cm_fid_t));
399 *(scp->dotdotFidp) = *volp->dotdotFidp;
402 if (volp->roID == fidp->volume)
403 scp->flags |= (CM_SCACHEFLAG_PURERO | CM_SCACHEFLAG_RO);
404 else if (volp->bkID == fidp->volume)
405 scp->flags |= CM_SCACHEFLAG_RO;
407 scp->nextp = cm_hashTablep[hash];
408 cm_hashTablep[hash] = scp;
409 scp->flags |= CM_SCACHEFLAG_INHASH;
412 /* XXX - The following fields in the cm_scache are
418 lock_ReleaseWrite(&cm_scacheLock);
420 /* now we have a held scache entry; just return it */
425 /* synchronize a fetch, store, read, write, fetch status or store status.
426 * Called with scache mutex held, and returns with it held, but temporarily
427 * drops it during the fetch.
429 * At most one flag can be on in flags, if this is an RPC request.
431 * Also, if we're fetching or storing data, we must ensure that we have a buffer.
433 * There are a lot of weird restrictions here; here's an attempt to explain the
434 * rationale for the concurrency restrictions implemented in this function.
436 * First, although the file server will break callbacks when *another* machine
437 * modifies a file or status block, the client itself is responsible for
438 * concurrency control on its own requests. Callback breaking events are rare,
439 * and simply invalidate any concurrent new status info.
441 * In the absence of callback breaking messages, we need to know how to
442 * synchronize incoming responses describing updates to files. We synchronize
443 * operations that update the data version by comparing the data versions.
444 * However, updates that do not update the data, but only the status, can't be
445 * synchronized with fetches or stores, since there's nothing to compare
446 * to tell which operation executed first at the server.
448 * Thus, we can allow multiple ops that change file data, or dir data, and
449 * fetches. However, status storing ops have to be done serially.
451 * Furthermore, certain data-changing ops are incompatible: we can't read or
452 * write a buffer while doing a truncate. We can't read and write the same
453 * buffer at the same time, or write while fetching or storing, or read while
454 * fetching a buffer (this may change). We can't fetch and store at the same
457 * With respect to status, we can't read and write at the same time, read while
458 * fetching, write while fetching or storing, or fetch and store at the same time.
460 * We can't allow a get callback RPC to run in concurrently with something that
461 * will return updated status, since we could start a call, have the server
462 * return status, have another machine make an update to the status (which
463 * doesn't change serverModTime), have the original machine get a new callback,
464 * and then have the original machine merge in the early, old info from the
465 * first call. At this point, the easiest way to avoid this problem is to have
466 * getcallback calls conflict with all others for the same vnode. Other calls
467 * to cm_MergeStatus that aren't associated with calls to cm_SyncOp on the same
468 * vnode must be careful not to merge in their status unless they have obtained
469 * a callback from the start of their call.
472 * Concurrent StoreData RPC's can cause trouble if the file is being extended.
473 * Each such RPC passes a FileLength parameter, which the server uses to do
474 * pre-truncation if necessary. So if two RPC's are processed out of order at
475 * the server, the one with the smaller FileLength will be processed last,
476 * possibly resulting in a bogus truncation. The simplest way to avoid this
477 * is to serialize all StoreData RPC's. This is the reason we defined
478 * CM_SCACHESYNC_STOREDATA_EXCL and CM_SCACHEFLAG_DATASTORING.
480 long cm_SyncOp(cm_scache_t *scp, cm_buf_t *bufp, cm_user_t *up, cm_req_t *reqp,
481 long rights, long flags)
483 osi_queueData_t *qdp;
489 /* lookup this first */
490 bufLocked = flags & CM_SCACHESYNC_BUFLOCKED;
492 /* some minor assertions */
493 if (flags & (CM_SCACHESYNC_STOREDATA | CM_SCACHESYNC_FETCHDATA
494 | CM_SCACHESYNC_READ | CM_SCACHESYNC_WRITE
495 | CM_SCACHESYNC_SETSIZE)) {
497 osi_assert(bufp->refCount > 0);
499 osi_assert(cm_FidCmp(&bufp->fid, &scp->fid) == 0);
503 else osi_assert(bufp == NULL);
505 /* Do the access check. Now we don't really do the access check
506 * atomically, since the caller doesn't expect the parent dir to be
507 * returned locked, and that is what we'd have to do to prevent a
508 * callback breaking message on the parent due to a setacl call from
509 * being processed while we're running. So, instead, we check things
510 * here, and if things look fine with the access, we proceed to finish
511 * the rest of this check. Sort of a hack, but probably good enough.
515 if (flags & CM_SCACHESYNC_FETCHSTATUS) {
516 /* if we're bringing in a new status block, ensure that
517 * we aren't already doing so, and that no one is
518 * changing the status concurrently, either. We need
519 * to do this, even if the status is of a different
520 * type, since we don't have the ability to figure out,
521 * in the AFS 3 protocols, which status-changing
522 * operation ran first, or even which order a read and
523 * a write occurred in.
525 if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
526 | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK))
529 if (flags & (CM_SCACHESYNC_STORESIZE | CM_SCACHESYNC_STORESTATUS
530 | CM_SCACHESYNC_SETSIZE | CM_SCACHESYNC_GETCALLBACK)) {
531 /* if we're going to make an RPC to change the status, make sure
532 * that no one is bringing in or sending out the status.
534 if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
535 | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK))
537 if (scp->bufReadsp || scp->bufWritesp) goto sleep;
539 if (flags & CM_SCACHESYNC_FETCHDATA) {
540 /* if we're bringing in a new chunk of data, make sure that
541 * nothing is happening to that chunk, and that we aren't
542 * changing the basic file status info, either.
544 if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
545 | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK))
547 if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)))
550 if (flags & CM_SCACHESYNC_STOREDATA) {
551 /* same as fetch data */
552 if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
553 | CM_SCACHEFLAG_SIZESTORING | CM_SCACHEFLAG_GETCALLBACK))
555 if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)))
559 if (flags & CM_SCACHESYNC_STOREDATA_EXCL) {
560 /* Don't allow concurrent StoreData RPC's */
561 if (scp->flags & CM_SCACHEFLAG_DATASTORING)
565 if (flags & CM_SCACHESYNC_ASYNCSTORE) {
566 /* Don't allow more than one BKG store request */
567 if (scp->flags & CM_SCACHEFLAG_ASYNCSTORING)
571 if (flags & CM_SCACHESYNC_LOCK) {
572 /* Don't allow concurrent fiddling with lock lists */
573 if (scp->flags & CM_SCACHEFLAG_LOCKING)
577 /* now the operations that don't correspond to making RPCs */
578 if (flags & CM_SCACHESYNC_GETSTATUS) {
579 /* we can use the status that's here, if we're not
580 * bringing in new status.
582 if (scp->flags & (CM_SCACHEFLAG_FETCHING))
585 if (flags & CM_SCACHESYNC_SETSTATUS) {
586 /* we can make a change to the local status, as long as
587 * the status isn't changing now.
589 * If we're fetching or storing a chunk of data, we can
590 * change the status locally, since the fetch/store
591 * operations don't change any of the data that we're
594 if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
595 | CM_SCACHEFLAG_SIZESTORING))
598 if (flags & CM_SCACHESYNC_READ) {
599 /* we're going to read the data, make sure that the
600 * status is available, and that the data is here. It
601 * is OK to read while storing the data back.
603 if (scp->flags & CM_SCACHEFLAG_FETCHING)
605 if (bufp && ((bufp->cmFlags
607 | CM_BUF_CMFULLYFETCHED))
608 == CM_BUF_CMFETCHING))
611 if (flags & CM_SCACHESYNC_WRITE) {
612 /* don't write unless the status is stable and the chunk
615 if (scp->flags & (CM_SCACHEFLAG_FETCHING | CM_SCACHEFLAG_STORING
616 | CM_SCACHEFLAG_SIZESTORING))
618 if (bufp && (bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)))
622 // yj: modified this so that callback only checked if we're
623 // not checking something on /afs
624 /* fix the conditional to match the one in cm_HaveCallback */
625 if ( (flags & CM_SCACHESYNC_NEEDCALLBACK)
626 #ifdef AFS_FREELANCE_CLIENT
627 && (!cm_freelanceEnabled ||
628 !(scp->fid.vnode==0x1 && scp->fid.unique==0x1) ||
629 scp->fid.cell!=AFS_FAKE_ROOT_CELL_ID ||
630 scp->fid.volume!=AFS_FAKE_ROOT_VOL_ID ||
631 cm_fakeDirCallback < 2)
632 #endif /* AFS_FREELANCE_CLIENT */
634 if (!cm_HaveCallback(scp)) {
635 osi_Log1(afsd_logp, "CM SyncOp getting callback on scp %x",
637 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
638 code = cm_GetCallback(scp, up, reqp, 0);
640 lock_ReleaseMutex(&scp->mx);
641 lock_ObtainMutex(&bufp->mx);
642 lock_ObtainMutex(&scp->mx);
644 if (code) return code;
650 /* can't check access rights without a callback */
651 osi_assert(flags & CM_SCACHESYNC_NEEDCALLBACK);
653 if ((rights & PRSFS_WRITE) && (scp->flags & CM_SCACHEFLAG_RO))
654 return CM_ERROR_READONLY;
656 if (cm_HaveAccessRights(scp, up, rights, &outRights)) {
657 if (~outRights & rights) return CM_ERROR_NOACCESS;
660 /* we don't know the required access rights */
661 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
662 code = cm_GetAccessRights(scp, up, reqp);
663 if (code) return code;
665 lock_ReleaseMutex(&scp->mx);
666 lock_ObtainMutex(&bufp->mx);
667 lock_ObtainMutex(&scp->mx);
673 /* if we get here, we're happy */
677 /* first check if we're not supposed to wait: fail
678 * in this case, returning with everything still locked.
680 if (flags & CM_SCACHESYNC_NOWAIT) return CM_ERROR_WOULDBLOCK;
682 /* wait here, then try again */
683 osi_Log1(afsd_logp, "CM SyncOp sleeping scp %x", (long) scp);
684 if ( scp->flags & CM_SCACHEFLAG_WAITING )
685 osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING already set for 0x%x", scp);
687 osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING set for 0x%x", scp);
688 scp->flags |= CM_SCACHEFLAG_WAITING;
689 if (bufLocked) lock_ReleaseMutex(&bufp->mx);
690 osi_SleepM((long) &scp->flags, &scp->mx);
691 osi_Log0(afsd_logp, "CM SyncOp woke!");
693 lock_ObtainMutex(&bufp->mx);
694 lock_ObtainMutex(&scp->mx);
695 } /* big while loop */
697 /* now, update the recorded state for RPC-type calls */
698 if (flags & CM_SCACHESYNC_FETCHSTATUS)
699 scp->flags |= CM_SCACHEFLAG_FETCHING;
700 if (flags & CM_SCACHESYNC_STORESTATUS)
701 scp->flags |= CM_SCACHEFLAG_STORING;
702 if (flags & CM_SCACHESYNC_STORESIZE)
703 scp->flags |= CM_SCACHEFLAG_SIZESTORING;
704 if (flags & CM_SCACHESYNC_GETCALLBACK)
705 scp->flags |= CM_SCACHEFLAG_GETCALLBACK;
706 if (flags & CM_SCACHESYNC_STOREDATA_EXCL)
707 scp->flags |= CM_SCACHEFLAG_DATASTORING;
708 if (flags & CM_SCACHESYNC_ASYNCSTORE)
709 scp->flags |= CM_SCACHEFLAG_ASYNCSTORING;
710 if (flags & CM_SCACHESYNC_LOCK)
711 scp->flags |= CM_SCACHEFLAG_LOCKING;
713 /* now update the buffer pointer */
714 if (flags & CM_SCACHESYNC_FETCHDATA) {
715 /* ensure that the buffer isn't already in the I/O list */
717 for(qdp = scp->bufReadsp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
718 tbufp = osi_GetQData(qdp);
719 osi_assert(tbufp != bufp);
723 /* queue a held reference to the buffer in the "reading" I/O list */
725 osi_SetQData(qdp, bufp);
728 bufp->cmFlags |= CM_BUF_CMFETCHING;
730 osi_QAdd((osi_queue_t **) &scp->bufReadsp, &qdp->q);
733 if (flags & CM_SCACHESYNC_STOREDATA) {
734 /* ensure that the buffer isn't already in the I/O list */
736 for(qdp = scp->bufWritesp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
737 tbufp = osi_GetQData(qdp);
738 osi_assert(tbufp != bufp);
742 /* queue a held reference to the buffer in the "writing" I/O list */
744 osi_SetQData(qdp, bufp);
747 bufp->cmFlags |= CM_BUF_CMSTORING;
749 osi_QAdd((osi_queue_t **) &scp->bufWritesp, &qdp->q);
755 /* for those syncops that setup for RPCs.
756 * Called with scache locked.
758 void cm_SyncOpDone(cm_scache_t *scp, cm_buf_t *bufp, long flags)
760 osi_queueData_t *qdp;
763 /* now, update the recorded state for RPC-type calls */
764 if (flags & CM_SCACHESYNC_FETCHSTATUS)
765 scp->flags &= ~CM_SCACHEFLAG_FETCHING;
766 if (flags & CM_SCACHESYNC_STORESTATUS)
767 scp->flags &= ~CM_SCACHEFLAG_STORING;
768 if (flags & CM_SCACHESYNC_STORESIZE)
769 scp->flags &= ~CM_SCACHEFLAG_SIZESTORING;
770 if (flags & CM_SCACHESYNC_GETCALLBACK)
771 scp->flags &= ~CM_SCACHEFLAG_GETCALLBACK;
772 if (flags & CM_SCACHESYNC_STOREDATA_EXCL)
773 scp->flags &= ~CM_SCACHEFLAG_DATASTORING;
774 if (flags & CM_SCACHESYNC_ASYNCSTORE)
775 scp->flags &= ~CM_SCACHEFLAG_ASYNCSTORING;
776 if (flags & CM_SCACHESYNC_LOCK)
777 scp->flags &= ~CM_SCACHEFLAG_LOCKING;
779 /* now update the buffer pointer */
780 if (flags & CM_SCACHESYNC_FETCHDATA) {
781 /* ensure that the buffer isn't already in the I/O list */
782 for(qdp = scp->bufReadsp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
783 tbufp = osi_GetQData(qdp);
784 if (tbufp == bufp) break;
786 osi_assert(qdp != NULL);
787 osi_assert(osi_GetQData(qdp) == bufp);
788 osi_QRemove((osi_queue_t **) &scp->bufReadsp, &qdp->q);
792 ~(CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED);
797 /* now update the buffer pointer */
798 if (flags & CM_SCACHESYNC_STOREDATA) {
799 /* ensure that the buffer isn't already in the I/O list */
800 for(qdp = scp->bufWritesp; qdp; qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
801 tbufp = osi_GetQData(qdp);
802 if (tbufp == bufp) break;
804 osi_assert(qdp != NULL);
805 osi_assert(osi_GetQData(qdp) == bufp);
806 osi_QRemove((osi_queue_t **) &scp->bufWritesp, &qdp->q);
809 bufp->cmFlags &= ~CM_BUF_CMSTORING;
814 /* and wakeup anyone who is waiting */
815 if (scp->flags & CM_SCACHEFLAG_WAITING) {
816 osi_Log1(afsd_logp, "CM SyncOp CM_SCACHEFLAG_WAITING reset for 0x%x", scp);
817 scp->flags &= ~CM_SCACHEFLAG_WAITING;
818 osi_Wakeup((long) &scp->flags);
822 /* merge in a response from an RPC. The scp must be locked, and the callback
825 * Don't overwrite any status info that is dirty, since we could have a store
826 * operation (such as store data) that merges some info in, and we don't want
827 * to lose the local updates. Typically, there aren't many updates we do
828 * locally, anyway, probably only mtime.
830 * There is probably a bug in here where a chmod (which doesn't change
831 * serverModTime) that occurs between two fetches, both of whose responses are
832 * handled after the callback breaking is done, but only one of whose calls
833 * started before that, can cause old info to be merged from the first call.
835 void cm_MergeStatus(cm_scache_t *scp, AFSFetchStatus *statusp, AFSVolSync *volp,
836 cm_user_t *userp, int flags)
838 // yj: i want to create some fake status for the /afs directory and the
839 // entries under that directory
840 #ifdef AFS_FREELANCE_CLIENT
841 if (cm_freelanceEnabled && scp == cm_rootSCachep) {
842 osi_Log0(afsd_logp,"cm_MergeStatus Freelance cm_rootSCachep");
843 statusp->InterfaceVersion = 0x1;
844 statusp->FileType = CM_SCACHETYPE_DIRECTORY;
845 statusp->LinkCount = scp->linkCount;
846 statusp->Length = cm_fakeDirSize;
847 statusp->DataVersion = cm_fakeDirVersion;
848 statusp->Author = 0x1;
849 statusp->Owner = 0x0;
850 statusp->CallerAccess = 0x9;
851 statusp->AnonymousAccess = 0x9;
852 statusp->UnixModeBits = 0x1ff;
853 statusp->ParentVnode = 0x1;
854 statusp->ParentUnique = 0x1;
855 statusp->ResidencyMask = 0;
856 statusp->ClientModTime = FakeFreelanceModTime;
857 statusp->ServerModTime = FakeFreelanceModTime;
859 statusp->SyncCounter = 0;
860 statusp->dataVersionHigh = 0;
862 #endif /* AFS_FREELANCE_CLIENT */
864 if (!(flags & CM_MERGEFLAG_FORCE)
865 && statusp->DataVersion < (unsigned long) scp->dataVersion) {
866 struct cm_cell *cellp;
867 struct cm_volume *volp;
869 cellp = cm_FindCellByID(scp->fid.cell);
870 cm_GetVolumeByID(cellp, scp->fid.volume, userp,
871 (cm_req_t *) NULL, &volp);
873 osi_Log2(afsd_logp, "old data from server %x volume %s",
874 scp->cbServerp->addr.sin_addr.s_addr,
876 osi_Log3(afsd_logp, "Bad merge, scp %x, scp dv %d, RPC dv %d",
877 scp, scp->dataVersion, statusp->DataVersion);
878 /* we have a number of data fetch/store operations running
879 * concurrently, and we can tell which one executed last at the
880 * server by its mtime.
881 * Choose the one with the largest mtime, and ignore the rest.
883 * These concurrent calls are incompatible with setting the
884 * mtime, so we won't have a locally changed mtime here.
886 * We could also have ACL info for a different user than usual,
887 * in which case we have to do that part of the merge, anyway.
888 * We won't have to worry about the info being old, since we
889 * won't have concurrent calls
890 * that change file status running from this machine.
892 * Added 3/17/98: if we see data version regression on an RO
893 * file, it's probably due to a server holding an out-of-date
894 * replica, rather than to concurrent RPC's. Failures to
895 * release replicas are now flagged by the volserver, but only
896 * since AFS 3.4 5.22, so there are plenty of clients getting
897 * out-of-date replicas out there.
899 * If we discover an out-of-date replica, by this time it's too
900 * late to go to another server and retry. Also, we can't
901 * reject the merge, because then there is no way for
902 * GetAccess to do its work, and the caller gets into an
903 * infinite loop. So we just grin and bear it.
905 if (!(scp->flags & CM_SCACHEFLAG_RO))
908 scp->serverModTime = statusp->ServerModTime;
910 if (!(scp->mask & CM_SCACHEMASK_CLIENTMODTIME)) {
911 scp->clientModTime = statusp->ClientModTime;
913 if (!(scp->mask & CM_SCACHEMASK_LENGTH)) {
914 scp->length.LowPart = statusp->Length;
915 scp->length.HighPart = 0;
918 scp->serverLength.LowPart = statusp->Length;
919 scp->serverLength.HighPart = 0;
921 scp->linkCount = statusp->LinkCount;
922 scp->dataVersion = statusp->DataVersion;
923 scp->owner = statusp->Owner;
924 scp->group = statusp->Group;
925 scp->unixModeBits = statusp->UnixModeBits & 07777;
927 if (statusp->FileType == File)
928 scp->fileType = CM_SCACHETYPE_FILE;
929 else if (statusp->FileType == Directory)
930 scp->fileType = CM_SCACHETYPE_DIRECTORY;
931 else if (statusp->FileType == SymbolicLink) {
932 if ((scp->unixModeBits & 0111) == 0)
933 scp->fileType = CM_SCACHETYPE_MOUNTPOINT;
935 scp->fileType = CM_SCACHETYPE_SYMLINK;
938 osi_Log1(afsd_logp, "Merge, Invalid File Type, scp %x", scp);
939 scp->fileType = 0; /* invalid */
941 /* and other stuff */
942 scp->parentVnode = statusp->ParentVnode;
943 scp->parentUnique = statusp->ParentUnique;
945 /* and merge in the private acl cache info, if this is more than the public
946 * info; merge in the public stuff in any case.
948 scp->anyAccess = statusp->AnonymousAccess;
951 cm_AddACLCache(scp, userp, statusp->CallerAccess);
955 /* note that our stat cache info is incorrect, so force us eventually
956 * to stat the file again. There may be dirty data associated with
957 * this vnode, and we want to preserve that information.
959 * This function works by simply simulating a loss of the callback.
961 * This function must be called with the scache locked.
963 void cm_DiscardSCache(cm_scache_t *scp)
965 lock_AssertMutex(&scp->mx);
966 if (scp->cbServerp) {
967 cm_PutServer(scp->cbServerp);
968 scp->cbServerp = NULL;
972 cm_FreeAllACLEnts(scp);
975 void cm_AFSFidFromFid(AFSFid *afsFidp, cm_fid_t *fidp)
977 afsFidp->Volume = fidp->volume;
978 afsFidp->Vnode = fidp->vnode;
979 afsFidp->Unique = fidp->unique;
982 void cm_HoldSCacheNoLock(cm_scache_t *scp)
985 osi_assert(scp->refCount > 0);
990 void cm_HoldSCache(cm_scache_t *scp)
992 lock_ObtainWrite(&cm_scacheLock);
993 osi_assert(scp->refCount > 0);
995 lock_ReleaseWrite(&cm_scacheLock);
998 void cm_ReleaseSCacheNoLock(cm_scache_t *scp)
1000 osi_assert(scp->refCount-- > 0);
1003 void cm_ReleaseSCache(cm_scache_t *scp)
1005 lock_ObtainWrite(&cm_scacheLock);
1006 osi_assert(scp->refCount-- > 0);
1007 lock_ReleaseWrite(&cm_scacheLock);
1010 /* just look for the scp entry to get filetype */
1011 /* doesn't need to be perfectly accurate, so locking doesn't matter too much */
1012 int cm_FindFileType(cm_fid_t *fidp)
1017 hash = CM_SCACHE_HASH(fidp);
1019 osi_assert(fidp->cell != 0);
1021 lock_ObtainWrite(&cm_scacheLock);
1022 for (scp=cm_hashTablep[hash]; scp; scp=scp->nextp) {
1023 if (cm_FidCmp(fidp, &scp->fid) == 0) {
1024 lock_ReleaseWrite(&cm_scacheLock);
1025 return scp->fileType;
1028 lock_ReleaseWrite(&cm_scacheLock);
1032 /* dump all scp's that have reference count > 0 to a file.
1033 * cookie is used to identify this batch for easy parsing,
1034 * and it a string provided by a caller
1036 int cm_DumpSCache(FILE *outputFile, char *cookie)
1043 lock_ObtainRead(&cm_scacheLock);
1045 sprintf(output, "%s - dumping scache - cm_currentSCaches=%d, cm_maxSCaches=%d\n", cookie, cm_currentSCaches, cm_maxSCaches);
1046 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1048 for (scp = cm_scacheLRULastp; scp; scp = (cm_scache_t *) osi_QPrev(&scp->q))
1050 if (scp->refCount > 0)
1052 sprintf(output, "%s fid (cell=%d, volume=%d, vnode=%d, unique=%d) refCount=%u\n",
1053 cookie, scp->fid.cell, scp->fid.volume, scp->fid.vnode, scp->fid.unique,
1055 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1059 sprintf(output, "%s - dumping cm_hashTable - cm_hashTableSize=%d\n", cookie, cm_hashTableSize);
1060 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1062 for (i = 0; i < cm_hashTableSize; i++)
1064 for(scp = cm_hashTablep[i]; scp; scp=scp->nextp)
1068 if (scp->refCount > 0)
1070 sprintf(output, "%s scp=0x%08X, hash=%d, fid (cell=%d, volume=%d, vnode=%d, unique=%d) refCount=%u\n",
1071 cookie, (void *)scp, i, scp->fid.cell, scp->fid.volume, scp->fid.vnode,
1072 scp->fid.unique, scp->refCount);
1073 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1079 sprintf(output, "%s - Done dumping scache.\n", cookie);
1080 WriteFile(outputFile, output, strlen(output), &zilch, NULL);
1082 lock_ReleaseRead(&cm_scacheLock);