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