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