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