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