2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include "afs/param.h"
13 #include "afs/sysincludes.h" /* Standard vendor system headers */
14 #ifndef AFS_LINUX22_ENV
15 #include "rpc/types.h"
23 #endif /* AFS_ALPHA_ENV */
24 #include "afsincludes.h" /* Afs-based standard headers */
25 #include "afs/afs_stats.h" /* statistics */
26 #include "afs_prototypes.h"
28 extern int cacheDiskType;
30 /* rock and operations for RX_FILESERVER */
32 struct rxfs_storeVariables {
38 struct AFSStoreStatus InStatus;
42 rxfs_storeUfsPrepare(void *r, afs_uint32 size, afs_uint32 *tlen)
44 *tlen = (size > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : size);
49 rxfs_storeMemPrepare(void *r, afs_uint32 size, afs_uint32 *tlen)
52 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *) r;
54 *tlen = (size > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : size);
56 code = rx_WritevAlloc(v->call, v->tiov, &v->tnio, RX_MAXIOVECS, *tlen);
59 code = rx_Error(v->call);
71 rxfs_storeUfsRead(void *r, struct osi_file *tfile, afs_uint32 offset,
72 afs_uint32 tlen, afs_uint32 *got)
74 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
76 *got = afs_osi_Read(tfile, -1, v->tbuffer, tlen);
78 #if defined(KERNEL_HAVE_UERROR)
79 || (*got != tlen && getuerror())
87 rxfs_storeMemRead(void *r, struct osi_file *tfile, afs_uint32 offset,
88 afs_uint32 tlen, afs_uint32 *bytesread)
91 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
92 struct memCacheEntry *mceP = (struct memCacheEntry *)tfile;
95 code = afs_MemReadvBlk(mceP, offset, v->tiov, v->tnio, tlen);
103 rxfs_storeMemWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
106 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
109 code = rx_Writev(v->call, v->tiov, v->tnio, l);
112 code = rx_Error(v->call);
113 return (code ? code : -33);
115 *byteswritten = code;
120 rxfs_storeUfsWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
123 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
126 code = rx_Write(v->call, v->tbuffer, l);
127 /* writing 0 bytes will
128 * push a short packet. Is that really what we want, just because the
129 * data didn't come back from the disk yet? Let's try it and see. */
132 code = rx_Error(v->call);
133 return (code ? code : -33);
135 *byteswritten = code;
140 rxfs_storeStatus(void *rock)
142 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)rock;
144 if (rx_GetRemoteStatus(v->call) & 1)
150 rxfs_storeDestroy(void **r, afs_int32 error)
152 afs_int32 code = error;
153 struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)*r;
157 osi_FreeLargeSpace(v->tbuffer);
159 osi_FreeSmallSpace(v->tiov);
160 osi_FreeSmallSpace(v);
165 struct storeOps rxfs_storeUfsOps = {
166 rxfs_storeUfsPrepare,
174 struct storeOps rxfs_storeMemOps = {
175 rxfs_storeMemPrepare,
183 rxfs_storeInit(struct vcache *avc, struct storeOps **ops, void **rock)
185 struct rxfs_storeVariables *v;
187 v = (struct rxfs_storeVariables *) osi_AllocSmallSpace(sizeof(struct rxfs_storeVariables));
189 osi_Panic("rxfs_storeInit: osi_AllocSmallSpace returned NULL\n");
190 memset(v, 0, sizeof(struct rxfs_storeVariables));
192 v->InStatus.ClientModTime = avc->f.m.Date;
193 v->InStatus.Mask = AFS_SETMODTIME;
195 if (cacheDiskType == AFS_FCACHE_TYPE_UFS) {
196 v->tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
199 ("rxfs_storeInit: osi_AllocLargeSpace for iovecs returned NULL\n");
200 *ops = (struct storeOps *) &rxfs_storeUfsOps;
202 v->tiov = osi_AllocSmallSpace(sizeof(struct iovec) * RX_MAXIOVECS);
205 ("rxfs_storeInit: osi_AllocSmallSpace for iovecs returned NULL\n");
206 *ops = (struct storeOps *) &rxfs_storeMemOps;
208 /* do this at a higher level now -- it's a parameter */
209 /* for now, only do 'continue from close' code if file fits in one
210 * chunk. Could clearly do better: if only one modified chunk
211 * then can still do this. can do this on *last* modified chunk */
212 tlen = avc->f.m.Length - 1; /* byte position of last byte we'll store */
214 if (AFS_CHUNK(tlen) != 0)
226 * afs_UFSCacheFetchProc
229 * Routine called on fetch; also tells people waiting for data
230 * that more has arrived.
233 * acall : Ptr to the Rx call structure.
234 * afile : File descriptor for the cache file.
235 * abase : Base offset to fetch.
236 * adc : Ptr to the dcache entry for the file, write-locked.
237 * avc : Ptr to the vcache entry for the file.
238 * abytesToXferP : Set to the number of bytes to xfer.
239 * NOTE: This parameter is only used if AFS_NOSTATS
241 * abytesXferredP : Set to the number of bytes actually xferred.
242 * NOTE: This parameter is only used if AFS_NOSTATS
246 * Nothing interesting.
250 afs_UFSCacheFetchProc(register struct rx_call *acall, struct osi_file *afile,
251 afs_size_t abase, struct dcache *adc,
252 struct vcache *avc, afs_size_t * abytesToXferP,
253 afs_size_t * abytesXferredP, afs_int32 lengthFound)
256 register afs_int32 code;
257 register char *tbuffer;
261 AFS_STATCNT(UFS_CacheFetchProc);
262 osi_Assert(WriteLocked(&adc->lock));
263 afile->offset = 0; /* Each time start from the beginning */
264 length = lengthFound;
266 (*abytesToXferP) = 0;
267 (*abytesXferredP) = 0;
268 #endif /* AFS_NOSTATS */
269 tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
270 adc->validPos = abase;
274 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
276 length = ntohl(length);
277 if (code != sizeof(afs_int32)) {
278 osi_FreeLargeSpace(tbuffer);
279 code = rx_Error(acall);
280 return (code ? code : -1); /* try to return code, not -1 */
284 * The fetch protocol is extended for the AFS/DFS translator
285 * to allow multiple blocks of data, each with its own length,
286 * to be returned. As long as the top bit is set, there are more
289 * We do not do this for AFS file servers because they sometimes
290 * return large negative numbers as the transfer size.
292 if (avc->f.states & CForeign) {
293 moredata = length & 0x80000000;
294 length &= ~0x80000000;
299 (*abytesToXferP) += length;
300 #endif /* AFS_NOSTATS */
302 tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
303 #ifdef RX_KERNEL_TRACE
304 afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
308 code = rx_Read(acall, tbuffer, tlen);
310 #ifdef RX_KERNEL_TRACE
311 afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
315 (*abytesXferredP) += code;
316 #endif /* AFS_NOSTATS */
318 osi_FreeLargeSpace(tbuffer);
319 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
320 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
321 ICL_TYPE_INT32, length);
324 code = afs_osi_Write(afile, -1, tbuffer, tlen);
326 osi_FreeLargeSpace(tbuffer);
331 adc->validPos = abase;
332 if (afs_osi_Wakeup(&adc->validPos) == 0)
333 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAKE, ICL_TYPE_STRING,
334 __FILE__, ICL_TYPE_INT32, __LINE__,
335 ICL_TYPE_POINTER, adc, ICL_TYPE_INT32,
339 osi_FreeLargeSpace(tbuffer);
342 } /* afs_UFSCacheFetchProc */
347 * \param acall Ptr to the Rx call structure involved.
348 * \param fP Ptr to the related file descriptor.
349 * \param alen Size of the file in bytes.
350 * \param avc Ptr to the vcache entry.
351 * \param shouldWake is it "safe" to return early from close() ?
352 * \param abytesToXferP Set to the number of bytes to xfer.
353 * NOTE: This parameter is only used if AFS_NOSTATS is not defined.
354 * \param abytesXferredP Set to the number of bytes actually xferred.
355 * NOTE: This parameter is only used if AFS_NOSTATS is not defined.
357 * \note Environment: Nothing interesting.
360 afs_CacheStoreProc(register struct rx_call *acall,
361 register struct osi_file *fP,
362 register afs_int32 alen, struct vcache *avc,
363 int *shouldWake, afs_size_t * abytesToXferP,
364 afs_size_t * abytesXferredP)
369 struct storeOps *ops;
372 afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
373 ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
374 ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
375 code = rxfs_storeInit(avc, &ops, &rock);
377 osi_Panic("afs_CacheStoreProc: rxfs_storeInit failed");
379 ((struct rxfs_storeVariables *)rock)->call = acall;
381 AFS_STATCNT(CacheStoreProc);
384 * In this case, alen is *always* the amount of data we'll be trying
387 *(abytesToXferP) = alen;
388 *(abytesXferredP) = 0;
389 #endif /* AFS_NOSTATS */
392 afs_int32 bytesread, byteswritten;
393 code = (*ops->prepare)(rock, alen, &tlen);
397 code = (*ops->read)(rock, fP, offset, tlen, &bytesread);
402 code = (*ops->write)(rock, tlen, &byteswritten);
406 (*abytesXferredP) += byteswritten;
407 #endif /* AFS_NOSTATS */
412 * if file has been locked on server, can allow
415 if (shouldWake && *shouldWake && ((*ops->status)(rock) == 0)) {
416 *shouldWake = 0; /* only do this once */
420 afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
421 ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
422 ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
423 code = (*ops->destroy)(&rock, code);
428 afs_MemCacheFetchProc(register struct rx_call *acall,
429 register struct osi_file *fP, afs_size_t abase,
430 struct dcache *adc, struct vcache *avc,
431 afs_size_t * abytesToXferP, afs_size_t * abytesXferredP,
432 afs_int32 lengthFound)
434 register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
435 register afs_int32 code;
438 struct iovec *tiov; /* no data copying with iovec */
439 register int tlen, offset = 0;
440 int tnio; /* temp for iovec size */
442 AFS_STATCNT(afs_MemCacheFetchProc);
443 length = lengthFound;
444 afs_Trace4(afs_iclSetp, CM_TRACE_MEMFETCH, ICL_TYPE_POINTER, avc,
445 ICL_TYPE_POINTER, mceP, ICL_TYPE_OFFSET,
446 ICL_HANDLE_OFFSET(abase), ICL_TYPE_INT32, length);
448 (*abytesToXferP) = 0;
449 (*abytesXferredP) = 0;
450 #endif /* AFS_NOSTATS */
452 * We need to alloc the iovecs on the heap so that they are "pinned" rather than
453 * declare them on the stack - defect 11272
456 (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec) *
460 ("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
462 adc->validPos = abase;
466 code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
467 length = ntohl(length);
469 if (code != sizeof(afs_int32)) {
470 code = rx_Error(acall);
471 osi_FreeSmallSpace(tiov);
472 return (code ? code : -1); /* try to return code, not -1 */
476 * The fetch protocol is extended for the AFS/DFS translator
477 * to allow multiple blocks of data, each with its own length,
478 * to be returned. As long as the top bit is set, there are more
481 * We do not do this for AFS file servers because they sometimes
482 * return large negative numbers as the transfer size.
484 if (avc->f.states & CForeign) {
485 moredata = length & 0x80000000;
486 length &= ~0x80000000;
491 (*abytesToXferP) += length;
492 #endif /* AFS_NOSTATS */
494 tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
496 code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
499 (*abytesXferredP) += code;
500 #endif /* AFS_NOSTATS */
502 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
503 ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
504 ICL_TYPE_INT32, length);
505 osi_FreeSmallSpace(tiov);
509 afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
513 adc->validPos = abase;
514 if (afs_osi_Wakeup(&adc->validPos) == 0)
515 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAKE, ICL_TYPE_STRING,
516 __FILE__, ICL_TYPE_INT32, __LINE__,
517 ICL_TYPE_POINTER, adc, ICL_TYPE_INT32,
521 /* max of two sizes */
522 osi_FreeSmallSpace(tiov);