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