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
18 * AFS_EQ_ATSYS (macro)
22 #include <afsconfig.h>
23 #include "../afs/param.h"
27 #include "../afs/sysincludes.h" /* Standard vendor system headers */
28 #include "../afs/afsincludes.h" /* Afs-based standard headers */
29 #include "../afs/afs_stats.h" /* statistics */
30 #include "../afs/afs_cbqueue.h"
31 #include "../afs/nfsclient.h"
32 #include "../afs/exporter.h"
33 #include "../afs/afs_osidnlc.h"
37 * A few definitions. This is until we have a proper header file
38 * which has prototypes for all functions
41 extern struct DirEntry * afs_dir_GetBlob();
43 extern afs_rwlock_t afs_xvcache;
44 extern afs_rwlock_t afs_xcbhash;
45 extern struct afs_exporter *afs_nfsexporter;
46 extern char *afs_sysname;
47 extern char *afs_sysnamelist[];
48 extern int afs_sysnamecount;
49 extern struct afs_q VLRU; /*vcache LRU*/
50 #ifdef AFS_LINUX22_ENV
51 extern struct inode_operations afs_symlink_iops, afs_dir_iops;
55 afs_int32 afs_bulkStatsDone;
56 static int bulkStatCounter = 0; /* counter for bulk stat seq. numbers */
59 /* this would be faster if it did comparison as int32word, but would be
60 * dependant on byte-order and alignment, and I haven't figured out
61 * what "@sys" is in binary... */
62 #define AFS_EQ_ATSYS(name) (((name)[0]=='@')&&((name)[1]=='s')&&((name)[2]=='y')&&((name)[3]=='s')&&(!(name)[4]))
66 register char *s1, *s2;
82 register char *a, c; {
84 AFS_STATCNT(afs_index);
86 if (tc == c) return a;
92 /* call under write lock, evaluate mvid field from a mt pt.
93 * avc is the vnode of the mount point object.
94 * advc is the vnode of the containing directory
95 * avolpp is where we return a pointer to the volume named by the mount pt, if success
96 * areq is the identity of the caller.
98 * NOTE: this function returns a held volume structure in *volpp if it returns 0!
100 EvalMountPoint(avc, advc, avolpp, areq)
101 register struct vcache *avc;
102 struct volume **avolpp;
103 struct vcache *advc; /* the containing dir */
104 register struct vrequest *areq;
107 struct volume *tvp = 0;
108 struct VenusFid tfid;
110 char *cpos, *volnamep;
112 afs_int32 prefetchRO; /* 1=>No 2=>Yes */
113 afs_int32 mtptCell, assocCell, hac=0;
114 afs_int32 samecell, roname, len;
116 AFS_STATCNT(EvalMountPoint);
118 if (avc->mvid && (avc->states & CMValid)) return 0; /* done while racing */
120 *avolpp = (struct volume *)0;
121 code = afs_HandleLink(avc, areq);
122 if (code) return code;
124 /* Determine which cell and volume the mointpoint goes to */
125 type = avc->linkData[0]; /* '#'=>Regular '%'=>RW */
126 cpos = afs_index(&avc->linkData[1], ':'); /* if cell name present */
130 tcell = afs_GetCellByName(&avc->linkData[1], READ_LOCK);
133 volnamep = &avc->linkData[1];
134 tcell = afs_GetCell(avc->fid.Cell, READ_LOCK);
136 if (!tcell) return ENODEV;
138 mtptCell = tcell->cell; /* The cell for the mountpoint */
140 hac = 1; /* has associated cell */
141 assocCell = tcell->lcellp->cell; /* The associated cell */
143 afs_PutCell(tcell, READ_LOCK);
145 /* Is volume name a "<n>.backup" or "<n>.readonly" name */
146 len = strlen(volnamep);
147 roname = ((len > 9) && (strcmp(&volnamep[len - 9],".readonly") == 0)) ||
148 ((len > 7) && (strcmp(&volnamep[len - 7],".backup") == 0));
150 /* When we cross mountpoint, do we stay in the same cell */
151 samecell = (avc->fid.Cell == mtptCell) || (hac && (avc->fid.Cell == assocCell));
153 /* Decide whether to prefetch the RO. Also means we want the RO.
154 * If this is a regular mountpoint with a RW volume name and
155 * we cross a cell boundary -or- start from a RO volume, then we will
156 * want to prefetch the RO volume when we get the RW below.
158 if ( (type == '#') && !roname && (!samecell || (avc->states & CRO)) ) {
159 prefetchRO = 2; /* Yes, prefetch the RO */
161 prefetchRO = 1; /* No prefetch of the RO */
164 /* Get the volume struct. Unless this volume name has ".readonly" or
165 * ".backup" in it, this will get the volume struct for the RW volume.
166 * The RO volume will be prefetched if requested (but not returned).
168 tvp = afs_GetVolumeByName(volnamep, mtptCell, prefetchRO, areq, WRITE_LOCK);
170 /* If no volume was found in this cell, try the associated linked cell */
171 if (!tvp && hac && areq->volumeError) {
172 tvp = afs_GetVolumeByName(volnamep, assocCell, prefetchRO, areq, WRITE_LOCK);
175 /* Still not found. If we are looking for the RO, then perhaps the RW
176 * doesn't exist? Try adding ".readonly" to volname and look for that.
177 * Don't know why we do this. Would have still found it in above call - jpm.
179 if (!tvp && (prefetchRO == 2)) {
180 strcpy(buf, volnamep);
181 afs_strcat(buf, ".readonly");
183 tvp = afs_GetVolumeByName(buf, mtptCell, 1, areq, WRITE_LOCK);
185 /* Try the associated linked cell if failed */
186 if (!tvp && hac && areq->volumeError) {
187 tvp = afs_GetVolumeByName(buf, assocCell, 1, areq, WRITE_LOCK);
191 if (!tvp) return ENODEV; /* Couldn't find the volume */
193 /* Don't cross mountpoint from a BK to a BK volume */
194 if ((avc->states & CBackup) && (tvp->states & VBackup)) {
195 afs_PutVolume(tvp, WRITE_LOCK);
199 /* If we want (prefetched) the RO and it exists, then drop the
200 * RW volume and get the RO. Othewise, go with the RW.
202 if ((prefetchRO == 2) && tvp->roVol) {
203 tfid.Fid.Volume = tvp->roVol; /* remember RO volume */
204 tfid.Cell = tvp->cell;
205 afs_PutVolume(tvp, WRITE_LOCK); /* release old volume */
206 tvp = afs_GetVolume(&tfid, areq, WRITE_LOCK); /* get the new one */
207 if (!tvp) return ENODEV; /* oops, can't do it */
211 avc->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
212 avc->mvid->Cell = tvp->cell;
213 avc->mvid->Fid.Volume = tvp->volume;
214 avc->mvid->Fid.Vnode = 1;
215 avc->mvid->Fid.Unique = 1;
216 avc->states |= CMValid;
218 /* Used to: if the mount point is stored within a backup volume,
219 * then we should only update the parent pointer information if
220 * there's none already set, so as to avoid updating a volume's ..
221 * info with something in an OldFiles directory.
223 * Next two lines used to be under this if:
225 * if (!(avc->states & CBackup) || tvp->dotdot.Fid.Volume == 0)
227 * Now: update mount point back pointer on every call, so that we handle
228 * multiple mount points better. This way, when du tries to go back
229 * via chddir(".."), it will end up exactly where it started, yet
230 * cd'ing via a new path to a volume will reset the ".." pointer
233 tvp->mtpoint = avc->fid; /* setup back pointer to mtpoint */
234 tvp->dotdot = advc->fid;
241 register char *aname; {
245 AFS_STATCNT(ENameOK);
246 tlen = strlen(aname);
247 if (tlen >= 4 && strcmp(aname+tlen-4, "@sys") == 0) return 0;
251 afs_getsysname(areq, adp, bufp)
252 register struct vrequest *areq;
253 register struct vcache *adp;
256 static char sysname[MAXSYSNAME];
257 register struct unixuser *au;
258 register afs_int32 error;
260 if (!afs_nfsexporter) {
261 strcpy(bufp, afs_sysname);
264 AFS_STATCNT(getsysname);
265 au = afs_GetUser(areq->uid, adp->fid.Cell, 0);
268 error = EXP_SYSNAME(au->exporter, (char *)0, bufp);
270 strcpy(bufp, "@sys");
273 strcpy(bufp, afs_sysname);
278 Check_AtSys(avc, aname, state, areq)
279 register struct vcache *avc;
281 struct sysname_info *state;
282 struct vrequest *areq;
284 if (AFS_EQ_ATSYS(aname)) {
286 state->name = (char *) osi_AllocLargeSpace(AFS_SMALLOCSIZ);
288 state->index = afs_getsysname(areq, avc, state->name);
297 Next_AtSys(avc, areq, state)
298 register struct vcache *avc;
299 struct vrequest *areq;
300 struct sysname_info *state;
302 if (state->index == -1)
303 return 0; /* No list */
305 /* Check for the initial state of aname != "@sys" in Check_AtSys*/
306 if (state->offset == -1 && state->allocked == 0) {
307 register char *tname;
308 /* Check for .*@sys */
309 for (tname=state->name; *tname; tname++)
310 /*Move to the end of the string*/;
311 if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname-4))) {
312 state->offset = (tname - 4) - state->name;
313 tname = (char *) osi_AllocLargeSpace(AFS_LRALLOCSIZ);
314 strncpy(tname, state->name, state->offset);
317 state->index = afs_getsysname(areq, avc, state->name+state->offset);
320 return 0; /* .*@sys doesn't match either */
321 } else if (++(state->index) >= afs_sysnamecount
322 || !afs_sysnamelist[state->index])
323 return 0; /* end of list */
324 strcpy(state->name+state->offset, afs_sysnamelist[state->index]);
328 #if (defined(AFS_SGI62_ENV) || defined(AFS_SUN57_64BIT_ENV))
329 extern int BlobScan(ino64_t *afile, afs_int32 ablob);
331 #if defined AFS_LINUX_64BIT_KERNEL
332 extern int BlobScan(long *afile, afs_int32 ablob);
334 extern int BlobScan(afs_int32 *afile, afs_int32 ablob);
339 /* called with an unlocked directory and directory cookie. Areqp
340 * describes who is making the call.
341 * Scans the next N (about 30, typically) directory entries, and does
342 * a bulk stat call to stat them all.
344 * Must be very careful when merging in RPC responses, since we dont
345 * want to overwrite newer info that was added by a file system mutating
346 * call that ran concurrently with our bulk stat call.
348 * We do that, as described below, by not merging in our info (always
349 * safe to skip the merge) if the status info is valid in the vcache entry.
351 * If adapt ever implements the bulk stat RPC, then this code will need to
352 * ensure that vcaches created for failed RPC's to older servers have the
355 struct vcache * BStvc = (struct vcache *) 0;
356 int afs_DoBulkStat(adp, dirCookie, areqp)
359 struct vrequest *areqp;
361 int nentries; /* # of entries to prefetch */
362 int nskip; /* # of slots in the LRU queue to skip */
363 struct vcache *lruvcp; /* vcache ptr of our goal pos in LRU queue */
364 struct dcache *dcp; /* chunk containing the dir block */
365 char *statMemp; /* status memory block */
366 char *cbfMemp; /* callback and fid memory block */
367 afs_size_t temp; /* temp for holding chunk length, &c. */
368 struct AFSFid *fidsp; /* file IDs were collecting */
369 struct AFSCallBack *cbsp; /* call back pointers */
370 struct AFSCallBack *tcbp; /* temp callback ptr */
371 struct AFSFetchStatus *statsp; /* file status info */
372 struct AFSVolSync volSync; /* vol sync return info */
373 struct vcache *tvcp; /* temp vcp */
374 struct afs_q *tq; /* temp queue variable */
375 AFSCBFids fidParm; /* file ID parm for bulk stat */
376 AFSBulkStats statParm; /* stat info parm for bulk stat */
377 int fidIndex; /* which file were stating */
378 struct conn *tcp; /* conn for call */
379 AFSCBs cbParm; /* callback parm for bulk stat */
380 struct server *hostp = 0; /* host we got callback from */
381 long origEvenCBs; /* original # of callbacks for even-fid files */
382 long origOddCBs; /* original # of callbacks for odd-fid files */
383 long origEvenZaps; /* original # of recycles for even-fid files */
384 long origOddZaps; /* original # of recycles for odd-fid files */
385 long startTime; /* time we started the call,
386 * for callback expiration base
388 afs_size_t statSeqNo; /* Valued of file size to detect races */
389 int code; /* error code */
390 long newIndex; /* new index in the dir */
391 struct DirEntry *dirEntryp; /* dir entry we are examining */
393 struct VenusFid afid; /* file ID we are using now */
394 struct VenusFid tfid; /* another temp. file ID */
395 afs_int32 retry; /* handle low-level SGI MP race conditions */
396 long volStates; /* flags from vol structure */
397 struct volume *volp=0; /* volume ptr */
398 struct VenusFid dotdot;
399 int flagIndex; /* First file with bulk fetch flag set */
400 int inlinebulk=0; /* Did we use InlineBulk RPC or not? */
403 /* first compute some basic parameters. We dont want to prefetch more
404 * than a fraction of the cache in any given call, and we want to preserve
405 * a portion of the LRU queue in any event, so as to avoid thrashing
406 * the entire stat cache (we will at least leave some of it alone).
407 * presently dont stat more than 1/8 the cache in any one call. */
408 nentries = afs_cacheStats / 8;
410 /* dont bother prefetching more than one calls worth of info */
411 if (nentries > AFSCBMAX) nentries = AFSCBMAX;
413 /* heuristic to make sure that things fit in 4K. This means that
414 * we shouldnt make it any bigger than 47 entries. I am typically
415 * going to keep it a little lower, since we don't want to load
416 * too much of the stat cache.
418 if (nentries > 30) nentries = 30;
420 /* now, to reduce the stack size, well allocate two 4K blocks,
421 * one for fids and callbacks, and one for stat info. Well set
422 * up our pointers to the memory from there, too.
424 statMemp = osi_AllocLargeSpace(nentries * sizeof(AFSFetchStatus));
425 statsp = (struct AFSFetchStatus *) statMemp;
426 cbfMemp = osi_AllocLargeSpace(nentries *
427 (sizeof(AFSCallBack) + sizeof(AFSFid)));
428 fidsp = (AFSFid *) cbfMemp;
429 cbsp = (AFSCallBack *) (cbfMemp + nentries * sizeof(AFSFid));
431 /* next, we must iterate over the directory, starting from the specified
432 * cookie offset (dirCookie), and counting out nentries file entries.
433 * We skip files that already have stat cache entries, since we
434 * dont want to bulk stat files that are already in the cache.
437 code = afs_VerifyVCache(adp, areqp);
440 dcp = afs_GetDCache(adp, (afs_size_t) 0, areqp, &temp, &temp, 1);
446 /* lock the directory cache entry */
447 ObtainReadLock(&adp->lock);
448 ObtainReadLock(&dcp->lock);
451 * Make sure that the data in the cache is current. There are two
452 * cases we need to worry about:
453 * 1. The cache data is being fetched by another process.
454 * 2. The cache data is no longer valid
456 while ((adp->states & CStatd)
457 && (dcp->dflags & DFFetching)
458 && hsame(adp->m.DataVersion, dcp->f.versionNo)) {
459 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAIT,
460 ICL_TYPE_STRING, __FILE__,
461 ICL_TYPE_INT32, __LINE__,
462 ICL_TYPE_POINTER, dcp,
463 ICL_TYPE_INT32, dcp->dflags);
464 ReleaseReadLock(&dcp->lock);
465 ReleaseReadLock(&adp->lock);
466 afs_osi_Sleep(&dcp->validPos);
467 ObtainReadLock(&adp->lock);
468 ObtainReadLock(&dcp->lock);
470 if (!(adp->states & CStatd)
471 || !hsame(adp->m.DataVersion, dcp->f.versionNo)) {
472 ReleaseReadLock(&dcp->lock);
473 ReleaseReadLock(&adp->lock);
478 /* Generate a sequence number so we can tell whether we should
479 * store the attributes when processing the response. This number is
480 * stored in the file size when we set the CBulkFetching bit. If the
481 * CBulkFetching is still set and this value hasn't changed, then
482 * we know we were the last to set CBulkFetching bit for this file,
483 * and it is safe to set the status information for this file.
485 statSeqNo = bulkStatCounter++;
487 /* now we have dir data in the cache, so scan the dir page */
490 while (1) { /* Should probably have some constant bound */
491 /* look for first safe entry to examine in the directory. BlobScan
492 * looks for a the 1st allocated dir after the dirCookie slot.
494 newIndex = BlobScan(&dcp->f.inode, (dirCookie>>5));
495 if (newIndex == 0) break;
497 /* remember the updated directory cookie */
498 dirCookie = newIndex << 5;
500 /* get a ptr to the dir entry */
501 dirEntryp =(struct DirEntry *)afs_dir_GetBlob(&dcp->f.inode, newIndex);
502 if (!dirEntryp) break;
504 /* dont copy more than we have room for */
505 if (fidIndex >= nentries) {
506 DRelease((char *) dirEntryp, 0);
510 /* now, if the dir entry looks good, copy it out to our list. Vnode
511 * 0 means deleted, although it should also be free were it deleted.
513 if (dirEntryp->fid.vnode != 0) {
514 /* dont copy entries we have in our cache. This check will
515 * also make us skip "." and probably "..", unless it has
516 * disappeared from the cache since we did our namei call.
518 tfid.Cell = adp->fid.Cell;
519 tfid.Fid.Volume = adp->fid.Fid.Volume;
520 tfid.Fid.Vnode = ntohl(dirEntryp->fid.vnode);
521 tfid.Fid.Unique = ntohl(dirEntryp->fid.vunique);
524 ObtainWriteLock(&afs_xvcache, 130);
525 tvcp = afs_FindVCache(&tfid, 0, 0, &retry, 0 /* no stats | LRU */);
527 ReleaseWriteLock(&afs_xvcache);
528 afs_PutVCache(tvcp, 0);
530 } while (tvcp && retry);
531 if (!tvcp) { /* otherwise, create manually */
532 tvcp = afs_NewVCache(&tfid, hostp, 0, 0);
533 ObtainWriteLock(&tvcp->lock, 505);
534 ReleaseWriteLock(&afs_xvcache);
535 afs_RemoveVCB(&tfid);
536 ReleaseWriteLock(&tvcp->lock);
538 ReleaseWriteLock(&afs_xvcache);
541 goto done; /* can't happen at present, more's the pity */
543 /* WARNING: afs_DoBulkStat uses the Length field to store a
544 * sequence number for each bulk status request. Under no
545 * circumstances should afs_DoBulkStat store a sequence number
546 * if the new length will be ignored when afs_ProcessFS is
547 * called with new stats. */
549 if (!(tvcp->states & (CStatd|CBulkFetching))
550 && (tvcp->execsOrWriters <= 0)
551 && !afs_DirtyPages(tvcp)
552 && !AFS_VN_MAPPED((vnode_t*)tvcp))
554 if (!(tvcp->states & (CStatd|CBulkFetching))
555 && (tvcp->execsOrWriters <= 0)
556 && !afs_DirtyPages(tvcp))
560 /* this entry doesnt exist in the cache, and is not
561 * already being fetched by someone else, so add it to the
562 * list of file IDs to obtain.
564 * We detect a callback breaking race condition by checking the
565 * CBulkFetching state bit and the value in the file size.
566 * It is safe to set the status only if the CBulkFetching
567 * flag is still set and the value in the file size does
570 * Don't fetch status for dirty files. We need to
571 * preserve the value of the file size. We could
572 * flush the pages, but it wouldn't be worthwhile.
574 memcpy((char *)(fidsp+fidIndex), (char *) &tfid.Fid, sizeof(*fidsp));
575 tvcp->states |= CBulkFetching;
576 tvcp->m.Length = statSeqNo;
579 afs_PutVCache(tvcp, 0);
580 } /* if dir vnode has non-zero entry */
582 /* move to the next dir entry by adding in the # of entries
583 * used by this dir entry.
585 temp = afs_dir_NameBlobs(dirEntryp->name) << 5;
586 DRelease((char *) dirEntryp, 0);
587 if (temp <= 0) break;
589 } /* while loop over all dir entries */
591 /* now release the dir lock and prepare to make the bulk RPC */
592 ReleaseReadLock(&dcp->lock);
593 ReleaseReadLock(&adp->lock);
595 /* release the chunk */
598 /* dont make a null call */
599 if (fidIndex == 0) goto done;
602 /* setup the RPC parm structures */
603 fidParm.AFSCBFids_len = fidIndex;
604 fidParm.AFSCBFids_val = fidsp;
605 statParm.AFSBulkStats_len = fidIndex;
606 statParm.AFSBulkStats_val = statsp;
607 cbParm.AFSCBs_len = fidIndex;
608 cbParm.AFSCBs_val = cbsp;
610 /* start the timer; callback expirations are relative to this */
611 startTime = osi_Time();
613 tcp = afs_Conn(&adp->fid, areqp, SHARED_LOCK);
615 hostp = tcp->srvr->server;
616 XSTATS_START_TIME(AFS_STATS_FS_RPCIDX_BULKSTATUS);
617 #ifdef RX_ENABLE_LOCKS
619 #endif /* RX_ENABLE_LOCKS */
621 if (!(tcp->srvr->server->flags & SNO_INLINEBULK)) {
622 code = RXAFS_InlineBulkStatus(tcp->id, &fidParm, &statParm,
624 if (code == RXGEN_OPCODE) {
625 tcp->srvr->server->flags |= SNO_INLINEBULK;
627 code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm,
633 code = RXAFS_BulkStatus(tcp->id, &fidParm, &statParm, &cbParm,
636 #ifdef RX_ENABLE_LOCKS
638 #endif /* RX_ENABLE_LOCKS */
642 } while (afs_Analyze(tcp, code, &adp->fid, areqp,
643 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK, (struct cell *)0));
645 /* now, if we didnt get the info, bail out. */
648 /* we need vol flags to create the entries properly */
649 dotdot.Fid.Volume = 0;
650 volp = afs_GetVolume(&adp->fid, areqp, READ_LOCK);
652 volStates = volp->states;
653 if (volp->dotdot.Fid.Volume != 0)
654 dotdot = volp->dotdot;
658 /* find the place to merge the info into We do this by skipping
659 * nskip entries in the LRU queue. The more we skip, the more
660 * we preserve, since the head of the VLRU queue is the most recently
664 nskip = afs_cacheStats / 2; /* preserved fraction of the cache */
665 ObtainReadLock(&afs_xvcache);
667 /* actually a serious error, probably should panic. Probably will
668 * panic soon, oh well. */
669 ReleaseReadLock(&afs_xvcache);
670 afs_warnuser("afs_DoBulkStat: VLRU empty!");
673 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
674 refpanic ("Bulkstat VLRU inconsistent");
676 for(tq = VLRU.next; tq != &VLRU; tq = QNext(tq)) {
677 if (--nskip <= 0) break;
678 else if (QNext(QPrev(tq)) != tq) {
680 refpanic ("BulkStat VLRU inconsistent");
683 if (tq != &VLRU) lruvcp = QTOV(tq);
684 else lruvcp = QTOV(VLRU.next);
686 /* now we have to hold this entry, so that it does not get moved
687 * into the free list while we're running. It could still get
688 * moved within the lru queue, but hopefully that will be rare; it
689 * doesn't hurt nearly as much.
692 osi_vnhold(lruvcp, &retry);
693 ReleaseReadLock(&afs_xvcache); /* could be read lock */
697 /* otherwise, merge in the info. We have to be quite careful here,
698 * since we need to ensure that we don't merge old info over newer
699 * stuff in a stat cache entry. We're very conservative here: we don't
700 * do the merge at all unless we ourselves create the stat cache
701 * entry. That's pretty safe, and should work pretty well, since we
702 * typically expect to do the stat cache creation ourselves.
704 * We also have to take into account racing token revocations.
706 for(i=0; i<fidIndex; i++) {
707 if ((&statsp[i])->errorCode)
709 afid.Cell = adp->fid.Cell;
710 afid.Fid.Volume = adp->fid.Fid.Volume;
711 afid.Fid.Vnode = fidsp[i].Vnode;
712 afid.Fid.Unique = fidsp[i].Unique;
715 ObtainReadLock(&afs_xvcache);
716 tvcp = afs_FindVCache(&afid, 1, 0, &retry, 0/* !stats&!lru*/);
717 ReleaseReadLock(&afs_xvcache);
718 } while (tvcp && retry);
720 /* The entry may no longer exist */
725 /* now we have the entry held, but we need to fill it in */
726 ObtainWriteLock(&tvcp->lock,131);
728 /* if CBulkFetching is not set, or if the file size no longer
729 * matches the value we placed there when we set the CBulkFetching
730 * flag, then someone else has done something with this node,
731 * and we may not have the latest status information for this
732 * file. Leave the entry alone.
734 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
736 ReleaseWriteLock(&tvcp->lock);
737 afs_PutVCache(tvcp, 0);
741 /* now copy ".." entry back out of volume structure, if necessary */
742 if (tvcp->mvstat == 2 && (dotdot.Fid.Volume != 0)) {
744 tvcp->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
745 *tvcp->mvid = dotdot;
748 ObtainWriteLock(&afs_xvcache,132);
749 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
750 refpanic ("Bulkstat VLRU inconsistent2");
752 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
753 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq))
754 refpanic ("Bulkstat VLRU inconsistent4");
755 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
756 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq))
757 refpanic ("Bulkstat VLRU inconsistent5");
759 if (tvcp != lruvcp) { /* if they are == don't move it, don't corrupt vlru */
760 QRemove(&tvcp->vlruq);
761 QAdd(&lruvcp->vlruq, &tvcp->vlruq);
764 if ((VLRU.next->prev != &VLRU) || (VLRU.prev->next != &VLRU)) {
765 refpanic ("Bulkstat VLRU inconsistent3");
767 if ((QNext(QPrev(&tvcp->vlruq)) != &tvcp->vlruq)
768 || (QPrev(QNext(&tvcp->vlruq)) != &tvcp->vlruq))
769 refpanic ("Bulkstat VLRU inconsistent5");
770 if ((QNext(QPrev(&lruvcp->vlruq)) != &lruvcp->vlruq)
771 || (QPrev(QNext(&lruvcp->vlruq)) != &lruvcp->vlruq))
772 refpanic ("Bulkstat VLRU inconsistent6");
773 ReleaseWriteLock(&afs_xvcache);
775 ObtainWriteLock(&afs_xcbhash, 494);
777 /* We need to check the flags again. We may have missed
778 * something while we were waiting for a lock.
780 if (!(tvcp->states & CBulkFetching) || (tvcp->m.Length != statSeqNo)) {
782 ReleaseWriteLock(&tvcp->lock);
783 ReleaseWriteLock(&afs_xcbhash);
784 afs_PutVCache(tvcp, 0);
788 /* now merge in the resulting status back into the vnode.
789 * We only do this if the entry looks clear.
791 afs_ProcessFS(tvcp, &statsp[i], areqp);
792 #ifdef AFS_LINUX22_ENV
793 /* overwrite the ops if it's a directory or symlink. */
794 if (vType(tvcp) == VDIR)
795 tvcp->v.v_op = &afs_dir_iops;
796 else if (vType(tvcp) == VLNK)
797 tvcp->v.v_op = &afs_symlink_iops;
800 /* do some accounting for bulk stats: mark this entry as
801 * loaded, so we can tell if we use it before it gets
804 tvcp->states |= CBulkStat;
805 tvcp->states &= ~CBulkFetching;
809 /* merge in vol info */
810 if (volStates & VRO) tvcp->states |= CRO;
811 if (volStates & VBackup) tvcp->states |= CBackup;
812 if (volStates & VForeign) tvcp->states |= CForeign;
814 /* merge in the callback info */
815 tvcp->states |= CTruth;
817 /* get ptr to the callback we are interested in */
820 if (tcbp->ExpirationTime != 0) {
821 tvcp->cbExpires = tcbp->ExpirationTime+startTime;
822 tvcp->callback = hostp;
823 tvcp->states |= CStatd;
824 afs_QueueCallback(tvcp, CBHash(tcbp->ExpirationTime), volp);
826 else if (tvcp->states & CRO) {
827 /* ordinary callback on a read-only volume -- AFS 3.2 style */
828 tvcp->cbExpires = 3600+startTime;
829 tvcp->callback = hostp;
830 tvcp->states |= CStatd;
831 afs_QueueCallback(tvcp, CBHash(3600), volp);
835 tvcp->states &= ~(CStatd|CUnique);
836 afs_DequeueCallback(tvcp);
837 if ((tvcp->states & CForeign) || (vType(tvcp) == VDIR))
838 osi_dnlc_purgedp (tvcp); /* if it (could be) a directory */
840 ReleaseWriteLock(&afs_xcbhash);
842 ReleaseWriteLock(&tvcp->lock);
843 /* finally, we're done with the entry */
844 afs_PutVCache(tvcp, 0);
845 } /* for all files we got back */
847 /* finally return the pointer into the LRU queue */
848 afs_PutVCache(lruvcp, 0);
851 /* Be sure to turn off the CBulkFetching flags */
852 for(i=flagIndex; i<fidIndex; i++) {
853 afid.Cell = adp->fid.Cell;
854 afid.Fid.Volume = adp->fid.Fid.Volume;
855 afid.Fid.Vnode = fidsp[i].Vnode;
856 afid.Fid.Unique = fidsp[i].Unique;
859 ObtainReadLock(&afs_xvcache);
860 tvcp = afs_FindVCache(&afid, 1, 0, &retry, 0/* !stats&!lru*/);
861 ReleaseReadLock(&afs_xvcache);
862 } while (tvcp && retry);
864 && (tvcp->states & CBulkFetching)
865 && (tvcp->m.Length == statSeqNo)) {
866 tvcp->states &= ~CBulkFetching;
869 afs_PutVCache(tvcp, 0);
873 afs_PutVolume(volp, READ_LOCK);
875 /* If we did the InlineBulk RPC pull out the return code */
877 if ((&statsp[0])->errorCode) {
878 afs_Analyze(tcp, (&statsp[0])->errorCode, &adp->fid, areqp,
879 AFS_STATS_FS_RPCIDX_BULKSTATUS, SHARED_LOCK,
881 code = (&statsp[0])->errorCode;
886 osi_FreeLargeSpace(statMemp);
887 osi_FreeLargeSpace(cbfMemp);
891 /* was: (AFS_DEC_ENV) || defined(AFS_OSF30_ENV) || defined(AFS_NCR_ENV) */
897 struct nameidata *ndp; {
898 char aname[MAXNAMLEN+1]; /* XXX */
899 struct vcache **avcp = (struct vcache **)&(ndp->ni_vp);
900 struct ucred *acred = ndp->ni_cred;
901 int wantparent = ndp->ni_nameiop & WANTPARENT;
902 int opflag = ndp->ni_nameiop & OPFLAG;
903 #else /* AFS_OSF_ENV */
904 #if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV)
905 afs_lookup(OSI_VC_ARG(adp), aname, avcp, pnp, flags, rdir, acred)
906 struct pathname *pnp;
911 afs_lookup(adp, aname, avcp, acred, flags)
914 afs_lookup(adp, aname, avcp, acred)
916 #endif /* SUN5 || SGI */
918 struct vcache **avcp;
920 struct AFS_UCRED *acred; {
922 struct vrequest treq;
923 char *tname = (char *)0;
924 register struct vcache *tvc=0;
925 register afs_int32 code;
926 register afs_int32 bulkcode = 0;
927 int pass = 0, hit = 0;
929 extern afs_int32 afs_mariner; /*Writing activity to log?*/
931 afs_hyper_t versionNo;
932 int no_read_access = 0;
933 struct sysname_info sysState; /* used only for @sys checking */
934 int dynrootRetry = 1;
936 AFS_STATCNT(afs_lookup);
938 ndp->ni_dvp = AFSTOV(adp);
939 memcpy(aname, ndp->ni_ptr, ndp->ni_namelen);
940 aname[ndp->ni_namelen] = '\0';
941 #endif /* AFS_OSF_ENV */
943 *avcp = (struct vcache *) 0; /* Since some callers don't initialize it */
945 if (code = afs_InitReq(&treq, acred)) {
949 /* come back to here if we encounter a non-existent object in a read-only
950 volume's directory */
953 *avcp = (struct vcache *) 0; /* Since some callers don't initialize it */
956 if (!(adp->states & CStatd)) {
957 if (code = afs_VerifyVCache2(adp, &treq)) {
963 /* watch for ".." in a volume root */
964 if (adp->mvstat == 2 && aname[0] == '.' && aname[1] == '.' && !aname[2]) {
965 /* looking up ".." in root via special hacks */
966 if (adp->mvid == (struct VenusFid *) 0 || adp->mvid->Fid.Volume == 0) {
968 extern struct vcache *afs_globalVp;
969 if (adp == afs_globalVp) {
970 struct vnode *rvp = AFSTOV(adp);
972 ndp->ni_vp = rvp->v_vfsp->vfs_vnodecovered;
973 ndp->ni_dvp = ndp->ni_vp;
983 /* otherwise we have the fid here, so we use it */
984 tvc = afs_GetVCache(adp->mvid, &treq, (afs_int32 *)0,
985 (struct vcache*)0, 0);
986 afs_Trace3(afs_iclSetp, CM_TRACE_GETVCDOTDOT,
987 ICL_TYPE_FID, adp->mvid, ICL_TYPE_POINTER, tvc,
988 ICL_TYPE_INT32, code);
990 code = (tvc ? 0 : ENOENT);
992 if (tvc && !VREFCOUNT(tvc)) {
996 /*printf("LOOKUP GETVCDOTDOT -> %d\n", code);*/
1001 /* now check the access */
1002 if (treq.uid != adp->last_looker) {
1003 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS)) {
1004 *avcp = (struct vcache *)0;
1008 else adp->last_looker = treq.uid;
1011 /* Check for read access as well. We need read access in order to
1012 stat files, but not to stat subdirectories. */
1013 if (!afs_AccessOK(adp, PRSFS_LOOKUP, &treq, CHECK_MODE_BITS))
1016 /* special case lookup of ".". Can we check for it sooner in this code,
1017 * for instance, way up before "redo:" ??
1018 * I'm not fiddling with the LRUQ here, either, perhaps I should, or else
1019 * invent a lightweight version of GetVCache.
1021 if (aname[0] == '.' && !aname[1]) { /* special case */
1022 ObtainReadLock(&afs_xvcache);
1024 ReleaseReadLock(&afs_xvcache);
1028 if (adp && !VREFCOUNT(adp)) {
1034 Check_AtSys(adp, aname, &sysState, &treq);
1035 tname = sysState.name;
1037 /* 1st Check_AtSys and lookup by tname is required here, for now,
1038 because the dnlc is *not* told to remove entries for the parent
1039 dir of file/dir op that afs_LocalHero likes, but dnlc is informed
1040 if the cached entry for the parent dir is invalidated for a
1042 Otherwise, we'd be able to do a dnlc lookup on an entry ending
1043 w/@sys and know the dnlc was consistent with reality. */
1044 tvc = osi_dnlc_lookup (adp, tname, WRITE_LOCK);
1045 *avcp = tvc; /* maybe wasn't initialized, but it is now */
1047 if (no_read_access && vType(tvc) != VDIR && vType(tvc) != VLNK) {
1048 /* need read access on dir to stat non-directory / non-link */
1049 afs_PutVCache(tvc, WRITE_LOCK);
1050 *avcp = (struct vcache *)0;
1054 #ifdef AFS_LINUX22_ENV
1055 if (tvc->mvstat == 2) { /* we don't trust the dnlc for root vcaches */
1064 #else /* non - LINUX */
1068 #endif /* linux22 */
1072 register struct dcache *tdc;
1073 afs_size_t dirOffset, dirLen;
1075 struct VenusFid tfid;
1077 /* now we have to lookup the next fid */
1078 tdc = afs_GetDCache(adp, (afs_size_t) 0, &treq, &dirOffset, &dirLen, 1);
1080 *avcp = (struct vcache *)0; /* redundant, but harmless */
1085 /* now we will just call dir package with appropriate inode.
1086 Dirs are always fetched in their entirety for now */
1087 ObtainReadLock(&adp->lock);
1088 ObtainReadLock(&tdc->lock);
1091 * Make sure that the data in the cache is current. There are two
1092 * cases we need to worry about:
1093 * 1. The cache data is being fetched by another process.
1094 * 2. The cache data is no longer valid
1096 while ((adp->states & CStatd)
1097 && (tdc->dflags & DFFetching)
1098 && hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1099 ReleaseReadLock(&tdc->lock);
1100 ReleaseReadLock(&adp->lock);
1101 afs_osi_Sleep(&tdc->validPos);
1102 ObtainReadLock(&adp->lock);
1103 ObtainReadLock(&tdc->lock);
1105 if (!(adp->states & CStatd)
1106 || !hsame(adp->m.DataVersion, tdc->f.versionNo)) {
1107 ReleaseReadLock(&tdc->lock);
1108 ReleaseReadLock(&adp->lock);
1113 /* Save the version number for when we call osi_dnlc_enter */
1114 hset(versionNo, tdc->f.versionNo);
1117 * check for, and handle "@sys" if it's there. We should be able
1118 * to avoid the alloc and the strcpy with a little work, but it's
1119 * not pressing. If there aren't any remote users (ie, via the
1120 * NFS translator), we have a slightly easier job.
1121 * the faster way to do this is to check for *aname == '@' and if
1122 * it's there, check for @sys, otherwise, assume there's no @sys
1123 * then, if the lookup fails, check for .*@sys...
1125 /* above now implemented by Check_AtSys and Next_AtSys */
1127 /* lookup the name in the appropriate dir, and return a cache entry
1128 on the resulting fid */
1129 theDir = tdc->f.inode;
1130 code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
1132 /* If the first lookup doesn't succeed, maybe it's got @sys in the name */
1133 while (code == ENOENT && Next_AtSys(adp, &treq, &sysState)) {
1134 code = afs_dir_LookupOffset(&theDir, sysState.name, &tfid.Fid, &dirCookie);
1136 tname = sysState.name;
1138 ReleaseReadLock(&tdc->lock);
1141 if (code == ENOENT && afs_IsDynroot(adp) && dynrootRetry) {
1144 ReleaseReadLock(&adp->lock);
1147 tcell = afs_GetCellByName(tname + 1, READ_LOCK);
1149 tcell = afs_GetCellByName(tname, READ_LOCK);
1151 afs_PutCell(tcell, READ_LOCK);
1152 afs_RefreshDynroot();
1153 if (tname != aname && tname) osi_FreeLargeSpace(tname);
1157 ReleaseReadLock(&adp->lock);
1160 /* new fid has same cell and volume */
1161 tfid.Cell = adp->fid.Cell;
1162 tfid.Fid.Volume = adp->fid.Fid.Volume;
1163 afs_Trace4(afs_iclSetp, CM_TRACE_LOOKUP, ICL_TYPE_POINTER, adp,
1164 ICL_TYPE_STRING, tname,
1165 ICL_TYPE_FID, &tfid, ICL_TYPE_INT32, code);
1168 if (code != ENOENT) {
1169 printf("LOOKUP dirLookupOff -> %d\n", code);
1174 /* prefetch some entries, if the dir is currently open. The variable
1175 * dirCookie tells us where to start prefetching from.
1177 if (AFSDOBULK && adp->opens > 0 && !(adp->states & CForeign) && !afs_IsDynroot(adp)) {
1179 /* if the entry is not in the cache, or is in the cache,
1180 * but hasn't been statd, then do a bulk stat operation.
1184 ObtainReadLock(&afs_xvcache);
1185 tvc = afs_FindVCache(&tfid, 1, 0, &retry, 0/* !stats,!lru */);
1186 ReleaseReadLock(&afs_xvcache);
1187 } while (tvc && retry);
1189 if (!tvc || !(tvc->states & CStatd))
1190 bulkcode = afs_DoBulkStat(adp, dirCookie, &treq);
1194 /* if the vcache isn't usable, release it */
1195 if (tvc && !(tvc->states & CStatd)) {
1196 afs_PutVCache(tvc, 0);
1197 tvc = (struct vcache *) 0;
1200 tvc = (struct vcache *) 0;
1204 /* now get the status info, if we don't already have it */
1205 /* This is kind of weird, but we might wind up accidentally calling
1206 * RXAFS_Lookup because we happened upon a file which legitimately
1207 * has a 0 uniquifier. That is the result of allowing unique to wrap
1208 * to 0. This was fixed in AFS 3.4. For CForeign, Unique == 0 means that
1209 * the file has not yet been looked up.
1212 afs_int32 cached = 0;
1213 if (!tfid.Fid.Unique && (adp->states & CForeign)) {
1214 tvc = afs_LookupVCache(&tfid, &treq, &cached, WRITE_LOCK,
1217 if (!tvc && !bulkcode) { /* lookup failed or wasn't called */
1218 tvc = afs_GetVCache(&tfid, &treq, &cached, (struct vcache*)0,
1222 } /* sub-block just to reduce stack usage */
1225 if (adp->states & CForeign)
1226 tvc->states |= CForeign;
1227 tvc->parentVnode = adp->fid.Fid.Vnode;
1228 tvc->parentUnique = adp->fid.Fid.Unique;
1229 tvc->states &= ~CBulkStat;
1231 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1232 if (!(flags & AFS_LOOKUP_NOEVAL))
1233 /* don't eval mount points */
1234 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1235 if (tvc->mvstat == 1) {
1236 /* a mt point, possibly unevaluated */
1237 struct volume *tvolp;
1239 ObtainWriteLock(&tvc->lock,133);
1240 code = EvalMountPoint(tvc, adp, &tvolp, &treq);
1241 ReleaseWriteLock(&tvc->lock);
1244 afs_PutVCache(tvc, WRITE_LOCK);
1245 if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
1249 /* next, we want to continue using the target of the mt point */
1250 if (tvc->mvid && (tvc->states & CMValid)) {
1252 /* now lookup target, to set .. pointer */
1253 afs_Trace2(afs_iclSetp, CM_TRACE_LOOKUP1,
1254 ICL_TYPE_POINTER, tvc, ICL_TYPE_FID, &tvc->fid);
1255 uvc = tvc; /* remember for later */
1257 if (tvolp && (tvolp->states & VForeign)) {
1258 /* XXXX tvolp has ref cnt on but not locked! XXX */
1259 tvc = afs_GetRootVCache(tvc->mvid, &treq, (afs_int32 *)0, tvolp, WRITE_LOCK);
1261 tvc = afs_GetVCache(tvc->mvid, &treq, (afs_int32 *)0,
1262 (struct vcache*)0, WRITE_LOCK);
1264 afs_PutVCache(uvc, WRITE_LOCK); /* we're done with it */
1269 afs_PutVolume(tvolp, WRITE_LOCK);
1274 /* now, if we came via a new mt pt (say because of a new
1275 * release of a R/O volume), we must reevaluate the ..
1276 * ptr to point back to the appropriate place */
1278 ObtainWriteLock(&tvc->lock,134);
1279 if (tvc->mvid == (struct VenusFid *) 0) {
1280 tvc->mvid = (struct VenusFid *) osi_AllocSmallSpace(sizeof(struct VenusFid));
1282 /* setup backpointer */
1283 *tvc->mvid = tvolp->dotdot;
1284 ReleaseWriteLock(&tvc->lock);
1285 afs_PutVolume(tvolp, WRITE_LOCK);
1289 afs_PutVCache(tvc, WRITE_LOCK);
1291 if (tvolp) afs_PutVolume(tvolp, WRITE_LOCK);
1296 if (tvc && !VREFCOUNT(tvc)) {
1302 /* if we get here, we found something in a directory that couldn't
1303 be located (a Multics "connection failure"). If the volume is
1304 read-only, we try flushing this entry from the cache and trying
1308 tv = afs_GetVolume(&adp->fid, &treq, READ_LOCK);
1310 if (tv->states & VRO) {
1311 pass = 1; /* try this *once* */
1312 ObtainWriteLock(&afs_xcbhash, 495);
1313 afs_DequeueCallback(adp);
1314 /* re-stat to get later version */
1315 adp->states &= ~CStatd;
1316 ReleaseWriteLock(&afs_xcbhash);
1317 osi_dnlc_purgedp(adp);
1318 afs_PutVolume(tv, READ_LOCK);
1321 afs_PutVolume(tv, READ_LOCK);
1328 /* put the network buffer back, if need be */
1329 if (tname != aname && tname) osi_FreeLargeSpace(tname);
1332 /* Handle RENAME; only need to check rename "." */
1333 if (opflag == RENAME && wantparent && *ndp->ni_next == 0) {
1334 if (!FidCmp(&(tvc->fid), &(adp->fid))) {
1335 afs_PutVCache(*avcp, WRITE_LOCK);
1337 return afs_CheckCode(EISDIR, &treq, 18);
1340 #endif /* AFS_OSF_ENV */
1343 afs_AddMarinerName(aname, tvc);
1345 #if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS)
1346 if (!(flags & AFS_LOOKUP_NOEVAL))
1347 /* Here we don't enter the name into the DNLC because we want the
1348 evaluated mount dir to be there (the vcache for the mounted volume)
1349 rather than the vc of the mount point itself. we can still find the
1350 mount point's vc in the vcache by its fid. */
1351 #endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */
1353 osi_dnlc_enter (adp, aname, tvc, &versionNo);
1356 #ifdef AFS_LINUX20_ENV
1357 /* So Linux inode cache is up to date. */
1358 code = afs_VerifyVCache(tvc, &treq);
1360 return 0; /* can't have been any errors if hit and !code */
1364 if (bulkcode) code = bulkcode; else
1365 code = afs_CheckCode(code, &treq, 19);
1367 /* If there is an error, make sure *avcp is null.
1368 * Alphas panic otherwise - defect 10719.
1370 *avcp = (struct vcache *)0;