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