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