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