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