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