Gathered alternative afs_TttCacheFetchProcs and afs_TttCacheStoreProcs
[openafs.git] / src / afs / afs_fetchstore.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 <afsconfig.h>
11 #include "afs/param.h"
12
13 #include "afs/sysincludes.h"    /* Standard vendor system headers */
14 #ifndef AFS_LINUX22_ENV
15 #include "rpc/types.h"
16 #endif
17 #ifdef  AFS_ALPHA_ENV
18 #undef kmem_alloc
19 #undef kmem_free
20 #undef mem_alloc
21 #undef mem_free
22 #undef register
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"
27
28 /*
29  * afs_UFSCacheStoreProc
30  *
31  * Description:
32  *      Called upon store.
33  *
34  * Parameters:
35  *      acall : Ptr to the Rx call structure involved.
36  *      afile : Ptr to the related file descriptor.
37  *      alen  : Size of the file in bytes.
38  *      avc   : Ptr to the vcache entry.
39  *      shouldWake : is it "safe" to return early from close() ?
40  *      abytesToXferP  : Set to the number of bytes to xfer.
41  *                       NOTE: This parameter is only used if AFS_NOSTATS
42  *                              is not defined.
43  *      abytesXferredP : Set to the number of bytes actually xferred.
44  *                       NOTE: This parameter is only used if AFS_NOSTATS
45  *                              is not defined.
46  *
47  * Environment:
48  *      Nothing interesting.
49  */
50 int
51 afs_UFSCacheStoreProc(register struct rx_call *acall, struct osi_file *afile,
52                       register afs_int32 alen, struct vcache *avc,
53                       int *shouldWake, afs_size_t * abytesToXferP,
54                       afs_size_t * abytesXferredP)
55 {
56     afs_int32 code, got;
57     register char *tbuffer;
58     register int tlen;
59
60     AFS_STATCNT(UFS_CacheStoreProc);
61
62 #ifndef AFS_NOSTATS
63     /*
64      * In this case, alen is *always* the amount of data we'll be trying
65      * to ship here.
66      */
67     (*abytesToXferP) = alen;
68     (*abytesXferredP) = 0;
69 #endif /* AFS_NOSTATS */
70
71     afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
72                ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
73                ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
74     tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
75     while (alen > 0) {
76         tlen = (alen > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : alen);
77         got = afs_osi_Read(afile, -1, tbuffer, tlen);
78         if ((got < 0)
79 #if defined(KERNEL_HAVE_UERROR)
80             || (got != tlen && getuerror())
81 #endif
82             ) {
83             osi_FreeLargeSpace(tbuffer);
84             return EIO;
85         }
86         afs_Trace2(afs_iclSetp, CM_TRACE_STOREPROC2, ICL_TYPE_OFFSET,
87                    ICL_HANDLE_OFFSET(*tbuffer), ICL_TYPE_INT32, got);
88         RX_AFS_GUNLOCK();
89         code = rx_Write(acall, tbuffer, got);   /* writing 0 bytes will
90                                                  * push a short packet.  Is that really what we want, just because the
91                                                  * data didn't come back from the disk yet?  Let's try it and see. */
92         RX_AFS_GLOCK();
93 #ifndef AFS_NOSTATS
94         (*abytesXferredP) += code;
95 #endif /* AFS_NOSTATS */
96         if (code != got) {
97             code = rx_Error(acall);
98             osi_FreeLargeSpace(tbuffer);
99             return code ? code : -33;
100         }
101         alen -= got;
102         /*
103          * If file has been locked on server, we can allow the store
104          * to continue.
105          */
106         if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
107             *shouldWake = 0;    /* only do this once */
108             afs_wakeup(avc);
109         }
110     }
111     afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
112                ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
113                ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
114     osi_FreeLargeSpace(tbuffer);
115     return 0;
116
117 }                               /* afs_UFSCacheStoreProc */
118
119
120 /*
121  * afs_UFSCacheFetchProc
122  *
123  * Description:
124  *      Routine called on fetch; also tells people waiting for data
125  *      that more has arrived.
126  *
127  * Parameters:
128  *      acall : Ptr to the Rx call structure.
129  *      afile : File descriptor for the cache file.
130  *      abase : Base offset to fetch.
131  *      adc   : Ptr to the dcache entry for the file, write-locked.
132  *      avc   : Ptr to the vcache entry for the file.
133  *      abytesToXferP  : Set to the number of bytes to xfer.
134  *                       NOTE: This parameter is only used if AFS_NOSTATS
135  *                              is not defined.
136  *      abytesXferredP : Set to the number of bytes actually xferred.
137  *                       NOTE: This parameter is only used if AFS_NOSTATS
138  *                              is not defined.
139  *
140  * Environment:
141  *      Nothing interesting.
142  */
143
144 int
145 afs_UFSCacheFetchProc(register struct rx_call *acall, struct osi_file *afile,
146                       afs_size_t abase, struct dcache *adc,
147                       struct vcache *avc, afs_size_t * abytesToXferP,
148                       afs_size_t * abytesXferredP, afs_int32 lengthFound)
149 {
150     afs_int32 length;
151     register afs_int32 code;
152     register char *tbuffer;
153     register int tlen;
154     int moredata = 0;
155
156     AFS_STATCNT(UFS_CacheFetchProc);
157     osi_Assert(WriteLocked(&adc->lock));
158     afile->offset = 0;          /* Each time start from the beginning */
159     length = lengthFound;
160 #ifndef AFS_NOSTATS
161     (*abytesToXferP) = 0;
162     (*abytesXferredP) = 0;
163 #endif /* AFS_NOSTATS */
164     tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
165     adc->validPos = abase;
166     do {
167         if (moredata) {
168             RX_AFS_GUNLOCK();
169             code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
170             RX_AFS_GLOCK();
171             length = ntohl(length);
172             if (code != sizeof(afs_int32)) {
173                 osi_FreeLargeSpace(tbuffer);
174                 code = rx_Error(acall);
175                 return (code ? code : -1);      /* try to return code, not -1 */
176             }
177         }
178         /*
179          * The fetch protocol is extended for the AFS/DFS translator
180          * to allow multiple blocks of data, each with its own length,
181          * to be returned. As long as the top bit is set, there are more
182          * blocks expected.
183          *
184          * We do not do this for AFS file servers because they sometimes
185          * return large negative numbers as the transfer size.
186          */
187         if (avc->f.states & CForeign) {
188             moredata = length & 0x80000000;
189             length &= ~0x80000000;
190         } else {
191             moredata = 0;
192         }
193 #ifndef AFS_NOSTATS
194         (*abytesToXferP) += length;
195 #endif /* AFS_NOSTATS */
196         while (length > 0) {
197             tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
198 #ifdef RX_KERNEL_TRACE
199             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
200                        "before rx_Read");
201 #endif
202             RX_AFS_GUNLOCK();
203             code = rx_Read(acall, tbuffer, tlen);
204             RX_AFS_GLOCK();
205 #ifdef RX_KERNEL_TRACE
206             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
207                        "after rx_Read");
208 #endif
209 #ifndef AFS_NOSTATS
210             (*abytesXferredP) += code;
211 #endif /* AFS_NOSTATS */
212             if (code != tlen) {
213                 osi_FreeLargeSpace(tbuffer);
214                 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
215                            ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
216                            ICL_TYPE_INT32, length);
217                 return -34;
218             }
219             code = afs_osi_Write(afile, -1, tbuffer, tlen);
220             if (code != tlen) {
221                 osi_FreeLargeSpace(tbuffer);
222                 return EIO;
223             }
224             abase += tlen;
225             length -= tlen;
226             adc->validPos = abase;
227             if (afs_osi_Wakeup(&adc->validPos) == 0)
228                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAKE, ICL_TYPE_STRING,
229                            __FILE__, ICL_TYPE_INT32, __LINE__,
230                            ICL_TYPE_POINTER, adc, ICL_TYPE_INT32,
231                            adc->dflags);
232         }
233     } while (moredata);
234     osi_FreeLargeSpace(tbuffer);
235     return 0;
236
237 }                               /* afs_UFSCacheFetchProc */
238
239 int
240 afs_MemCacheStoreProc(register struct rx_call *acall,
241                       register struct osi_file *fP,
242                       register afs_int32 alen, struct vcache *avc,
243                       int *shouldWake, afs_size_t * abytesToXferP,
244                       afs_size_t * abytesXferredP)
245 {
246     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
247
248     register afs_int32 code;
249     register int tlen;
250     int offset = 0;
251     struct iovec *tiov;         /* no data copying with iovec */
252     int tnio;                   /* temp for iovec size */
253
254     AFS_STATCNT(afs_MemCacheStoreProc);
255 #ifndef AFS_NOSTATS
256     /*
257      * In this case, alen is *always* the amount of data we'll be trying
258      * to ship here.
259      */
260     *(abytesToXferP) = alen;
261     *(abytesXferredP) = 0;
262 #endif /* AFS_NOSTATS */
263
264     /*
265      * We need to alloc the iovecs on the heap so that they are "pinned" rather than
266      * declare them on the stack - defect 11272
267      */
268     tiov =
269         (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec) *
270                                             RX_MAXIOVECS);
271     if (!tiov) {
272         osi_Panic
273             ("afs_MemCacheStoreProc: osi_AllocSmallSpace for iovecs returned NULL\n");
274     }
275 #ifdef notdef
276     /* do this at a higher level now -- it's a parameter */
277     /* for now, only do 'continue from close' code if file fits in one
278      * chunk.  Could clearly do better: if only one modified chunk
279      * then can still do this.  can do this on *last* modified chunk */
280     tlen = avc->f.m.Length - 1; /* byte position of last byte we'll store */
281     if (shouldWake) {
282         if (AFS_CHUNK(tlen) != 0)
283             *shouldWake = 0;
284         else
285             *shouldWake = 1;
286     }
287 #endif /* notdef */
288
289     while (alen > 0) {
290         tlen = (alen > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : alen);
291         RX_AFS_GUNLOCK();
292         code = rx_WritevAlloc(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
293         RX_AFS_GLOCK();
294         if (code <= 0) {
295             code = rx_Error(acall);
296             osi_FreeSmallSpace(tiov);
297             return code ? code : -33;
298         }
299         tlen = code;
300         code = afs_MemReadvBlk(mceP, offset, tiov, tnio, tlen);
301         if (code != tlen) {
302             osi_FreeSmallSpace(tiov);
303             return -33;
304         }
305         RX_AFS_GUNLOCK();
306         code = rx_Writev(acall, tiov, tnio, tlen);
307         RX_AFS_GLOCK();
308 #ifndef AFS_NOSTATS
309         (*abytesXferredP) += code;
310 #endif /* AFS_NOSTATS */
311         if (code != tlen) {
312             code = rx_Error(acall);
313             osi_FreeSmallSpace(tiov);
314             return code ? code : -33;
315         }
316         offset += tlen;
317         alen -= tlen;
318         /* if file has been locked on server, can allow store to continue */
319         if (shouldWake && *shouldWake && (rx_GetRemoteStatus(acall) & 1)) {
320             *shouldWake = 0;    /* only do this once */
321             afs_wakeup(avc);
322         }
323     }
324     osi_FreeSmallSpace(tiov);
325     return 0;
326 }
327
328 int
329 afs_MemCacheFetchProc(register struct rx_call *acall,
330                       register struct osi_file *fP, afs_size_t abase,
331                       struct dcache *adc, struct vcache *avc,
332                       afs_size_t * abytesToXferP, afs_size_t * abytesXferredP,
333                       afs_int32 lengthFound)
334 {
335     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
336     register afs_int32 code;
337     afs_int32 length;
338     int moredata = 0;
339     struct iovec *tiov;         /* no data copying with iovec */
340     register int tlen, offset = 0;
341     int tnio;                   /* temp for iovec size */
342
343     AFS_STATCNT(afs_MemCacheFetchProc);
344     length = lengthFound;
345     afs_Trace4(afs_iclSetp, CM_TRACE_MEMFETCH, ICL_TYPE_POINTER, avc,
346                ICL_TYPE_POINTER, mceP, ICL_TYPE_OFFSET,
347                ICL_HANDLE_OFFSET(abase), ICL_TYPE_INT32, length);
348 #ifndef AFS_NOSTATS
349     (*abytesToXferP) = 0;
350     (*abytesXferredP) = 0;
351 #endif /* AFS_NOSTATS */
352     /*
353      * We need to alloc the iovecs on the heap so that they are "pinned" rather than
354      * declare them on the stack - defect 11272
355      */
356     tiov =
357         (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec) *
358                                             RX_MAXIOVECS);
359     if (!tiov) {
360         osi_Panic
361             ("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
362     }
363     adc->validPos = abase;
364     do {
365         if (moredata) {
366             RX_AFS_GUNLOCK();
367             code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
368             length = ntohl(length);
369             RX_AFS_GLOCK();
370             if (code != sizeof(afs_int32)) {
371                 code = rx_Error(acall);
372                 osi_FreeSmallSpace(tiov);
373                 return (code ? code : -1);      /* try to return code, not -1 */
374             }
375         }
376         /*
377          * The fetch protocol is extended for the AFS/DFS translator
378          * to allow multiple blocks of data, each with its own length,
379          * to be returned. As long as the top bit is set, there are more
380          * blocks expected.
381          *
382          * We do not do this for AFS file servers because they sometimes
383          * return large negative numbers as the transfer size.
384          */
385         if (avc->f.states & CForeign) {
386             moredata = length & 0x80000000;
387             length &= ~0x80000000;
388         } else {
389             moredata = 0;
390         }
391 #ifndef AFS_NOSTATS
392         (*abytesToXferP) += length;
393 #endif /* AFS_NOSTATS */
394         while (length > 0) {
395             tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
396             RX_AFS_GUNLOCK();
397             code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
398             RX_AFS_GLOCK();
399 #ifndef AFS_NOSTATS
400             (*abytesXferredP) += code;
401 #endif /* AFS_NOSTATS */
402             if (code <= 0) {
403                 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
404                            ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
405                            ICL_TYPE_INT32, length);
406                 osi_FreeSmallSpace(tiov);
407                 return -34;
408             }
409             tlen = code;
410             afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
411             offset += tlen;
412             abase += tlen;
413             length -= tlen;
414             adc->validPos = abase;
415             if (afs_osi_Wakeup(&adc->validPos) == 0)
416                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAKE, ICL_TYPE_STRING,
417                            __FILE__, ICL_TYPE_INT32, __LINE__,
418                            ICL_TYPE_POINTER, adc, ICL_TYPE_INT32,
419                            adc->dflags);
420         }
421     } while (moredata);
422     /* max of two sizes */
423     osi_FreeSmallSpace(tiov);
424     return 0;
425 }
426