31688c404c9a9435b271f428ac5b596d2c0a5eb8
[openafs.git] / src / afs / VNOPS / afs_vnop_write.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * Implements:
12  * afs_UFSWrite
13  * afs_MemWrite
14  * afs_StoreOnLastReference
15  * afs_close
16  * afs_closex
17  * afs_fsync
18  */
19
20 #include <afsconfig.h>
21 #include "../afs/param.h"
22
23 RCSID("$Header$");
24
25 #include "../afs/sysincludes.h" /* Standard vendor system headers */
26 #include "../afs/afsincludes.h" /* Afs-based standard headers */
27 #include "../afs/afs_stats.h" /* statistics */
28 #include "../afs/afs_cbqueue.h"
29 #include "../afs/nfsclient.h"
30 #include "../afs/afs_osidnlc.h"
31
32
33 extern unsigned char *afs_indexFlags;
34
35 /* Called by all write-on-close routines: regular afs_close,
36  * store via background daemon and store via the
37  * afs_FlushActiveVCaches routine (when CCORE is on).
38  * avc->lock must be write-locked.
39  */
40 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     char *tfile;
107     register afs_int32 code;
108     struct vrequest treq;
109
110     AFS_STATCNT(afs_MemWrite);
111     if (avc->vc_error)
112         return avc->vc_error;
113
114     startDate = osi_Time();
115     if ((code = afs_InitReq(&treq, acred))) return code;
116     /* otherwise we read */
117     totalLength = auio->afsio_resid;
118     filePos = auio->afsio_offset;
119     error = 0;
120     transferLength = 0;
121     afs_Trace4(afs_iclSetp, CM_TRACE_WRITE, ICL_TYPE_POINTER, avc, 
122                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
123                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(totalLength),
124                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
125     if (!noLock) {
126         afs_MaybeWakeupTruncateDaemon();
127         ObtainWriteLock(&avc->lock,126);
128     }
129 #if defined(AFS_SGI_ENV)
130     {
131     off_t diff;
132     /*
133      * afs_xwrite handles setting m.Length
134      * and handles APPEND mode.
135      * Since we are called via strategy, we need to trim the write to
136      * the actual size of the file
137      */
138     osi_Assert(filePos <= avc->m.Length);
139     diff = avc->m.Length - filePos;
140     auio->afsio_resid = MIN(totalLength, diff);
141     totalLength = auio->afsio_resid;
142     }
143 #else
144     if (aio & IO_APPEND) {
145         /* append mode, start it at the right spot */
146 #if     defined(AFS_SUN56_ENV)
147         auio->uio_loffset = 0;
148 #endif
149         filePos = auio->afsio_offset = avc->m.Length;
150     }
151 #endif
152     /*
153      * Note that we use startDate rather than calling osi_Time() here.
154      * This is to avoid counting lock-waiting time in file date (for ranlib).
155      */
156     avc->m.Date = startDate;
157
158 #if     defined(AFS_HPUX_ENV) || defined(AFS_GFS_ENV)
159 #if     defined(AFS_HPUX101_ENV)
160     if ((totalLength + filePos) >> 9 > (p_rlimit(u.u_procp))[RLIMIT_FSIZE].rlim_cur) {
161 #else
162 #ifdef  AFS_HPUX_ENV
163     if ((totalLength + filePos) >> 9 > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
164 #else
165     if (totalLength + filePos > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
166 #endif
167 #endif
168         if (!noLock)
169             ReleaseWriteLock(&avc->lock);
170         return (EFBIG);
171     }
172 #endif
173 #ifdef AFS_VM_RDWR_ENV
174     /*
175      * If write is implemented via VM, afs_FakeOpen() is called from the
176      * high-level write op.
177      */
178     if (avc->execsOrWriters <= 0) {
179         printf("WARNING: afs_ufswr vp=%x, exOrW=%d\n", avc, avc->execsOrWriters);
180     }
181 #else
182     afs_FakeOpen(avc);
183 #endif
184     avc->states |= CDirty;
185     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
186     while (totalLength > 0) {
187         /* Read the cached info. If we call GetDCache while the cache
188          * truncate daemon is running we risk overflowing the disk cache.
189          * Instead we check for an existing cache slot. If we cannot
190          * find an existing slot we wait for the cache to drain
191          * before calling GetDCache.
192          */
193         if (noLock) {
194             tdc = afs_FindDCache(avc, filePos);
195             if (tdc) ObtainWriteLock(&tdc->lock, 653);
196         } else if (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
197             tdc = afs_FindDCache(avc, filePos);
198             if (tdc) {
199                 ObtainWriteLock(&tdc->lock, 654);
200                 if (!hsame(tdc->f.versionNo, avc->m.DataVersion) ||
201                     (tdc->dflags & DFFetching)) {
202                     ReleaseWriteLock(&tdc->lock);
203                     afs_PutDCache(tdc);
204                     tdc = NULL;
205                 }
206             }
207             if (!tdc) {
208                 afs_MaybeWakeupTruncateDaemon();
209                 while (afs_blocksUsed >
210                        (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
211                     ReleaseWriteLock(&avc->lock);
212                     if (afs_blocksUsed - afs_blocksDiscarded >
213                         (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
214                         afs_WaitForCacheDrain = 1;
215                         afs_osi_Sleep(&afs_WaitForCacheDrain);
216                     }
217                     afs_MaybeFreeDiscardedDCache();
218                     afs_MaybeWakeupTruncateDaemon();
219                     ObtainWriteLock(&avc->lock,506);
220                 }
221                 avc->states |= CDirty;
222                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
223                 if (tdc) ObtainWriteLock(&tdc->lock, 655);
224             }
225         } else {
226             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
227             if (tdc) ObtainWriteLock(&tdc->lock, 656);
228         }
229         if (!tdc) {
230             error = EIO;
231             break;
232         }
233         if (!(afs_indexFlags[tdc->index] & IFDataMod)) {
234           afs_stats_cmperf.cacheCurrDirtyChunks++;
235           afs_indexFlags[tdc->index] |= IFDataMod;    /* so it doesn't disappear */
236         }
237         if (!(tdc->f.states & DWriting)) {
238             /* don't mark entry as mod if we don't have to */
239             tdc->f.states |= DWriting;
240             tdc->dflags |= DFEntryMod;
241         }
242         len = totalLength;      /* write this amount by default */
243         offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
244         max = AFS_CHUNKTOSIZE(tdc->f.chunk);    /* max size of this chunk */
245         if (max <= len + offset)        {   /*if we'd go past the end of this chunk */
246             /* it won't all fit in this chunk, so write as much
247                 as will fit */
248             len = max - offset;
249         }
250         /* mung uio structure to be right for this transfer */
251         afsio_copy(auio, &tuio, tvec);
252         trimlen = len;
253         afsio_trim(&tuio, trimlen);
254         tuio.afsio_offset = offset;
255
256         code = afs_MemWriteUIO(tdc->f.inode, &tuio);
257         if (code) {
258             void *mep; /* XXX in prototype world is struct memCacheEntry * */
259             error = code;
260             ZapDCE(tdc);                /* bad data */
261             mep = afs_MemCacheOpen(tdc->f.inode);
262             afs_MemCacheTruncate(mep, 0);
263             afs_MemCacheClose(mep);
264             afs_stats_cmperf.cacheCurrDirtyChunks--;
265             afs_indexFlags[tdc->index] &= ~IFDataMod;    /* so it does disappear */
266             ReleaseWriteLock(&tdc->lock);
267             afs_PutDCache(tdc);
268             break;
269         }
270         /* otherwise we've written some, fixup length, etc and continue with next seg */
271         len = len - tuio.afsio_resid; /* compute amount really transferred */
272         tlen = len;
273         afsio_skip(auio, tlen);     /* advance auio over data written */
274         /* compute new file size */
275         if (offset + len > tdc->f.chunkBytes) {
276             afs_int32 tlength = offset+len;
277             afs_AdjustSize(tdc, tlength);
278         }
279         totalLength -= len;
280         transferLength += len;
281         filePos += len;
282 #if defined(AFS_SGI_ENV)
283         /* afs_xwrite handles setting m.Length */
284         osi_Assert(filePos <= avc->m.Length);
285 #else
286         if (filePos > avc->m.Length) {
287             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
288                 ICL_TYPE_STRING, __FILE__,
289                 ICL_TYPE_LONG, __LINE__,
290                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
291                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos));
292             avc->m.Length = filePos;
293         }
294 #endif
295         ReleaseWriteLock(&tdc->lock);
296         afs_PutDCache(tdc);
297 #if !defined(AFS_VM_RDWR_ENV)
298         /*
299          * If write is implemented via VM, afs_DoPartialWrite() is called from
300          * the high-level write op.
301          */
302         if (!noLock) {
303             code = afs_DoPartialWrite(avc, &treq);
304             if (code) {
305                 error = code;
306                 break;
307             }
308         }
309 #endif
310     }
311 #ifndef AFS_VM_RDWR_ENV
312     afs_FakeClose(avc, acred);
313 #endif
314     if (error && !avc->vc_error)
315         avc->vc_error = error;
316     if (!noLock)
317         ReleaseWriteLock(&avc->lock);
318     osi_FreeSmallSpace(tvec);
319 #ifdef AFS_DEC_ENV
320     /* next, on GFS systems, we update g_size so that lseek's relative to EOF will
321        work.  GFS is truly a poorly-designed interface!  */
322     afs_gfshack((struct gnode *) avc);
323 #endif
324     error = afs_CheckCode(error, &treq, 6);
325     return error;
326 }
327
328
329 /* called on writes */
330 int afs_UFSWrite(register struct vcache *avc, struct uio *auio, 
331         int aio, struct AFS_UCRED *acred, int noLock)
332 {
333     afs_size_t totalLength;
334     afs_size_t transferLength;
335     afs_size_t filePos;
336     afs_size_t offset, len;
337     afs_int32  tlen;
338     afs_int32  trimlen;
339     afs_int32 startDate;
340     afs_int32 max;
341     register struct dcache *tdc;
342 #ifdef _HIGHC_
343     volatile
344 #endif
345     afs_int32 error;
346     struct uio tuio;
347     struct iovec *tvec;  /* again, should have define */
348     struct osi_file *tfile;
349     register afs_int32 code;
350     struct vnode *vp;
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 vp=%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 lines are 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         }
601         totalLength -= len;
602         transferLength += len;
603         filePos += len;
604 #if defined(AFS_SGI_ENV)
605         /* afs_xwrite handles setting m.Length */
606         osi_Assert(filePos <= avc->m.Length);
607 #else
608         if (filePos > avc->m.Length) {
609             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
610                 ICL_TYPE_STRING, __FILE__,
611                 ICL_TYPE_LONG, __LINE__,
612                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
613                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos));
614             avc->m.Length = filePos;
615         }
616 #endif
617         osi_UFSClose(tfile);
618         ReleaseWriteLock(&tdc->lock);
619         afs_PutDCache(tdc);
620 #if !defined(AFS_VM_RDWR_ENV)
621         /*
622          * If write is implemented via VM, afs_DoPartialWrite() is called from
623          * the high-level write op.
624          */
625         if (!noLock) {
626             code = afs_DoPartialWrite(avc, &treq);
627             if (code) {
628                 error = code;
629                 break;
630             }
631         }
632 #endif
633     }
634 #ifndef AFS_VM_RDWR_ENV
635     afs_FakeClose(avc, acred);
636 #endif
637     error = afs_CheckCode(error, &treq, 7);
638     /* This set is here so we get the CheckCode. */
639     if (error && !avc->vc_error)
640         avc->vc_error = error;
641     if (!noLock)
642         ReleaseWriteLock(&avc->lock);
643     osi_FreeSmallSpace(tvec);
644 #ifdef AFS_DEC_ENV
645     /* next, on GFS systems, we update g_size so that lseek's relative to EOF will
646        work.  GFS is truly a poorly-designed interface!  */
647     afs_gfshack((struct gnode *) avc);
648 #endif
649 #ifndef AFS_VM_RDWR_ENV
650     /*
651      * If write is implemented via VM, afs_fsync() is called from the high-level
652      * write op.
653      */
654 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
655      if (noLock && (aio & IO_SYNC)) {
656 #else 
657 #ifdef  AFS_HPUX_ENV
658     /* On hpux on synchronous writes syncio will be set to IO_SYNC. If
659      * we're doing them because the file was opened with O_SYNCIO specified,
660      * we have to look in the u area. No single mechanism here!!
661      */
662     if (noLock && ((aio & IO_SYNC) | (auio->uio_fpflags & FSYNCIO))) {    
663 #else
664     if (noLock && (aio & FSYNC)) {
665 #endif
666 #endif
667         if (!AFS_NFSXLATORREQ(acred))
668             afs_fsync(avc, acred);
669     }
670 #endif
671     return error;
672 }
673
674 /* do partial write if we're low on unmodified chunks */
675 int afs_DoPartialWrite(register struct vcache *avc, struct vrequest *areq)
676 {
677     register afs_int32 code;
678
679     if (afs_stats_cmperf.cacheCurrDirtyChunks <= afs_stats_cmperf.cacheMaxDirtyChunks) 
680         return 0;       /* nothing to do */
681     /* otherwise, call afs_StoreDCache (later try to do this async, if possible) */
682     afs_Trace2(afs_iclSetp, CM_TRACE_PARTIALWRITE, ICL_TYPE_POINTER, avc,
683                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
684 #if     defined(AFS_SUN5_ENV)
685     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC | AFS_VMSYNC_INVAL);
686 #else
687     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC);
688 #endif
689     return code;
690 }
691
692
693
694 #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)
695 #ifdef AFS_DUX50_ENV
696 #define vno_close(X) vn_close((X), 0, NOCRED)
697 #elif defined(AFS_DUX40_ENV)
698 #define      vno_close       vn_close
699 #endif
700 /* We don't need this for AIX since: 
701  * (1) aix doesn't use fileops and it call close directly intead
702  * (where the unlocking should be done) and 
703  * (2) temporarily, the aix lockf isn't supported yet.
704  *
705  *  this stupid routine is used to release the flocks held on a
706  *  particular file descriptor.  Sun doesn't pass file descr. info
707  *  through to the vnode layer, and yet we must unlock flocked files
708  *  on the *appropriate* (not first, as in System V) close call.  Thus
709  *  this code.
710  * How does this code get invoked? The afs AFS_FLOCK plugs in the new afs
711  * file ops structure into any afs file when it gets flocked. 
712  * N.B: Intercepting close syscall doesn't trap aborts or exit system
713  * calls.
714 */
715 int afs_closex(register struct file *afd)
716 {
717     struct vrequest treq;
718     struct vcache *tvc;
719     afs_int32 flags;
720     int closeDone;
721     afs_int32 code = 0;
722     struct afs_fakestat_state fakestat;
723
724     AFS_STATCNT(afs_closex);
725     /* setup the credentials */
726     if ((code = afs_InitReq(&treq, u.u_cred))) return code;
727     afs_InitFakeStat(&fakestat);
728
729     closeDone = 0;
730     /* we're the last one.  If we're an AFS vnode, clear the flags,
731      * close the file and release the lock when done.  Otherwise, just
732      * let the regular close code work.      */
733     if (afd->f_type == DTYPE_VNODE) {
734         tvc = VTOAFS(afd->f_data);
735         if (IsAfsVnode(AFSTOV(tvc))) {
736             code = afs_EvalFakeStat(&tvc, &fakestat, &treq);
737             if (code) {
738                 afs_PutFakeStat(&fakestat);
739                 return code;
740             }
741             VN_HOLD(AFSTOV(tvc));
742             flags = afd->f_flag & (FSHLOCK | FEXLOCK);
743             afd->f_flag &= ~(FSHLOCK | FEXLOCK);
744             code = vno_close(afd);
745             if (flags) 
746 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
747                 HandleFlock(tvc, LOCK_UN, &treq,
748                             u.u_procp->p_pid, 1/*onlymine*/);
749 #else
750                 HandleFlock(tvc, LOCK_UN, &treq, 0, 1/*onlymine*/);
751 #endif
752 #ifdef  AFS_DEC_ENV
753             grele((struct gnode *) tvc);
754 #else
755             AFS_RELE(AFSTOV(tvc));
756 #endif
757             closeDone = 1;
758         }
759     }
760     /* now, if close not done, do it */
761     if (!closeDone) {
762         code = vno_close(afd);
763     }
764     afs_PutFakeStat(&fakestat);
765     return code;        /* return code from vnode layer */
766 }
767 #endif
768
769
770 /* handle any closing cleanup stuff */
771 #ifdef  AFS_SGI_ENV
772 afs_close(OSI_VC_ARG(avc), aflags, lastclose,
773 #if !defined(AFS_SGI65_ENV)
774           offset,
775 #endif
776           acred
777 #if defined(AFS_SGI64_ENV) && !defined(AFS_SGI65_ENV)
778           , flp
779 #endif
780           )
781 lastclose_t lastclose;
782 #if !defined(AFS_SGI65_ENV)
783 off_t offset;
784 #if defined(AFS_SGI64_ENV)
785 struct flid *flp;
786 #endif
787 #endif
788 #else /* SGI */
789 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
790 #ifdef  AFS_SUN5_ENV
791 afs_close(OSI_VC_ARG(avc), aflags, count, offset, acred)
792     offset_t offset;
793 #else
794 afs_close(OSI_VC_ARG(avc), aflags, count, acred)
795 #endif
796 int count;
797 #else
798 afs_close(OSI_VC_ARG(avc), aflags, acred)
799 #endif
800 #endif
801     OSI_VC_DECL(avc);
802     afs_int32 aflags;
803     struct AFS_UCRED *acred; 
804 {
805     register afs_int32 code;
806     register struct brequest *tb;
807     struct vrequest treq;
808 #ifdef AFS_SGI65_ENV
809     struct flid flid;
810 #endif
811     struct afs_fakestat_state fakestat;
812     OSI_VC_CONVERT(avc)
813
814     AFS_STATCNT(afs_close);
815     afs_Trace2(afs_iclSetp, CM_TRACE_CLOSE, ICL_TYPE_POINTER, avc,
816                ICL_TYPE_INT32, aflags);
817     code = afs_InitReq(&treq, acred);
818     if (code) return code;
819     afs_InitFakeStat(&fakestat);
820     code = afs_EvalFakeStat(&avc, &fakestat, &treq);
821     if (code) {
822         afs_PutFakeStat(&fakestat);
823         return code;
824     }
825 #ifdef  AFS_SUN5_ENV
826     if (avc->flockCount) {
827         HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
828     }
829 #endif
830 #if defined(AFS_SGI_ENV)
831     if (!lastclose) {
832         afs_PutFakeStat(&fakestat);
833         return 0;
834     }
835 #else
836 #if     defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV)
837     if (count > 1) {
838         /* 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. */
839         afs_PutFakeStat(&fakestat);
840         return 0;
841     }
842 #endif
843 #endif
844 #ifndef AFS_SUN5_ENV
845 #if defined(AFS_SGI_ENV)
846     /* unlock any locks for pid - could be wrong for child .. */
847     AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
848 #ifdef AFS_SGI65_ENV
849     get_current_flid(&flid);
850     cleanlocks((vnode_t *)avc, flid.fl_pid, flid.fl_sysid);
851     HandleFlock(avc, LOCK_UN, &treq, flid.fl_pid, 1/*onlymine*/);
852 #else
853 #ifdef AFS_SGI64_ENV
854     cleanlocks((vnode_t *)avc, flp);
855 #else /* AFS_SGI64_ENV */
856     cleanlocks((vnode_t *)avc, u.u_procp->p_epid, u.u_procp->p_sysid);
857 #endif /* AFS_SGI64_ENV */
858     HandleFlock(avc, LOCK_UN, &treq, OSI_GET_CURRENT_PID(), 1/*onlymine*/);
859 #endif /* AFS_SGI65_ENV */
860     /* afs_chkpgoob will drop and re-acquire the global lock. */
861     afs_chkpgoob(&avc->v, btoc(avc->m.Length));
862 #else
863     if (avc->flockCount) {              /* Release Lock */
864 #if     defined(AFS_OSF_ENV) || defined(AFS_SUN_ENV)
865         HandleFlock(avc, LOCK_UN, &treq, u.u_procp->p_pid, 1/*onlymine*/);
866 #else
867         HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
868 #endif
869     }
870 #endif
871 #endif
872     if (aflags & (FWRITE | FTRUNC)) {
873         if (afs_BBusy()) {
874             /* do it yourself if daemons are all busy */
875             ObtainWriteLock(&avc->lock,124);
876             code = afs_StoreOnLastReference(avc, &treq);
877             ReleaseWriteLock(&avc->lock);
878 #if defined(AFS_SGI_ENV)
879             AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
880 #endif
881         }
882         else {
883 #if defined(AFS_SGI_ENV)
884             AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
885 #endif
886             /* at least one daemon is idle, so ask it to do the store.
887                 Also, note that  we don't lock it any more... */
888             tb = afs_BQueue(BOP_STORE, avc, 0, 1, acred,
889                                 (afs_size_t) acred->cr_uid, (afs_size_t) 0,
890                                 (void *) 0);
891             /* sleep waiting for the store to start, then retrieve error code */
892             while ((tb->flags & BUVALID) == 0) {
893                 tb->flags |= BUWAIT;
894                 afs_osi_Sleep(tb);
895             }
896             code = tb->code;
897             afs_BRelease(tb);
898         }
899
900         /* VNOVNODE is "acceptable" error code from close, since
901             may happen when deleting a file on another machine while
902             it is open here. We do the same for ENOENT since in afs_CheckCode we map VNOVNODE -> ENOENT */
903         if (code == VNOVNODE || code == ENOENT)
904             code = 0;
905         
906         /* Ensure last closer gets the error. If another thread caused
907          * DoPartialWrite and this thread does not actually store the data,
908          * it may not see the quota error.
909          */
910         ObtainWriteLock(&avc->lock,406);
911         if (avc->vc_error) {
912 #ifdef AFS_AIX32_ENV
913             osi_ReleaseVM(avc, acred);
914 #endif
915             code = avc->vc_error;
916             avc->vc_error = 0;
917         }
918         ReleaseWriteLock(&avc->lock);
919
920         /* some codes merit specific complaint */
921         if (code < 0) {
922             afs_warnuser("afs: failed to store file (network problems)\n");
923         }
924 #ifdef  AFS_SUN5_ENV
925         else if (code == ENOSPC) {
926             afs_warnuser("afs: failed to store file (over quota or partition full)\n");
927         }
928 #else
929         else if (code == ENOSPC) {
930             afs_warnuser("afs: failed to store file (partition full)\n");
931         }
932         else if (code == EDQUOT) {
933             afs_warnuser("afs: failed to store file (over quota)\n");
934         }
935 #endif
936         else if (code != 0)
937             afs_warnuser("afs: failed to store file (%d)\n", code);
938
939         /* finally, we flush any text pages lying around here */
940         hzero(avc->flushDV);
941         osi_FlushText(avc);
942     }
943     else {
944 #if defined(AFS_SGI_ENV)
945         AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
946         osi_Assert(avc->opens > 0);
947 #endif
948         /* file open for read */
949         ObtainWriteLock(&avc->lock, 411);
950         if (avc->vc_error) {
951 #ifdef AFS_AIX32_ENV
952             osi_ReleaseVM(avc, acred);
953 #endif
954             code = avc->vc_error;
955             avc->vc_error = 0;
956         }
957         avc->opens--;
958         ReleaseWriteLock(&avc->lock);
959     }
960 #ifdef  AFS_OSF_ENV
961     if ((VREFCOUNT(avc) <= 2) && (avc->states & CUnlinked)) {
962         afs_remunlink(avc, 1);  /* ignore any return code */
963     }
964 #endif
965     afs_PutFakeStat(&fakestat);
966     code = afs_CheckCode(code, &treq, 5);
967     return code;
968 }
969
970
971
972 #ifdef  AFS_OSF_ENV
973 afs_fsync(avc, fflags, acred, waitfor)
974 int fflags;
975 int waitfor;
976 #else   /* AFS_OSF_ENV */
977 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
978 afs_fsync(OSI_VC_ARG(avc), flag, acred
979 #ifdef AFS_SGI65_ENV
980           , start, stop
981 #endif
982           )
983 #else
984 afs_fsync(avc, acred)
985 #endif
986 #endif
987     OSI_VC_DECL(avc);
988      struct AFS_UCRED *acred;
989 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
990 int flag;
991 #ifdef AFS_SGI65_ENV
992 off_t start, stop;
993 #endif
994 #endif
995 {
996     register afs_int32 code;
997     struct vrequest treq;
998     OSI_VC_CONVERT(avc)
999
1000     if (avc->vc_error)
1001         return avc->vc_error;
1002
1003 #if defined(AFS_SUN5_ENV)
1004      /* back out if called from NFS server */
1005     if (curthread->t_flag & T_DONTPEND)
1006         return 0;
1007 #endif
1008
1009     AFS_STATCNT(afs_fsync);
1010     afs_Trace1(afs_iclSetp, CM_TRACE_FSYNC, ICL_TYPE_POINTER, avc);
1011     if ((code = afs_InitReq(&treq, acred))) return code;
1012
1013 #if defined(AFS_SGI_ENV)
1014     AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
1015     if (flag & FSYNC_INVAL)
1016         osi_VM_FSyncInval(avc);
1017 #endif /* AFS_SGI_ENV */
1018
1019     ObtainSharedLock(&avc->lock,18);
1020     code = 0;
1021     if (avc->execsOrWriters > 0) {
1022         /* put the file back */
1023         UpgradeSToWLock(&avc->lock,41);
1024         code = afs_StoreAllSegments(avc, &treq, AFS_SYNC);
1025         ConvertWToSLock(&avc->lock);
1026     }
1027
1028 #if defined(AFS_SGI_ENV)
1029     AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
1030     if (code == VNOVNODE) {
1031         /* syncing an unlinked file! - non-informative to pass an errno
1032          * 102 (== VNOVNODE) to user
1033          */
1034         code =  ENOENT;
1035     }
1036 #endif
1037
1038     code = afs_CheckCode(code, &treq, 33);
1039     ReleaseSharedLock(&avc->lock);
1040     return code;
1041 }