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