Unite CacheStoreProcs and add abstraction calls.
[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 extern int cacheDiskType;
29
30 /* rock and operations for RX_FILESERVER */
31
32 struct rxfs_storeVariables {
33     struct rx_call *call;
34     char *tbuffer;
35     struct iovec *tiov;
36     afs_uint32 tnio;
37     afs_int32 hasNo64bit;
38     struct AFSStoreStatus InStatus;
39 };
40
41 afs_int32
42 rxfs_storeUfsPrepare(void *r, afs_uint32 size, afs_uint32 *tlen)
43 {
44     *tlen = (size > AFS_LRALLOCSIZ ?  AFS_LRALLOCSIZ : size);
45     return 0;
46 }
47
48 afs_int32
49 rxfs_storeMemPrepare(void *r, afs_uint32 size, afs_uint32 *tlen)
50 {
51     afs_int32 code;
52     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *) r;
53
54     *tlen = (size > AFS_LRALLOCSIZ ?  AFS_LRALLOCSIZ : size);
55     RX_AFS_GUNLOCK();
56     code = rx_WritevAlloc(v->call, v->tiov, &v->tnio, RX_MAXIOVECS, *tlen);
57     RX_AFS_GLOCK();
58     if (code <= 0) {
59         code = rx_Error(v->call);
60         if ( !code )
61             code = -33;
62     }
63     else {
64         *tlen = code;
65         code = 0;
66     }
67     return code;
68 }
69
70 afs_int32
71 rxfs_storeUfsRead(void *r, struct osi_file *tfile, afs_uint32 offset,
72                   afs_uint32 tlen, afs_uint32 *got)
73 {
74     afs_int32 code;
75     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
76
77     *got = afs_osi_Read(tfile, -1, v->tbuffer, tlen);
78     if ((*got < 0)
79 #if defined(KERNEL_HAVE_UERROR)
80                 || (*got != tlen && getuerror())
81 #endif
82                 )
83         return EIO;
84     return 0;
85 }
86
87 afs_int32
88 rxfs_storeMemRead(void *r, struct osi_file *tfile, afs_uint32 offset,
89                   afs_uint32 tlen, afs_uint32 *bytesread)
90 {
91     afs_int32 code;
92     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
93     struct memCacheEntry *mceP = (struct memCacheEntry *)tfile;
94
95     *bytesread = 0;
96     code = afs_MemReadvBlk(mceP, offset, v->tiov, v->tnio, tlen);
97     if (code != tlen)
98         return -33;
99     *bytesread = code;
100     return 0;
101 }
102
103 afs_int32
104 rxfs_storeMemWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
105 {
106     afs_int32 code;
107     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
108
109     RX_AFS_GUNLOCK();
110     code = rx_Writev(v->call, v->tiov, v->tnio, l);
111     RX_AFS_GLOCK();
112     if (code != l) {
113         code = rx_Error(v->call);
114         return (code ? code : -33);
115     }
116     *byteswritten = code;
117     return 0;
118 }
119
120 afs_int32
121 rxfs_storeUfsWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
122 {
123     afs_int32 code;
124     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
125
126     RX_AFS_GUNLOCK();
127     code = rx_Write(v->call, v->tbuffer, l);
128         /* writing 0 bytes will
129          * push a short packet.  Is that really what we want, just because the
130          * data didn't come back from the disk yet?  Let's try it and see. */
131     RX_AFS_GLOCK();
132     if (code != l) {
133         code = rx_Error(v->call);
134         return (code ? code : -33);
135     }
136     *byteswritten = code;
137     return 0;
138 }
139
140 afs_int32
141 rxfs_storeStatus(void *rock)
142 {
143     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)rock;
144
145     if (rx_GetRemoteStatus(v->call) & 1)
146         return 0;
147     return 1;
148 }
149
150 afs_int32
151 rxfs_storeDestroy(void **r, afs_int32 error)
152 {
153     afs_int32 code = error;
154     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)*r;
155
156     *r = NULL;
157     if (v->tbuffer)
158         osi_FreeLargeSpace(v->tbuffer);
159     if (v->tiov)
160         osi_FreeSmallSpace(v->tiov);
161     osi_FreeSmallSpace(v);
162     return code;
163 }
164
165 static
166 struct storeOps rxfs_storeUfsOps = {
167     rxfs_storeUfsPrepare,
168     rxfs_storeUfsRead,
169     rxfs_storeUfsWrite,
170     rxfs_storeStatus,
171     rxfs_storeDestroy
172 };
173
174 static
175 struct storeOps rxfs_storeMemOps = {
176     rxfs_storeMemPrepare,
177     rxfs_storeMemRead,
178     rxfs_storeMemWrite,
179     rxfs_storeStatus,
180     rxfs_storeDestroy
181 };
182
183 afs_int32
184 rxfs_storeInit(struct vcache *avc, struct storeOps **ops, void **rock)
185 {
186     struct rxfs_storeVariables *v;
187
188     v = (struct rxfs_storeVariables *) osi_AllocSmallSpace(sizeof(struct rxfs_storeVariables));
189     if (!v)
190         osi_Panic("rxfs_storeInit: osi_AllocSmallSpace returned NULL\n");
191     memset(v, 0, sizeof(struct rxfs_storeVariables));
192
193     v->InStatus.ClientModTime = avc->f.m.Date;
194     v->InStatus.Mask = AFS_SETMODTIME;
195
196     if (cacheDiskType == AFS_FCACHE_TYPE_UFS) {
197         v->tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
198         if (!v->tbuffer)
199             osi_Panic
200               ("rxfs_storeInit: osi_AllocLargeSpace for iovecs returned NULL\n");
201         *ops = (struct storeOps *) &rxfs_storeUfsOps;
202     } else {
203         v->tiov = osi_AllocSmallSpace(sizeof(struct iovec) * RX_MAXIOVECS);
204         if (!v->tiov)
205             osi_Panic
206               ("rxfs_storeInit: osi_AllocSmallSpace for iovecs returned NULL\n");
207         *ops = (struct storeOps *) &rxfs_storeMemOps;
208 #ifdef notdef
209         /* do this at a higher level now -- it's a parameter */
210         /* for now, only do 'continue from close' code if file fits in one
211          * chunk.  Could clearly do better: if only one modified chunk
212          * then can still do this.  can do this on *last* modified chunk */
213         tlen = avc->f.m.Length - 1;     /* byte position of last byte we'll store */
214         if (shouldWake) {
215             if (AFS_CHUNK(tlen) != 0)
216                 *shouldWake = 0;
217             else
218                 *shouldWake = 1;
219         }
220 #endif /* notdef */
221     }
222     *rock = (void *)v;
223     return 0;
224 }
225
226 /*
227  * afs_UFSCacheFetchProc
228  *
229  * Description:
230  *      Routine called on fetch; also tells people waiting for data
231  *      that more has arrived.
232  *
233  * Parameters:
234  *      acall : Ptr to the Rx call structure.
235  *      afile : File descriptor for the cache file.
236  *      abase : Base offset to fetch.
237  *      adc   : Ptr to the dcache entry for the file, write-locked.
238  *      avc   : Ptr to the vcache entry for the file.
239  *      abytesToXferP  : Set to the number of bytes to xfer.
240  *                       NOTE: This parameter is only used if AFS_NOSTATS
241  *                              is not defined.
242  *      abytesXferredP : Set to the number of bytes actually xferred.
243  *                       NOTE: This parameter is only used if AFS_NOSTATS
244  *                              is not defined.
245  *
246  * Environment:
247  *      Nothing interesting.
248  */
249
250 int
251 afs_UFSCacheFetchProc(register struct rx_call *acall, struct osi_file *afile,
252                       afs_size_t abase, struct dcache *adc,
253                       struct vcache *avc, afs_size_t * abytesToXferP,
254                       afs_size_t * abytesXferredP, afs_int32 lengthFound)
255 {
256     afs_int32 length;
257     register afs_int32 code;
258     register char *tbuffer;
259     register int tlen;
260     int moredata = 0;
261
262     AFS_STATCNT(UFS_CacheFetchProc);
263     osi_Assert(WriteLocked(&adc->lock));
264     afile->offset = 0;          /* Each time start from the beginning */
265     length = lengthFound;
266 #ifndef AFS_NOSTATS
267     (*abytesToXferP) = 0;
268     (*abytesXferredP) = 0;
269 #endif /* AFS_NOSTATS */
270     tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
271     adc->validPos = abase;
272     do {
273         if (moredata) {
274             RX_AFS_GUNLOCK();
275             code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
276             RX_AFS_GLOCK();
277             length = ntohl(length);
278             if (code != sizeof(afs_int32)) {
279                 osi_FreeLargeSpace(tbuffer);
280                 code = rx_Error(acall);
281                 return (code ? code : -1);      /* try to return code, not -1 */
282             }
283         }
284         /*
285          * The fetch protocol is extended for the AFS/DFS translator
286          * to allow multiple blocks of data, each with its own length,
287          * to be returned. As long as the top bit is set, there are more
288          * blocks expected.
289          *
290          * We do not do this for AFS file servers because they sometimes
291          * return large negative numbers as the transfer size.
292          */
293         if (avc->f.states & CForeign) {
294             moredata = length & 0x80000000;
295             length &= ~0x80000000;
296         } else {
297             moredata = 0;
298         }
299 #ifndef AFS_NOSTATS
300         (*abytesToXferP) += length;
301 #endif /* AFS_NOSTATS */
302         while (length > 0) {
303             tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
304 #ifdef RX_KERNEL_TRACE
305             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
306                        "before rx_Read");
307 #endif
308             RX_AFS_GUNLOCK();
309             code = rx_Read(acall, tbuffer, tlen);
310             RX_AFS_GLOCK();
311 #ifdef RX_KERNEL_TRACE
312             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
313                        "after rx_Read");
314 #endif
315 #ifndef AFS_NOSTATS
316             (*abytesXferredP) += code;
317 #endif /* AFS_NOSTATS */
318             if (code != tlen) {
319                 osi_FreeLargeSpace(tbuffer);
320                 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
321                            ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
322                            ICL_TYPE_INT32, length);
323                 return -34;
324             }
325             code = afs_osi_Write(afile, -1, tbuffer, tlen);
326             if (code != tlen) {
327                 osi_FreeLargeSpace(tbuffer);
328                 return EIO;
329             }
330             abase += tlen;
331             length -= tlen;
332             adc->validPos = abase;
333             if (afs_osi_Wakeup(&adc->validPos) == 0)
334                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAKE, ICL_TYPE_STRING,
335                            __FILE__, ICL_TYPE_INT32, __LINE__,
336                            ICL_TYPE_POINTER, adc, ICL_TYPE_INT32,
337                            adc->dflags);
338         }
339     } while (moredata);
340     osi_FreeLargeSpace(tbuffer);
341     return 0;
342
343 }                               /* afs_UFSCacheFetchProc */
344
345 /*!
346  *      Called upon store.
347  *
348  * \param acall Ptr to the Rx call structure involved.
349  * \param fP Ptr to the related file descriptor.
350  * \param alen Size of the file in bytes.
351  * \param avc Ptr to the vcache entry.
352  * \param shouldWake is it "safe" to return early from close() ?
353  * \param abytesToXferP Set to the number of bytes to xfer.
354  *      NOTE: This parameter is only used if AFS_NOSTATS is not defined.
355  * \param abytesXferredP Set to the number of bytes actually xferred.
356  *      NOTE: This parameter is only used if AFS_NOSTATS is not defined.
357  *
358  * \note Environment: Nothing interesting.
359  */
360 int
361 afs_CacheStoreProc(register struct rx_call *acall,
362                       register struct osi_file *fP,
363                       register afs_int32 alen, struct vcache *avc,
364                       int *shouldWake, afs_size_t * abytesToXferP,
365                       afs_size_t * abytesXferredP)
366 {
367     afs_int32 code;
368     afs_uint32 tlen;
369     int offset = 0;
370     struct storeOps *ops;
371     void * rock = NULL;
372
373     afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
374                ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
375                ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
376     code =  rxfs_storeInit(avc, &ops, &rock);
377     if ( code ) {
378         osi_Panic("afs_CacheStoreProc: rxfs_storeInit failed");
379     }
380     ((struct rxfs_storeVariables *)rock)->call = acall;
381
382     AFS_STATCNT(CacheStoreProc);
383 #ifndef AFS_NOSTATS
384     /*
385      * In this case, alen is *always* the amount of data we'll be trying
386      * to ship here.
387      */
388     *(abytesToXferP) = alen;
389     *(abytesXferredP) = 0;
390 #endif /* AFS_NOSTATS */
391
392     while ( alen > 0 ) {
393         afs_int32 bytesread, byteswritten;
394         code = (*ops->prepare)(rock, alen, &tlen);
395         if ( code )
396             break;
397
398         code = (*ops->read)(rock, fP, offset, tlen, &bytesread);
399         if (code)
400             break;
401
402         tlen = bytesread;
403         code = (*ops->write)(rock, tlen, &byteswritten);
404         if (code)
405             break;
406 #ifndef AFS_NOSTATS
407         (*abytesXferredP) += byteswritten;
408 #endif /* AFS_NOSTATS */
409
410         offset += tlen;
411         alen -= tlen;
412         /*
413          * if file has been locked on server, can allow
414          * store to continue
415          */
416         if (shouldWake && *shouldWake && ((*ops->status)(rock) == 0)) {
417             *shouldWake = 0;    /* only do this once */
418             afs_wakeup(avc);
419         }
420     }
421     afs_Trace4(afs_iclSetp, CM_TRACE_STOREPROC, ICL_TYPE_POINTER, avc,
422                ICL_TYPE_FID, &(avc->f.fid), ICL_TYPE_OFFSET,
423                ICL_HANDLE_OFFSET(avc->f.m.Length), ICL_TYPE_INT32, alen);
424     code = (*ops->destroy)(&rock, code);
425     return code;
426 }
427
428 int
429 afs_MemCacheFetchProc(register struct rx_call *acall,
430                       register struct osi_file *fP, afs_size_t abase,
431                       struct dcache *adc, struct vcache *avc,
432                       afs_size_t * abytesToXferP, afs_size_t * abytesXferredP,
433                       afs_int32 lengthFound)
434 {
435     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
436     register afs_int32 code;
437     afs_int32 length;
438     int moredata = 0;
439     struct iovec *tiov;         /* no data copying with iovec */
440     register int tlen, offset = 0;
441     int tnio;                   /* temp for iovec size */
442
443     AFS_STATCNT(afs_MemCacheFetchProc);
444     length = lengthFound;
445     afs_Trace4(afs_iclSetp, CM_TRACE_MEMFETCH, ICL_TYPE_POINTER, avc,
446                ICL_TYPE_POINTER, mceP, ICL_TYPE_OFFSET,
447                ICL_HANDLE_OFFSET(abase), ICL_TYPE_INT32, length);
448 #ifndef AFS_NOSTATS
449     (*abytesToXferP) = 0;
450     (*abytesXferredP) = 0;
451 #endif /* AFS_NOSTATS */
452     /*
453      * We need to alloc the iovecs on the heap so that they are "pinned" rather than
454      * declare them on the stack - defect 11272
455      */
456     tiov =
457         (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec) *
458                                             RX_MAXIOVECS);
459     if (!tiov) {
460         osi_Panic
461             ("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
462     }
463     adc->validPos = abase;
464     do {
465         if (moredata) {
466             RX_AFS_GUNLOCK();
467             code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
468             length = ntohl(length);
469             RX_AFS_GLOCK();
470             if (code != sizeof(afs_int32)) {
471                 code = rx_Error(acall);
472                 osi_FreeSmallSpace(tiov);
473                 return (code ? code : -1);      /* try to return code, not -1 */
474             }
475         }
476         /*
477          * The fetch protocol is extended for the AFS/DFS translator
478          * to allow multiple blocks of data, each with its own length,
479          * to be returned. As long as the top bit is set, there are more
480          * blocks expected.
481          *
482          * We do not do this for AFS file servers because they sometimes
483          * return large negative numbers as the transfer size.
484          */
485         if (avc->f.states & CForeign) {
486             moredata = length & 0x80000000;
487             length &= ~0x80000000;
488         } else {
489             moredata = 0;
490         }
491 #ifndef AFS_NOSTATS
492         (*abytesToXferP) += length;
493 #endif /* AFS_NOSTATS */
494         while (length > 0) {
495             tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
496             RX_AFS_GUNLOCK();
497             code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
498             RX_AFS_GLOCK();
499 #ifndef AFS_NOSTATS
500             (*abytesXferredP) += code;
501 #endif /* AFS_NOSTATS */
502             if (code <= 0) {
503                 afs_Trace3(afs_iclSetp, CM_TRACE_FETCH64READ,
504                            ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, code,
505                            ICL_TYPE_INT32, length);
506                 osi_FreeSmallSpace(tiov);
507                 return -34;
508             }
509             tlen = code;
510             afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
511             offset += tlen;
512             abase += tlen;
513             length -= tlen;
514             adc->validPos = abase;
515             if (afs_osi_Wakeup(&adc->validPos) == 0)
516                 afs_Trace4(afs_iclSetp, CM_TRACE_DCACHEWAKE, ICL_TYPE_STRING,
517                            __FILE__, ICL_TYPE_INT32, __LINE__,
518                            ICL_TYPE_POINTER, adc, ICL_TYPE_INT32,
519                            adc->dflags);
520         }
521     } while (moredata);
522     /* max of two sizes */
523     osi_FreeSmallSpace(tiov);
524     return 0;
525 }
526