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