Enable afs_DoPartialWrite() and afs_PrefetchChunk() in afs_UFSRead
[openafs.git] / src / afs / VNOPS / afs_vnop_write.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 /*
11  * Implements:
12  * afs_UFSWrite
13  * afs_MemWrite
14  * afs_StoreOnLastReference
15  * afs_close
16  * afs_closex
17  * afs_fsync
18  */
19
20 #include <afsconfig.h>
21 #include "../afs/param.h"
22
23 RCSID("$Header$");
24
25 #include "../afs/sysincludes.h" /* Standard vendor system headers */
26 #include "../afs/afsincludes.h" /* Afs-based standard headers */
27 #include "../afs/afs_stats.h" /* statistics */
28 #include "../afs/afs_cbqueue.h"
29 #include "../afs/nfsclient.h"
30 #include "../afs/afs_osidnlc.h"
31
32
33 extern unsigned char *afs_indexFlags;
34
35 /* Called by all write-on-close routines: regular afs_close,
36  * store via background daemon and store via the
37  * afs_FlushActiveVCaches routine (when CCORE is on).
38  * avc->lock must be write-locked.
39  */
40 afs_StoreOnLastReference(avc, treq)
41 register struct vcache *avc;
42 register struct vrequest *treq;
43 {
44     int code = 0;
45  
46     AFS_STATCNT(afs_StoreOnLastReference);
47     /* if CCore flag is set, we clear it and do the extra decrement
48      * ourselves now. If we're called by the CCore clearer, the CCore
49      * flag will already be clear, so we don't have to worry about
50      * clearing it twice. */
51     if (avc->states & CCore) {
52         avc->states &= ~CCore;
53 #if defined(AFS_SGI_ENV)
54         osi_Assert(avc->opens > 0 && avc->execsOrWriters > 0);
55 #endif
56         /* WARNING: Our linux cm code treats the execsOrWriters counter differently 
57          * depending on the flags the file was opened with. So, if you make any 
58          * changes to the way the execsOrWriters flag is handled check with the 
59          * top level code.  */
60         avc->opens--;
61         avc->execsOrWriters--;
62         AFS_RELE(AFSTOV(avc)); /* VN_HOLD at set CCore(afs_FakeClose)*/
63         crfree((struct AFS_UCRED *)avc->linkData);      /* "crheld" in afs_FakeClose */
64         avc->linkData = (char *)0;
65     }
66     /* Now, send the file back.  Used to require 0 writers left, but now do
67      * it on every close for write, since two closes in a row are harmless
68      * since first will clean all chunks, and second will be noop.  Note that
69      * this will also save confusion when someone keeps a file open 
70      * inadvertently, since with old system, writes to the server would never
71      * happen again. 
72      */
73     code = afs_StoreAllSegments(avc, treq, AFS_LASTSTORE/*!sync-to-disk*/);
74     /*
75      * We have to do these after the above store in done: in some systems like
76      * aix they'll need to flush all the vm dirty pages to the disk via the
77      * strategy routine. During that all procedure (done under no avc locks)
78      * opens, refcounts would be zero, since it didn't reach the afs_{rd,wr}
79      * routines which means the vcache is a perfect candidate for flushing!
80      */
81 #if defined(AFS_SGI_ENV)
82     osi_Assert(avc->opens > 0 && avc->execsOrWriters > 0);
83 #endif
84     avc->opens--;
85     avc->execsOrWriters--;
86     return code;
87 }
88
89
90
91 afs_MemWrite(avc, auio, aio, acred, noLock)
92     register struct vcache *avc;
93     struct uio *auio;
94     int aio, noLock;
95     struct AFS_UCRED *acred; 
96 {
97     afs_size_t totalLength;
98     afs_size_t transferLength;
99     afs_size_t filePos;
100     afs_size_t offset, len;
101     afs_int32 tlen, trimlen;
102     afs_int32 startDate;
103     afs_int32 max;
104     register struct dcache *tdc;
105 #ifdef _HIGHC_
106     volatile
107 #endif
108     afs_int32 error;
109     struct uio tuio;
110     struct iovec *tvec;  /* again, should have define */
111     char *tfile;
112     register afs_int32 code;
113     struct vrequest treq;
114
115     AFS_STATCNT(afs_MemWrite);
116     if (avc->vc_error)
117         return avc->vc_error;
118
119     startDate = osi_Time();
120     if (code = afs_InitReq(&treq, acred)) return code;
121     /* otherwise we read */
122     totalLength = auio->afsio_resid;
123     filePos = auio->afsio_offset;
124     error = 0;
125     transferLength = 0;
126     afs_Trace4(afs_iclSetp, CM_TRACE_WRITE, ICL_TYPE_POINTER, avc, 
127                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
128                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(totalLength),
129                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
130     if (!noLock) {
131         afs_MaybeWakeupTruncateDaemon();
132         ObtainWriteLock(&avc->lock,126);
133     }
134 #if defined(AFS_SGI_ENV)
135     {
136     off_t diff;
137     /*
138      * afs_xwrite handles setting m.Length
139      * and handles APPEND mode.
140      * Since we are called via strategy, we need to trim the write to
141      * the actual size of the file
142      */
143     osi_Assert(filePos <= avc->m.Length);
144     diff = avc->m.Length - filePos;
145     auio->afsio_resid = MIN(totalLength, diff);
146     totalLength = auio->afsio_resid;
147     }
148 #else
149     if (aio & IO_APPEND) {
150         /* append mode, start it at the right spot */
151 #if     defined(AFS_SUN56_ENV)
152         auio->uio_loffset = 0;
153 #endif
154         filePos = auio->afsio_offset = avc->m.Length;
155     }
156 #endif
157     /*
158      * Note that we use startDate rather than calling osi_Time() here.
159      * This is to avoid counting lock-waiting time in file date (for ranlib).
160      */
161     avc->m.Date = startDate;
162
163 #if     defined(AFS_HPUX_ENV) || defined(AFS_GFS_ENV)
164 #if     defined(AFS_HPUX101_ENV)
165     if ((totalLength + filePos) >> 9 > (p_rlimit(u.u_procp))[RLIMIT_FSIZE].rlim_cur) {
166 #else
167 #ifdef  AFS_HPUX_ENV
168     if ((totalLength + filePos) >> 9 > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
169 #else
170     if (totalLength + filePos > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
171 #endif
172 #endif
173         if (!noLock)
174             ReleaseWriteLock(&avc->lock);
175         return (EFBIG);
176     }
177 #endif
178 #ifdef AFS_VM_RDWR_ENV
179     /*
180      * If write is implemented via VM, afs_FakeOpen() is called from the
181      * high-level write op.
182      */
183     if (avc->execsOrWriters <= 0) {
184         printf("WARNING: afs_ufswr vp=%x, exOrW=%d\n", avc, avc->execsOrWriters);
185     }
186 #else
187     afs_FakeOpen(avc);
188 #endif
189     avc->states |= CDirty;
190     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
191     while (totalLength > 0) {
192         /* Read the cached info. If we call GetDCache while the cache
193          * truncate daemon is running we risk overflowing the disk cache.
194          * Instead we check for an existing cache slot. If we cannot
195          * find an existing slot we wait for the cache to drain
196          * before calling GetDCache.
197          */
198         if (noLock) {
199             tdc = afs_FindDCache(avc, filePos);
200             if (tdc) ObtainWriteLock(&tdc->lock, 653);
201         } else if (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
202             tdc = afs_FindDCache(avc, filePos);
203             if (tdc) {
204                 ObtainWriteLock(&tdc->lock, 654);
205                 if (!hsame(tdc->f.versionNo, avc->m.DataVersion) ||
206                     (tdc->dflags & DFFetching)) {
207                     ReleaseWriteLock(&tdc->lock);
208                     afs_PutDCache(tdc);
209                     tdc = NULL;
210                 }
211             }
212             if (!tdc) {
213                 afs_MaybeWakeupTruncateDaemon();
214                 while (afs_blocksUsed >
215                        (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
216                     ReleaseWriteLock(&avc->lock);
217                     if (afs_blocksUsed - afs_blocksDiscarded >
218                         (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
219                         afs_WaitForCacheDrain = 1;
220                         afs_osi_Sleep(&afs_WaitForCacheDrain);
221                     }
222                     afs_MaybeFreeDiscardedDCache();
223                     afs_MaybeWakeupTruncateDaemon();
224                     ObtainWriteLock(&avc->lock,506);
225                 }
226                 avc->states |= CDirty;
227                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
228                 if (tdc) ObtainWriteLock(&tdc->lock, 655);
229             }
230         } else {
231             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
232             if (tdc) ObtainWriteLock(&tdc->lock, 656);
233         }
234         if (!tdc) {
235             error = EIO;
236             break;
237         }
238         if (!(afs_indexFlags[tdc->index] & IFDataMod)) {
239           afs_stats_cmperf.cacheCurrDirtyChunks++;
240           afs_indexFlags[tdc->index] |= IFDataMod;    /* so it doesn't disappear */
241         }
242         if (!(tdc->f.states & DWriting)) {
243             /* don't mark entry as mod if we don't have to */
244             tdc->f.states |= DWriting;
245             tdc->dflags |= DFEntryMod;
246         }
247         len = totalLength;      /* write this amount by default */
248         offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
249         max = AFS_CHUNKTOSIZE(tdc->f.chunk);    /* max size of this chunk */
250         if (max <= len + offset)        {   /*if we'd go past the end of this chunk */
251             /* it won't all fit in this chunk, so write as much
252                 as will fit */
253             len = max - offset;
254         }
255         /* mung uio structure to be right for this transfer */
256         afsio_copy(auio, &tuio, tvec);
257         trimlen = len;
258         afsio_trim(&tuio, trimlen);
259         tuio.afsio_offset = offset;
260
261         code = afs_MemWriteUIO(tdc->f.inode, &tuio);
262         if (code) {
263             void *mep; /* XXX in prototype world is struct memCacheEntry * */
264             error = code;
265             ZapDCE(tdc);                /* bad data */
266             mep = afs_MemCacheOpen(tdc->f.inode);
267             afs_MemCacheTruncate(mep, 0);
268             afs_MemCacheClose(mep);
269             afs_stats_cmperf.cacheCurrDirtyChunks--;
270             afs_indexFlags[tdc->index] &= ~IFDataMod;    /* so it does disappear */
271             ReleaseWriteLock(&tdc->lock);
272             afs_PutDCache(tdc);
273             break;
274         }
275         /* otherwise we've written some, fixup length, etc and continue with next seg */
276         len = len - tuio.afsio_resid; /* compute amount really transferred */
277         tlen = len;
278         afsio_skip(auio, tlen);     /* advance auio over data written */
279         /* compute new file size */
280         if (offset + len > tdc->f.chunkBytes) {
281             afs_int32 tlength = offset+len;
282             afs_AdjustSize(tdc, tlength);
283         }
284         totalLength -= len;
285         transferLength += len;
286         filePos += len;
287 #if defined(AFS_SGI_ENV)
288         /* afs_xwrite handles setting m.Length */
289         osi_Assert(filePos <= avc->m.Length);
290 #else
291         if (filePos > avc->m.Length) {
292             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
293                 ICL_TYPE_STRING, __FILE__,
294                 ICL_TYPE_LONG, __LINE__,
295                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
296                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos));
297             avc->m.Length = filePos;
298         }
299 #endif
300         ReleaseWriteLock(&tdc->lock);
301         afs_PutDCache(tdc);
302 #if !defined(AFS_VM_RDWR_ENV) || defined(AFS_LINUX22_ENV)
303         /*
304          * If write is implemented via VM, afs_DoPartialWrite() is called from
305          * the high-level write op.
306          */
307         if (!noLock) {
308             code = afs_DoPartialWrite(avc, &treq);
309             if (code) {
310                 error = code;
311                 break;
312             }
313         }
314 #endif
315     }
316 #ifndef AFS_VM_RDWR_ENV
317     afs_FakeClose(avc, acred);
318 #endif
319     if (error && !avc->vc_error)
320         avc->vc_error = error;
321     if (!noLock)
322         ReleaseWriteLock(&avc->lock);
323     osi_FreeSmallSpace(tvec);
324 #ifdef AFS_DEC_ENV
325     /* next, on GFS systems, we update g_size so that lseek's relative to EOF will
326        work.  GFS is truly a poorly-designed interface!  */
327     afs_gfshack((struct gnode *) avc);
328 #endif
329     error = afs_CheckCode(error, &treq, 6);
330     return error;
331 }
332
333
334 /* called on writes */
335 afs_UFSWrite(avc, auio, aio, acred, noLock)
336     register struct vcache *avc;
337     struct uio *auio;
338     int aio, noLock;
339     struct AFS_UCRED *acred; 
340 {
341     afs_size_t totalLength;
342     afs_size_t transferLength;
343     afs_size_t filePos;
344     afs_size_t offset, len;
345     afs_int32  tlen;
346     afs_int32  trimlen;
347     afs_int32 startDate;
348     afs_int32 max;
349     register struct dcache *tdc;
350 #ifdef _HIGHC_
351     volatile
352 #endif
353     afs_int32 error;
354     struct uio tuio;
355     struct iovec *tvec;  /* again, should have define */
356     struct osi_file *tfile;
357     register afs_int32 code;
358     struct vnode *vp;
359     struct vrequest treq;
360
361     AFS_STATCNT(afs_UFSWrite);
362     if (avc->vc_error)
363         return avc->vc_error;
364
365     startDate = osi_Time();
366     if (code = afs_InitReq(&treq, acred)) return code;
367     /* otherwise we read */
368     totalLength = auio->afsio_resid;
369     filePos = auio->afsio_offset;
370     error = 0;
371     transferLength = 0;
372     afs_Trace4(afs_iclSetp, CM_TRACE_WRITE, ICL_TYPE_POINTER, avc, 
373                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
374                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(totalLength),
375                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
376     if (!noLock) {
377         afs_MaybeWakeupTruncateDaemon();
378         ObtainWriteLock(&avc->lock,556);
379     }
380 #if defined(AFS_SGI_ENV)
381     {
382     off_t diff;
383     /*
384      * afs_xwrite handles setting m.Length
385      * and handles APPEND mode.
386      * Since we are called via strategy, we need to trim the write to
387      * the actual size of the file
388      */
389     osi_Assert(filePos <= avc->m.Length);
390     diff = avc->m.Length - filePos;
391     auio->afsio_resid = MIN(totalLength, diff);
392     totalLength = auio->afsio_resid;
393     }
394 #else
395     if (aio & IO_APPEND) {
396         /* append mode, start it at the right spot */
397 #if     defined(AFS_SUN56_ENV)
398         auio->uio_loffset = 0;
399 #endif
400         filePos = auio->afsio_offset = avc->m.Length;
401     }
402 #endif
403     /*
404      * Note that we use startDate rather than calling osi_Time() here.
405      * This is to avoid counting lock-waiting time in file date (for ranlib).
406      */
407     avc->m.Date = startDate;
408
409 #if     defined(AFS_HPUX_ENV) || defined(AFS_GFS_ENV)
410 #if     defined(AFS_HPUX101_ENV)
411     if ((totalLength + filePos) >> 9 > p_rlimit(u.u_procp)[RLIMIT_FSIZE].rlim_cur) {
412 #else
413 #ifdef  AFS_HPUX_ENV
414     if ((totalLength + filePos) >> 9 > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
415 #else
416     if (totalLength + filePos > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
417 #endif
418 #endif
419         if (!noLock)
420             ReleaseWriteLock(&avc->lock);
421         return (EFBIG);
422     }
423 #endif
424 #ifdef  AFS_VM_RDWR_ENV
425     /*
426      * If write is implemented via VM, afs_FakeOpen() is called from the
427      * high-level write op.
428      */
429     if (avc->execsOrWriters <= 0) {
430         printf("WARNING: afs_ufswr vp=%x, exOrW=%d\n", avc, avc->execsOrWriters);
431     }
432 #else
433     afs_FakeOpen(avc);
434 #endif
435     avc->states |= CDirty;
436     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
437     while (totalLength > 0) {
438         /* read the cached info */
439         if (noLock) {
440             tdc = afs_FindDCache(avc, filePos);
441             if (tdc) ObtainWriteLock(&tdc->lock, 657);
442         } else if (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
443             tdc = afs_FindDCache(avc, filePos);
444             if (tdc) {
445                 ObtainWriteLock(&tdc->lock, 658);
446                 if (!hsame(tdc->f.versionNo, avc->m.DataVersion) ||
447                     (tdc->dflags & DFFetching)) {
448                     ReleaseWriteLock(&tdc->lock);
449                     afs_PutDCache(tdc);
450                     tdc = NULL;
451                 }
452             }
453             if (!tdc) {
454                 afs_MaybeWakeupTruncateDaemon();
455                 while (afs_blocksUsed >
456                        (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
457                     ReleaseWriteLock(&avc->lock);
458                     if (afs_blocksUsed - afs_blocksDiscarded >
459                         (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
460                         afs_WaitForCacheDrain = 1;
461                         afs_osi_Sleep(&afs_WaitForCacheDrain);
462                     }
463                     afs_MaybeFreeDiscardedDCache();
464                     afs_MaybeWakeupTruncateDaemon();
465                     ObtainWriteLock(&avc->lock,509);
466                 }
467                 avc->states |= CDirty;
468                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
469                 if (tdc) ObtainWriteLock(&tdc->lock, 659);
470             }
471         } else {
472             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
473             if (tdc) ObtainWriteLock(&tdc->lock, 660);
474         }
475         if (!tdc) {
476             error = EIO;
477             break;
478         }
479         if (!(afs_indexFlags[tdc->index] & IFDataMod)) {
480           afs_stats_cmperf.cacheCurrDirtyChunks++;
481           afs_indexFlags[tdc->index] |= IFDataMod;    /* so it doesn't disappear */
482         }
483         if (!(tdc->f.states & DWriting)) {
484             /* don't mark entry as mod if we don't have to */
485             tdc->f.states |= DWriting;
486             tdc->dflags |= DFEntryMod;
487         }
488         tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
489         len = totalLength;      /* write this amount by default */
490         offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
491         max = AFS_CHUNKTOSIZE(tdc->f.chunk);    /* max size of this chunk */
492         if (max <= len + offset)        {   /*if we'd go past the end of this chunk */
493             /* it won't all fit in this chunk, so write as much
494                 as will fit */
495             len = max - offset;
496         }
497         /* mung uio structure to be right for this transfer */
498         afsio_copy(auio, &tuio, tvec);
499         trimlen = len;
500         afsio_trim(&tuio, trimlen);
501         tuio.afsio_offset = offset;
502 #ifdef  AFS_AIX_ENV
503 #ifdef  AFS_AIX41_ENV
504         AFS_GUNLOCK();
505         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, &tuio, NULL, NULL, NULL, &afs_osi_cred);
506         AFS_GLOCK();
507 #else
508 #ifdef AFS_AIX32_ENV
509         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, &tuio, NULL, NULL);
510 #else
511         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, (off_t)&offset, &tuio, NULL, NULL, -1);
512 #endif
513 #endif /* AFS_AIX41_ENV */
514 #else /* AFS_AIX_ENV */
515 #ifdef  AFS_SUN5_ENV
516         AFS_GUNLOCK();
517         VOP_RWLOCK(tfile->vnode, 1);
518         code = VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred);
519         VOP_RWUNLOCK(tfile->vnode, 1);
520         AFS_GLOCK();
521         if (code == ENOSPC) afs_warnuser("\n\n\n*** Cache partition is full - decrease cachesize!!! ***\n\n\n"); 
522 #else
523 #if defined(AFS_SGI_ENV)
524         AFS_GUNLOCK();
525         avc->states |= CWritingUFS;
526         AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_WRITE);
527         AFS_VOP_WRITE(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred, code);
528         AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_WRITE);
529         avc->states &= ~CWritingUFS;
530         AFS_GLOCK();
531 #else
532 #ifdef  AFS_OSF_ENV
533     {
534         struct ucred *tmpcred = u.u_cred;
535         u.u_cred = &afs_osi_cred;
536         tuio.uio_rw = UIO_WRITE;
537         AFS_GUNLOCK();
538         VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
539         AFS_GLOCK();
540         u.u_cred = tmpcred;
541     }
542 #else   /* AFS_OSF_ENV */
543 #if defined(AFS_HPUX100_ENV)
544     {
545         AFS_GUNLOCK();
546         code = VOP_RDWR(tfile->vnode, &tuio, UIO_WRITE, 0, &afs_osi_cred);
547         AFS_GLOCK();
548     }
549 #else
550 #ifdef  AFS_HPUX_ENV
551         tuio.uio_fpflags &= ~FSYNCIO;   /* don't do sync io */
552 #endif
553 #if defined(AFS_LINUX20_ENV)
554         AFS_GUNLOCK();
555         code = osi_file_uio_rdwr(tfile, &tuio, UIO_WRITE);
556         AFS_GLOCK();
557 #else
558 #if defined(AFS_DARWIN_ENV)
559         AFS_GUNLOCK();
560         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
561         code = VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred);
562         VOP_UNLOCK(tfile->vnode, 0, current_proc());
563         AFS_GLOCK();
564 #else
565 #if defined(AFS_FBSD_ENV)
566         AFS_GUNLOCK();
567         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
568         code = VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred);
569         VOP_UNLOCK(tfile->vnode, 0, curproc);
570         AFS_GLOCK();
571 #else
572         code = VOP_RDWR(tfile->vnode, &tuio, UIO_WRITE, 0, &afs_osi_cred);
573 #endif /* AFS_FBSD_ENV */
574 #endif /* AFS_DARWIN_ENV */
575 #endif /* AFS_LINUX20_ENV */
576 #endif /* AFS_HPUX100_ENV */
577 #endif /* AFS_OSF_ENV */
578 #endif /* AFS_SGI_ENV */
579 #endif /* AFS_SUN5_ENV */
580 #endif /* AFS_AIX41_ENV */
581         if (code) {
582             error = code;
583             ZapDCE(tdc);                /* bad data */
584             osi_UFSTruncate(tfile,0);   /* fake truncate the segment */
585             afs_AdjustSize(tdc, 0);     /* sets f.chunkSize to 0 */
586             afs_stats_cmperf.cacheCurrDirtyChunks--;
587             afs_indexFlags[tdc->index] &= ~IFDataMod;    /* so it does disappear */
588             afs_CFileClose(tfile);
589             ReleaseWriteLock(&tdc->lock);
590             afs_PutDCache(tdc);
591             break;
592         }
593         /* otherwise we've written some, fixup length, etc and continue with next seg */
594         len = len - tuio.afsio_resid; /* compute amount really transferred */
595         tlen = len;
596         afsio_skip(auio, tlen);     /* advance auio over data written */
597         /* compute new file size */
598         if (offset + len > tdc->f.chunkBytes) {
599             afs_int32 tlength = offset+len;
600             afs_AdjustSize(tdc, tlength);
601         }
602         totalLength -= len;
603         transferLength += len;
604         filePos += len;
605 #if defined(AFS_SGI_ENV)
606         /* afs_xwrite handles setting m.Length */
607         osi_Assert(filePos <= avc->m.Length);
608 #else
609         if (filePos > avc->m.Length) {
610             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
611                 ICL_TYPE_STRING, __FILE__,
612                 ICL_TYPE_LONG, __LINE__,
613                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
614                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos));
615             avc->m.Length = filePos;
616         }
617 #endif
618         osi_UFSClose(tfile);
619         ReleaseWriteLock(&tdc->lock);
620         afs_PutDCache(tdc);
621 #if !defined(AFS_VM_RDWR_ENV) || defined(AFS_LINUX22_ENV)
622         /*
623          * If write is implemented via VM, afs_DoPartialWrite() is called from
624          * the high-level write op.
625          */
626         if (!noLock) {
627             code = afs_DoPartialWrite(avc, &treq);
628             if (code) {
629                 error = code;
630                 break;
631             }
632         }
633 #endif
634     }
635 #ifndef AFS_VM_RDWR_ENV
636     afs_FakeClose(avc, acred);
637 #endif
638     error = afs_CheckCode(error, &treq, 7);
639     /* This set is here so we get the CheckCode. */
640     if (error && !avc->vc_error)
641         avc->vc_error = error;
642     if (!noLock)
643         ReleaseWriteLock(&avc->lock);
644     osi_FreeSmallSpace(tvec);
645 #ifdef AFS_DEC_ENV
646     /* next, on GFS systems, we update g_size so that lseek's relative to EOF will
647        work.  GFS is truly a poorly-designed interface!  */
648     afs_gfshack((struct gnode *) avc);
649 #endif
650 #ifndef AFS_VM_RDWR_ENV
651     /*
652      * If write is implemented via VM, afs_fsync() is called from the high-level
653      * write op.
654      */
655 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
656      if (noLock && (aio & IO_SYNC)) {
657 #else 
658 #ifdef  AFS_HPUX_ENV
659     /* On hpux on synchronous writes syncio will be set to IO_SYNC. If
660      * we're doing them because the file was opened with O_SYNCIO specified,
661      * we have to look in the u area. No single mechanism here!!
662      */
663     if (noLock && ((aio & IO_SYNC) | (auio->uio_fpflags & FSYNCIO))) {    
664 #else
665     if (noLock && (aio & FSYNC)) {
666 #endif
667 #endif
668         if (!AFS_NFSXLATORREQ(acred))
669             afs_fsync(avc, acred);
670     }
671 #endif
672     return error;
673 }
674
675 /* do partial write if we're low on unmodified chunks */
676 afs_DoPartialWrite(avc, areq)
677 register struct vcache *avc;
678 struct vrequest *areq; {
679     register afs_int32 code;
680
681     if (afs_stats_cmperf.cacheCurrDirtyChunks <= afs_stats_cmperf.cacheMaxDirtyChunks) 
682         return 0;       /* nothing to do */
683     /* otherwise, call afs_StoreDCache (later try to do this async, if possible) */
684     afs_Trace2(afs_iclSetp, CM_TRACE_PARTIALWRITE, ICL_TYPE_POINTER, avc,
685                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
686 #if     defined(AFS_SUN5_ENV)
687     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC | AFS_VMSYNC_INVAL);
688 #else
689     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC);
690 #endif
691     return code;
692 }
693
694
695
696 #if !defined (AFS_AIX_ENV) && !defined (AFS_HPUX_ENV) && !defined (AFS_SUN5_ENV) && !defined(AFS_SGI_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_FBSD_ENV)
697 #ifdef AFS_DUX50_ENV
698 #define vno_close(X) vn_close((X), 0, NOCRED)
699 #elif defined(AFS_DUX40_ENV)
700 #define      vno_close       vn_close
701 #endif
702 /* We don't need this for AIX since: 
703  * (1) aix doesn't use fileops and it call close directly intead
704  * (where the unlocking should be done) and 
705  * (2) temporarily, the aix lockf isn't supported yet.
706  *
707  *  this stupid routine is used to release the flocks held on a
708  *  particular file descriptor.  Sun doesn't pass file descr. info
709  *  through to the vnode layer, and yet we must unlock flocked files
710  *  on the *appropriate* (not first, as in System V) close call.  Thus
711  *  this code.
712  * How does this code get invoked? The afs AFS_FLOCK plugs in the new afs
713  * file ops structure into any afs file when it gets flocked. 
714  * N.B: Intercepting close syscall doesn't trap aborts or exit system
715  * calls.
716 */
717 afs_closex(afd)
718     register struct file *afd; {
719     struct vrequest treq;
720     struct vcache *tvc;
721     afs_int32 flags;
722     int closeDone;
723     afs_int32 code = 0;
724     struct afs_fakestat_state fakestat;
725
726     AFS_STATCNT(afs_closex);
727     /* setup the credentials */
728     if (code = afs_InitReq(&treq, u.u_cred)) return code;
729     afs_InitFakeStat(&fakestat);
730
731     closeDone = 0;
732     /* we're the last one.  If we're an AFS vnode, clear the flags,
733      * close the file and release the lock when done.  Otherwise, just
734      * let the regular close code work.      */
735     if (afd->f_type == DTYPE_VNODE) {
736         tvc = VTOAFS(afd->f_data);
737         if (IsAfsVnode(AFSTOV(tvc))) {
738             code = afs_EvalFakeStat(&tvc, &fakestat, &treq);
739             if (code) {
740                 afs_PutFakeStat(&fakestat);
741                 return code;
742             }
743             VN_HOLD(AFSTOV(tvc));
744             flags = afd->f_flag & (FSHLOCK | FEXLOCK);
745             afd->f_flag &= ~(FSHLOCK | FEXLOCK);
746             code = vno_close(afd);
747             if (flags) 
748 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
749                 HandleFlock(tvc, LOCK_UN, &treq,
750                             u.u_procp->p_pid, 1/*onlymine*/);
751 #else
752                 HandleFlock(tvc, LOCK_UN, &treq, 0, 1/*onlymine*/);
753 #endif
754 #ifdef  AFS_DEC_ENV
755             grele((struct gnode *) tvc);
756 #else
757             AFS_RELE(AFSTOV(tvc));
758 #endif
759             closeDone = 1;
760         }
761     }
762     /* now, if close not done, do it */
763     if (!closeDone) {
764         code = vno_close(afd);
765     }
766     afs_PutFakeStat(&fakestat);
767     return code;        /* return code from vnode layer */
768 }
769 #endif
770
771
772 /* handle any closing cleanup stuff */
773 #ifdef  AFS_SGI_ENV
774 afs_close(OSI_VC_ARG(avc), aflags, lastclose,
775 #if !defined(AFS_SGI65_ENV)
776           offset,
777 #endif
778           acred
779 #if defined(AFS_SGI64_ENV) && !defined(AFS_SGI65_ENV)
780           , flp
781 #endif
782           )
783 lastclose_t lastclose;
784 #if !defined(AFS_SGI65_ENV)
785 off_t offset;
786 #if defined(AFS_SGI64_ENV)
787 struct flid *flp;
788 #endif
789 #endif
790 #else /* SGI */
791 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
792 #ifdef  AFS_SUN5_ENV
793 afs_close(OSI_VC_ARG(avc), aflags, count, offset, acred)
794     offset_t offset;
795 #else
796 afs_close(OSI_VC_ARG(avc), aflags, count, acred)
797 #endif
798 int count;
799 #else
800 afs_close(OSI_VC_ARG(avc), aflags, acred)
801 #endif
802 #endif
803     OSI_VC_DECL(avc);
804     afs_int32 aflags;
805     struct AFS_UCRED *acred; 
806 {
807     register afs_int32 code;
808     register struct brequest *tb;
809     struct vrequest treq;
810 #ifdef AFS_SGI65_ENV
811     struct flid flid;
812 #endif
813     struct afs_fakestat_state fakestat;
814     OSI_VC_CONVERT(avc)
815
816     AFS_STATCNT(afs_close);
817     afs_Trace2(afs_iclSetp, CM_TRACE_CLOSE, ICL_TYPE_POINTER, avc,
818                ICL_TYPE_INT32, aflags);
819     code = afs_InitReq(&treq, acred);
820     if (code) return code;
821     afs_InitFakeStat(&fakestat);
822     code = afs_EvalFakeStat(&avc, &fakestat, &treq);
823     if (code) {
824         afs_PutFakeStat(&fakestat);
825         return code;
826     }
827 #ifdef  AFS_SUN5_ENV
828     if (avc->flockCount) {
829         HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
830     }
831 #endif
832 #if defined(AFS_SGI_ENV)
833     if (!lastclose) {
834         afs_PutFakeStat(&fakestat);
835         return 0;
836     }
837 #else
838 #if     defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV)
839     if (count > 1) {
840         /* The vfs layer may call this repeatedly with higher "count"; only on the last close (i.e. count = 1) we should actually proceed with the close. */
841         afs_PutFakeStat(&fakestat);
842         return 0;
843     }
844 #endif
845 #endif
846 #ifndef AFS_SUN5_ENV
847 #if defined(AFS_SGI_ENV)
848     /* unlock any locks for pid - could be wrong for child .. */
849     AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
850 #ifdef AFS_SGI65_ENV
851     get_current_flid(&flid);
852     cleanlocks((vnode_t *)avc, flid.fl_pid, flid.fl_sysid);
853     HandleFlock(avc, LOCK_UN, &treq, flid.fl_pid, 1/*onlymine*/);
854 #else
855 #ifdef AFS_SGI64_ENV
856     cleanlocks((vnode_t *)avc, flp);
857 #else /* AFS_SGI64_ENV */
858     cleanlocks((vnode_t *)avc, u.u_procp->p_epid, u.u_procp->p_sysid);
859 #endif /* AFS_SGI64_ENV */
860     HandleFlock(avc, LOCK_UN, &treq, OSI_GET_CURRENT_PID(), 1/*onlymine*/);
861 #endif /* AFS_SGI65_ENV */
862     /* afs_chkpgoob will drop and re-acquire the global lock. */
863     afs_chkpgoob(&avc->v, btoc(avc->m.Length));
864 #else
865     if (avc->flockCount) {              /* Release Lock */
866 #if     defined(AFS_OSF_ENV) || defined(AFS_SUN_ENV)
867         HandleFlock(avc, LOCK_UN, &treq, u.u_procp->p_pid, 1/*onlymine*/);
868 #else
869         HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
870 #endif
871     }
872 #endif
873 #endif
874     if (aflags & (FWRITE | FTRUNC)) {
875         if (afs_BBusy()) {
876             /* do it yourself if daemons are all busy */
877             ObtainWriteLock(&avc->lock,124);
878             code = afs_StoreOnLastReference(avc, &treq);
879             ReleaseWriteLock(&avc->lock);
880 #if defined(AFS_SGI_ENV)
881             AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
882 #endif
883         }
884         else {
885 #if defined(AFS_SGI_ENV)
886             AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
887 #endif
888             /* at least one daemon is idle, so ask it to do the store.
889                 Also, note that  we don't lock it any more... */
890             tb = afs_BQueue(BOP_STORE, avc, 0, 1, acred,
891                                 (afs_size_t) acred->cr_uid, (afs_size_t) 0,
892                                 (void *) 0);
893             /* sleep waiting for the store to start, then retrieve error code */
894             while ((tb->flags & BUVALID) == 0) {
895                 tb->flags |= BUWAIT;
896                 afs_osi_Sleep(tb);
897             }
898             code = tb->code;
899             afs_BRelease(tb);
900         }
901
902         /* VNOVNODE is "acceptable" error code from close, since
903             may happen when deleting a file on another machine while
904             it is open here. We do the same for ENOENT since in afs_CheckCode we map VNOVNODE -> ENOENT */
905         if (code == VNOVNODE || code == ENOENT)
906             code = 0;
907         
908         /* Ensure last closer gets the error. If another thread caused
909          * DoPartialWrite and this thread does not actually store the data,
910          * it may not see the quota error.
911          */
912         ObtainWriteLock(&avc->lock,406);
913         if (avc->vc_error) {
914 #ifdef AFS_AIX32_ENV
915             osi_ReleaseVM(avc, acred);
916 #endif
917             code = avc->vc_error;
918             avc->vc_error = 0;
919         }
920         ReleaseWriteLock(&avc->lock);
921
922         /* some codes merit specific complaint */
923         if (code < 0) {
924             afs_warnuser("afs: failed to store file (network problems)\n");
925         }
926 #ifdef  AFS_SUN5_ENV
927         else if (code == ENOSPC) {
928             afs_warnuser("afs: failed to store file (over quota or partition full)\n");
929         }
930 #else
931         else if (code == ENOSPC) {
932             afs_warnuser("afs: failed to store file (partition full)\n");
933         }
934         else if (code == EDQUOT) {
935             afs_warnuser("afs: failed to store file (over quota)\n");
936         }
937 #endif
938         else if (code != 0)
939             afs_warnuser("afs: failed to store file (%d)\n", code);
940
941         /* finally, we flush any text pages lying around here */
942         hzero(avc->flushDV);
943         osi_FlushText(avc);
944     }
945     else {
946 #if defined(AFS_SGI_ENV)
947         AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
948         osi_Assert(avc->opens > 0);
949 #endif
950         /* file open for read */
951         ObtainWriteLock(&avc->lock, 411);
952         if (avc->vc_error) {
953 #ifdef AFS_AIX32_ENV
954             osi_ReleaseVM(avc, acred);
955 #endif
956             code = avc->vc_error;
957             avc->vc_error = 0;
958         }
959         avc->opens--;
960         ReleaseWriteLock(&avc->lock);
961     }
962 #ifdef  AFS_OSF_ENV
963     if ((VREFCOUNT(avc) <= 2) && (avc->states & CUnlinked)) {
964         afs_remunlink(avc, 1);  /* ignore any return code */
965     }
966 #endif
967     afs_PutFakeStat(&fakestat);
968     code = afs_CheckCode(code, &treq, 5);
969     return code;
970 }
971
972
973
974 #ifdef  AFS_OSF_ENV
975 afs_fsync(avc, fflags, acred, waitfor)
976 int fflags;
977 int waitfor;
978 #else   /* AFS_OSF_ENV */
979 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
980 afs_fsync(OSI_VC_ARG(avc), flag, acred
981 #ifdef AFS_SGI65_ENV
982           , start, stop
983 #endif
984           )
985 #else
986 afs_fsync(avc, acred)
987 #endif
988 #endif
989     OSI_VC_DECL(avc);
990      struct AFS_UCRED *acred;
991 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
992 int flag;
993 #ifdef AFS_SGI65_ENV
994 off_t start, stop;
995 #endif
996 #endif
997 {
998     register afs_int32 code;
999     struct vrequest treq;
1000     OSI_VC_CONVERT(avc)
1001
1002     if (avc->vc_error)
1003         return avc->vc_error;
1004
1005 #if defined(AFS_SUN5_ENV)
1006      /* back out if called from NFS server */
1007     if (curthread->t_flag & T_DONTPEND)
1008         return 0;
1009 #endif
1010
1011     AFS_STATCNT(afs_fsync);
1012     afs_Trace1(afs_iclSetp, CM_TRACE_FSYNC, ICL_TYPE_POINTER, avc);
1013     if (code = afs_InitReq(&treq, acred)) return code;
1014
1015 #if defined(AFS_SGI_ENV)
1016     AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
1017     if (flag & FSYNC_INVAL)
1018         osi_VM_FSyncInval(avc);
1019 #endif /* AFS_SGI_ENV */
1020
1021     ObtainSharedLock(&avc->lock,18);
1022     code = 0;
1023     if (avc->execsOrWriters > 0) {
1024         /* put the file back */
1025         UpgradeSToWLock(&avc->lock,41);
1026         code = afs_StoreAllSegments(avc, &treq, AFS_SYNC);
1027         ConvertWToSLock(&avc->lock);
1028     }
1029
1030 #if defined(AFS_SGI_ENV)
1031     AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
1032     if (code == VNOVNODE) {
1033         /* syncing an unlinked file! - non-informative to pass an errno
1034          * 102 (== VNOVNODE) to user
1035          */
1036         code =  ENOENT;
1037     }
1038 #endif
1039
1040     code = afs_CheckCode(code, &treq, 33);
1041     ReleaseSharedLock(&avc->lock);
1042     return code;
1043 }