193f7aab807c41973ddc13cac742bb1c8d5d7d9f
[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((struct vnode *)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             error = code;
264             ZapDCE(tdc);                /* bad data */
265             afs_MemCacheTruncate(tdc->f.inode, 0);
266             afs_stats_cmperf.cacheCurrDirtyChunks--;
267             afs_indexFlags[tdc->index] &= ~IFDataMod;    /* so it does disappear */
268             ReleaseWriteLock(&tdc->lock);
269             afs_PutDCache(tdc);
270             break;
271         }
272         /* otherwise we've written some, fixup length, etc and continue with next seg */
273         len = len - tuio.afsio_resid; /* compute amount really transferred */
274         tlen = len;
275         afsio_skip(auio, tlen);     /* advance auio over data written */
276         /* compute new file size */
277         if (offset + len > tdc->f.chunkBytes) {
278             afs_int32 tlength = offset+len;
279             afs_AdjustSize(tdc, tlength);
280         }
281         totalLength -= len;
282         transferLength += len;
283         filePos += len;
284 #if defined(AFS_SGI_ENV)
285         /* afs_xwrite handles setting m.Length */
286         osi_Assert(filePos <= avc->m.Length);
287 #else
288         if (filePos > avc->m.Length) {
289             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
290                 ICL_TYPE_STRING, __FILE__,
291                 ICL_TYPE_LONG, __LINE__,
292                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
293                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos));
294             avc->m.Length = filePos;
295         }
296 #endif
297 #ifndef AFS_VM_RDWR_ENV
298         /*
299          * If write is implemented via VM, afs_DoPartialWrite() is called from
300          * the high-level write op.
301          */
302         if (!noLock) {
303             code = afs_DoPartialWrite(avc, &treq);
304             if (code) {
305                 error = code;
306                 ReleaseWriteLock(&tdc->lock);
307                 afs_PutDCache(tdc);
308                 break;
309             }
310         }
311 #endif
312         ReleaseWriteLock(&tdc->lock);
313         afs_PutDCache(tdc);
314     }
315 #ifndef AFS_VM_RDWR_ENV
316     afs_FakeClose(avc, acred);
317 #endif
318     if (error && !avc->vc_error)
319         avc->vc_error = error;
320     if (!noLock)
321         ReleaseWriteLock(&avc->lock);
322     osi_FreeSmallSpace(tvec);
323 #ifdef AFS_DEC_ENV
324     /* next, on GFS systems, we update g_size so that lseek's relative to EOF will
325        work.  GFS is truly a poorly-designed interface!  */
326     afs_gfshack((struct gnode *) avc);
327 #endif
328     error = afs_CheckCode(error, &treq, 6);
329     return error;
330 }
331
332
333 /* called on writes */
334 afs_UFSWrite(avc, auio, aio, acred, noLock)
335     register struct vcache *avc;
336     struct uio *auio;
337     int aio, noLock;
338     struct AFS_UCRED *acred; 
339 {
340     afs_size_t totalLength;
341     afs_size_t transferLength;
342     afs_size_t filePos;
343     afs_size_t offset, len;
344     afs_int32  tlen;
345     afs_int32  trimlen;
346     afs_int32 startDate;
347     afs_int32 max;
348     register struct dcache *tdc;
349 #ifdef _HIGHC_
350     volatile
351 #endif
352     afs_int32 error;
353     struct uio tuio;
354     struct iovec *tvec;  /* again, should have define */
355     struct osi_file *tfile;
356     register afs_int32 code;
357     struct vnode *vp;
358     struct vrequest treq;
359
360     AFS_STATCNT(afs_UFSWrite);
361     if (avc->vc_error)
362         return avc->vc_error;
363
364     startDate = osi_Time();
365     if (code = afs_InitReq(&treq, acred)) return code;
366     /* otherwise we read */
367     totalLength = auio->afsio_resid;
368     filePos = auio->afsio_offset;
369     error = 0;
370     transferLength = 0;
371     afs_Trace4(afs_iclSetp, CM_TRACE_WRITE, ICL_TYPE_POINTER, avc, 
372                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos),
373                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(totalLength),
374                         ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
375     if (!noLock) {
376         afs_MaybeWakeupTruncateDaemon();
377         ObtainWriteLock(&avc->lock,556);
378     }
379 #if defined(AFS_SGI_ENV)
380     {
381     off_t diff;
382     /*
383      * afs_xwrite handles setting m.Length
384      * and handles APPEND mode.
385      * Since we are called via strategy, we need to trim the write to
386      * the actual size of the file
387      */
388     osi_Assert(filePos <= avc->m.Length);
389     diff = avc->m.Length - filePos;
390     auio->afsio_resid = MIN(totalLength, diff);
391     totalLength = auio->afsio_resid;
392     }
393 #else
394     if (aio & IO_APPEND) {
395         /* append mode, start it at the right spot */
396 #if     defined(AFS_SUN56_ENV)
397         auio->uio_loffset = 0;
398 #endif
399         filePos = auio->afsio_offset = avc->m.Length;
400     }
401 #endif
402     /*
403      * Note that we use startDate rather than calling osi_Time() here.
404      * This is to avoid counting lock-waiting time in file date (for ranlib).
405      */
406     avc->m.Date = startDate;
407
408 #if     defined(AFS_HPUX_ENV) || defined(AFS_GFS_ENV)
409 #if     defined(AFS_HPUX101_ENV)
410     if ((totalLength + filePos) >> 9 > p_rlimit(u.u_procp)[RLIMIT_FSIZE].rlim_cur) {
411 #else
412 #ifdef  AFS_HPUX_ENV
413     if ((totalLength + filePos) >> 9 > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
414 #else
415     if (totalLength + filePos > u.u_rlimit[RLIMIT_FSIZE].rlim_cur) {
416 #endif
417 #endif
418         if (!noLock)
419             ReleaseWriteLock(&avc->lock);
420         return (EFBIG);
421     }
422 #endif
423 #ifdef  AFS_VM_RDWR_ENV
424     /*
425      * If write is implemented via VM, afs_FakeOpen() is called from the
426      * high-level write op.
427      */
428     if (avc->execsOrWriters <= 0) {
429         printf("WARNING: afs_ufswr vp=%x, exOrW=%d\n", avc, avc->execsOrWriters);
430     }
431 #else
432     afs_FakeOpen(avc);
433 #endif
434     avc->states |= CDirty;
435     tvec = (struct iovec *) osi_AllocSmallSpace(sizeof(struct iovec));
436     while (totalLength > 0) {
437         /* read the cached info */
438         if (noLock) {
439             tdc = afs_FindDCache(avc, filePos);
440             if (tdc) ObtainWriteLock(&tdc->lock, 657);
441         } else if (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
442             tdc = afs_FindDCache(avc, filePos);
443             if (tdc) {
444                 ObtainWriteLock(&tdc->lock, 658);
445                 if (!hsame(tdc->f.versionNo, avc->m.DataVersion) ||
446                     (tdc->dflags & DFFetching)) {
447                     ReleaseWriteLock(&tdc->lock);
448                     afs_PutDCache(tdc);
449                     tdc = NULL;
450                 }
451             }
452             if (!tdc) {
453                 afs_MaybeWakeupTruncateDaemon();
454                 while (afs_blocksUsed >
455                        (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
456                     ReleaseWriteLock(&avc->lock);
457                     if (afs_blocksUsed - afs_blocksDiscarded >
458                         (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
459                         afs_WaitForCacheDrain = 1;
460                         afs_osi_Sleep(&afs_WaitForCacheDrain);
461                     }
462                     afs_MaybeFreeDiscardedDCache();
463                     afs_MaybeWakeupTruncateDaemon();
464                     ObtainWriteLock(&avc->lock,509);
465                 }
466                 avc->states |= CDirty;
467                 tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
468                 if (tdc) ObtainWriteLock(&tdc->lock, 659);
469             }
470         } else {
471             tdc = afs_GetDCache(avc, filePos, &treq, &offset, &len, 4);
472             if (tdc) ObtainWriteLock(&tdc->lock, 660);
473         }
474         if (!tdc) {
475             error = EIO;
476             break;
477         }
478         if (!(afs_indexFlags[tdc->index] & IFDataMod)) {
479           afs_stats_cmperf.cacheCurrDirtyChunks++;
480           afs_indexFlags[tdc->index] |= IFDataMod;    /* so it doesn't disappear */
481         }
482         if (!(tdc->f.states & DWriting)) {
483             /* don't mark entry as mod if we don't have to */
484             tdc->f.states |= DWriting;
485             tdc->dflags |= DFEntryMod;
486         }
487         tfile = (struct osi_file *)osi_UFSOpen(tdc->f.inode);
488         len = totalLength;      /* write this amount by default */
489         offset = filePos - AFS_CHUNKTOBASE(tdc->f.chunk);
490         max = AFS_CHUNKTOSIZE(tdc->f.chunk);    /* max size of this chunk */
491         if (max <= len + offset)        {   /*if we'd go past the end of this chunk */
492             /* it won't all fit in this chunk, so write as much
493                 as will fit */
494             len = max - offset;
495         }
496         /* mung uio structure to be right for this transfer */
497         afsio_copy(auio, &tuio, tvec);
498         trimlen = len;
499         afsio_trim(&tuio, trimlen);
500         tuio.afsio_offset = offset;
501 #ifdef  AFS_AIX_ENV
502 #ifdef  AFS_AIX41_ENV
503         AFS_GUNLOCK();
504         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, &tuio, NULL, NULL, NULL, &afs_osi_cred);
505         AFS_GLOCK();
506 #else
507 #ifdef AFS_AIX32_ENV
508         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, &tuio, NULL, NULL);
509 #else
510         code = VNOP_RDWR(tfile->vnode, UIO_WRITE, FWRITE, (off_t)&offset, &tuio, NULL, NULL, -1);
511 #endif
512 #endif /* AFS_AIX41_ENV */
513 #else /* AFS_AIX_ENV */
514 #ifdef  AFS_SUN5_ENV
515         AFS_GUNLOCK();
516         VOP_RWLOCK(tfile->vnode, 1);
517         code = VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred);
518         VOP_RWUNLOCK(tfile->vnode, 1);
519         AFS_GLOCK();
520         if (code == ENOSPC) afs_warnuser("\n\n\n*** Cache partition is full - decrease cachesize!!! ***\n\n\n"); 
521 #else
522 #if defined(AFS_SGI_ENV)
523         AFS_GUNLOCK();
524         avc->states |= CWritingUFS;
525         AFS_VOP_RWLOCK(tfile->vnode, VRWLOCK_WRITE);
526         AFS_VOP_WRITE(tfile->vnode, &tuio, IO_ISLOCKED, &afs_osi_cred, code);
527         AFS_VOP_RWUNLOCK(tfile->vnode, VRWLOCK_WRITE);
528         avc->states &= ~CWritingUFS;
529         AFS_GLOCK();
530 #else
531 #ifdef  AFS_OSF_ENV
532     {
533         struct ucred *tmpcred = u.u_cred;
534         u.u_cred = &afs_osi_cred;
535         tuio.uio_rw = UIO_WRITE;
536         AFS_GUNLOCK();
537         VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred, code);
538         AFS_GLOCK();
539         u.u_cred = tmpcred;
540     }
541 #else   /* AFS_OSF_ENV */
542 #if defined(AFS_HPUX100_ENV)
543     {
544         AFS_GUNLOCK();
545         code = VOP_RDWR(tfile->vnode, &tuio, UIO_WRITE, 0, &afs_osi_cred);
546         AFS_GLOCK();
547     }
548 #else
549 #ifdef  AFS_HPUX_ENV
550         tuio.uio_fpflags &= ~FSYNCIO;   /* don't do sync io */
551 #endif
552 #if defined(AFS_LINUX20_ENV)
553         AFS_GUNLOCK();
554         code = osi_file_uio_rdwr(tfile, &tuio, UIO_WRITE);
555         AFS_GLOCK();
556 #else
557 #if defined(AFS_DARWIN_ENV)
558         AFS_GUNLOCK();
559         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, current_proc());
560         code = VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred);
561         VOP_UNLOCK(tfile->vnode, 0, current_proc());
562         AFS_GLOCK();
563 #else
564 #if defined(AFS_FBSD_ENV)
565         AFS_GUNLOCK();
566         VOP_LOCK(tfile->vnode, LK_EXCLUSIVE, curproc);
567         code = VOP_WRITE(tfile->vnode, &tuio, 0, &afs_osi_cred);
568         VOP_UNLOCK(tfile->vnode, 0, curproc);
569         AFS_GLOCK();
570 #else
571         code = VOP_RDWR(tfile->vnode, &tuio, UIO_WRITE, 0, &afs_osi_cred);
572 #endif /* AFS_FBSD_ENV */
573 #endif /* AFS_DARWIN_ENV */
574 #endif /* AFS_LINUX20_ENV */
575 #endif /* AFS_HPUX100_ENV */
576 #endif /* AFS_OSF_ENV */
577 #endif /* AFS_SGI_ENV */
578 #endif /* AFS_SUN5_ENV */
579 #endif /* AFS_AIX41_ENV */
580         if (code) {
581             error = code;
582             ZapDCE(tdc);                /* bad data */
583             osi_UFSTruncate(tfile,0);   /* fake truncate the segment */
584             afs_AdjustSize(tdc, 0);     /* sets f.chunkSize to 0 */
585             afs_stats_cmperf.cacheCurrDirtyChunks--;
586             afs_indexFlags[tdc->index] &= ~IFDataMod;    /* so it does disappear */
587             afs_CFileClose(tfile);
588             ReleaseWriteLock(&tdc->lock);
589             afs_PutDCache(tdc);
590             break;
591         }
592         /* otherwise we've written some, fixup length, etc and continue with next seg */
593         len = len - tuio.afsio_resid; /* compute amount really transferred */
594         tlen = len;
595         afsio_skip(auio, tlen);     /* advance auio over data written */
596         /* compute new file size */
597         if (offset + len > tdc->f.chunkBytes) {
598             afs_int32 tlength = offset+len;
599             afs_AdjustSize(tdc, tlength);
600         }
601         totalLength -= len;
602         transferLength += len;
603         filePos += len;
604 #if defined(AFS_SGI_ENV)
605         /* afs_xwrite handles setting m.Length */
606         osi_Assert(filePos <= avc->m.Length);
607 #else
608         if (filePos > avc->m.Length) {
609             afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH,
610                 ICL_TYPE_STRING, __FILE__,
611                 ICL_TYPE_LONG, __LINE__,
612                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length),
613                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(filePos));
614             avc->m.Length = filePos;
615         }
616 #endif
617         osi_UFSClose(tfile);
618 #ifndef 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                 ReleaseWriteLock(&tdc->lock);
628                 afs_PutDCache(tdc);
629                 break;
630             }
631         }
632 #endif
633         ReleaseWriteLock(&tdc->lock);
634         afs_PutDCache(tdc);
635     }
636 #ifndef AFS_VM_RDWR_ENV
637     afs_FakeClose(avc, acred);
638 #endif
639     error = afs_CheckCode(error, &treq, 7);
640     /* This set is here so we get the CheckCode. */
641     if (error && !avc->vc_error)
642         avc->vc_error = error;
643     if (!noLock)
644         ReleaseWriteLock(&avc->lock);
645     osi_FreeSmallSpace(tvec);
646 #ifdef AFS_DEC_ENV
647     /* next, on GFS systems, we update g_size so that lseek's relative to EOF will
648        work.  GFS is truly a poorly-designed interface!  */
649     afs_gfshack((struct gnode *) avc);
650 #endif
651 #ifndef AFS_VM_RDWR_ENV
652     /*
653      * If write is implemented via VM, afs_fsync() is called from the high-level
654      * write op.
655      */
656 #if defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV)
657      if (noLock && (aio & IO_SYNC)) {
658 #else 
659 #ifdef  AFS_HPUX_ENV
660     /* On hpux on synchronous writes syncio will be set to IO_SYNC. If
661      * we're doing them because the file was opened with O_SYNCIO specified,
662      * we have to look in the u area. No single mechanism here!!
663      */
664     if (noLock && ((aio & IO_SYNC) | (auio->uio_fpflags & FSYNCIO))) {    
665 #else
666     if (noLock && (aio & FSYNC)) {
667 #endif
668 #endif
669         if (!AFS_NFSXLATORREQ(acred))
670             afs_fsync(avc, acred);
671     }
672 #endif
673     return error;
674 }
675
676 /* do partial write if we're low on unmodified chunks */
677 afs_DoPartialWrite(avc, areq)
678 register struct vcache *avc;
679 struct vrequest *areq; {
680     register afs_int32 code;
681
682     if (afs_stats_cmperf.cacheCurrDirtyChunks <= afs_stats_cmperf.cacheMaxDirtyChunks) 
683         return 0;       /* nothing to do */
684     /* otherwise, call afs_StoreDCache (later try to do this async, if possible) */
685     afs_Trace2(afs_iclSetp, CM_TRACE_PARTIALWRITE, ICL_TYPE_POINTER, avc,
686                 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(avc->m.Length));
687 #if     defined(AFS_SUN5_ENV)
688     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC | AFS_VMSYNC_INVAL);
689 #else
690     code = afs_StoreAllSegments(avc, areq, AFS_ASYNC);
691 #endif
692     return code;
693 }
694
695
696
697 #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)
698 #ifdef AFS_DUX50_ENV
699 #define vno_close(X) vn_close((X), 0, NOCRED)
700 #elif defined(AFS_DUX40_ENV)
701 #define      vno_close       vn_close
702 #endif
703 /* We don't need this for AIX since: 
704  * (1) aix doesn't use fileops and it call close directly intead
705  * (where the unlocking should be done) and 
706  * (2) temporarily, the aix lockf isn't supported yet.
707  *
708  *  this stupid routine is used to release the flocks held on a
709  *  particular file descriptor.  Sun doesn't pass file descr. info
710  *  through to the vnode layer, and yet we must unlock flocked files
711  *  on the *appropriate* (not first, as in System V) close call.  Thus
712  *  this code.
713  * How does this code get invoked? The afs AFS_FLOCK plugs in the new afs
714  * file ops structure into any afs file when it gets flocked. 
715  * N.B: Intercepting close syscall doesn't trap aborts or exit system
716  * calls.
717 */
718 afs_closex(afd)
719     register struct file *afd; {
720     struct vrequest treq;
721     register struct vcache *tvc;
722     afs_int32 flags;
723     int closeDone;
724     afs_int32 code = 0;
725
726     AFS_STATCNT(afs_closex);
727     /* setup the credentials */
728     if (code = afs_InitReq(&treq, u.u_cred)) return code;
729
730     closeDone = 0;
731     /* we're the last one.  If we're an AFS vnode, clear the flags,
732      * close the file and release the lock when done.  Otherwise, just
733      * let the regular close code work.      */
734     if (afd->f_type == DTYPE_VNODE) {
735         tvc = (struct vcache *) afd->f_data;
736         if (IsAfsVnode((struct vnode *)tvc)) {
737             VN_HOLD((struct vnode *) tvc);
738             flags = afd->f_flag & (FSHLOCK | FEXLOCK);
739             afd->f_flag &= ~(FSHLOCK | FEXLOCK);
740             code = vno_close(afd);
741             if (flags) 
742 #if defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
743                 HandleFlock(tvc, LOCK_UN, &treq,
744                             u.u_procp->p_pid, 1/*onlymine*/);
745 #else
746                 HandleFlock(tvc, LOCK_UN, &treq, 0, 1/*onlymine*/);
747 #endif
748 #ifdef  AFS_DEC_ENV
749             grele((struct gnode *) tvc);
750 #else
751             AFS_RELE((struct vnode *) tvc);
752 #endif
753             closeDone = 1;
754         }
755     }
756     /* now, if close not done, do it */
757     if (!closeDone) {
758         code = vno_close(afd);
759     }
760     return code;        /* return code from vnode layer */
761 }
762 #endif
763
764
765 /* handle any closing cleanup stuff */
766 #ifdef  AFS_SGI_ENV
767 afs_close(OSI_VC_ARG(avc), aflags, lastclose,
768 #if !defined(AFS_SGI65_ENV)
769           offset,
770 #endif
771           acred
772 #if defined(AFS_SGI64_ENV) && !defined(AFS_SGI65_ENV)
773           , flp
774 #endif
775           )
776 lastclose_t lastclose;
777 #if !defined(AFS_SGI65_ENV)
778 off_t offset;
779 #if defined(AFS_SGI64_ENV)
780 struct flid *flp;
781 #endif
782 #endif
783 #else /* SGI */
784 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
785 #ifdef  AFS_SUN5_ENV
786 afs_close(OSI_VC_ARG(avc), aflags, count, offset, acred)
787     offset_t offset;
788 #else
789 afs_close(OSI_VC_ARG(avc), aflags, count, acred)
790 #endif
791 int count;
792 #else
793 afs_close(OSI_VC_ARG(avc), aflags, acred)
794 #endif
795 #endif
796     OSI_VC_DECL(avc);
797     afs_int32 aflags;
798     struct AFS_UCRED *acred; 
799 {
800     register afs_int32 code, initreq=0;
801     register struct brequest *tb;
802     struct vrequest treq;
803 #ifdef AFS_SGI65_ENV
804     struct flid flid;
805 #endif
806     OSI_VC_CONVERT(avc)
807
808     AFS_STATCNT(afs_close);
809     afs_Trace2(afs_iclSetp, CM_TRACE_CLOSE, ICL_TYPE_POINTER, avc,
810                ICL_TYPE_INT32, aflags);
811 #ifdef  AFS_SUN5_ENV
812     if (avc->flockCount) {
813         if (code = afs_InitReq(&treq, acred)) return code;
814         initreq = 1;
815         HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
816     }
817 #endif
818 #if defined(AFS_SGI_ENV)
819     if (!lastclose)
820         return 0;
821 #else
822 #if     defined(AFS_SUN_ENV) || defined(AFS_SGI_ENV)
823     if (count > 1) {
824         /* 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. */
825         return 0;
826     }
827 #endif
828 #ifdef  AFS_SUN5_ENV
829     if (!initreq) {
830 #endif
831 #endif
832         if (code = afs_InitReq(&treq, acred)) return code;
833 #ifdef  AFS_SUN5_ENV
834     }
835 #endif
836 #ifndef AFS_SUN5_ENV
837 #if defined(AFS_SGI_ENV)
838     /* unlock any locks for pid - could be wrong for child .. */
839     AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
840 #ifdef AFS_SGI65_ENV
841     get_current_flid(&flid);
842     cleanlocks((vnode_t *)avc, flid.fl_pid, flid.fl_sysid);
843     HandleFlock(avc, LOCK_UN, &treq, flid.fl_pid, 1/*onlymine*/);
844 #else
845 #ifdef AFS_SGI64_ENV
846     cleanlocks((vnode_t *)avc, flp);
847 #else /* AFS_SGI64_ENV */
848     cleanlocks((vnode_t *)avc, u.u_procp->p_epid, u.u_procp->p_sysid);
849 #endif /* AFS_SGI64_ENV */
850     HandleFlock(avc, LOCK_UN, &treq, OSI_GET_CURRENT_PID(), 1/*onlymine*/);
851 #endif /* AFS_SGI65_ENV */
852     /* afs_chkpgoob will drop and re-acquire the global lock. */
853     afs_chkpgoob(&avc->v, btoc(avc->m.Length));
854 #else
855     if (avc->flockCount) {              /* Release Lock */
856 #if     defined(AFS_OSF_ENV) || defined(AFS_SUN_ENV)
857         HandleFlock(avc, LOCK_UN, &treq, u.u_procp->p_pid, 1/*onlymine*/);
858 #else
859         HandleFlock(avc, LOCK_UN, &treq, 0, 1/*onlymine*/);
860 #endif
861     }
862 #endif
863 #endif
864     if (aflags & (FWRITE | FTRUNC)) {
865         if (afs_BBusy()) {
866             /* do it yourself if daemons are all busy */
867             ObtainWriteLock(&avc->lock,124);
868             code = afs_StoreOnLastReference(avc, &treq);
869             ReleaseWriteLock(&avc->lock);
870 #if defined(AFS_SGI_ENV)
871             AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
872 #endif
873         }
874         else {
875 #if defined(AFS_SGI_ENV)
876             AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
877 #endif
878             /* at least one daemon is idle, so ask it to do the store.
879                 Also, note that  we don't lock it any more... */
880             tb = afs_BQueue(BOP_STORE, avc, 0, 1, acred,
881                                 (afs_size_t) acred->cr_uid, (afs_size_t) 0,
882                                 (void *) 0);
883             /* sleep waiting for the store to start, then retrieve error code */
884             while ((tb->flags & BUVALID) == 0) {
885                 tb->flags |= BUWAIT;
886                 afs_osi_Sleep(tb);
887             }
888             code = tb->code;
889             afs_BRelease(tb);
890         }
891
892         /* VNOVNODE is "acceptable" error code from close, since
893             may happen when deleting a file on another machine while
894             it is open here. We do the same for ENOENT since in afs_CheckCode we map VNOVNODE -> ENOENT */
895         if (code == VNOVNODE || code == ENOENT)
896             code = 0;
897         
898         /* Ensure last closer gets the error. If another thread caused
899          * DoPartialWrite and this thread does not actually store the data,
900          * it may not see the quota error.
901          */
902         ObtainWriteLock(&avc->lock,406);
903         if (avc->vc_error) {
904 #ifdef AFS_AIX32_ENV
905             osi_ReleaseVM(avc, acred);
906 #endif
907             code = avc->vc_error;
908             avc->vc_error = 0;
909         }
910         ReleaseWriteLock(&avc->lock);
911
912         /* some codes merit specific complaint */
913         if (code < 0) {
914             afs_warnuser("afs: failed to store file (network problems)\n");
915         }
916 #ifdef  AFS_SUN5_ENV
917         else if (code == ENOSPC) {
918             afs_warnuser("afs: failed to store file (over quota or partition full)\n");
919         }
920 #else
921         else if (code == ENOSPC) {
922             afs_warnuser("afs: failed to store file (partition full)\n");
923         }
924         else if (code == EDQUOT) {
925             afs_warnuser("afs: failed to store file (over quota)\n");
926         }
927 #endif
928         else if (code != 0)
929             afs_warnuser("afs: failed to store file (%d)\n", code);
930
931         /* finally, we flush any text pages lying around here */
932         hzero(avc->flushDV);
933         osi_FlushText(avc);
934     }
935     else {
936 #if defined(AFS_SGI_ENV)
937         AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
938         osi_Assert(avc->opens > 0);
939 #endif
940         /* file open for read */
941         ObtainWriteLock(&avc->lock, 411);
942         if (avc->vc_error) {
943 #ifdef AFS_AIX32_ENV
944             osi_ReleaseVM(avc, acred);
945 #endif
946             code = avc->vc_error;
947             avc->vc_error = 0;
948         }
949         avc->opens--;
950         ReleaseWriteLock(&avc->lock);
951     }
952 #ifdef  AFS_OSF_ENV
953     if ((VREFCOUNT(avc) <= 2) && (avc->states & CUnlinked)) {
954         afs_remunlink(avc, 1);  /* ignore any return code */
955     }
956 #endif
957     code = afs_CheckCode(code, &treq, 5);
958     return code;
959 }
960
961
962
963 #ifdef  AFS_OSF_ENV
964 afs_fsync(avc, fflags, acred, waitfor)
965 int fflags;
966 int waitfor;
967 #else   /* AFS_OSF_ENV */
968 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
969 afs_fsync(OSI_VC_ARG(avc), flag, acred
970 #ifdef AFS_SGI65_ENV
971           , start, stop
972 #endif
973           )
974 #else
975 afs_fsync(avc, acred)
976 #endif
977 #endif
978     OSI_VC_DECL(avc);
979      struct AFS_UCRED *acred;
980 #if defined(AFS_SGI_ENV) || defined(AFS_SUN53_ENV)
981 int flag;
982 #ifdef AFS_SGI65_ENV
983 off_t start, stop;
984 #endif
985 #endif
986 {
987     register afs_int32 code;
988     struct vrequest treq;
989     OSI_VC_CONVERT(avc)
990
991     if (avc->vc_error)
992         return avc->vc_error;
993
994 #if defined(AFS_SUN5_ENV)
995      /* back out if called from NFS server */
996     if (curthread->t_flag & T_DONTPEND)
997         return 0;
998 #endif
999
1000     AFS_STATCNT(afs_fsync);
1001     afs_Trace1(afs_iclSetp, CM_TRACE_FSYNC, ICL_TYPE_POINTER, avc);
1002     if (code = afs_InitReq(&treq, acred)) return code;
1003
1004 #if defined(AFS_SGI_ENV)
1005     AFS_RWLOCK((vnode_t *)avc, VRWLOCK_WRITE);
1006     if (flag & FSYNC_INVAL)
1007         osi_VM_FSyncInval(avc);
1008 #endif /* AFS_SGI_ENV */
1009
1010     ObtainSharedLock(&avc->lock,18);
1011     code = 0;
1012     if (avc->execsOrWriters > 0) {
1013         /* put the file back */
1014         UpgradeSToWLock(&avc->lock,41);
1015         code = afs_StoreAllSegments(avc, &treq, AFS_SYNC);
1016         ConvertWToSLock(&avc->lock);
1017     }
1018
1019 #if defined(AFS_SGI_ENV)
1020     AFS_RWUNLOCK((vnode_t *)avc, VRWLOCK_WRITE);
1021     if (code == VNOVNODE) {
1022         /* syncing an unlinked file! - non-informative to pass an errno
1023          * 102 (== VNOVNODE) to user
1024          */
1025         code =  ENOENT;
1026     }
1027 #endif
1028
1029     code = afs_CheckCode(code, &treq, 33);
1030     ReleaseSharedLock(&avc->lock);
1031     return code;
1032 }