disconnected-lseek-extension-20090126
[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->states & CCore) {
53         avc->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->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->m.Length);
156         diff = avc->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->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->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->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->m.Length);
265 #else
266         if (filePos > avc->m.Length) {
267 #if 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->m.Length), ICL_TYPE_OFFSET,
274                        ICL_HANDLE_OFFSET(filePos));
275             avc->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->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->m.Length);
373         diff = avc->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->m.Length;
384         AFS_UIO_SETOFFSET(auio, avc->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->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->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 #if defined(LINUX_USE_FH)
429         tfile = (struct osi_file *)osi_UFSOpen_fh(&tdc->f.fh, tdc->f.fh_type);
430 #else
431         tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
432 #endif
433         len = totalLength;      /* write this amount by default */
434         offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
435         max = AFS_CHUNKTOSIZE(tdc->f.chunk);    /* max size of this chunk */
436         if (max <= len + offset) {      /*if we'd go past the end of this chunk */
437             /* it won't all fit in this chunk, so write as much
438              * as will fit */
439             len = max - offset;
440         }
441
442 #ifdef  AFS_DARWIN80_ENV
443         if (tuiop)
444             uio_free(tuiop);
445         trimlen = len;
446         tuiop = afsio_darwin_partialcopy(auio, trimlen);
447 #else
448         /* mung uio structure to be right for this transfer */
449         afsio_copy(auio, &tuio, tvec);
450         trimlen = len;
451         afsio_trim(&tuio, trimlen);
452 #endif
453         AFS_UIO_SETOFFSET(tuiop, offset);
454
455 #if defined(AFS_AIX41_ENV)
456         AFS_GUNLOCK();
457         code =
458             VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, &tuio, NULL, NULL,
459                       NULL, afs_osi_credp);
460         AFS_GLOCK();
461 #elif defined(AFS_AIX32_ENV)
462         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, &tuio, NULL, NULL);
463 #elif defined(AFS_AIX_ENV)
464         code =
465             VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, (off_t) & offset,
466                       &tuio, NULL, NULL, -1);
467 #elif defined(AFS_SUN5_ENV)
468         AFS_GUNLOCK();
469 #ifdef AFS_SUN510_ENV
470         {
471             caller_context_t ct;
472
473             VOP_RWLOCK(tfile->vnode, 1, &ct);
474             code = VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp, &ct);
475             VOP_RWUNLOCK(tfile->vnode, 1, &ct);
476         }
477 #else
478         VOP_RWLOCK(tfile->vnode, 1);
479         code = VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp);
480         VOP_RWUNLOCK(tfile->vnode, 1);
481 #endif
482         AFS_GLOCK();
483         if (code == ENOSPC)
484             afs_warnuser
485                 ("\n\n\n*** Cache partition is full - decrease cachesize!!! ***\n\n\n");
486 #elif defined(AFS_SGI_ENV)
487         AFS_GUNLOCK();
488         avc->states |= CWritingUFS;
489         AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_WRITE);
490         AFS_VOP_WRITE(tfile->vnode, &tuio, IO_ISLOCKED, afs_osi_credp, code);
491         AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_WRITE);
492         avc->states &= ~CWritingUFS;
493         AFS_GLOCK();
494 #elif defined(AFS_OSF_ENV)
495         {
496             struct ucred *tmpcred = u.u_cred;
497             u.u_cred = afs_osi_credp;
498             tuio.uio_rw = UIO_WRITE;
499             AFS_GUNLOCK();
500             VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp, code);
501             AFS_GLOCK();
502             u.u_cred = tmpcred;
503         }
504 #elif defined(AFS_HPUX100_ENV)
505         {
506             AFS_GUNLOCK();
507             code = VOP_RDWR(tfile->vnode, &tuio, UIO_WRITE, 0, afs_osi_credp);
508             AFS_GLOCK();
509         }
510 #elif defined(AFS_LINUX20_ENV)
511         AFS_GUNLOCK();
512         code = osi_rdwr(tfile, &tuio, UIO_WRITE);
513         AFS_GLOCK();
514 #elif defined(AFS_DARWIN80_ENV)
515         AFS_GUNLOCK();
516         code = VNOP_WRITE(tfile->vnode, tuiop, 0, afs_osi_ctxtp);
517         AFS_GLOCK();
518 #elif defined(AFS_DARWIN_ENV)
519         AFS_GUNLOCK();
520         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
521         code = VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp);
522         VOP_UNLOCK(tfile->vnode, 0, current_proc());
523         AFS_GLOCK();
524 #elif defined(AFS_FBSD80_ENV)
525         AFS_GUNLOCK();
526         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE);
527         code = VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp);
528         VOP_UNLOCK(tfile->vnode, 0);
529         AFS_GLOCK();
530 #elif defined(AFS_FBSD50_ENV)
531         AFS_GUNLOCK();
532         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curthread);
533         code = VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp);
534         VOP_UNLOCK(tfile->vnode, 0, curthread);
535         AFS_GLOCK();
536 #elif defined(AFS_XBSD_ENV)
537         AFS_GUNLOCK();
538         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
539         code = VOP_WRITE(tfile->vnode, &tuio, 0, afs_osi_credp);
540         VOP_UNLOCK(tfile->vnode, 0, curproc);
541         AFS_GLOCK();
542 #else
543 #ifdef  AFS_HPUX_ENV
544         tuio.uio_fpflags &= ~FSYNCIO;   /* don't do sync io */
545 #endif
546         code = VOP_RDWR(tfile->vnode, &tuio, UIO_WRITE, 0, afs_osi_credp);
547 #endif
548         if (code) {
549             error = code;
550             ZapDCE(tdc);        /* bad data */
551             osi_UFSTruncate(tfile, 0);  /* fake truncate the segment */
552             afs_AdjustSize(tdc, 0);     /* sets f.chunkSize to 0 */
553             afs_stats_cmperf.cacheCurrDirtyChunks--;
554             afs_indexFlags[tdc->index] &= ~IFDataMod;   /* so it does disappear */
555             afs_CFileClose(tfile);
556             ReleaseWriteLock(&tdc->lock);
557             afs_PutDCache(tdc);
558             break;
559         }
560         /* otherwise we've written some, fixup length, etc and continue with next seg */
561         len = len - AFS_UIO_RESID(tuiop);       /* compute amount really transferred */
562         tlen = len;
563         afsio_skip(auio, tlen); /* advance auio over data written */
564         /* compute new file size */
565         if (offset + len > tdc->f.chunkBytes) {
566             afs_int32 tlength = offset + len;
567             afs_AdjustSize(tdc, tlength);
568             if (tdc->validPos < filePos + len)
569                 tdc->validPos = filePos + len;
570         }
571         totalLength -= len;
572         transferLength += len;
573         filePos += len;
574 #if defined(AFS_SGI_ENV)
575         /* afs_xwrite handles setting m.Length */
576         osi_Assert(filePos <= avc->m.Length);
577 #else
578         if (filePos > avc->m.Length) {
579 # ifdef AFS_DISCON_ENV
580             if (AFS_IS_DISCON_RW)
581                 afs_PopulateDCache(avc, filePos, &treq);
582 # endif
583             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH, ICL_TYPE_STRING,
584                        __FILE__, ICL_TYPE_LONG, __LINE__, ICL_TYPE_OFFSET,
585                        ICL_HANDLE_OFFSET(avc->m.Length), ICL_TYPE_OFFSET,
586                        ICL_HANDLE_OFFSET(filePos));
587             avc->m.Length = filePos;
588         }
589 #endif
590         osi_UFSClose(tfile);
591         ReleaseWriteLock(&tdc->lock);
592         afs_PutDCache(tdc);
593 #if !defined(AFS_VM_RDWR_ENV)
594         /*
595          * If write is implemented via VM, afs_DoPartialWrite() is called from
596          * the high-level write op.
597          */
598         if (!noLock) {
599             code = afs_DoPartialWrite(avc, &treq);
600             if (code) {
601                 error = code;
602                 break;
603             }
604         }
605 #endif
606     }
607 #ifndef AFS_VM_RDWR_ENV
608     afs_FakeClose(avc, acred);
609 #endif
610     error = afs_CheckCode(error, &treq, 7);
611     /* This set is here so we get the CheckCode. */
612     if (error && !avc->vc_error)
613         avc->vc_error = error;
614     if (!noLock)
615         ReleaseWriteLock(&avc->lock);
616 #ifdef AFS_DARWIN80_ENV
617     uio_free(tuiop);
618 #else
619     osi_FreeSmallSpace(tvec);
620 #endif
621 #ifndef AFS_VM_RDWR_ENV
622     /*
623      * If write is implemented via VM, afs_fsync() is called from the high-level
624      * write op.
625      */
626 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
627     if (noLock && (aio & IO_SYNC)) {
628 #else
629 #ifdef  AFS_HPUX_ENV
630     /* On hpux on synchronous writes syncio will be set to IO_SYNC. If
631      * we're doing them because the file was opened with O_SYNCIO specified,
632      * we have to look in the u area. No single mechanism here!!
633      */
634     if (noLock && ((aio & IO_SYNC) | (auio->uio_fpflags & FSYNCIO))) {
635 #else
636     if (noLock && (aio & FSYNC)) {
637 #endif
638 #endif
639         if (!AFS_NFSXLATORREQ(acred))
640             afs_fsync(avc, acred);
641     }
642 #endif
643     return error;
644 }
645
646 /* do partial write if we're low on unmodified chunks */
647 int
648 afs_DoPartialWrite(register struct vcache *avc, struct vrequest *areq)
649 {
650     register afs_int32 code;
651
652     if (afs_stats_cmperf.cacheCurrDirtyChunks <=
653         afs_stats_cmperf.cacheMaxDirtyChunks
654         || AFS_IS_DISCONNECTED)
655         return 0;               /* nothing to do */
656     /* otherwise, call afs_StoreDCache (later try to do this async, if possible) */
657     afs_Trace2(afs_iclSetp, CM_TRACE_PARTIALWRITE, ICL_TYPE_POINTER, avc,
658                ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
659
660 #if     defined(AFS_SUN5_ENV)
661     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC | AFS_VMSYNC_INVAL);
662 #else
663     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC);
664 #endif
665     return code;
666 }
667
668 #ifdef AFS_OSF_ENV
669 #ifdef AFS_DUX50_ENV
670 #define vno_close(X) vn_close((X), 0, NOCRED)
671 #elif defined(AFS_DUX40_ENV)
672 #define      vno_close       vn_close
673 #endif
674 /* We don't need this for AIX since: 
675  * (1) aix doesn't use fileops and it call close directly intead
676  * (where the unlocking should be done) and 
677  * (2) temporarily, the aix lockf isn't supported yet.
678  *
679  *  this stupid routine is used to release the flocks held on a
680  *  particular file descriptor.  Sun doesn't pass file descr. info
681  *  through to the vnode layer, and yet we must unlock flocked files
682  *  on the *appropriate* (not first, as in System V) close call.  Thus
683  *  this code.
684  * How does this code get invoked? The afs AFS_FLOCK plugs in the new afs
685  * file ops structure into any afs file when it gets flocked. 
686  * N.B: Intercepting close syscall doesn't trap aborts or exit system
687  * calls.
688 */
689 int
690 afs_closex(register struct file *afd)
691 {
692     struct vrequest treq;
693     struct vcache *tvc;
694     afs_int32 flags;
695     int closeDone;
696     afs_int32 code = 0;
697     struct afs_fakestat_state fakestat;
698
699     AFS_STATCNT(afs_closex);
700     /* setup the credentials */
701     if ((code = afs_InitReq(&treq, u.u_cred)))
702         return code;
703     afs_InitFakeStat(&fakestat);
704
705     closeDone = 0;
706     /* we're the last one.  If we're an AFS vnode, clear the flags,
707      * close the file and release the lock when done.  Otherwise, just
708      * let the regular close code work.      */
709     if (afd->f_type == DTYPE_VNODE) {
710         tvc = VTOAFS(afd->f_data);
711         if (IsAfsVnode(AFSTOV(tvc))) {
712             code = afs_EvalFakeStat(&tvc, &fakestat, &treq);
713             if (code) {
714                 afs_PutFakeStat(&fakestat);
715                 return code;
716             }
717             VN_HOLD(AFSTOV(tvc));
718             flags = afd->f_flag & (FSHLOCK | FEXLOCK);
719             afd->f_flag &= ~(FSHLOCK | FEXLOCK);
720             code = vno_close(afd);
721             if (flags)
722                 HandleFlock(tvc, LOCK_UN, &treq, u.u_procp->p_pid,
723                             1 /*onlymine */ );
724             AFS_RELE(AFSTOV(tvc));
725             closeDone = 1;
726         }
727     }
728     /* now, if close not done, do it */
729     if (!closeDone) {
730         code = vno_close(afd);
731     }
732     afs_PutFakeStat(&fakestat);
733     return code;                /* return code from vnode layer */
734 }
735 #endif
736
737
738 /* handle any closing cleanup stuff */
739 int
740 #if defined(AFS_SGI65_ENV)
741 afs_close(OSI_VC_DECL(avc), afs_int32 aflags, lastclose_t lastclose,
742           struct AFS_UCRED *acred)
743 #elif defined(AFS_SGI64_ENV)
744 afs_close(OSI_VC_DECL(avc), afs_int32 aflags, lastclose_t lastclose,
745           off_t offset, struct AFS_UCRED *acred, struct flid *flp)
746 #elif defined(AFS_SGI_ENV)
747 afs_close(OSI_VC_DECL(avc), afs_int32 aflags, lastclose_t lastclose
748           off_t offset, struct AFS_UCRED *acred)
749 #elif defined(AFS_SUN5_ENV)
750 afs_close(OSI_VC_DECL(avc), afs_int32 aflags, int count, offset_t offset, 
751          struct AFS_UCRED *acred)
752 #else
753 afs_close(OSI_VC_DECL(avc), afs_int32 aflags, struct AFS_UCRED *acred)
754 #endif
755 {
756     register afs_int32 code;
757     register struct brequest *tb;
758     struct vrequest treq;
759 #ifdef AFS_SGI65_ENV
760     struct flid flid;
761 #endif
762     struct afs_fakestat_state fakestat;
763     OSI_VC_CONVERT(avc);
764
765     AFS_STATCNT(afs_close);
766     afs_Trace2(afs_iclSetp, CM_TRACE_CLOSE, ICL_TYPE_POINTER, avc,
767                ICL_TYPE_INT32, aflags);
768     code = afs_InitReq(&treq, acred);
769     if (code)
770         return code;
771     afs_InitFakeStat(&fakestat);
772     code = afs_EvalFakeStat(&avc, &fakestat, &treq);
773     if (code) {
774         afs_PutFakeStat(&fakestat);
775         return code;
776     }
777     AFS_DISCON_LOCK();
778 #ifdef  AFS_SUN5_ENV
779     if (avc->flockCount) {
780         HandleFlock(avc, LOCK_UN, &treq, 0, 1 /*onlymine */ );
781     }
782 #endif
783 #if defined(AFS_SGI_ENV)
784     if (!lastclose) {
785         afs_PutFakeStat(&fakestat);
786         AFS_DISCON_UNLOCK();
787         return 0;
788     }
789     /* unlock any locks for pid - could be wrong for child .. */
790     AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE);
791 #ifdef AFS_SGI65_ENV
792     get_current_flid(&flid);
793     cleanlocks((vnode_t *) avc, flid.fl_pid, flid.fl_sysid);
794     HandleFlock(avc, LOCK_UN, &treq, flid.fl_pid, 1 /*onlymine */ );
795 #else
796 #ifdef AFS_SGI64_ENV
797     cleanlocks((vnode_t *) avc, flp);
798 #else /* AFS_SGI64_ENV */
799     cleanlocks((vnode_t *) avc, u.u_procp->p_epid, u.u_procp->p_sysid);
800 #endif /* AFS_SGI64_ENV */
801     HandleFlock(avc, LOCK_UN, &treq, OSI_GET_CURRENT_PID(), 1 /*onlymine */ );
802 #endif /* AFS_SGI65_ENV */
803     /* afs_chkpgoob will drop and re-acquire the global lock. */
804     afs_chkpgoob(&avc->v, btoc(avc->m.Length));
805 #elif   defined(AFS_SUN5_ENV)
806     if (count > 1) {
807         /* 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. */
808         afs_PutFakeStat(&fakestat);
809         AFS_DISCON_UNLOCK();
810         return 0;
811     }
812 #else /* AFS_SGI_ENV */
813     if (avc->flockCount) {      /* Release Lock */
814 #if     defined(AFS_OSF_ENV) 
815         HandleFlock(avc, LOCK_UN, &treq, u.u_procp->p_pid, 1 /*onlymine */ );
816 #else
817         HandleFlock(avc, LOCK_UN, &treq, 0, 1 /*onlymine */ );
818 #endif
819     }
820 #endif /* AFS_SGI_ENV */
821     if (aflags & (FWRITE | FTRUNC)) {
822         if (afs_BBusy() || (AFS_NFSXLATORREQ(acred)) || AFS_IS_DISCONNECTED) {
823             /* do it yourself if daemons are all busy */
824             ObtainWriteLock(&avc->lock, 124);
825             code = afs_StoreOnLastReference(avc, &treq);
826             ReleaseWriteLock(&avc->lock);
827 #if defined(AFS_SGI_ENV)
828             AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
829 #endif
830         } else {
831 #if defined(AFS_SGI_ENV)
832             AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
833 #endif
834             /* at least one daemon is idle, so ask it to do the store.
835              * Also, note that  we don't lock it any more... */
836             tb = afs_BQueue(BOP_STORE, avc, 0, 1, acred,
837                             (afs_size_t) acred->cr_uid, (afs_size_t) 0,
838                             (void *)0);
839             /* sleep waiting for the store to start, then retrieve error code */
840             while ((tb->flags & BUVALID) == 0) {
841                 tb->flags |= BUWAIT;
842                 afs_osi_Sleep(tb);
843             }
844             code = tb->code;
845             afs_BRelease(tb);
846         }
847
848         /* VNOVNODE is "acceptable" error code from close, since
849          * may happen when deleting a file on another machine while
850          * it is open here. We do the same for ENOENT since in afs_CheckCode we map VNOVNODE -> ENOENT */
851         if (code == VNOVNODE || code == ENOENT)
852             code = 0;
853
854         /* Ensure last closer gets the error. If another thread caused
855          * DoPartialWrite and this thread does not actually store the data,
856          * it may not see the quota error.
857          */
858         ObtainWriteLock(&avc->lock, 406);
859         if (avc->vc_error) {
860 #ifdef AFS_AIX32_ENV
861             osi_ReleaseVM(avc, acred);
862 #endif
863             printf("avc->vc_error=%d\n", avc->vc_error);
864             code = avc->vc_error;
865             avc->vc_error = 0;
866         }
867         ReleaseWriteLock(&avc->lock);
868
869         /* some codes merit specific complaint */
870         if (code < 0) {
871             afs_warnuser("afs: failed to store file (network problems)\n");
872         }
873 #ifdef  AFS_SUN5_ENV
874         else if (code == ENOSPC) {
875             afs_warnuser
876                 ("afs: failed to store file (over quota or partition full)\n");
877         }
878 #else
879         else if (code == ENOSPC) {
880             afs_warnuser("afs: failed to store file (partition full)\n");
881         } else if (code == EDQUOT) {
882             afs_warnuser("afs: failed to store file (over quota)\n");
883         }
884 #endif
885         else if (code != 0)
886             afs_warnuser("afs: failed to store file (%d)\n", code);
887
888         /* finally, we flush any text pages lying around here */
889         hzero(avc->flushDV);
890         osi_FlushText(avc);
891     } else {
892 #if defined(AFS_SGI_ENV)
893         AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
894         osi_Assert(avc->opens > 0);
895 #endif
896         /* file open for read */
897         ObtainWriteLock(&avc->lock, 411);
898         if (avc->vc_error) {
899 #ifdef AFS_AIX32_ENV
900             osi_ReleaseVM(avc, acred);
901 #endif
902             code = avc->vc_error;
903             avc->vc_error = 0;
904         }
905         avc->opens--;
906         ReleaseWriteLock(&avc->lock);
907     }
908 #ifdef  AFS_OSF_ENV
909     if ((VREFCOUNT(avc) <= 2) && (avc->states & CUnlinked)) {
910         afs_remunlink(avc, 1);  /* ignore any return code */
911     }
912 #endif
913     AFS_DISCON_UNLOCK();
914     afs_PutFakeStat(&fakestat);
915     code = afs_CheckCode(code, &treq, 5);
916     return code;
917 }
918
919
920 int
921 #ifdef  AFS_OSF_ENV
922 afs_fsync(OSI_VC_DECL(avc), int fflags, struct AFS_UCRED *acred, int waitfor)
923 #else                           /* AFS_OSF_ENV */
924 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
925 afs_fsync(OSI_VC_DECL(avc), int flag, struct AFS_UCRED *acred
926 #ifdef AFS_SGI65_ENV
927           , off_t start, off_t stop
928 #endif /* AFS_SGI65_ENV */
929     )
930 #else /* !OSF && !SUN53 && !SGI */
931 afs_fsync(OSI_VC_DECL(avc), struct AFS_UCRED *acred)
932 #endif 
933 #endif
934 {
935     register afs_int32 code;
936     struct vrequest treq;
937     OSI_VC_CONVERT(avc);
938
939     if (avc->vc_error)
940         return avc->vc_error;
941
942 #if defined(AFS_SUN5_ENV)
943     /* back out if called from NFS server */
944     if (curthread->t_flag & T_DONTPEND)
945         return 0;
946 #endif
947
948     AFS_STATCNT(afs_fsync);
949     afs_Trace1(afs_iclSetp, CM_TRACE_FSYNC, ICL_TYPE_POINTER, avc);
950     if ((code = afs_InitReq(&treq, acred)))
951         return code;
952     AFS_DISCON_LOCK();
953 #if defined(AFS_SGI_ENV)
954     AFS_RWLOCK((vnode_t *) avc, VRWLOCK_WRITE);
955     if (flag & FSYNC_INVAL)
956         osi_VM_FSyncInval(avc);
957 #endif /* AFS_SGI_ENV */
958
959     ObtainSharedLock(&avc->lock, 18);
960     code = 0;
961     if (avc->execsOrWriters > 0) {
962
963         if (!AFS_IS_DISCONNECTED && !AFS_IS_DISCON_RW) {
964                 /* Your average flush. */
965
966                 /* put the file back */
967                 UpgradeSToWLock(&avc->lock, 41);
968                 code = afs_StoreAllSegments(avc, &treq, AFS_SYNC);
969                 ConvertWToSLock(&avc->lock);
970
971 #if defined(AFS_DISCON_ENV)
972         } else {
973
974             UpgradeSToWLock(&avc->lock, 711);
975             afs_DisconAddDirty(avc, VDisconWriteFlush, 1);
976             ConvertWToSLock(&avc->lock);
977 #endif
978         }               /* if not disconnected */
979     }                   /* if (avc->execsOrWriters > 0) */
980
981 #if defined(AFS_SGI_ENV)
982     AFS_RWUNLOCK((vnode_t *) avc, VRWLOCK_WRITE);
983     if (code == VNOVNODE) {
984         /* syncing an unlinked file! - non-informative to pass an errno
985          * 102 (== VNOVNODE) to user
986          */
987         code = ENOENT;
988     }
989 #endif
990     AFS_DISCON_UNLOCK();
991     code = afs_CheckCode(code, &treq, 33);
992     ReleaseSharedLock(&avc->lock);
993     return code;
994 }