0f189aff1757a94780590a14ce62e040aa6d9b26
[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     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
75
76     *got = afs_osi_Read(tfile, -1, v->tbuffer, tlen);
77     if ((*got < 0)
78 #if defined(KERNEL_HAVE_UERROR)
79                 || (*got != tlen && getuerror())
80 #endif
81                 )
82         return EIO;
83     return 0;
84 }
85
86 afs_int32
87 rxfs_storeMemRead(void *r, struct osi_file *tfile, afs_uint32 offset,
88                   afs_uint32 tlen, afs_uint32 *bytesread)
89 {
90     afs_int32 code;
91     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
92     struct memCacheEntry *mceP = (struct memCacheEntry *)tfile;
93
94     *bytesread = 0;
95     code = afs_MemReadvBlk(mceP, offset, v->tiov, v->tnio, tlen);
96     if (code != tlen)
97         return -33;
98     *bytesread = code;
99     return 0;
100 }
101
102 afs_int32
103 rxfs_storeMemWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
104 {
105     afs_int32 code;
106     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
107
108     RX_AFS_GUNLOCK();
109     code = rx_Writev(v->call, v->tiov, v->tnio, l);
110     RX_AFS_GLOCK();
111     if (code != l) {
112         code = rx_Error(v->call);
113         return (code ? code : -33);
114     }
115     *byteswritten = code;
116     return 0;
117 }
118
119 afs_int32
120 rxfs_storeUfsWrite(void *r, afs_uint32 l, afs_uint32 *byteswritten)
121 {
122     afs_int32 code;
123     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)r;
124
125     RX_AFS_GUNLOCK();
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. */
130     RX_AFS_GLOCK();
131     if (code != l) {
132         code = rx_Error(v->call);
133         return (code ? code : -33);
134     }
135     *byteswritten = code;
136     return 0;
137 }
138
139 afs_int32
140 rxfs_storeStatus(void *rock)
141 {
142     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)rock;
143
144     if (rx_GetRemoteStatus(v->call) & 1)
145         return 0;
146     return 1;
147 }
148
149 afs_int32
150 rxfs_storeDestroy(void **r, afs_int32 error)
151 {
152     afs_int32 code = error;
153     struct rxfs_storeVariables *v = (struct rxfs_storeVariables *)*r;
154
155     *r = NULL;
156     if (v->tbuffer)
157         osi_FreeLargeSpace(v->tbuffer);
158     if (v->tiov)
159         osi_FreeSmallSpace(v->tiov);
160     osi_FreeSmallSpace(v);
161     return code;
162 }
163
164 static
165 struct storeOps rxfs_storeUfsOps = {
166     rxfs_storeUfsPrepare,
167     rxfs_storeUfsRead,
168     rxfs_storeUfsWrite,
169     rxfs_storeStatus,
170     rxfs_storeDestroy
171 };
172
173 static
174 struct storeOps rxfs_storeMemOps = {
175     rxfs_storeMemPrepare,
176     rxfs_storeMemRead,
177     rxfs_storeMemWrite,
178     rxfs_storeStatus,
179     rxfs_storeDestroy
180 };
181
182 afs_int32
183 rxfs_storeInit(struct vcache *avc, struct storeOps **ops, void **rock)
184 {
185     struct rxfs_storeVariables *v;
186
187     v = (struct rxfs_storeVariables *) osi_AllocSmallSpace(sizeof(struct rxfs_storeVariables));
188     if (!v)
189         osi_Panic("rxfs_storeInit: osi_AllocSmallSpace returned NULL\n");
190     memset(v, 0, sizeof(struct rxfs_storeVariables));
191
192     v->InStatus.ClientModTime = avc->f.m.Date;
193     v->InStatus.Mask = AFS_SETMODTIME;
194
195     if (cacheDiskType == AFS_FCACHE_TYPE_UFS) {
196         v->tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
197         if (!v->tbuffer)
198             osi_Panic
199               ("rxfs_storeInit: osi_AllocLargeSpace for iovecs returned NULL\n");
200         *ops = (struct storeOps *) &rxfs_storeUfsOps;
201     } else {
202         v->tiov = osi_AllocSmallSpace(sizeof(struct iovec) * RX_MAXIOVECS);
203         if (!v->tiov)
204             osi_Panic
205               ("rxfs_storeInit: osi_AllocSmallSpace for iovecs returned NULL\n");
206         *ops = (struct storeOps *) &rxfs_storeMemOps;
207 #ifdef notdef
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 */
213         if (shouldWake) {
214             if (AFS_CHUNK(tlen) != 0)
215                 *shouldWake = 0;
216             else
217                 *shouldWake = 1;
218         }
219 #endif /* notdef */
220     }
221     *rock = (void *)v;
222     return 0;
223 }
224
225 /*
226  * afs_UFSCacheFetchProc
227  *
228  * Description:
229  *      Routine called on fetch; also tells people waiting for data
230  *      that more has arrived.
231  *
232  * Parameters:
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
240  *                              is not defined.
241  *      abytesXferredP : Set to the number of bytes actually xferred.
242  *                       NOTE: This parameter is only used if AFS_NOSTATS
243  *                              is not defined.
244  *
245  * Environment:
246  *      Nothing interesting.
247  */
248
249 int
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)
254 {
255     afs_int32 length;
256     register afs_int32 code;
257     register char *tbuffer;
258     register int tlen;
259     int moredata = 0;
260
261     AFS_STATCNT(UFS_CacheFetchProc);
262     osi_Assert(WriteLocked(&adc->lock));
263     afile->offset = 0;          /* Each time start from the beginning */
264     length = lengthFound;
265 #ifndef AFS_NOSTATS
266     (*abytesToXferP) = 0;
267     (*abytesXferredP) = 0;
268 #endif /* AFS_NOSTATS */
269     tbuffer = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
270     adc->validPos = abase;
271     do {
272         if (moredata) {
273             RX_AFS_GUNLOCK();
274             code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
275             RX_AFS_GLOCK();
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 */
281             }
282         }
283         /*
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
287          * blocks expected.
288          *
289          * We do not do this for AFS file servers because they sometimes
290          * return large negative numbers as the transfer size.
291          */
292         if (avc->f.states & CForeign) {
293             moredata = length & 0x80000000;
294             length &= ~0x80000000;
295         } else {
296             moredata = 0;
297         }
298 #ifndef AFS_NOSTATS
299         (*abytesToXferP) += length;
300 #endif /* AFS_NOSTATS */
301         while (length > 0) {
302             tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
303 #ifdef RX_KERNEL_TRACE
304             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
305                        "before rx_Read");
306 #endif
307             RX_AFS_GUNLOCK();
308             code = rx_Read(acall, tbuffer, tlen);
309             RX_AFS_GLOCK();
310 #ifdef RX_KERNEL_TRACE
311             afs_Trace1(afs_iclSetp, CM_TRACE_TIMESTAMP, ICL_TYPE_STRING,
312                        "after rx_Read");
313 #endif
314 #ifndef AFS_NOSTATS
315             (*abytesXferredP) += code;
316 #endif /* AFS_NOSTATS */
317             if (code != tlen) {
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);
322                 return -34;
323             }
324             code = afs_osi_Write(afile, -1, tbuffer, tlen);
325             if (code != tlen) {
326                 osi_FreeLargeSpace(tbuffer);
327                 return EIO;
328             }
329             abase += tlen;
330             length -= tlen;
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,
336                            adc->dflags);
337         }
338     } while (moredata);
339     osi_FreeLargeSpace(tbuffer);
340     return 0;
341
342 }                               /* afs_UFSCacheFetchProc */
343
344 /*!
345  *      Called upon store.
346  *
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.
356  *
357  * \note Environment: Nothing interesting.
358  */
359 int
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)
365 {
366     afs_int32 code;
367     afs_uint32 tlen;
368     int offset = 0;
369     struct storeOps *ops;
370     void * rock = NULL;
371
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);
376     if ( code ) {
377         osi_Panic("afs_CacheStoreProc: rxfs_storeInit failed");
378     }
379     ((struct rxfs_storeVariables *)rock)->call = acall;
380
381     AFS_STATCNT(CacheStoreProc);
382 #ifndef AFS_NOSTATS
383     /*
384      * In this case, alen is *always* the amount of data we'll be trying
385      * to ship here.
386      */
387     *(abytesToXferP) = alen;
388     *(abytesXferredP) = 0;
389 #endif /* AFS_NOSTATS */
390
391     while ( alen > 0 ) {
392         afs_int32 bytesread, byteswritten;
393         code = (*ops->prepare)(rock, alen, &tlen);
394         if ( code )
395             break;
396
397         code = (*ops->read)(rock, fP, offset, tlen, &bytesread);
398         if (code)
399             break;
400
401         tlen = bytesread;
402         code = (*ops->write)(rock, tlen, &byteswritten);
403         if (code)
404             break;
405 #ifndef AFS_NOSTATS
406         (*abytesXferredP) += byteswritten;
407 #endif /* AFS_NOSTATS */
408
409         offset += tlen;
410         alen -= tlen;
411         /*
412          * if file has been locked on server, can allow
413          * store to continue
414          */
415         if (shouldWake && *shouldWake && ((*ops->status)(rock) == 0)) {
416             *shouldWake = 0;    /* only do this once */
417             afs_wakeup(avc);
418         }
419     }
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);
424     return code;
425 }
426
427 int
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)
433 {
434     register struct memCacheEntry *mceP = (struct memCacheEntry *)fP;
435     register afs_int32 code;
436     afs_int32 length;
437     int moredata = 0;
438     struct iovec *tiov;         /* no data copying with iovec */
439     register int tlen, offset = 0;
440     int tnio;                   /* temp for iovec size */
441
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);
447 #ifndef AFS_NOSTATS
448     (*abytesToXferP) = 0;
449     (*abytesXferredP) = 0;
450 #endif /* AFS_NOSTATS */
451     /*
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
454      */
455     tiov =
456         (struct iovec *)osi_AllocSmallSpace(sizeof(struct iovec) *
457                                             RX_MAXIOVECS);
458     if (!tiov) {
459         osi_Panic
460             ("afs_MemCacheFetchProc: osi_AllocSmallSpace for iovecs returned NULL\n");
461     }
462     adc->validPos = abase;
463     do {
464         if (moredata) {
465             RX_AFS_GUNLOCK();
466             code = rx_Read(acall, (char *)&length, sizeof(afs_int32));
467             length = ntohl(length);
468             RX_AFS_GLOCK();
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 */
473             }
474         }
475         /*
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
479          * blocks expected.
480          *
481          * We do not do this for AFS file servers because they sometimes
482          * return large negative numbers as the transfer size.
483          */
484         if (avc->f.states & CForeign) {
485             moredata = length & 0x80000000;
486             length &= ~0x80000000;
487         } else {
488             moredata = 0;
489         }
490 #ifndef AFS_NOSTATS
491         (*abytesToXferP) += length;
492 #endif /* AFS_NOSTATS */
493         while (length > 0) {
494             tlen = (length > AFS_LRALLOCSIZ ? AFS_LRALLOCSIZ : length);
495             RX_AFS_GUNLOCK();
496             code = rx_Readv(acall, tiov, &tnio, RX_MAXIOVECS, tlen);
497             RX_AFS_GLOCK();
498 #ifndef AFS_NOSTATS
499             (*abytesXferredP) += code;
500 #endif /* AFS_NOSTATS */
501             if (code <= 0) {
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);
506                 return -34;
507             }
508             tlen = code;
509             afs_MemWritevBlk(mceP, offset, tiov, tnio, tlen);
510             offset += tlen;
511             abase += tlen;
512             length -= 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,
518                            adc->dflags);
519         }
520     } while (moredata);
521     /* max of two sizes */
522     osi_FreeSmallSpace(tiov);
523     return 0;
524 }
525