cc548fd2bd2b5b95d1f86260168c40ff89598a11
[openafs.git] / src / WINNT / afsd / cm_dcache.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 #ifdef COMMENT
19 #include <malloc.h>
20 #endif
21 #include <string.h>
22 #include <stdlib.h>
23 #include <osi.h>
24
25 #include "afsd.h"
26
27 #ifdef DEBUG
28 extern void afsi_log(char *pattern, ...);
29 #endif
30
31 osi_mutex_t cm_bufGetMutex;
32 #ifdef AFS_FREELANCE_CLIENT
33 extern osi_mutex_t cm_Freelance_Lock;
34 #endif
35
36 #ifdef AFS_LARGEFILES
37 /* we can access connp->serverp without holding a lock because that
38    never changes since the connection is made. */
39 #define SERVERHAS64BIT(connp) (!((connp)->serverp->flags & CM_SERVERFLAG_NO64BIT))
40 #define SET_SERVERHASNO64BIT(connp) (cm_SetServerNo64Bit((connp)->serverp, TRUE))
41 #else
42 #define SERVERHAS64BIT(connp) (FALSE)
43 #define SET_SERVERHASNO64BIT(connp) (FALSE)
44 #endif
45
46 /* functions called back from the buffer package when reading or writing data,
47  * or when holding or releasing a vnode pointer.
48  */
49 long cm_BufWrite(void *vfidp, osi_hyper_t *offsetp, long length, long flags,
50                  cm_user_t *userp, cm_req_t *reqp)
51 {
52     /* store the data back from this buffer; the buffer is locked and held,
53      * but the vnode involved isn't locked, yet.  It is held by its
54      * reference from the buffer, which won't change until the buffer is
55      * released by our caller.  Thus, we don't have to worry about holding
56      * bufp->scp.
57      */
58     long code;
59     cm_fid_t *fidp = vfidp;
60     cm_scache_t *scp;
61     long nbytes;
62     long temp;
63     AFSFetchStatus outStatus;
64     AFSStoreStatus inStatus;
65     osi_hyper_t thyper;
66     AFSVolSync volSync;
67     AFSFid tfid;
68     struct rx_call *callp;
69     struct rx_connection *rxconnp;
70     osi_queueData_t *qdp;
71     cm_buf_t *bufp;
72     long wbytes;
73     char *bufferp;
74     cm_conn_t *connp;
75     osi_hyper_t truncPos;
76     cm_bulkIO_t biod;           /* bulk IO descriptor */
77     int require_64bit_ops = 0;
78
79     osi_assert(userp != NULL);
80
81     /* now, the buffer may or may not be filled with good data (buf_GetNew
82      * drops lots of locks, and may indeed return a properly initialized
83      * buffer, although more likely it will just return a new, empty, buffer.
84      */
85     scp = cm_FindSCache(fidp);
86     if (scp == NULL)
87         return CM_ERROR_NOSUCHFILE;     /* shouldn't happen */
88
89     cm_AFSFidFromFid(&tfid, fidp);
90
91     lock_ObtainMutex(&scp->mx);
92
93     code = cm_SetupStoreBIOD(scp, offsetp, length, &biod, userp, reqp);
94     if (code) {
95         osi_Log1(afsd_logp, "cm_SetupStoreBIOD code %x", code);
96         lock_ReleaseMutex(&scp->mx);
97         cm_ReleaseSCache(scp);
98         return code;
99     }
100
101     if (biod.length == 0) {
102         osi_Log0(afsd_logp, "cm_SetupStoreBIOD length 0");
103         lock_ReleaseMutex(&scp->mx);
104         cm_ReleaseBIOD(&biod, 1);       /* should be a NOOP */
105         cm_ReleaseSCache(scp);
106         return 0;
107     }
108
109     /* Serialize StoreData RPC's; for rationale see cm_scache.c */
110     (void) cm_SyncOp(scp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA_EXCL);
111
112     /* prepare the output status for the store */
113     scp->mask |= CM_SCACHEMASK_CLIENTMODTIME;
114     cm_StatusFromAttr(&inStatus, scp, NULL);
115     truncPos = scp->length;
116     if ((scp->mask & CM_SCACHEMASK_TRUNCPOS)
117         && LargeIntegerLessThan(scp->truncPos, truncPos))
118         truncPos = scp->truncPos;
119         scp->mask &= ~CM_SCACHEMASK_TRUNCPOS;
120                 
121     /* compute how many bytes to write from this buffer */
122     thyper = LargeIntegerSubtract(scp->length, biod.offset);
123     if (LargeIntegerLessThanZero(thyper)) {
124         /* entire buffer is past EOF */
125         nbytes = 0;
126     }
127     else {
128         /* otherwise write out part of buffer before EOF, but not
129          * more than bufferSize bytes.
130          */
131         if (LargeIntegerGreaterThan(thyper,
132                                     ConvertLongToLargeInteger(biod.length))) {
133             nbytes = biod.length;
134         } else {
135             /* if thyper is less than or equal to biod.length, then we
136                can safely assume that the value fits in a long. */
137             nbytes = thyper.LowPart;
138         }
139     }
140
141     if (LargeIntegerGreaterThan(LargeIntegerAdd(biod.offset,
142                                                  ConvertLongToLargeInteger(nbytes)),
143                                  ConvertLongToLargeInteger(LONG_MAX)) ||
144          LargeIntegerGreaterThan(truncPos,
145                                  ConvertLongToLargeInteger(LONG_MAX))) {
146         require_64bit_ops = 1;
147     }
148         
149     lock_ReleaseMutex(&scp->mx);
150
151     /* now we're ready to do the store operation */
152     do {
153         code = cm_Conn(&scp->fid, userp, reqp, &connp);
154         if (code) 
155             continue;
156
157     retry:
158         rxconnp = cm_GetRxConn(connp);
159         callp = rx_NewCall(rxconnp);
160         rx_PutConnection(rxconnp);
161
162 #ifdef AFS_LARGEFILES
163         if (SERVERHAS64BIT(connp)) {
164             osi_Log4(afsd_logp, "CALL StoreData64 scp 0x%p, offset 0x%x:%08x, length 0x%x",
165                      scp, biod.offset.HighPart, biod.offset.LowPart, nbytes);
166
167             code = StartRXAFS_StoreData64(callp, &tfid, &inStatus,
168                                           biod.offset.QuadPart,
169                                           nbytes,
170                                           truncPos.QuadPart);
171         } else {
172
173             if (require_64bit_ops) {
174                 osi_Log0(afsd_logp, "Skipping StoreData.  The operation requires StoreData64");
175                 code = CM_ERROR_TOOBIG;
176             } else {
177                 osi_Log4(afsd_logp, "CALL StoreData scp 0x%p, offset 0x%x:%08x, length 0x%x",
178                          scp, biod.offset.HighPart, biod.offset.LowPart, nbytes);
179
180                 code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
181                                             biod.offset.LowPart, nbytes, truncPos.LowPart);
182             }
183         }
184 #else
185         osi_Log4(afsd_logp, "CALL StoreData scp 0x%p, offset 0x%x:%08x, length 0x%x",
186                  scp, biod.offset.HighPart, biod.offset.LowPart, nbytes);
187
188         code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
189                                     biod.offset.LowPart, nbytes, truncPos.LowPart);
190 #endif
191
192         if (code == 0) {
193             /* write the data from the the list of buffers */
194             qdp = NULL;
195             while(nbytes > 0) {
196                 if (qdp == NULL)
197                     qdp = biod.bufListEndp;
198                 else
199                     qdp = (osi_queueData_t *) osi_QPrev(&qdp->q);
200                 osi_assert(qdp != NULL);
201                 bufp = osi_GetQData(qdp);
202                 bufferp = bufp->datap;
203                 wbytes = nbytes;
204                 if (wbytes > cm_data.buf_blockSize) 
205                     wbytes = cm_data.buf_blockSize;
206
207                 /* write out wbytes of data from bufferp */
208                 temp = rx_Write(callp, bufferp, wbytes);
209                 if (temp != wbytes) {
210                     osi_Log3(afsd_logp, "rx_Write failed bp 0x%p, %d != %d",bufp,temp,wbytes);
211                     code = -1;
212                     break;
213                 } else {
214                     osi_Log2(afsd_logp, "rx_Write succeeded bp 0x%p, %d",bufp,temp);
215                 }       
216                 nbytes -= wbytes;
217             }   /* while more bytes to write */
218         }               /* if RPC started successfully */
219         else {
220             osi_Log2(afsd_logp, "StartRXAFS_StoreData?? scp 0x%p failed (%lX)",scp,code);
221         }
222
223         if (code == 0) {
224             if (SERVERHAS64BIT(connp)) {
225                 code = EndRXAFS_StoreData64(callp, &outStatus, &volSync);
226                 if (code)
227                     osi_Log2(afsd_logp, "EndRXAFS_StoreData64 scp 0x%p failed (%lX)", scp, code);
228             } else {
229                 code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
230                 if (code)
231                     osi_Log2(afsd_logp, "EndRXAFS_StoreData scp 0x%p failed (%lX)",scp,code);
232             }
233         }
234
235         code = rx_EndCall(callp, code);
236
237 #ifdef AFS_LARGEFILES
238         if (code == RXGEN_OPCODE && SERVERHAS64BIT(connp)) {
239             SET_SERVERHASNO64BIT(connp);
240             goto retry;
241         }
242 #endif
243                 
244     } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
245
246     code = cm_MapRPCError(code, reqp);
247
248     if (code)
249         osi_Log2(afsd_logp, "CALL StoreData FAILURE scp 0x%p, code 0x%x", scp, code);
250     else
251         osi_Log1(afsd_logp, "CALL StoreData SUCCESS scp 0x%p", scp);
252
253     /* now, clean up our state */
254     lock_ObtainMutex(&scp->mx);
255
256     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
257
258     if (code == 0) {
259         osi_hyper_t t;
260         /* now, here's something a little tricky: in AFS 3, a dirty
261          * length can't be directly stored, instead, a dirty chunk is
262          * stored that sets the file's size (by writing and by using
263          * the truncate-first option in the store call).
264          *
265          * At this point, we've just finished a store, and so the trunc
266          * pos field is clean.  If the file's size at the server is at
267          * least as big as we think it should be, then we turn off the
268          * length dirty bit, since all the other dirty buffers must
269          * precede this one in the file.
270          *
271          * The file's desired size shouldn't be smaller than what's
272          * stored at the server now, since we just did the trunc pos
273          * store.
274          *
275          * We have to turn off the length dirty bit as soon as we can,
276          * so that we see updates made by other machines.
277          */
278
279         if (SERVERHAS64BIT(connp)) {
280             t.LowPart = outStatus.Length;
281             t.HighPart = outStatus.Length_hi;
282         } else {
283             t = ConvertLongToLargeInteger(outStatus.Length);
284         }
285
286         if (LargeIntegerGreaterThanOrEqualTo(t, scp->length))
287             scp->mask &= ~CM_SCACHEMASK_LENGTH;
288
289         cm_MergeStatus(scp, &outStatus, &volSync, userp, 0);
290     } else {
291         if (code == CM_ERROR_SPACE)
292             scp->flags |= CM_SCACHEFLAG_OUTOFSPACE;
293         else if (code == CM_ERROR_QUOTA)
294             scp->flags |= CM_SCACHEFLAG_OVERQUOTA;
295     }
296     lock_ReleaseMutex(&scp->mx);
297     cm_ReleaseBIOD(&biod, 1);
298     cm_ReleaseSCache(scp);
299
300     return code;
301 }
302
303 /*
304  * Truncate the file, by sending a StoreData RPC with zero length.
305  *
306  * Called with scp locked.  Releases and re-obtains the lock.
307  */
308 long cm_StoreMini(cm_scache_t *scp, cm_user_t *userp, cm_req_t *reqp)
309 {
310     AFSFetchStatus outStatus;
311     AFSStoreStatus inStatus;
312     AFSVolSync volSync;
313     AFSFid tfid;
314     long code;
315     osi_hyper_t truncPos;
316     cm_conn_t *connp;
317     struct rx_call *callp;
318     struct rx_connection *rxconnp;
319     int require_64bit_ops = 0;
320
321     /* Serialize StoreData RPC's; for rationale see cm_scache.c */
322     (void) cm_SyncOp(scp, NULL, userp, reqp, 0,
323                      CM_SCACHESYNC_STOREDATA_EXCL);
324
325     /* prepare the output status for the store */
326     inStatus.Mask = AFS_SETMODTIME;
327     inStatus.ClientModTime = scp->clientModTime;
328     scp->mask &= ~CM_SCACHEMASK_CLIENTMODTIME;
329
330     /* calculate truncation position */
331     truncPos = scp->length;
332     if ((scp->mask & CM_SCACHEMASK_TRUNCPOS)
333         && LargeIntegerLessThan(scp->truncPos, truncPos))
334         truncPos = scp->truncPos;
335     scp->mask &= ~CM_SCACHEMASK_TRUNCPOS;
336
337     if (LargeIntegerGreaterThan(truncPos,
338                                 ConvertLongToLargeInteger(LONG_MAX))) {
339
340         require_64bit_ops = 1;
341     }
342
343     lock_ReleaseMutex(&scp->mx);
344
345     cm_AFSFidFromFid(&tfid, &scp->fid);
346
347     /* now we're ready to do the store operation */
348     do {
349         code = cm_Conn(&scp->fid, userp, reqp, &connp);
350         if (code) 
351             continue;
352
353     retry:      
354         rxconnp = cm_GetRxConn(connp);
355         callp = rx_NewCall(rxconnp);
356         rx_PutConnection(rxconnp);
357
358 #ifdef AFS_LARGEFILES
359         if (SERVERHAS64BIT(connp)) {
360             code = StartRXAFS_StoreData64(callp, &tfid, &inStatus,
361                                           0, 0, truncPos.QuadPart);
362         } else {
363             if (require_64bit_ops) {
364                 code = CM_ERROR_TOOBIG;
365             } else {
366                 code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
367                                             0, 0, truncPos.LowPart);
368             }
369         }
370 #else
371         code = StartRXAFS_StoreData(callp, &tfid, &inStatus,
372                                     0, 0, truncPos.LowPart);
373 #endif
374
375         if (code == 0) {
376             if (SERVERHAS64BIT(connp))
377                 code = EndRXAFS_StoreData64(callp, &outStatus, &volSync);
378             else
379                 code = EndRXAFS_StoreData(callp, &outStatus, &volSync);
380         }
381         code = rx_EndCall(callp, code);
382
383 #ifdef AFS_LARGEFILES
384         if (code == RXGEN_OPCODE && SERVERHAS64BIT(connp)) {
385             SET_SERVERHASNO64BIT(connp);
386             goto retry;
387         }
388 #endif
389
390     } while (cm_Analyze(connp, userp, reqp, &scp->fid, &volSync, NULL, NULL, code));
391     code = cm_MapRPCError(code, reqp);
392         
393     /* now, clean up our state */
394     lock_ObtainMutex(&scp->mx);
395
396     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_STOREDATA_EXCL);
397
398     if (code == 0) {
399         osi_hyper_t t;
400         /*
401          * For explanation of handling of CM_SCACHEMASK_LENGTH,
402          * see cm_BufWrite().
403          */
404         if (SERVERHAS64BIT(connp)) {
405             t.HighPart = outStatus.Length_hi;
406             t.LowPart = outStatus.Length;
407         } else {
408             t = ConvertLongToLargeInteger(outStatus.Length);
409         }
410
411         if (LargeIntegerGreaterThanOrEqualTo(t, scp->length))
412             scp->mask &= ~CM_SCACHEMASK_LENGTH;
413         cm_MergeStatus(scp, &outStatus, &volSync, userp, 0);
414     }
415
416     return code;
417 }
418
419 long cm_BufRead(cm_buf_t *bufp, long nbytes, long *bytesReadp, cm_user_t *userp)
420 {
421     *bytesReadp = cm_data.buf_blockSize;
422
423     /* now return a code that means that I/O is done */
424     return 0;
425 }
426
427 /* stabilize scache entry, and return with it locked so 
428  * it stays stable.
429  */
430 long cm_BufStabilize(void *parmp, cm_user_t *userp, cm_req_t *reqp)
431 {
432     cm_scache_t *scp;
433     long code;
434
435     scp = parmp;
436         
437     lock_ObtainMutex(&scp->mx);
438     code = cm_SyncOp(scp, NULL, userp, reqp, 0, 
439                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS | CM_SCACHESYNC_SETSIZE);
440     if (code) {
441         lock_ReleaseMutex(&scp->mx);
442         return code;
443     }
444         
445     return 0;
446 }
447
448 /* undoes the work that cm_BufStabilize does: releases lock so things can change again */
449 long cm_BufUnstabilize(void *parmp, cm_user_t *userp)
450 {
451     cm_scache_t *scp;
452         
453     scp = parmp;
454         
455     lock_ReleaseMutex(&scp->mx);
456         
457     /* always succeeds */
458     return 0;
459 }
460
461 cm_buf_ops_t cm_bufOps = {
462     cm_BufWrite,
463     cm_BufRead,
464     cm_BufStabilize,
465     cm_BufUnstabilize
466 };
467
468 long cm_ValidateDCache(void)
469 {
470     return buf_ValidateBuffers();
471 }
472
473 long cm_ShutdownDCache(void)
474 {
475     return 0;
476 }
477
478 int cm_InitDCache(int newFile, long chunkSize, afs_uint64 nbuffers)
479 {
480     lock_InitializeMutex(&cm_bufGetMutex, "buf_Get mutex");
481     return buf_Init(newFile, &cm_bufOps, nbuffers);
482 }
483
484 /* check to see if we have an up-to-date buffer.  The buffer must have
485  * previously been obtained by calling buf_Get.
486  *
487  * Make sure we have a callback, and that the dataversion matches.
488  *
489  * Scp must be locked.
490  *
491  * Bufp *may* be locked.
492  */
493 int cm_HaveBuffer(cm_scache_t *scp, cm_buf_t *bufp, int isBufLocked)
494 {
495     int code;
496     if (!cm_HaveCallback(scp))
497         return 0;
498     if ((bufp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED)) == (CM_BUF_CMFETCHING | CM_BUF_CMFULLYFETCHED))
499         return 1;
500     if (bufp->dataVersion == scp->dataVersion)
501         return 1;
502     if (!isBufLocked) {
503         code = lock_TryMutex(&bufp->mx);
504         if (code == 0) {
505             /* don't have the lock, and can't lock it, then
506              * return failure.
507              */
508             return 0;
509         }
510     }
511
512     /* remember dirty flag for later */
513     code = bufp->flags & CM_BUF_DIRTY;
514
515     /* release lock if we obtained it here */
516     if (!isBufLocked) 
517         lock_ReleaseMutex(&bufp->mx);
518
519     /* if buffer was dirty, buffer is acceptable for use */
520     if (code) 
521         return 1;
522     else 
523         return 0;
524 }
525
526 /* used when deciding whether to do a prefetch or not */
527 long cm_CheckFetchRange(cm_scache_t *scp, osi_hyper_t *startBasep, long length,
528                         cm_user_t *up, cm_req_t *reqp, osi_hyper_t *realBasep)
529 {
530     osi_hyper_t toffset;
531     osi_hyper_t tbase;
532     long code;
533     cm_buf_t *bp;
534     int stop;
535         
536     /* now scan all buffers in the range, looking for any that look like
537      * they need work.
538      */
539     tbase = *startBasep;
540     stop = 0;
541     lock_ObtainMutex(&scp->mx);
542     while(length > 0) {
543         /* get callback so we can do a meaningful dataVersion comparison */
544         code = cm_SyncOp(scp, NULL, up, reqp, 0,
545                          CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
546         if (code) {
547             scp->flags &= ~CM_SCACHEFLAG_PREFETCHING;
548             lock_ReleaseMutex(&scp->mx);
549             return code;
550         }
551                 
552         if (LargeIntegerGreaterThanOrEqualTo(tbase, scp->length)) {
553             /* we're past the end of file */
554             break;
555         }
556
557         bp = buf_Find(scp, &tbase);
558         /* We cheat slightly by not locking the bp mutex. */
559         if (bp) {
560             if ((bp->cmFlags & (CM_BUF_CMFETCHING | CM_BUF_CMSTORING)) == 0
561                  && bp->dataVersion != scp->dataVersion)
562                 stop = 1;
563             buf_Release(bp);
564         }
565         else 
566             stop = 1;
567
568         /* if this buffer is essentially guaranteed to require a fetch,
569          * break out here and return this position.
570          */
571         if (stop) 
572             break;
573                 
574         toffset.LowPart = cm_data.buf_blockSize;
575         toffset.HighPart = 0;
576         tbase = LargeIntegerAdd(toffset, tbase);
577         length -= cm_data.buf_blockSize;
578     }
579         
580     /* if we get here, either everything is fine or stop stopped us at a
581      * particular buffer in the range that definitely needs to be fetched.
582      */
583     if (stop == 0) {
584         /* return non-zero code since realBasep won't be valid */
585         scp->flags &= ~CM_SCACHEFLAG_PREFETCHING;
586         code = -1;
587     }   
588     else {
589         /* successfully found a page that will need fetching */
590         *realBasep = tbase;
591         code = 0;
592     }
593     lock_ReleaseMutex(&scp->mx);
594     return code;
595 }
596
597 void cm_BkgStore(cm_scache_t *scp, long p1, long p2, long p3, long p4,
598                  cm_user_t *userp)
599 {
600     osi_hyper_t toffset;
601     long length;
602     cm_req_t req;
603
604     cm_InitReq(&req);
605     req.flags |= CM_REQ_NORETRY;
606
607     toffset.LowPart = p1;
608     toffset.HighPart = p2;
609     length = p3;
610
611     osi_Log4(afsd_logp, "Starting BKG store scp 0x%p, offset 0x%x:%08x, length 0x%x", scp, p2, p1, p3);
612
613     cm_BufWrite(&scp->fid, &toffset, length, /* flags */ 0, userp, &req);
614
615     lock_ObtainMutex(&scp->mx);
616     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_ASYNCSTORE);
617     lock_ReleaseMutex(&scp->mx);
618 }
619
620 /* Called with scp locked */
621 void cm_ClearPrefetchFlag(long code, cm_scache_t *scp, osi_hyper_t *base)
622 {
623     osi_hyper_t thyper;
624
625     if (code == 0) {
626         thyper.LowPart = cm_chunkSize;
627         thyper.HighPart = 0;
628         thyper =  LargeIntegerAdd(*base, thyper);
629         thyper.LowPart &= (-cm_chunkSize);
630         if (LargeIntegerGreaterThan(*base, scp->prefetch.base))
631             scp->prefetch.base = *base;
632         if (LargeIntegerGreaterThan(thyper, scp->prefetch.end))
633             scp->prefetch.end = thyper;
634     }
635     scp->flags &= ~CM_SCACHEFLAG_PREFETCHING;
636 }
637
638 /* do the prefetch */
639 void cm_BkgPrefetch(cm_scache_t *scp, long p1, long p2, long p3, long p4,
640                     cm_user_t *userp)
641 {
642     long length;
643     osi_hyper_t base;
644     long code;
645     cm_buf_t *bp;
646     int cpff = 0;                       /* cleared prefetch flag */
647     cm_req_t req;
648
649     cm_InitReq(&req);
650     req.flags |= CM_REQ_NORETRY;
651         
652     base.LowPart = p1;
653     base.HighPart = p2;
654     length = p3;
655         
656     osi_Log2(afsd_logp, "Starting BKG prefetch scp 0x%p, base 0x%x", scp, p1);
657
658     code = buf_Get(scp, &base, &bp);
659
660     lock_ObtainMutex(&scp->mx);
661
662     if (code || (bp->cmFlags & CM_BUF_CMFETCHING)) {
663         scp->flags &= ~CM_SCACHEFLAG_PREFETCHING;
664         lock_ReleaseMutex(&scp->mx);
665         return;
666     }
667
668     code = cm_GetBuffer(scp, bp, &cpff, userp, &req);
669     if (!cpff) 
670         cm_ClearPrefetchFlag(code, scp, &base);
671     lock_ReleaseMutex(&scp->mx);
672     buf_Release(bp);
673     return;
674 }
675
676 /* a read was issued to offsetp, and we have to determine whether we should
677  * do a prefetch.
678  */
679 void cm_ConsiderPrefetch(cm_scache_t *scp, osi_hyper_t *offsetp,
680                          cm_user_t *userp, cm_req_t *reqp)
681 {
682     long code;
683     osi_hyper_t realBase;
684     osi_hyper_t readBase;
685         
686     readBase = *offsetp;
687     /* round up to chunk boundary */
688     readBase.LowPart += (cm_chunkSize-1);
689     readBase.LowPart &= (-cm_chunkSize);
690
691     lock_ObtainMutex(&scp->mx);
692     if ((scp->flags & CM_SCACHEFLAG_PREFETCHING)
693          || LargeIntegerLessThanOrEqualTo(readBase, scp->prefetch.base)) {
694         lock_ReleaseMutex(&scp->mx);
695         return;
696     }
697     scp->flags |= CM_SCACHEFLAG_PREFETCHING;
698
699     /* start the scan at the latter of the end of this read or
700      * the end of the last fetched region.
701      */
702     if (LargeIntegerGreaterThan(scp->prefetch.end, readBase))
703         readBase = scp->prefetch.end;
704
705     lock_ReleaseMutex(&scp->mx);
706
707     code = cm_CheckFetchRange(scp, &readBase, cm_chunkSize, userp, reqp,
708                               &realBase);
709     if (code) 
710         return; /* can't find something to prefetch */
711
712     osi_Log2(afsd_logp, "BKG Prefetch request scp 0x%p, base 0x%x",
713              scp, realBase.LowPart);
714
715     cm_QueueBKGRequest(scp, cm_BkgPrefetch, realBase.LowPart,
716                        realBase.HighPart, cm_chunkSize, 0, userp);
717 }
718
719 /* scp must be locked; temporarily unlocked during processing.
720  * If returns 0, returns buffers held in biop, and with
721  * CM_BUF_CMSTORING set.
722  *
723  * Caller *must* set CM_BUF_WRITING and reset the over.hEvent field if the
724  * buffer is ever unlocked before CM_BUF_DIRTY is cleared.  And if
725  * CM_BUF_WRITING is ever viewed by anyone, then it must be cleared, sleepers
726  * must be woken, and the event must be set when the I/O is done.  All of this
727  * is required so that buf_WaitIO synchronizes properly with the buffer as it
728  * is being written out.
729  */
730 long cm_SetupStoreBIOD(cm_scache_t *scp, osi_hyper_t *inOffsetp, long inSize,
731                        cm_bulkIO_t *biop, cm_user_t *userp, cm_req_t *reqp)
732 {
733     cm_buf_t *bufp;
734     osi_queueData_t *qdp;
735     osi_hyper_t thyper;
736     osi_hyper_t tbase;
737     osi_hyper_t scanStart;              /* where to start scan for dirty pages */
738     osi_hyper_t scanEnd;                /* where to stop scan for dirty pages */
739     osi_hyper_t firstModOffset; /* offset of first modified page in range */
740     long temp;
741     long code;
742     long flags;                 /* flags to cm_SyncOp */
743         
744     /* clear things out */
745     biop->scp = scp;            /* don't hold */
746     biop->offset = *inOffsetp;
747     biop->length = 0;
748     biop->bufListp = NULL;
749     biop->bufListEndp = NULL;
750     biop->reserved = 0;
751
752     /* reserve a chunk's worth of buffers */
753     lock_ReleaseMutex(&scp->mx);
754     buf_ReserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
755     lock_ObtainMutex(&scp->mx);
756
757     bufp = NULL;
758     for (temp = 0; temp < inSize; temp += cm_data.buf_blockSize, bufp = NULL) {
759         thyper.HighPart = 0;
760         thyper.LowPart = temp;
761         tbase = LargeIntegerAdd(*inOffsetp, thyper);
762
763         bufp = buf_Find(scp, &tbase);
764         if (bufp) {
765             /* get buffer mutex and scp mutex safely */
766             lock_ReleaseMutex(&scp->mx);
767             lock_ObtainMutex(&bufp->mx);
768             lock_ObtainMutex(&scp->mx);
769
770             flags = CM_SCACHESYNC_NEEDCALLBACK
771                 | CM_SCACHESYNC_GETSTATUS
772                     | CM_SCACHESYNC_STOREDATA
773                         | CM_SCACHESYNC_BUFLOCKED;
774             code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags); 
775             if (code) {
776                 lock_ReleaseMutex(&bufp->mx);
777                 buf_Release(bufp);
778                 buf_UnreserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
779                 return code;
780             }   
781                         
782             /* if the buffer is dirty, we're done */
783             if (bufp->flags & CM_BUF_DIRTY) {
784                 osi_assertx(!(bufp->flags & CM_BUF_WRITING),
785                             "WRITING w/o CMSTORING in SetupStoreBIOD");
786                 bufp->flags |= CM_BUF_WRITING;
787                 break;
788             }
789
790             /* this buffer is clean, so there's no reason to process it */
791             cm_SyncOpDone(scp, bufp, flags);
792             lock_ReleaseMutex(&bufp->mx);
793             buf_Release(bufp);
794         }       
795     }
796
797     biop->reserved = 1;
798         
799     /* if we get here, if bufp is null, we didn't find any dirty buffers
800      * that weren't already being stored back, so we just quit now.
801      */
802     if (!bufp) {
803         return 0;
804     }
805
806     /* don't need buffer mutex any more */
807     lock_ReleaseMutex(&bufp->mx);
808         
809     /* put this element in the list */
810     qdp = osi_QDAlloc();
811     osi_SetQData(qdp, bufp);
812     /* don't have to hold bufp, since held by buf_Find above */
813     osi_QAddH((osi_queue_t **) &biop->bufListp,
814               (osi_queue_t **) &biop->bufListEndp,
815               &qdp->q);
816     biop->length = cm_data.buf_blockSize;
817     firstModOffset = bufp->offset;
818     biop->offset = firstModOffset;
819
820     /* compute the window surrounding *inOffsetp of size cm_chunkSize */
821     scanStart = *inOffsetp;
822     scanStart.LowPart &= (-cm_chunkSize);
823     thyper.LowPart = cm_chunkSize;
824     thyper.HighPart = 0;
825     scanEnd = LargeIntegerAdd(scanStart, thyper);
826
827     flags = CM_SCACHESYNC_NEEDCALLBACK
828         | CM_SCACHESYNC_GETSTATUS
829         | CM_SCACHESYNC_STOREDATA
830         | CM_SCACHESYNC_BUFLOCKED
831         | CM_SCACHESYNC_NOWAIT;
832
833     /* start by looking backwards until scanStart */
834     thyper.HighPart = 0;                /* hyper version of cm_data.buf_blockSize */
835     thyper.LowPart = cm_data.buf_blockSize;
836     tbase = LargeIntegerSubtract(firstModOffset, thyper);
837     while(LargeIntegerGreaterThanOrEqualTo(tbase, scanStart)) {
838         /* see if we can find the buffer */
839         bufp = buf_Find(scp, &tbase);
840         if (!bufp) 
841             break;
842
843         /* try to lock it, and quit if we can't (simplifies locking) */
844         lock_ReleaseMutex(&scp->mx);
845         code = lock_TryMutex(&bufp->mx);
846         lock_ObtainMutex(&scp->mx);
847         if (code == 0) {
848             buf_Release(bufp);
849             break;
850         }
851                 
852         code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags);
853         if (code) {
854             lock_ReleaseMutex(&bufp->mx);
855             buf_Release(bufp);
856             break;
857         }
858                 
859         if (!(bufp->flags & CM_BUF_DIRTY)) {
860             /* buffer is clean, so we shouldn't add it */
861             cm_SyncOpDone(scp, bufp, flags);
862             lock_ReleaseMutex(&bufp->mx);
863             buf_Release(bufp);
864             break;
865         }
866
867         /* don't need buffer mutex any more */
868         lock_ReleaseMutex(&bufp->mx);
869
870         /* we have a dirty buffer ready for storing.  Add it to the tail
871          * of the list, since it immediately precedes all of the disk
872          * addresses we've already collected.
873          */
874         qdp = osi_QDAlloc();
875         osi_SetQData(qdp, bufp);
876         /* no buf_hold necessary, since we have it held from buf_Find */
877         osi_QAddT((osi_queue_t **) &biop->bufListp,
878                   (osi_queue_t **) &biop->bufListEndp,
879                   &qdp->q);
880
881         /* update biod info describing the transfer */
882         biop->offset = LargeIntegerSubtract(biop->offset, thyper);
883         biop->length += cm_data.buf_blockSize;
884
885         /* update loop pointer */
886         tbase = LargeIntegerSubtract(tbase, thyper);
887     }   /* while loop looking for pages preceding the one we found */
888
889     /* now, find later dirty, contiguous pages, and add them to the list */
890     thyper.HighPart = 0;                /* hyper version of cm_data.buf_blockSize */
891     thyper.LowPart = cm_data.buf_blockSize;
892     tbase = LargeIntegerAdd(firstModOffset, thyper);
893     while(LargeIntegerLessThan(tbase, scanEnd)) {
894         /* see if we can find the buffer */
895         bufp = buf_Find(scp, &tbase);
896         if (!bufp) 
897             break;
898
899         /* try to lock it, and quit if we can't (simplifies locking) */
900         lock_ReleaseMutex(&scp->mx);
901         code = lock_TryMutex(&bufp->mx);
902         lock_ObtainMutex(&scp->mx);
903         if (code == 0) {
904             buf_Release(bufp);
905             break;
906         }
907
908         code = cm_SyncOp(scp, bufp, userp, reqp, 0, flags);
909         if (code) {
910             lock_ReleaseMutex(&bufp->mx);
911             buf_Release(bufp);
912             break;
913         }
914                 
915         if (!(bufp->flags & CM_BUF_DIRTY)) {
916             /* buffer is clean, so we shouldn't add it */
917             cm_SyncOpDone(scp, bufp, flags);
918             lock_ReleaseMutex(&bufp->mx);
919             buf_Release(bufp);
920             break;
921         }
922
923         /* don't need buffer mutex any more */
924         lock_ReleaseMutex(&bufp->mx);
925
926         /* we have a dirty buffer ready for storing.  Add it to the head
927          * of the list, since it immediately follows all of the disk
928          * addresses we've already collected.
929          */
930         qdp = osi_QDAlloc();
931         osi_SetQData(qdp, bufp);
932         /* no buf_hold necessary, since we have it held from buf_Find */
933         osi_QAddH((osi_queue_t **) &biop->bufListp,
934                   (osi_queue_t **) &biop->bufListEndp,
935                   &qdp->q);
936
937         /* update biod info describing the transfer */
938         biop->length += cm_data.buf_blockSize;
939                 
940         /* update loop pointer */
941         tbase = LargeIntegerAdd(tbase, thyper);
942     }   /* while loop looking for pages following the first page we found */
943         
944     /* finally, we're done */
945     return 0;
946 }
947
948 /* scp must be locked; temporarily unlocked during processing.
949  * If returns 0, returns buffers held in biop, and with
950  * CM_BUF_CMFETCHING flags set.
951  * If an error is returned, we don't return any buffers.
952  */
953 long cm_SetupFetchBIOD(cm_scache_t *scp, osi_hyper_t *offsetp,
954                         cm_bulkIO_t *biop, cm_user_t *up, cm_req_t *reqp)
955 {
956     long code;
957     cm_buf_t *tbp;
958     osi_hyper_t toffset;                /* a long long temp variable */
959     osi_hyper_t pageBase;               /* base offset we're looking at */
960     osi_queueData_t *qdp;               /* one temp queue structure */
961     osi_queueData_t *tqdp;              /* another temp queue structure */
962     long collected;                     /* how many bytes have been collected */
963     int isFirst;
964     long flags;
965     osi_hyper_t fileSize;               /* the # of bytes in the file */
966     osi_queueData_t *heldBufListp;      /* we hold all buffers in this list */
967     osi_queueData_t *heldBufListEndp;   /* first one */
968     int reserving;
969
970     biop->scp = scp;
971     biop->offset = *offsetp;
972     /* null out the list of buffers */
973     biop->bufListp = biop->bufListEndp = NULL;
974     biop->reserved = 0;
975
976     /* first lookup the file's length, so we know when to stop */
977     code = cm_SyncOp(scp, NULL, up, reqp, 0, 
978                      CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
979     if (code) 
980         return code;
981         
982     /* copy out size, since it may change */
983     fileSize = scp->serverLength;
984         
985     lock_ReleaseMutex(&scp->mx);
986
987     pageBase = *offsetp;
988     collected = pageBase.LowPart & (cm_chunkSize - 1);
989     heldBufListp = NULL;
990     heldBufListEndp = NULL;
991
992     /*
993      * Obtaining buffers can cause dirty buffers to be recycled, which
994      * can cause a storeback, so cannot be done while we have buffers
995      * reserved.
996      *
997      * To get around this, we get buffers twice.  Before reserving buffers,
998      * we obtain and release each one individually.  After reserving
999      * buffers, we try to obtain them again, but only by lookup, not by
1000      * recycling.  If a buffer has gone away while we were waiting for
1001      * the others, we just use whatever buffers we already have.
1002      *
1003      * On entry to this function, we are already holding a buffer, so we
1004      * can't wait for reservation.  So we call buf_TryReserveBuffers()
1005      * instead.  Not only that, we can't really even call buf_Get(), for
1006      * the same reason.  We can't avoid that, though.  To avoid deadlock
1007      * we allow only one thread to be executing the buf_Get()-buf_Release()
1008      * sequence at a time.
1009      */
1010
1011     // lock_ObtainMutex(&cm_bufGetMutex);
1012     /* first hold all buffers, since we can't hold any locks in buf_Get */
1013     while (1) {
1014         /* stop at chunk boundary */
1015         if (collected >= cm_chunkSize) 
1016             break;
1017                 
1018         /* see if the next page would be past EOF */
1019         if (LargeIntegerGreaterThanOrEqualTo(pageBase, fileSize)) 
1020             break;
1021
1022         code = buf_Get(scp, &pageBase, &tbp);
1023         if (code) {
1024             //lock_ReleaseMutex(&cm_bufGetMutex);
1025             lock_ObtainMutex(&scp->mx);
1026             cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
1027             return code;
1028         }
1029                 
1030         buf_Release(tbp);
1031
1032         toffset.HighPart = 0;
1033         toffset.LowPart = cm_data.buf_blockSize;
1034         pageBase = LargeIntegerAdd(toffset, pageBase);
1035         collected += cm_data.buf_blockSize;
1036     }
1037
1038     /* reserve a chunk's worth of buffers if possible */
1039     reserving = buf_TryReserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
1040
1041     // lock_ReleaseMutex(&cm_bufGetMutex);
1042
1043     pageBase = *offsetp;
1044     collected = pageBase.LowPart & (cm_chunkSize - 1);
1045
1046     /* now hold all buffers, if they are still there */
1047     while (1) {
1048         /* stop at chunk boundary */
1049         if (collected >= cm_chunkSize) 
1050             break;
1051                 
1052         /* see if the next page would be past EOF */
1053         if (LargeIntegerGreaterThanOrEqualTo(pageBase, fileSize)) 
1054             break;
1055
1056         tbp = buf_Find(scp, &pageBase);
1057         if (!tbp) 
1058             break;
1059
1060         /* add the buffer to the list */
1061         qdp = osi_QDAlloc();
1062         osi_SetQData(qdp, tbp);
1063         osi_QAdd((osi_queue_t **)&heldBufListp, &qdp->q);
1064         if (!heldBufListEndp) heldBufListEndp = qdp;
1065         /* leave tbp held (from buf_Get) */
1066
1067         if (!reserving) 
1068             break;
1069
1070         collected += cm_data.buf_blockSize;
1071         toffset.HighPart = 0;
1072         toffset.LowPart = cm_data.buf_blockSize;
1073         pageBase = LargeIntegerAdd(toffset, pageBase);
1074     }
1075
1076     /* look at each buffer, adding it into the list if it looks idle and
1077      * filled with old data.  One special case: wait for idle if it is the
1078      * first buffer since we really need that one for our caller to make
1079      * any progress.
1080      */
1081     isFirst = 1;
1082     collected = 0;              /* now count how many we'll really use */
1083     for (tqdp = heldBufListEndp;
1084         tqdp;
1085           tqdp = (osi_queueData_t *) osi_QPrev(&tqdp->q)) {
1086         /* get a ptr to the held buffer */
1087         tbp = osi_GetQData(tqdp);
1088         pageBase = tbp->offset;
1089
1090         /* now lock the buffer lock */
1091         lock_ObtainMutex(&tbp->mx);
1092         lock_ObtainMutex(&scp->mx);
1093
1094         /* don't bother fetching over data that is already current */
1095         if (tbp->dataVersion == scp->dataVersion) {
1096             /* we don't need this buffer, since it is current */
1097             lock_ReleaseMutex(&scp->mx);
1098             lock_ReleaseMutex(&tbp->mx);
1099             break;
1100         }
1101
1102         flags = CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_FETCHDATA
1103             | CM_SCACHESYNC_BUFLOCKED;
1104         if (!isFirst) 
1105             flags |= CM_SCACHESYNC_NOWAIT;
1106
1107         /* wait for the buffer to serialize, if required.  Doesn't
1108          * release the scp or buffer lock(s) if NOWAIT is specified.
1109          */
1110         code = cm_SyncOp(scp, tbp, up, reqp, 0, flags);
1111         if (code) {
1112             lock_ReleaseMutex(&scp->mx);
1113             lock_ReleaseMutex(&tbp->mx);
1114             break;
1115         }
1116                 
1117         /* don't fetch over dirty buffers */
1118         if (tbp->flags & CM_BUF_DIRTY) {
1119             cm_SyncOpDone(scp, tbp, flags);
1120             lock_ReleaseMutex(&scp->mx);
1121             lock_ReleaseMutex(&tbp->mx);
1122             break;
1123         }
1124
1125         /* Release locks */
1126         lock_ReleaseMutex(&scp->mx);
1127         lock_ReleaseMutex(&tbp->mx);
1128
1129         /* add the buffer to the list */
1130         qdp = osi_QDAlloc();
1131         osi_SetQData(qdp, tbp);
1132         osi_QAdd((osi_queue_t **)&biop->bufListp, &qdp->q);
1133         if (!biop->bufListEndp) 
1134             biop->bufListEndp = qdp;
1135         buf_Hold(tbp);
1136
1137         /* from now on, a failure just stops our collection process, but
1138          * we still do the I/O to whatever we've already managed to collect.
1139          */
1140         isFirst = 0;
1141         collected += cm_data.buf_blockSize;
1142     }
1143         
1144     /* now, we've held in biop->bufListp all the buffer's we're really
1145      * interested in.  We also have holds left from heldBufListp, and we
1146      * now release those holds on the buffers.
1147      */
1148     for (qdp = heldBufListp; qdp; qdp = tqdp) {
1149         tqdp = (osi_queueData_t *) osi_QNext(&qdp->q);
1150         tbp = osi_GetQData(qdp);
1151         osi_QDFree(qdp);
1152         buf_Release(tbp);
1153     }
1154
1155     /* Caller expects this */
1156     lock_ObtainMutex(&scp->mx);
1157  
1158     /* if we got a failure setting up the first buffer, then we don't have
1159      * any side effects yet, and we also have failed an operation that the
1160      * caller requires to make any progress.  Give up now.
1161      */
1162     if (code && isFirst) {
1163         buf_UnreserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
1164         return code;
1165     }
1166         
1167     /* otherwise, we're still OK, and should just return the I/O setup we've
1168      * got.
1169      */
1170     biop->length = collected;
1171     biop->reserved = reserving;
1172     return 0;
1173 }
1174
1175 /* release a bulk I/O structure that was setup by cm_SetupFetchBIOD or by
1176  * cm_SetupStoreBIOD
1177  */
1178 void cm_ReleaseBIOD(cm_bulkIO_t *biop, int isStore)
1179 {
1180     cm_scache_t *scp;
1181     cm_buf_t *bufp;
1182     osi_queueData_t *qdp;
1183     osi_queueData_t *nqdp;
1184     int flags;
1185
1186     /* Give back reserved buffers */
1187     if (biop->reserved)
1188         buf_UnreserveBuffers(cm_chunkSize / cm_data.buf_blockSize);
1189         
1190     flags = CM_SCACHESYNC_NEEDCALLBACK;
1191     if (isStore)
1192         flags |= CM_SCACHESYNC_STOREDATA;
1193     else
1194         flags |= CM_SCACHESYNC_FETCHDATA;
1195
1196     scp = biop->scp;
1197     for(qdp = biop->bufListp; qdp; qdp = nqdp) {
1198         /* lookup next guy first, since we're going to free this one */
1199         nqdp = (osi_queueData_t *) osi_QNext(&qdp->q);
1200                 
1201         /* extract buffer and free queue data */
1202         bufp = osi_GetQData(qdp);
1203         osi_QDFree(qdp);
1204
1205         /* now, mark I/O as done, unlock the buffer and release it */
1206         lock_ObtainMutex(&bufp->mx);
1207         lock_ObtainMutex(&scp->mx);
1208         cm_SyncOpDone(scp, bufp, flags);
1209                 
1210         /* turn off writing and wakeup users */
1211         if (isStore) {
1212             if (bufp->flags & CM_BUF_WAITING) {
1213                 osi_Log2(afsd_logp, "cm_ReleaseBIOD Waking [scp 0x%p] bp 0x%p", scp, bufp);
1214                 osi_Wakeup((LONG_PTR) bufp);
1215             }
1216             bufp->flags &= ~(CM_BUF_WRITING | CM_BUF_DIRTY);
1217         }
1218
1219         lock_ReleaseMutex(&scp->mx);
1220         lock_ReleaseMutex(&bufp->mx);
1221         buf_Release(bufp);
1222     }
1223
1224     /* clean things out */
1225     biop->bufListp = NULL;
1226     biop->bufListEndp = NULL;
1227 }   
1228
1229 /* Fetch a buffer.  Called with scp locked.
1230  * The scp is locked on return.
1231  */
1232 long cm_GetBuffer(cm_scache_t *scp, cm_buf_t *bufp, int *cpffp, cm_user_t *up,
1233                   cm_req_t *reqp)
1234 {
1235     long code;
1236     afs_int32 nbytes;                   /* bytes in transfer */
1237     afs_int32 nbytes_hi = 0;            /* high-order 32 bits of bytes in transfer */
1238     afs_int64 length_found = 0;
1239     long rbytes;                        /* bytes in rx_Read call */
1240     long temp;
1241     AFSFetchStatus afsStatus;
1242     AFSCallBack callback;
1243     AFSVolSync volSync;
1244     char *bufferp;
1245     cm_buf_t *tbufp;                    /* buf we're filling */
1246     osi_queueData_t *qdp;               /* q element we're scanning */
1247     AFSFid tfid;
1248     struct rx_call *callp;
1249     struct rx_connection *rxconnp;
1250     cm_bulkIO_t biod;           /* bulk IO descriptor */
1251     cm_conn_t *connp;
1252     int getroot;
1253     long t1, t2;
1254     int require_64bit_ops = 0;
1255
1256     /* now, the buffer may or may not be filled with good data (buf_GetNew
1257      * drops lots of locks, and may indeed return a properly initialized
1258      * buffer, although more likely it will just return a new, empty, buffer.
1259      */
1260
1261 #ifdef AFS_FREELANCE_CLIENT
1262
1263     // yj: if they're trying to get the /afs directory, we need to
1264     // handle it differently, since it's local rather than on any
1265     // server
1266
1267     getroot = (scp==cm_data.rootSCachep);
1268     if (getroot)
1269         osi_Log1(afsd_logp,"GetBuffer returns cm_data.rootSCachep=%x",cm_data.rootSCachep);
1270 #endif
1271
1272     cm_AFSFidFromFid(&tfid, &scp->fid);
1273
1274     code = cm_SetupFetchBIOD(scp, &bufp->offset, &biod, up, reqp);
1275     if (code) {
1276         /* couldn't even get the first page setup properly */
1277         osi_Log1(afsd_logp, "SetupFetchBIOD failure code %d", code);
1278         return code;
1279     }
1280
1281     /* once we get here, we have the callback in place, we know that no one
1282      * is fetching the data now.  Check one last time that we still have
1283      * the wrong data, and then fetch it if we're still wrong.
1284      *
1285      * We can lose a race condition and end up with biod.length zero, in
1286      * which case we just retry.
1287      */
1288     if (bufp->dataVersion == scp->dataVersion || biod.length == 0) {
1289         osi_Log3(afsd_logp, "Bad DVs %d, %d or length 0x%x",
1290                  bufp->dataVersion, scp->dataVersion, biod.length);
1291         if ((bufp->dataVersion == -1
1292              || bufp->dataVersion < scp->dataVersion)
1293              && LargeIntegerGreaterThanOrEqualTo(bufp->offset,
1294                                                  scp->serverLength)) {
1295             if (bufp->dataVersion == -1)
1296                 memset(bufp->datap, 0, cm_data.buf_blockSize);
1297             bufp->dataVersion = scp->dataVersion;
1298         }
1299         lock_ReleaseMutex(&scp->mx);
1300         cm_ReleaseBIOD(&biod, 0);
1301         lock_ObtainMutex(&scp->mx);
1302         return 0;
1303     }
1304
1305     lock_ReleaseMutex(&scp->mx);
1306
1307     if (LargeIntegerGreaterThan(LargeIntegerAdd(biod.offset,
1308                                                 ConvertLongToLargeInteger(biod.length)),
1309                                 ConvertLongToLargeInteger(LONG_MAX))) {
1310         require_64bit_ops = 1;
1311     }
1312
1313 #ifdef DISKCACHE95
1314     DPRINTF("cm_GetBuffer: fetching data scpDV=%d bufDV=%d scp=%x bp=%x dcp=%x\n",
1315             scp->dataVersion, bufp->dataVersion, scp, bufp, bufp->dcp);
1316 #endif /* DISKCACHE95 */
1317
1318 #ifdef AFS_FREELANCE_CLIENT
1319
1320     // yj code
1321     // if getroot then we don't need to make any calls
1322     // just return fake data
1323         
1324     if (cm_freelanceEnabled && getroot) {
1325         // setup the fake status                        
1326         afsStatus.InterfaceVersion = 0x1;
1327         afsStatus.FileType = 0x2;
1328         afsStatus.LinkCount = scp->linkCount;
1329         afsStatus.Length = cm_fakeDirSize;
1330         afsStatus.DataVersion = cm_data.fakeDirVersion;
1331         afsStatus.Author = 0x1;
1332         afsStatus.Owner = 0x0;
1333         afsStatus.CallerAccess = 0x9;
1334         afsStatus.AnonymousAccess = 0x9;
1335         afsStatus.UnixModeBits = 0x1ff;
1336         afsStatus.ParentVnode = 0x1;
1337         afsStatus.ParentUnique = 0x1;
1338         afsStatus.ResidencyMask = 0;
1339         afsStatus.ClientModTime = (afs_uint32)FakeFreelanceModTime;
1340         afsStatus.ServerModTime = (afs_uint32)FakeFreelanceModTime;
1341         afsStatus.Group = 0;
1342         afsStatus.SyncCounter = 0;
1343         afsStatus.dataVersionHigh = 0;
1344         afsStatus.lockCount = 0;
1345         afsStatus.Length_hi = 0;
1346         afsStatus.errorCode = 0;
1347         
1348         // once we're done setting up the status info,
1349         // we just fill the buffer pages with fakedata
1350         // from cm_FakeRootDir. Extra pages are set to
1351         // 0. 
1352                 
1353         lock_ObtainMutex(&cm_Freelance_Lock);
1354         t1 = bufp->offset.LowPart;
1355         qdp = biod.bufListEndp;
1356         while (qdp) {
1357             tbufp = osi_GetQData(qdp);
1358             bufferp=tbufp->datap;
1359             memset(bufferp, 0, cm_data.buf_blockSize);
1360             t2 = cm_fakeDirSize - t1;
1361             if (t2>cm_data.buf_blockSize) t2=cm_data.buf_blockSize;
1362             if (t2 > 0) {
1363                 memcpy(bufferp, cm_FakeRootDir+t1, t2);
1364             } else {
1365                 t2 = 0;
1366             }
1367             t1+=t2;
1368             qdp = (osi_queueData_t *) osi_QPrev(&qdp->q);
1369
1370         }
1371         lock_ReleaseMutex(&cm_Freelance_Lock);
1372         
1373         // once we're done, we skip over the part of the
1374         // code that does the ACTUAL fetching of data for
1375         // real files
1376
1377         goto fetchingcompleted;
1378     }
1379
1380 #endif /* AFS_FREELANCE_CLIENT */
1381
1382         /* now make the call */
1383     do {
1384         code = cm_Conn(&scp->fid, up, reqp, &connp);
1385         if (code) 
1386             continue;
1387
1388         rxconnp = cm_GetRxConn(connp);
1389         callp = rx_NewCall(rxconnp);
1390         rx_PutConnection(rxconnp);
1391
1392 #ifdef AFS_LARGEFILES
1393         nbytes = nbytes_hi = 0;
1394
1395         if (SERVERHAS64BIT(connp)) {
1396             osi_Log4(afsd_logp, "CALL FetchData64 scp 0x%p, off 0x%x:%08x, size 0x%x",
1397                      scp, biod.offset.HighPart, biod.offset.LowPart, biod.length);
1398
1399             code = StartRXAFS_FetchData64(callp, &tfid, biod.offset.QuadPart, biod.length);
1400
1401             if (code == 0) {
1402                 temp = rx_Read(callp, (char *) &nbytes_hi, sizeof(afs_int32));
1403                 if (temp == sizeof(afs_int32)) {
1404                     nbytes_hi = ntohl(nbytes_hi);
1405                 } else {
1406                     nbytes_hi = 0;
1407                                         code = callp->error;
1408                     rx_EndCall(callp, code);
1409                     callp = NULL;
1410                 }
1411             }
1412         }
1413
1414         if (code == RXGEN_OPCODE || !SERVERHAS64BIT(connp)) {
1415             if (require_64bit_ops) {
1416                 osi_Log0(afsd_logp, "Skipping FetchData.  Operation requires FetchData64");
1417                 code = CM_ERROR_TOOBIG;
1418             } else {
1419                 if (!callp) {
1420                     rxconnp = cm_GetRxConn(connp);
1421                     callp = rx_NewCall(rxconnp);
1422                     rx_PutConnection(rxconnp);
1423                 }
1424
1425                 osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x",
1426                          scp, biod.offset.LowPart, biod.length);
1427
1428                 code = StartRXAFS_FetchData(callp, &tfid, biod.offset.LowPart,
1429                                             biod.length);
1430
1431                 SET_SERVERHASNO64BIT(connp);
1432             }
1433         }
1434
1435         if (code == 0) {
1436             temp  = rx_Read(callp, (char *)&nbytes, sizeof(afs_int32));
1437             if (temp == sizeof(afs_int32)) {
1438                 nbytes = ntohl(nbytes);
1439                 FillInt64(length_found, nbytes_hi, nbytes);
1440                 if (length_found > biod.length) 
1441                     code = (callp->error < 0) ? callp->error : -1;
1442             } else {
1443                 code = (callp->error < 0) ? callp->error : -1;
1444             }
1445         }
1446         /* for the moment, nbytes_hi will always be 0 if code == 0
1447            because biod.length is a 32-bit quantity. */
1448 #else
1449         osi_Log3(afsd_logp, "CALL FetchData scp 0x%p, off 0x%x, size 0x%x",
1450                  scp, biod.offset.LowPart, biod.length);
1451
1452         code = StartRXAFS_FetchData(callp, &tfid, biod.offset.LowPart,
1453                                     biod.length);
1454
1455         /* now copy the data out of the pipe and put it in the buffer */
1456         if (code == 0) {
1457             temp  = rx_Read(callp, (char *)&nbytes, sizeof(afs_int32));
1458             if (temp == sizeof(afs_int32)) {
1459                 nbytes = ntohl(nbytes);
1460                 if (nbytes > biod.length) 
1461                     code = (callp->error < 0) ? callp->error : -1;
1462             }
1463             else 
1464                 code = (callp->error < 0) ? callp->error : -1;
1465         }
1466 #endif
1467
1468         if (code == 0) {
1469             qdp = biod.bufListEndp;
1470             if (qdp) {
1471                 tbufp = osi_GetQData(qdp);
1472                 bufferp = tbufp->datap;
1473             }
1474             else 
1475                 bufferp = NULL;
1476             /* fill nbytes of data from the pipe into the pages.
1477              * When we stop, qdp will point at the last page we're
1478              * dealing with, and bufferp will tell us where we
1479              * stopped.  We'll need this info below when we clear
1480              * the remainder of the last page out (and potentially
1481              * clear later pages out, if we fetch past EOF).
1482              */
1483             while (nbytes > 0) {
1484                 /* assert that there are still more buffers;
1485                  * our check above for nbytes being less than
1486                  * biod.length should ensure this.
1487                  */
1488                 osi_assert(bufferp != NULL);
1489
1490                 /* read rbytes of data */
1491                 rbytes = (nbytes > cm_data.buf_blockSize? cm_data.buf_blockSize : nbytes);
1492                 temp = rx_Read(callp, bufferp, rbytes);
1493                 if (temp < rbytes) {
1494                     code = (callp->error < 0) ? callp->error : -1;
1495                     break;
1496                 }
1497
1498                 /* allow read-while-fetching.
1499                  * if this is the last buffer, clear the
1500                  * PREFETCHING flag, so the reader waiting for
1501                  * this buffer will start a prefetch.
1502                  */
1503                 tbufp->cmFlags |= CM_BUF_CMFULLYFETCHED;
1504                 lock_ObtainMutex(&scp->mx);
1505                 if (scp->flags & CM_SCACHEFLAG_WAITING) {
1506                     osi_Log1(afsd_logp, "CM GetBuffer Waking scp 0x%p", scp);
1507                     osi_Wakeup((LONG_PTR) &scp->flags);
1508                 }
1509                 if (cpffp && !*cpffp && !osi_QPrev(&qdp->q)) {
1510                     *cpffp = 1;
1511                     cm_ClearPrefetchFlag(0, scp, &biod.offset);
1512                 }
1513                 lock_ReleaseMutex(&scp->mx);
1514
1515                 /* and adjust counters */
1516                 nbytes -= temp;
1517
1518                 /* and move to the next buffer */
1519                 if (nbytes != 0) {
1520                     qdp = (osi_queueData_t *) osi_QPrev(&qdp->q);
1521                     if (qdp) {
1522                         tbufp = osi_GetQData(qdp);
1523                         bufferp = tbufp->datap;
1524                     }
1525                     else 
1526                         bufferp = NULL;
1527                 } else 
1528                     bufferp += temp;
1529             }
1530
1531             /* zero out remainder of last pages, in case we are
1532              * fetching past EOF.  We were fetching an integral #
1533              * of pages, but stopped, potentially in the middle of
1534              * a page.  Zero the remainder of that page, and then
1535              * all of the rest of the pages.
1536              */
1537             /* bytes fetched */
1538             osi_assert((bufferp - tbufp->datap) < LONG_MAX);
1539             rbytes = (long) (bufferp - tbufp->datap);
1540
1541             /* bytes left to zero */
1542             rbytes = cm_data.buf_blockSize - rbytes;
1543             while(qdp) {
1544                 if (rbytes != 0)
1545                     memset(bufferp, 0, rbytes);
1546                 qdp = (osi_queueData_t *) osi_QPrev(&qdp->q);
1547                 if (qdp == NULL) 
1548                     break;
1549                 tbufp = osi_GetQData(qdp);
1550                 bufferp = tbufp->datap;
1551                 /* bytes to clear in this page */
1552                 rbytes = cm_data.buf_blockSize;
1553             }   
1554         }
1555
1556         if (code == 0) {
1557             if (SERVERHAS64BIT(connp))
1558                 code = EndRXAFS_FetchData64(callp, &afsStatus, &callback, &volSync);
1559             else
1560                 code = EndRXAFS_FetchData(callp, &afsStatus, &callback, &volSync);
1561         } else {
1562             if (SERVERHAS64BIT(connp))
1563                 osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData64 skipped due to error %d", code);
1564             else
1565                 osi_Log1(afsd_logp, "CALL EndRXAFS_FetchData skipped due to error %d", code);
1566         }
1567
1568         if (callp)
1569             code = rx_EndCall(callp, code);
1570
1571         if (code == RXKADUNKNOWNKEY)
1572             osi_Log0(afsd_logp, "CALL EndCall returns RXKADUNKNOWNKEY");
1573
1574         osi_Log0(afsd_logp, "CALL FetchData DONE");
1575
1576     } while (cm_Analyze(connp, up, reqp, &scp->fid, &volSync, NULL, NULL, code));
1577
1578   fetchingcompleted:
1579     code = cm_MapRPCError(code, reqp);
1580
1581     lock_ObtainMutex(&scp->mx);
1582     
1583     cm_SyncOpDone(scp, NULL, CM_SCACHESYNC_FETCHSTATUS);
1584
1585     /* we know that no one else has changed the buffer, since we still have
1586      * the fetching flag on the buffers, and we have the scp locked again.
1587      * Copy in the version # into the buffer if we got code 0 back from the
1588      * read.
1589      */
1590     if (code == 0) {
1591         for(qdp = biod.bufListp;
1592              qdp;
1593              qdp = (osi_queueData_t *) osi_QNext(&qdp->q)) {
1594             tbufp = osi_GetQData(qdp);
1595             tbufp->dataVersion = afsStatus.DataVersion;
1596
1597 #ifdef DISKCACHE95
1598             /* write buffer out to disk cache */
1599             diskcache_Update(tbufp->dcp, tbufp->datap, cm_data.buf_blockSize,
1600                               tbufp->dataVersion);
1601 #endif /* DISKCACHE95 */
1602         }
1603     }
1604
1605     /* release scatter/gather I/O structure (buffers, locks) */
1606     lock_ReleaseMutex(&scp->mx);
1607     cm_ReleaseBIOD(&biod, 0);
1608     lock_ObtainMutex(&scp->mx);
1609
1610     if (code == 0) 
1611         cm_MergeStatus(scp, &afsStatus, &volSync, up, 0);
1612     
1613     return code;
1614 }