support-namei-fileserver-on-solaris8-20010305
[openafs.git] / src / afs / SOLARIS / osi_vnodeops.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 #include "../afs/param.h"       /* Should be always first */
11 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
12 /*
13  * SOLARIS/osi_vnodeops.c
14  *
15  * Implements:
16  *
17  * Functions: AFS_TRYUP, _init, _info, _fini, afs_addmap, afs_delmap,
18  * afs_vmread, afs_vmwrite, afs_getpage, afs_GetOnePage, afs_putpage,
19  * afs_putapage, afs_nfsrdwr, afs_map, afs_PageLeft, afs_pathconf/afs_cntl,
20  * afs_ioctl, afs_rwlock, afs_rwunlock, afs_seek, afs_space, afs_dump,
21  * afs_cmp, afs_realvp, afs_pageio, afs_dumpctl, afs_dispose, afs_setsecattr,
22  * afs_getsecattr, gafs_open, gafs_close, gafs_getattr, gafs_setattr,
23  * gafs_access, gafs_lookup, gafs_create, gafs_remove, gafs_link,
24  * gafs_rename, gafs_mkdir, gafs_rmdir, gafs_readdir, gafs_symlink,
25  * gafs_readlink, gafs_fsync, afs_inactive, gafs_inactive, gafs_fid
26  *
27  *
28  * Variables: Afs_vnodeops
29  *
30  */
31 #include "../afs/sysincludes.h" /* Standard vendor system headers */
32 #include "../afs/afsincludes.h" /* Afs-based standard headers */
33 #include "../afs/afs_stats.h"  /* statistics */
34 #include "../afs/nfsclient.h"  
35
36
37 #include <sys/mman.h>
38 #include <vm/hat.h>
39 #include <vm/as.h>
40 #include <vm/page.h>
41 #include <vm/pvn.h>
42 #include <vm/seg.h>
43 #include <vm/seg_map.h>
44 #include <vm/seg_vn.h>
45 #include <vm/rm.h>
46 #if     defined(AFS_SUN5_ENV) 
47 #include <sys/modctl.h>
48 #include <sys/syscall.h>
49 #else
50 #include <vm/swap.h>
51 #endif
52 #include <sys/debug.h>
53 #if     defined(AFS_SUN5_ENV)
54 #include <sys/fs_subr.h>
55 #endif
56
57 #if     defined(AFS_SUN5_ENV)
58 /* 
59  * XXX Temporary fix for problems with Solaris rw_tryupgrade() lock.
60  * It isn't very persistent in getting the upgrade when others are
61  * waiting for it and returns 0.  So the UpgradeSToW() macro that the
62  * rw_tryupgrade used to map to wasn't good enough and we need to use
63  * the following code instead.  Obviously this isn't the proper place
64  * for it but it's only called from here for now
65  * 
66  */
67 #ifndef AFS_SUN54_ENV
68 AFS_TRYUP(lock)
69      afs_rwlock_t *lock;
70 {
71     if (!rw_tryupgrade(lock)) {
72         rw_exit(lock);
73         rw_enter(lock, RW_WRITER);
74     }
75 }
76 #endif
77 #endif
78
79
80 extern struct as kas;   /* kernel addr space */
81 extern unsigned char *afs_indexFlags;          
82 extern afs_lock_t afs_xdcache;          
83
84 /* Additional vnodeops for SunOS 4.0.x */
85 int afs_nfsrdwr(), afs_getpage(), afs_putpage(), afs_map();
86 int afs_dump(), afs_cmp(), afs_realvp(), afs_GetOnePage();
87
88 int afs_pvn_vptrunc;
89
90 #ifdef  AFS_SUN5_ENV
91
92 int afs_addmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
93     register struct vnode *avp;
94     offset_t offset;
95     struct as *asp;
96     caddr_t addr;
97     int length, prot, maxprot, flags;
98     struct AFS_UCRED *credp;
99 {
100     /* XXX What should we do here?? XXX */
101     return (0);
102 }
103
104 int afs_delmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
105     register struct vnode *avp;
106     offset_t offset;
107     struct as *asp;
108     caddr_t addr;
109     int length, prot, maxprot, flags;
110     struct AFS_UCRED *credp;
111 {
112     /* XXX What should we do here?? XXX */
113     return (0);
114 }
115
116 int afs_vmread(avp, auio, ioflag, acred)
117     register struct vnode *avp;
118     struct uio *auio;
119     int ioflag;
120     struct AFS_UCRED *acred;
121 {
122     register int code;
123
124     if (!RW_READ_HELD(&((struct vcache *)avp)->rwlock))
125         osi_Panic("afs_vmread: !rwlock");
126     AFS_GLOCK();
127     code = afs_nfsrdwr((struct vcache *)avp, auio, UIO_READ, ioflag, acred);
128     AFS_GUNLOCK();
129     return code;
130 }
131
132
133 int afs_vmwrite(avp, auio, ioflag, acred)
134     register struct vnode *avp;
135     struct uio *auio;
136     int ioflag;
137     struct AFS_UCRED *acred;
138 {
139     register int code;
140
141     if (!RW_WRITE_HELD(&((struct vcache *)avp)->rwlock))
142         osi_Panic("afs_vmwrite: !rwlock");
143     AFS_GLOCK();
144     code = afs_nfsrdwr((struct vcache *)avp, auio, UIO_WRITE, ioflag, acred);
145     AFS_GUNLOCK();
146     return code;
147 }
148
149 #endif  /* AFS_SUN5_ENV */
150
151 int afs_getpage(vp, off, len, protp, pl, plsz, seg, addr, rw, acred)
152 struct vnode *vp;
153 u_int len;
154 u_int *protp;
155 struct page *pl[];
156 u_int plsz;
157 struct seg *seg;
158 #ifdef  AFS_SUN5_ENV
159 offset_t off;
160 caddr_t addr;
161 #else
162 u_int off;
163 addr_t addr;
164 #endif
165 enum seg_rw rw;
166 struct AFS_UCRED *acred;
167 {
168     register afs_int32 code = 0;
169 #if     defined(AFS_SUN56_ENV)
170     u_offset_t  toff = (u_offset_t)off;
171 #endif
172
173     AFS_STATCNT(afs_getpage);
174 #ifdef  AFS_SUN5_ENV
175     if (vp->v_flag & VNOMAP)    /* File doesn't allow mapping */
176         return (ENOSYS);
177 #endif
178
179     AFS_GLOCK();
180
181 #if     defined(AFS_SUN56_ENV)
182     if (len <= PAGESIZE)
183         code = afs_GetOnePage((struct vnode *) vp, toff, len, protp, pl, plsz,
184                               seg, addr, rw, acred);
185 #else
186 #ifdef  AFS_SUN5_ENV
187     if (len <= PAGESIZE)
188         code = afs_GetOnePage(vp, (u_int)off, len, protp, pl, plsz,
189                               seg, addr, rw, acred);
190 #else
191     if (len == PAGESIZE)
192         code = afs_GetOnePage(vp, off, protp, pl, plsz,
193                               seg, addr, rw, acred);
194 #endif
195 #endif
196     else {
197         struct vcache *vcp = (struct vcache *)vp;
198 #ifdef  AFS_SUN5_ENV
199         ObtainWriteLock(&vcp->vlock, 548);
200         vcp->multiPage++;
201         ReleaseWriteLock(&vcp->vlock);
202 #endif
203         afs_BozonLock(&vcp->pvnLock, vcp);
204 #if     defined(AFS_SUN56_ENV)
205         code = pvn_getpages(afs_GetOnePage, (struct vnode *) vp, toff, 
206                             len, protp, pl, plsz, seg, addr, rw, acred);
207 #else
208         code = pvn_getpages(afs_GetOnePage, (struct vnode *) vp, (u_int)off, 
209                             len, protp, pl, plsz, seg, addr, rw, acred);
210 #endif
211         afs_BozonUnlock(&vcp->pvnLock, vcp);
212 #ifdef  AFS_SUN5_ENV
213         ObtainWriteLock(&vcp->vlock, 549);
214         vcp->multiPage--;
215         ReleaseWriteLock(&vcp->vlock);
216 #endif
217     }
218     AFS_GUNLOCK();
219     return code;
220 }
221
222 /* Return all the pages from [off..off+len) in file */
223 #ifdef  AFS_SUN5_ENV
224 int afs_GetOnePage(vp, off, alen, protp, pl, plsz, seg, addr, rw, acred)
225 u_int alen;
226 #else
227 int afs_GetOnePage(vp, off, protp, pl, plsz, seg, addr, rw, acred)
228 #endif
229 struct vnode *vp;
230 #if     defined(AFS_SUN56_ENV)
231 u_offset_t off;
232 #else
233 u_int off;
234 #endif
235 u_int *protp;
236 struct page *pl[];
237 u_int plsz;
238 struct seg *seg;
239 #ifdef  AFS_SUN5_ENV
240 caddr_t addr;
241 #else
242 addr_t addr;
243 #endif
244 enum seg_rw rw;
245 struct AFS_UCRED *acred;
246 {
247     register struct page *page;
248     register afs_int32 code = 0;
249     u_int len;
250     struct buf *buf;
251     afs_int32 tlen;
252     register struct vcache *avc;
253     register struct dcache *tdc;
254     int i, s, pexists;
255     int slot, offset, nlen;
256     struct vrequest treq;
257     afs_int32 mapForRead = 0, Code=0;
258 #if     defined(AFS_SUN56_ENV)
259     u_offset_t  toffset;
260 #else
261     afs_int32       toffset;
262 #endif
263
264     if (!pl) return 0;                  /* punt asynch requests */
265
266     len = PAGESIZE;
267     pl[0] = NULL;                       /* Make sure it's empty */
268     if (!acred) 
269 #ifdef  AFS_SUN5_ENV
270         osi_Panic("GetOnePage: !acred");
271 #else
272         acred = u.u_cred;               /* better than nothing */
273 #endif
274
275     /* first, obtain the proper lock for the VM system */
276     avc = (struct vcache *) vp; /* cast to afs vnode */
277
278     /* if this is a read request, map the page in read-only.  This will
279      * allow us to swap out the dcache entry if there are only read-only
280      * pages created for the chunk, which helps a *lot* when dealing
281      * with small caches.  Otherwise, we have to invalidate the vm
282      * pages for the range covered by a chunk when we swap out the
283      * chunk.
284      */
285     if (rw == S_READ || rw == S_EXEC) 
286         mapForRead = 1;
287
288     if (protp) *protp = PROT_ALL;
289 #ifdef  AFS_SUN5_ENV
290     if (avc->credp /*&& AFS_NFSXLATORREQ(acred)*/ && AFS_NFSXLATORREQ(avc->credp)) {
291         acred = avc->credp;
292     }
293 #endif
294     if (code = afs_InitReq(&treq, acred)) return code;
295 #ifndef AFS_SUN5_ENV
296     if (AFS_NFSXLATORREQ(acred)) {
297         if (rw == S_READ) {
298             if (!afs_AccessOK(avc, PRSFS_READ, &treq,
299                               CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
300                 return EACCES;
301             }
302         }
303     }
304 #endif
305 retry:
306 #ifdef  AFS_SUN5_ENV
307     if (rw == S_WRITE || rw == S_CREATE)
308         tdc = afs_GetDCache(avc, (afs_int32)off, &treq, &offset, &nlen, 5);
309     else
310         tdc = afs_GetDCache(avc, (afs_int32)off, &treq, &offset, &nlen, 1);
311     if (!tdc) return EINVAL;
312 #endif
313     code = afs_VerifyVCache(avc, &treq);
314     if (code) {
315 #ifdef  AFS_SUN5_ENV
316         afs_PutDCache(tdc);
317 #endif  
318         return afs_CheckCode(code, &treq, 44); /* failed to get it */
319     }
320
321     afs_BozonLock(&avc->pvnLock, avc);
322     ObtainSharedLock(&avc->lock,566);
323
324     afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, (afs_int32) vp,
325                ICL_TYPE_LONG, (afs_int32) off, ICL_TYPE_LONG, (afs_int32) len,
326                ICL_TYPE_LONG, (int) rw);
327
328     tlen = len;
329     slot = 0;
330     toffset = off;
331 #ifdef  AFS_SUN5_ENV
332     /* Check to see if we're in the middle of a VM purge, and if we are, release
333      * the locks and try again when the VM purge is done. */
334     ObtainWriteLock(&avc->vlock, 550);
335     if (avc->activeV) {
336         ReleaseSharedLock(&avc->lock); 
337         ReleaseWriteLock(&avc->vlock); 
338         afs_BozonUnlock(&avc->pvnLock, avc);
339         afs_PutDCache(tdc);
340         /* Check activeV again, it may have been turned off
341          * while we were waiting for a lock in afs_PutDCache */
342         ObtainWriteLock(&avc->vlock, 574);
343         if (avc->activeV) {
344             avc->vstates |= VRevokeWait;
345             ReleaseWriteLock(&avc->vlock);
346             afs_osi_Sleep(&avc->vstates);
347         } else {
348             ReleaseWriteLock(&avc->vlock);
349         }
350         goto retry;
351     }
352     ReleaseWriteLock(&avc->vlock); 
353 #endif
354
355     /* Check to see whether the cache entry is still valid */
356     if (!(avc->states & CStatd)
357         || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
358         ReleaseSharedLock(&avc->lock); 
359         afs_BozonUnlock(&avc->pvnLock, avc);
360         afs_PutDCache(tdc);
361         goto retry;
362     }
363
364     AFS_GUNLOCK();
365     while (1) { /* loop over all pages */
366         /* now, try to find the page in memory (it may already be intransit or laying
367            around the free list */
368         page = page_lookup( vp, toffset, (rw == S_CREATE ? SE_EXCL : SE_SHARED) );
369         if (page) 
370             goto nextpage;
371
372         /* if we make it here, we can't find the page in memory.  Do a real disk read
373            from the cache to get the data */
374         Code |= 0x200;          /* XXX */
375 #ifdef  AFS_SUN5_ENV
376 #if     defined(AFS_SUN54_ENV)
377         /* use PG_EXCL because we know the page does not exist already.  If it 
378          * actually does exist, we have somehow raced between lookup and create.
379          * As of 4/98, that shouldn't be possible, but we'll be defensive here
380          * in case someone tries to relax all the serialization of read and write
381          * operations with harmless things like stat. */
382 #if    defined(AFS_SUN58_ENV)
383         page = page_create_va(vp, toffset, PAGESIZE, PG_WAIT|PG_EXCL, seg, addr);
384 #else
385         page = page_create_va(vp, toffset, PAGESIZE, PG_WAIT|PG_EXCL, seg->s_as, addr);
386 #endif
387 #else
388         page = page_create(vp, toffset, PAGESIZE, PG_WAIT);
389 #endif
390         if (!page) {
391             continue;
392         }
393         if (alen < PAGESIZE)
394             pagezero(page, alen, PAGESIZE-alen); 
395 #else
396         page = rm_allocpage(seg, addr, PAGESIZE, 1);    /* can't fail */
397         if (!page) osi_Panic("afs_getpage alloc page");
398         /* we get a circularly-linked list of pages back, but we expect only
399            one, since that's what we asked for */
400         if (page->p_next != page) osi_Panic("afs_getpage list");
401         /* page enter returns a locked page; we'll drop the lock as a side-effect
402            of the pvn_done done by afs_ustrategy.  If we decide not to call
403            strategy, we must be sure to call pvn_fail, at least, to release the
404            page locks and otherwise reset the pages.  The page, while locked, is
405            not held, for what it is worth */
406         page->p_intrans = 1;    /* set appropriate flags */
407         page->p_pagein = 1;
408         /* next call shouldn't fail, since we have pvnLock set */
409         if (page_enter(page, vp, toffset)) osi_Panic("afs_getpage enter race");
410 #endif  /* AFS_SUN5_ENV */
411
412 #ifdef  AFS_SUN5_ENV
413         if (rw == S_CREATE) {
414             /* XXX Don't read from AFS in write only cases XXX */
415             page_io_unlock(page);
416         } else 
417 #else
418         if (0) {
419             /* XXX Don't read from AFS in write only cases XXX */
420             page->p_intrans = page->p_pagein = 0;
421             page_unlock(page);  /* XXX */
422         } else 
423 #endif
424             {
425 #ifndef AFS_SUN5_ENV
426             PAGE_HOLD(page);
427 #endif
428             /* now it is time to start I/O operation */
429             buf = pageio_setup(page, PAGESIZE, vp, B_READ);     /* allocate a buf structure */
430 #if     defined(AFS_SUN5_ENV)
431             buf->b_edev = 0;
432 #endif
433             buf->b_dev = 0;
434             buf->b_blkno = btodb(toffset);
435             bp_mapin(buf);              /* map it in to our address space */
436 #ifndef AFS_SUN5_ENV    
437             ReleaseSharedLock(&avc->lock);
438 #endif
439 #if     defined(AFS_SUN5_ENV)
440             AFS_GLOCK();
441             UpgradeSToWLock(&avc->lock, 564);
442             code = afs_ustrategy(buf, acred);   /* do the I/O */
443             ConvertWToSLock(&avc->lock);
444             AFS_GUNLOCK();
445 #else
446             code = afs_ustrategy(buf);  /* do the I/O */
447 #endif
448 #ifndef AFS_SUN5_ENV    
449             ObtainSharedLock(&avc->lock,245);
450 #endif
451 #ifdef  AFS_SUN5_ENV
452             /* Before freeing unmap the buffer */
453             bp_mapout(buf);
454             pageio_done(buf);
455 #endif
456             if (code) {
457 #ifndef AFS_SUN5_ENV
458                 PAGE_RELE(page);
459 #endif
460                 goto bad;
461             }
462 #ifdef  AFS_SUN5_ENV
463             page_io_unlock(page);
464 #endif
465         }
466
467         /* come here when we have another page (already held) to enter */
468       nextpage:
469         /* put page in array and continue */
470 #ifdef  AFS_SUN5_ENV
471         /* The p_selock must be downgraded to a shared lock after the page is read */
472 #if     defined(AFS_SUN56_ENV)
473         if ((rw != S_CREATE) && !(PAGE_SHARED(page))) 
474 #else
475         if ((rw != S_CREATE) && !(se_shared_assert(&page->p_selock))) 
476 #endif
477         {
478             page_downgrade(page);
479         }
480 #endif
481         pl[slot++] = page;
482 #ifdef  AFS_SUN5_ENV
483         code = page_iolock_assert(page);
484 #endif
485         code = 0;
486         toffset += PAGESIZE;
487         addr += PAGESIZE;
488         tlen -= PAGESIZE;
489         if (tlen <= 0) break;   /* done all the pages */
490     } /* while (1) ... */
491
492     AFS_GLOCK();
493     pl[slot] = (struct page *) 0;
494     avc->states |= CHasPages;
495     ReleaseSharedLock(&avc->lock);
496 #ifdef  AFS_SUN5_ENV
497     ObtainWriteLock(&afs_xdcache,246);
498     if (!mapForRead) {
499         /* track that we have dirty (or dirty-able) pages for this chunk. */
500         afs_indexFlags[tdc->index] |= IFDirtyPages;
501     }
502     afs_indexFlags[tdc->index] |= IFAnyPages;
503     ReleaseWriteLock(&afs_xdcache);
504 #endif
505     afs_BozonUnlock(&avc->pvnLock, avc);
506 #ifdef  AFS_SUN5_ENV
507     afs_PutDCache(tdc);
508 #endif
509     afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, (int)page, 
510                ICL_TYPE_LONG, Code);
511     return 0;
512
513   bad:
514     AFS_GLOCK();
515     afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, (int)page, 
516                ICL_TYPE_LONG, Code);
517     /* release all pages, drop locks, return code */
518 #ifdef  AFS_SUN5_ENV
519     if (page) 
520         pvn_read_done(page, B_ERROR);
521 #else
522     for(i=0; i<slot; i++)
523         PAGE_RELE(pl[i]);
524 #endif
525     ReleaseSharedLock(&avc->lock);
526     afs_BozonUnlock(&avc->pvnLock, avc);
527 #ifdef  AFS_SUN5_ENV
528     afs_PutDCache(tdc);
529 #endif
530     return code;
531 }
532
533 #ifdef  AFS_SUN5_ENV
534 int afs_putpage(vp, off, len, flags, cred)
535     struct vnode *vp;
536     offset_t off;
537     u_int len;
538     int flags;
539     struct AFS_UCRED *cred;
540 {
541     struct vcache *avc;
542     struct page *pages;
543     afs_int32 code = 0;
544 #if    defined(AFS_SUN58_ENV)
545     size_t tlen;
546 #else
547     afs_int32 tlen;
548 #endif
549     afs_int32 endPos, NPages=0;
550 #if     defined(AFS_SUN56_ENV)
551     u_offset_t toff = off;
552 #else
553     int toff = (int)off;
554 #endif
555
556     AFS_STATCNT(afs_putpage);
557     if (vp->v_flag & VNOMAP)            /* file doesn't allow mapping */
558         return (ENOSYS);
559
560     /*
561      * Putpage (ASYNC) is called every sec to flush out dirty vm pages 
562      */
563     AFS_GLOCK();
564     afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER, (afs_int32) vp,
565                ICL_TYPE_LONG, (afs_int32) off, ICL_TYPE_LONG, (afs_int32) len,
566                ICL_TYPE_LONG, (int) flags);
567     avc = (struct vcache *) vp;
568     afs_BozonLock(&avc->pvnLock, avc);
569     ObtainWriteLock(&avc->lock,247);
570
571     /* Get a list of modified (or whatever) pages */
572     if (len) {
573         endPos = (int)off + len;                /* position we're supposed to write up to */
574         while ((afs_int32)toff < endPos && (afs_int32)toff < avc->m.Length) {
575             /* If not invalidating pages use page_lookup_nowait to avoid reclaiming
576              * them from the free list
577              */
578             AFS_GUNLOCK();
579             if (flags & (B_FREE|B_INVAL))
580                 pages = page_lookup(vp, toff, SE_EXCL);
581             else
582                 pages = page_lookup_nowait(vp, toff, SE_SHARED);
583             if (!pages || !pvn_getdirty(pages, flags)) 
584                 tlen = PAGESIZE;
585             else {
586                 NPages++;
587                 code = afs_putapage(vp, pages, &toff, &tlen, flags, cred);
588                 if (code) {
589                     AFS_GLOCK();
590                     break;
591                 }
592             }
593             toff += tlen;
594             AFS_GLOCK();
595         }
596     } else {
597         AFS_GUNLOCK();
598 #if     defined(AFS_SUN56_ENV) 
599         code = pvn_vplist_dirty(vp, toff, afs_putapage, flags, cred);
600 #else
601         code = pvn_vplist_dirty(vp, (u_int)off, afs_putapage, flags, cred);
602 #endif
603         AFS_GLOCK();
604     }
605
606     if (code && !avc->vc_error)
607         avc->vc_error = code;
608
609     ReleaseWriteLock(&avc->lock);
610     afs_BozonUnlock(&avc->pvnLock, avc);
611     afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, NPages);
612     AFS_GUNLOCK();
613     return (code);
614 }
615
616
617 int afs_putapage(struct vnode *vp, struct page *pages,
618 #if     defined(AFS_SUN56_ENV)
619                  u_offset_t *offp,
620 #else
621                  u_int *offp,
622 #endif
623 #if    defined(AFS_SUN58_ENV)
624                  size_t *lenp,
625 #else
626                  u_int *lenp,
627 #endif
628                  int flags, struct AFS_UCRED *credp)
629 {
630     struct buf *tbuf;
631     struct vcache *avc = (struct vcache *)vp;
632     afs_int32 code = 0;
633     u_int toff, tlen = PAGESIZE, off = (pages->p_offset/PAGESIZE)*PAGESIZE;
634     u_int poff = pages->p_offset;
635
636     /*
637      * Now we've got the modified pages.  All pages are locked and held 
638      * XXX Find a kluster that fits in one block (or page). We also
639      * adjust the i/o if the file space is less than a while page. XXX
640      */
641     toff = off;
642     if (tlen+toff > avc->m.Length) {
643         tlen = avc->m.Length - toff;
644     }
645     /* can't call mapout with 0 length buffers (rmfree panics) */
646     if (((tlen>>24)&0xff) == 0xff) {
647         tlen = 0;
648     }
649     if ((int)tlen > 0) {
650         /*
651          * Can't call mapout with 0 length buffers since we'll get rmfree panics
652          */
653         tbuf = pageio_setup(pages, tlen, vp, B_WRITE | flags);
654         if (!tbuf) return (ENOMEM);
655
656         tbuf->b_dev = 0;
657         tbuf->b_blkno = btodb(pages->p_offset);
658         bp_mapin(tbuf);
659         AFS_GLOCK();
660         afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUTONE, ICL_TYPE_LONG, avc, ICL_TYPE_LONG, pages,
661                ICL_TYPE_LONG, tlen, ICL_TYPE_LONG, toff);
662         code = afs_ustrategy(tbuf, credp);      /* unlocks page */
663         AFS_GUNLOCK();
664         bp_mapout(tbuf);
665     }
666     pvn_write_done(pages, ((code) ? B_ERROR:0) | B_WRITE | flags);
667     if ((int)tlen > 0)
668         pageio_done(tbuf);
669     if (offp) *offp = toff;
670     if (lenp) *lenp = tlen;
671     return code;
672 }
673
674 #else   AFS_SUN5_ENV
675
676 int afs_putpage(vp, off, len, flags, cred)
677 struct vnode *vp;
678 u_int off;
679 u_int len;
680 int flags;
681 struct AFS_UCRED *cred;
682 {
683     int wholeEnchilada; /* true if we must get all of the pages */
684     struct vcache *avc;
685     struct page *pages;
686     struct page *tpage;
687     struct buf *tbuf;
688     afs_int32 tlen;
689     afs_int32 code = 0, rcode;
690     afs_int32 poffset;
691     afs_int32 clusterStart, clusterEnd, endPos;
692
693     /* In the wholeEnchilada case, we must ensure that we get all of the pages
694        from the system, since we're doing this to shutdown the use of a vnode */
695
696     AFS_STATCNT(afs_putpage);
697     wholeEnchilada = (off == 0 && len == 0 && (flags & (B_INVAL|B_ASYNC)) == B_INVAL);
698
699     avc = (struct vcache *) vp;
700     afs_BozonLock(&avc->pvnLock, avc);
701     ObtainWriteLock(&avc->lock,248);
702
703     while (1) {
704         /* in whole enchilada case, loop until call to pvn_getdirty can't find
705            any more modified pages */
706
707         /* first we try to get a list of modified (or whatever) pages */
708         if (len == 0) {
709             pages = pvn_vplist_dirty(vp, off, flags);
710         }
711         else {
712             endPos = off + len; /* position we're supposed to write up to */
713             if (endPos > avc->m.Length) endPos = avc->m.Length; /* bound by this */
714             clusterStart = off & ~(PAGESIZE-1); /* round down to nearest page */
715             clusterEnd = ((endPos-1) | (PAGESIZE-1))+1; /* round up to nearest page */
716             pages = pvn_range_dirty(vp, off, endPos, clusterStart, clusterEnd, flags);
717         }
718         
719         /* Now we've got the modified pages.  All pages are locked and held */
720         rcode = 0;              /* return code */
721         while(pages) {  /* look over all pages in the returned set */
722             tpage = pages;      /* get first page in the list */
723
724             /* write out the page */
725             poffset = tpage->p_offset;  /* where the page starts in the file */
726             /* tlen will represent the end of the range to write, for a while */
727             tlen = PAGESIZE+poffset;    /* basic place to end tpage write */
728             /* but we also don't want to write past end of off..off+len range */
729             if (len != 0 && tlen > off+len) tlen = off+len;
730             /* and we don't want to write past the end of the file */
731             if (tlen > avc->m.Length) tlen = avc->m.Length;
732             /* and we don't want to write at all if page starts after end */
733             if (poffset >= tlen) {
734                 pvn_fail(pages, B_WRITE | flags);
735                 goto done;
736             }
737             /* finally change tlen from end position to length */
738             tlen -= poffset;    /* compute bytes to write from this page */
739             page_sub(&pages, tpage);    /* remove tpage from "pages" list */
740             tbuf = pageio_setup(tpage, tlen, vp, B_WRITE | flags);
741             if (!tbuf) {
742                 pvn_fail(tpage, B_WRITE|flags);
743                 pvn_fail(pages, B_WRITE|flags);
744                 goto done;
745             }
746             tbuf->b_dev = 0;
747             tbuf->b_blkno = btodb(tpage->p_offset);
748             bp_mapin(tbuf);
749             ReleaseWriteLock(&avc->lock);       /* can't hold during strategy call */
750             code = afs_ustrategy(tbuf);         /* unlocks page */
751             ObtainWriteLock(&avc->lock,249);    /* re-obtain */
752             if (code) {
753                 /* unlocking of tpage is done by afs_ustrategy */
754                 rcode = code;
755                 if (pages)      /* may have already removed last page */
756                     pvn_fail(pages, B_WRITE|flags);
757                 goto done;
758             }
759         }       /* for (tpage=pages....) */
760
761         /* see if we've gotten all of the pages in the whole enchilada case */
762         if (!wholeEnchilada || !vp->v_pages) break;
763     }   /* while(1) obtaining all pages */
764
765     /*
766      * If low on chunks, and if writing the last byte of a chunk, try to
767      * free some.  Note that afs_DoPartialWrite calls osi_SyncVM which now
768      * calls afs_putpage, so this is recursion.  It stops there because we
769      * insist on len being non-zero.
770      */
771     if (afs_stats_cmperf.cacheCurrDirtyChunks > afs_stats_cmperf.cacheMaxDirtyChunks
772         && len != 0 && AFS_CHUNKOFFSET((off + len)) == 0)  {
773         struct vrequest treq;
774         if (!afs_InitReq(&treq, cred ? cred : u.u_cred)) {
775             rcode = afs_DoPartialWrite(avc, &treq);     /* XXX */
776         }
777     }
778     
779   done:
780
781     if (rcode && !avc->vc_error)
782         avc->vc_error = rcode;
783
784     /* when we're here, we just return code. */
785     ReleaseWriteLock(&avc->lock);
786     afs_BozonUnlock(&avc->pvnLock, avc);
787     return rcode;
788 }
789
790 #endif  /* AFS_SUN5_ENV */
791
792 int afs_nfsrdwr(avc, auio, arw, ioflag, acred)
793 register struct vcache *avc;
794 struct uio *auio;
795 enum uio_rw arw;
796 int ioflag;
797 struct AFS_UCRED *acred;
798 {
799     register afs_int32 code;
800     afs_int32 code2;
801     int counter;
802     afs_int32 mode, sflags;
803     register char *data;
804     struct dcache *dcp, *dcp_newpage;
805     afs_int32 fileBase, size;
806     afs_int32 pageBase;
807     register afs_int32 tsize;
808     register afs_int32 pageOffset, extraResid=0;
809     register long origLength;           /* length when reading/writing started */
810     register long appendLength;         /* length when this call will finish */
811     int created;                        /* created pages instead of faulting them */
812     int lockCode;
813     int didFakeOpen, eof;
814     struct vrequest treq;
815     caddr_t raddr;
816     u_int rsize;
817
818     AFS_STATCNT(afs_nfsrdwr);
819
820     /* can't read or write other things */
821     if (vType(avc) != VREG) return EISDIR;
822
823     if (auio->uio_resid == 0)
824         return (0);
825
826     afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, (afs_int32)avc,
827                ICL_TYPE_LONG, (arw==UIO_WRITE? 1 : 0),
828                ICL_TYPE_LONG, auio->uio_offset,
829                ICL_TYPE_LONG, auio->uio_resid);
830
831     if ( AfsLargeFileUio(auio) )        /* file is larger than 2 GB */
832         return (EFBIG);
833     
834 #ifdef  AFS_SUN5_ENV
835     if (!acred) osi_Panic("rdwr: !acred");
836 #else
837     if (!acred) acred = u.u_cred;
838 #endif
839     if (code = afs_InitReq(&treq, acred)) return code;
840
841     /* It's not really possible to know if a write cause a growth in the
842      * cache size, we we wait for a cache drain for any write.
843      */
844     afs_MaybeWakeupTruncateDaemon();
845     while ((arw == UIO_WRITE) &&
846            (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100)) {
847         if (afs_blocksUsed - afs_blocksDiscarded >
848             (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
849             afs_WaitForCacheDrain = 1;
850             afs_osi_Sleep(&afs_WaitForCacheDrain);
851         }
852         afs_MaybeFreeDiscardedDCache();
853         afs_MaybeWakeupTruncateDaemon();
854     }
855     code = afs_VerifyVCache(avc, &treq);
856     if (code) return afs_CheckCode(code, &treq, 45);
857
858     afs_BozonLock(&avc->pvnLock, avc);
859     osi_FlushPages(avc, acred); /* hold bozon lock, but not basic vnode lock */
860
861     ObtainWriteLock(&avc->lock,250);
862
863     /* adjust parameters when appending files */
864     if ((ioflag & IO_APPEND) && arw == UIO_WRITE)
865     {
866 #if     defined(AFS_SUN56_ENV)
867         auio->uio_loffset = 0;
868 #endif
869         auio->uio_offset = avc->m.Length;       /* write at EOF position */
870     }
871     if (auio->uio_offset < 0 || (auio->uio_offset + auio->uio_resid) < 0) {
872         ReleaseWriteLock(&avc->lock);   
873         afs_BozonUnlock(&avc->pvnLock, avc);
874         return EINVAL;
875     }
876
877                                         /* file is larger than 2GB */
878     if ( AfsLargeFileSize(auio->uio_offset, auio->uio_resid) ) {
879         ReleaseWriteLock(&avc->lock);   
880         afs_BozonUnlock(&avc->pvnLock, avc);
881         return EFBIG;
882     }
883
884     didFakeOpen=0;      /* keep track of open so we can do close */
885     if (arw == UIO_WRITE) {
886         /* do ulimit processing; shrink resid or fail */
887 #if     defined(AFS_SUN56_ENV)
888         if (auio->uio_loffset + auio->afsio_resid > auio->uio_llimit) {
889             if (auio->uio_llimit >= auio->uio_llimit) {
890                 ReleaseWriteLock(&avc->lock);
891                 afs_BozonUnlock(&avc->pvnLock, avc);
892                 return EFBIG;
893             } else {
894                 /* track # of bytes we should write, but won't because of
895                  * ulimit; we must add this into the final resid value
896                  * so caller knows we punted some data.
897                  */
898                 extraResid = auio->uio_resid;
899                 auio->uio_resid = auio->uio_llimit - auio->uio_loffset;
900                 extraResid -= auio->uio_resid;
901             }
902         }
903 #else
904 #ifdef  AFS_SUN52_ENV   
905         if (auio->afsio_offset + auio->afsio_resid > auio->uio_limit) {
906             if (auio->afsio_offset >= auio->uio_limit) {
907                 ReleaseWriteLock(&avc->lock);   
908                 afs_BozonUnlock(&avc->pvnLock, avc);
909                 return EFBIG;
910             } else {
911                 /* track # of bytes we should write, but won't because of
912                  * ulimit; we must add this into the final resid value
913                  * so caller knows we punted some data.
914                  */
915                 extraResid = auio->uio_resid;
916                 auio->uio_resid = auio->uio_limit - auio->afsio_offset;
917                 extraResid -= auio->uio_resid;
918             }
919         }
920 #endif
921 #endif /* SUN56 */
922         mode = S_WRITE;         /* segment map-in mode */
923         afs_FakeOpen(avc);      /* do this for writes, so data gets put back
924                                    when we want it to be put back */
925         didFakeOpen = 1;        /* we'll be doing a fake open */
926         /* before starting any I/O, we must ensure that the file is big enough
927            to hold the results (since afs_putpage will be called to force the I/O */
928         size = auio->afsio_resid + auio->afsio_offset;  /* new file size */
929         appendLength = size;            
930         origLength = avc->m.Length;
931         if (size > avc->m.Length) 
932             avc->m.Length = size;       /* file grew */
933         avc->states |= CDirty;          /* Set the dirty bit */
934         avc->m.Date = osi_Time();       /* Set file date (for ranlib) */
935     } else {
936         mode = S_READ;                  /* map-in read-only */
937         origLength = avc->m.Length;
938     }
939
940     if (acred && AFS_NFSXLATORREQ(acred)) {
941         if (arw == UIO_READ) {
942             if (!afs_AccessOK(avc, PRSFS_READ, &treq,
943                               CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
944                 ReleaseWriteLock(&avc->lock);   
945                 afs_BozonUnlock(&avc->pvnLock, avc);
946                 return EACCES;
947             }
948         }
949 #ifdef  AFS_SUN5_ENV
950         crhold(acred);
951         if (avc->credp) {
952             crfree(avc->credp);
953         }
954         avc->credp = acred;
955 #endif
956     }
957     counter = 0; /* don't call afs_DoPartialWrite first time through. */
958     while (1) {
959         /* compute the amount of data to move into this block,
960            based on auio->afsio_resid.  Note that we copy data in units of
961            MAXBSIZE, not PAGESIZE.  This is because segmap_getmap panics if you
962            call it with an offset based on blocks smaller than MAXBSIZE
963            (implying that it should be named BSIZE, since it is clearly both a
964            max and a min). */
965         size = auio->afsio_resid;               /* transfer size */
966         fileBase = auio->afsio_offset;          /* start file position for xfr */
967         pageBase = fileBase & ~(MAXBSIZE-1);    /* file position of the page */
968         pageOffset = fileBase & (MAXBSIZE-1);   /* xfr start's offset within page */
969         tsize = MAXBSIZE-pageOffset;            /* how much more fits in this page */
970         /* we'll read tsize bytes, but first must make sure tsize isn't too big */
971         if (tsize > size) tsize = size; /* don't read past end of request */
972         eof = 0;        /* flag telling us if we hit the EOF on the read */
973         if (arw == UIO_READ) {          /* we're doing a read operation */
974             /* don't read past EOF */
975             if (tsize + fileBase > origLength) {
976                 tsize = origLength - fileBase;
977                 eof = 1;                /* we did hit the EOF */
978                 if (tsize < 0) tsize = 0;       /* better safe than sorry */
979             }
980             sflags = 0;
981         }
982         else {
983 #ifdef  AFS_SUN5_ENV
984             /* Purge dirty chunks of file if there are too many dirty
985              * chunks. Inside the write loop, we only do this at a chunk
986              * boundary. Clean up partial chunk if necessary at end of loop.
987              */
988             if (counter > 0 && code == 0 && AFS_CHUNKOFFSET(fileBase) == 0)
989                 {
990                     code = afs_DoPartialWrite(avc, &treq);
991                     if (code)
992                         break;
993                 }
994 #endif  /* AFS_SUN5_ENV */
995             /* write case, we ask segmap_release to call putpage.  Really, we
996                don't have to do this on every page mapin, but for now we're
997                lazy, and don't modify the rest of AFS to scan for modified
998                pages on a close or other "synchronize with file server"
999                operation.  This makes things a little cleaner, but probably
1000                hurts performance. */
1001             sflags = SM_WRITE;
1002         }
1003         if (tsize <= 0) {
1004             code = 0;
1005             break;      /* nothing to transfer, we're done */
1006         }
1007 #ifdef  AFS_SUN5_ENV
1008         if (arw == UIO_WRITE)
1009             avc->states |= CDirty; /* may have been cleared by DoPartialWrite*/
1010
1011         /* Before dropping lock, hold the chunk (create it if necessary).  This
1012          * serves two purposes:  (1) Ensure Cache Truncate Daemon doesn't try
1013          * to purge the chunk's pages while we have them locked.  This would
1014          * cause deadlock because we might be waiting for the CTD to free up
1015          * a chunk.  (2)  If we're writing past the original EOF, and we're
1016          * at the base of the chunk, then make sure it exists online
1017          * before we do the uiomove, since the segmap_release will
1018          * write out to the chunk, causing it to get fetched if it hasn't
1019          * been created yet.  The code that would otherwise notice that
1020          * we're fetching a chunk past EOF won't work, since we've
1021          * already adjusted the file size above.
1022          */
1023         ObtainWriteLock(&avc->vlock, 551);
1024         while (avc->vstates & VPageCleaning) {
1025             ReleaseWriteLock(&avc->vlock);
1026             ReleaseWriteLock(&avc->lock);
1027             afs_osi_Sleep(&avc->vstates);
1028             ObtainWriteLock(&avc->lock, 334);
1029             ObtainWriteLock(&avc->vlock, 552);
1030         }
1031         ReleaseWriteLock(&avc->vlock);
1032         {
1033             int toff, tlen;
1034             dcp = afs_GetDCache(avc, fileBase, &treq, &toff, &tlen, 2);
1035             if (!dcp) {
1036                 code = ENOENT;  
1037                 break;
1038             }
1039         }
1040 #endif
1041         ReleaseWriteLock(&avc->lock);   /* uiomove may page fault */
1042         AFS_GUNLOCK();
1043 #if     defined(AFS_SUN56_ENV)
1044         data = segmap_getmap(segkmap,(struct vnode *)avc,(u_offset_t)pageBase);
1045 #else
1046         data = segmap_getmap(segkmap, (struct vnode *) avc, pageBase);
1047 #endif
1048 #ifndef AFS_SUN5_ENV
1049         code = as_fault(&kas, data+pageOffset, tsize, F_SOFTLOCK, mode);
1050         if (code == 0) {
1051             AFS_UIOMOVE(data+pageOffset, tsize, arw, auio, code);
1052             as_fault(&kas, data+pageOffset, tsize, F_SOFTUNLOCK, mode);
1053             code2 = segmap_release(segkmap, data, sflags);
1054             if (!code)
1055                 code = code2;
1056         }
1057         else {
1058             (void) segmap_release(segkmap, data, 0);
1059         }
1060 #else
1061 #if defined(AFS_SUN56_ENV)
1062         raddr = (caddr_t) (((uintptr_t)data +pageOffset) & PAGEMASK);
1063 #else
1064         raddr = (caddr_t) (((u_int)data +pageOffset) & PAGEMASK);
1065 #endif
1066         rsize = (((u_int)data+pageOffset+tsize+PAGEOFFSET) & PAGEMASK)-(u_int)raddr;
1067         if (code == 0) {
1068             /* if we're doing a write, and we're starting at the rounded
1069              * down page base, and we're writing enough data to cover all
1070              * created pages, then we must be writing all of the pages
1071              * in this MAXBSIZE window that we're creating.
1072              */
1073             created = 0;
1074             if (arw == UIO_WRITE
1075                     && ((long)raddr == (long)data+pageOffset)
1076                     && tsize >= rsize) {
1077                 /* probably the dcache backing this guy is around, but if
1078                  * not, we can't do this optimization, since we're creating
1079                  * writable pages, which must be backed by a chunk.
1080                  */
1081                 AFS_GLOCK();
1082                 dcp_newpage = afs_FindDCache(avc, pageBase);
1083                 if (dcp_newpage
1084                     && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)) {
1085                     ObtainWriteLock(&avc->lock,251);
1086                     ObtainWriteLock(&avc->vlock,576);
1087                     if ((avc->activeV == 0)
1088                         && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)
1089                         && !(dcp_newpage->flags & (DFFetching))) {
1090                         AFS_GUNLOCK();
1091                         segmap_pagecreate(segkmap, raddr, rsize, 1);
1092                         AFS_GLOCK();
1093                         ObtainWriteLock(&afs_xdcache,252);
1094                         /* Mark the pages as created and dirty */
1095                         afs_indexFlags[dcp_newpage->index]
1096                             |= (IFAnyPages | IFDirtyPages);
1097                         ReleaseWriteLock(&afs_xdcache);             
1098                         avc->states |= CHasPages;
1099                         created = 1;
1100                     }
1101                     afs_PutDCache(dcp_newpage);
1102                     ReleaseWriteLock(&avc->vlock);
1103                     ReleaseWriteLock(&avc->lock);
1104                 }
1105                 else if ( dcp_newpage )
1106                     afs_PutDCache(dcp_newpage);
1107                 AFS_GUNLOCK();
1108             }
1109             if (!created)
1110                 code = segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTLOCK, mode);
1111         }
1112         if (code == 0) {
1113             AFS_UIOMOVE(data+pageOffset, tsize, arw, auio, code);
1114             segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTUNLOCK, mode);
1115         }
1116         if (code == 0) {
1117             code = segmap_release(segkmap, data, sflags);
1118         } else {
1119             (void) segmap_release(segkmap, data, 0);
1120         }
1121 #endif  /* AFS_SUN5_ENV */
1122         AFS_GLOCK();
1123         ObtainWriteLock(&avc->lock,253);
1124 #ifdef  AFS_SUN5_ENV
1125         /*
1126          * If at a chunk boundary, start prefetch of next chunk.
1127          */
1128         if (counter == 0 || AFS_CHUNKOFFSET(fileBase) == 0) {
1129             if (!(dcp->flags & DFNextStarted))
1130                 afs_PrefetchChunk(avc, dcp, acred, &treq);
1131         }
1132         counter++;
1133         if (dcp)        
1134             afs_PutDCache(dcp);
1135 #endif  /* AFS_SUN5_ENV */
1136         if (code) break;
1137     }
1138     if (didFakeOpen) {
1139         afs_FakeClose(avc, acred);
1140     }
1141
1142 #ifdef  AFS_SUN5_ENV
1143     if (arw == UIO_WRITE && (avc->states & CDirty)) {
1144         code2 = afs_DoPartialWrite(avc, &treq);
1145         if (!code)
1146             code = code2;
1147     }
1148 #endif  /* AFS_SUN5_ENV */
1149
1150     if (!code && avc->vc_error) {
1151         code = avc->vc_error;
1152     }
1153     ReleaseWriteLock(&avc->lock);
1154     afs_BozonUnlock(&avc->pvnLock, avc);
1155     if (!code) {
1156 #ifdef  AFS_SUN53_ENV
1157         if ((ioflag & FSYNC) && (arw == UIO_WRITE) && !AFS_NFSXLATORREQ(acred))
1158             code = afs_fsync(avc, 0, acred);
1159 #else
1160         if ((ioflag & IO_SYNC) && (arw == UIO_WRITE)
1161             && !AFS_NFSXLATORREQ(acred))
1162             code = afs_fsync(avc, acred);
1163 #endif
1164     }
1165 #ifdef  AFS_SUN52_ENV   
1166     /* 
1167      * If things worked, add in as remaining in request any bytes
1168      * we didn't write due to file size ulimit.
1169      */
1170     if (code == 0 && extraResid > 0)
1171         auio->uio_resid += extraResid;
1172 #endif
1173     return afs_CheckCode(code, &treq, 46);
1174 }
1175
1176 afs_map(vp, off, as, addr, len, prot, maxprot, flags, cred)
1177 struct vnode *vp;
1178 struct as *as;
1179 #ifdef  AFS_SUN5_ENV
1180 offset_t off;
1181 caddr_t *addr;
1182 #else
1183 u_int off;
1184 addr_t *addr;
1185 #endif
1186 u_int len;
1187 #ifdef  AFS_SUN5_ENV
1188 u_char prot, maxprot;
1189 #else
1190 u_int prot, maxprot;
1191 #endif
1192 u_int flags;
1193 struct AFS_UCRED *cred;
1194 {
1195        struct segvn_crargs crargs;
1196         register afs_int32 code;
1197         struct vrequest treq;
1198         register struct vcache *avc = (struct vcache *) vp;
1199
1200         AFS_STATCNT(afs_map);
1201
1202
1203         /* check for reasonableness on segment bounds; apparently len can be < 0 */
1204         if ((int)off < 0 || (int)(off + len) < 0) {
1205             return (EINVAL);
1206         }
1207         if ( AfsLargeFileSize(off, len) ) /* file is larger than 2 GB */
1208         {
1209             code = EFBIG;
1210             goto out;
1211         }
1212
1213 #if     defined(AFS_SUN5_ENV)
1214         if (vp->v_flag & VNOMAP)        /* File isn't allowed to be mapped */
1215             return (ENOSYS);
1216
1217         if (vp->v_filocks)              /* if locked, disallow mapping */
1218             return (EAGAIN);
1219 #endif
1220        AFS_GLOCK();     
1221        if (code = afs_InitReq(&treq, cred)) goto out;
1222
1223         if (vp->v_type != VREG) {
1224             code = ENODEV;
1225             goto out;
1226         }
1227
1228         code = afs_VerifyVCache(avc, &treq);
1229         if (code) {
1230             goto out;
1231         }
1232         afs_BozonLock(&avc->pvnLock, avc);
1233         osi_FlushPages(avc, cred);      /* ensure old pages are gone */
1234         avc->states |= CMAPPED; /* flag cleared at afs_inactive */
1235         afs_BozonUnlock(&avc->pvnLock, avc);
1236
1237         AFS_GUNLOCK();
1238 #ifdef  AFS_SUN5_ENV
1239         as_rangelock(as);
1240 #endif
1241         if ((flags & MAP_FIXED) == 0) {
1242 #if     defined(AFS_SUN57_ENV)
1243            map_addr(addr, len, off, 1, flags); 
1244 #elif   defined(AFS_SUN56_ENV)
1245             map_addr(addr, len, off, 1);
1246 #else
1247             map_addr(addr, len, (off_t)off, 1);
1248 #endif
1249             if (*addr == NULL) {
1250 #ifdef  AFS_SUN5_ENV
1251                 as_rangeunlock(as);
1252 #endif
1253                 code = ENOMEM;
1254                 goto out1;
1255             }
1256         } else
1257             (void) as_unmap(as, *addr, len);    /* unmap old address space use */
1258         /* setup the create parameter block for the call */
1259         crargs.vp = (struct vnode *) avc;
1260         crargs.offset = (u_int)off;
1261         crargs.cred = cred;
1262         crargs.type = flags&MAP_TYPE;
1263         crargs.prot = prot;
1264         crargs.maxprot = maxprot;
1265         crargs.amp = (struct anon_map *) 0;
1266 #if     defined(AFS_SUN5_ENV)
1267         crargs.flags = flags & ~MAP_TYPE;
1268 #endif
1269
1270         code = as_map(as, *addr, len, segvn_create, (char *) &crargs);
1271 #ifdef  AFS_SUN5_ENV
1272         as_rangeunlock(as);
1273 #endif
1274 out1:
1275         AFS_GLOCK();
1276         code = afs_CheckCode(code, &treq, 47);
1277         AFS_GUNLOCK();
1278         return code;
1279 out:
1280         code = afs_CheckCode(code, &treq, 48);
1281         AFS_GUNLOCK();
1282         return code;
1283 }
1284
1285 /* Sun 4.0.X-specific code.  It computes the number of bytes that need
1286     to be zeroed at the end of a page by pvn_vptrunc, given that you're
1287     trying to get vptrunc to truncate a file to alen bytes.  The result
1288     will be passed to pvn_vptrunc by the truncate code */
1289 #ifndef AFS_SUN5_ENV            /* Not good for Solaris */
1290 afs_PageLeft(alen)
1291 register afs_int32 alen; {
1292     register afs_int32 nbytes;
1293
1294     AFS_STATCNT(afs_PageLeft);
1295     nbytes = PAGESIZE - (alen & PAGEOFFSET); /* amount to zap in last page */
1296     /* now check if we'd zero the entire last page.  Don't need to do this
1297        since pvn_vptrunc will handle this case properly (it will invalidate
1298        this page) */
1299     if (nbytes == PAGESIZE) nbytes = 0;
1300     if (nbytes < 0) nbytes = 0; /* just in case */
1301     return nbytes;
1302 }
1303 #endif
1304
1305
1306 /*
1307  * For Now We use standard local kernel params for AFS system values. Change this
1308  * at some point.
1309  */
1310 #if     defined(AFS_SUN5_ENV)
1311 afs_pathconf(vp, cmd, outdatap, credp)
1312     register struct AFS_UCRED *credp;
1313 #else
1314 afs_cntl(vp, cmd, indatap, outdatap, inflag, outflag)
1315     int inflag, outflag;
1316     char *indatap;
1317 #endif
1318     struct vnode *vp;
1319     int cmd;
1320     u_long *outdatap;
1321 {
1322     AFS_STATCNT(afs_cntl);
1323     switch (cmd) {
1324       case _PC_LINK_MAX:
1325         *outdatap = MAXLINK;
1326         break;
1327       case _PC_NAME_MAX:
1328         *outdatap = MAXNAMLEN;
1329         break;
1330       case _PC_PATH_MAX:
1331         *outdatap = MAXPATHLEN;
1332         break;
1333       case _PC_CHOWN_RESTRICTED:
1334         *outdatap = 1;
1335         break;
1336       case _PC_NO_TRUNC:
1337         *outdatap = 1;
1338         break;
1339 #if     !defined(AFS_SUN5_ENV)
1340       case _PC_MAX_CANON:
1341         *outdatap = CANBSIZ;
1342         break;
1343       case _PC_VDISABLE:
1344         *outdatap = VDISABLE;
1345         break;
1346       case _PC_PIPE_BUF:
1347         return EINVAL;
1348         break;
1349 #endif
1350       default:
1351         return EINVAL;
1352     }
1353     return 0;
1354 }
1355
1356 #endif /* AFS_SUN_ENV */
1357
1358 #if     defined(AFS_SUN5_ENV)
1359
1360 afs_ioctl(vnp, com, arg, flag, credp, rvalp)
1361     struct vnode *vnp;
1362     int com, arg, flag;
1363     cred_t *credp;
1364     int *rvalp;
1365 {
1366     return (ENOTTY);
1367 }
1368
1369 void afs_rwlock(vnp, wlock)
1370     struct vnode *vnp;
1371     int wlock;
1372 {
1373     rw_enter(&((struct vcache *)vnp)->rwlock, (wlock ? RW_WRITER : RW_READER));
1374 }
1375
1376
1377 void afs_rwunlock(vnp, wlock)
1378     struct vnode *vnp;
1379     int wlock;
1380 {
1381     rw_exit(&((struct vcache *)vnp)->rwlock);
1382 }
1383
1384
1385 /* NOT SUPPORTED */
1386 afs_seek(vnp, ooff, noffp)
1387     struct vnode *vnp;
1388     offset_t ooff;
1389     offset_t *noffp;
1390 {
1391     register int code = 0;
1392
1393     if ((*noffp < 0 || *noffp > MAXOFF_T))
1394         code = EINVAL;
1395     return code;
1396 }
1397
1398 int afs_frlock(vnp, cmd, ap, flag, off, credp)
1399     struct vnode *vnp;
1400     int cmd;
1401 #if     defined(AFS_SUN56_ENV)
1402     struct flock64 *ap;
1403 #else
1404     struct flock *ap;
1405 #endif
1406     int flag;
1407     offset_t off;
1408     struct AFS_UCRED *credp;
1409 {
1410     register afs_int32 code = 0;
1411     /*
1412      * Implement based on afs_lockctl
1413      */
1414     AFS_GLOCK();
1415     if ((cmd == F_GETLK) || (cmd == F_O_GETLK) || (cmd == F_SETLK) || (cmd ==  F_SETLKW)) {
1416 #ifdef  AFS_SUN53_ENV
1417         ap->l_pid = ttoproc(curthread)->p_pid;
1418         ap->l_sysid = 0;
1419 #else
1420         ap->l_pid = ttoproc(curthread)->p_epid;
1421         ap->l_sysid = ttoproc(curthread)->p_sysid;
1422 #endif
1423
1424         AFS_GUNLOCK();
1425 #ifdef  AFS_SUN56_ENV
1426         code = convoff(vnp, ap, 0, off);
1427 #else
1428         code = convoff(vnp, ap, 0, (off_t)off);
1429 #endif
1430         if (code) return code;
1431         AFS_GLOCK();
1432     }
1433
1434     code = afs_lockctl((struct vcache *)vnp, ap, cmd, credp);
1435     AFS_GUNLOCK();
1436     return code;
1437 }
1438
1439
1440 int afs_space(vnp, cmd, ap, flag, off, credp)
1441     struct vnode *vnp;
1442     int cmd;
1443 #if     defined(AFS_SUN56_ENV)
1444     struct flock64 *ap;
1445 #else
1446     struct flock *ap;
1447 #endif
1448     int flag;
1449     offset_t off;
1450     struct AFS_UCRED *credp;
1451 {
1452     register afs_int32 code = EINVAL;
1453     struct vattr vattr;
1454
1455     if ((cmd == F_FREESP)
1456 #ifdef  AFS_SUN56_ENV
1457         && ((code = convoff(vnp, ap, 0, off)) == 0)) {
1458 #else
1459         && ((code = convoff(vnp, ap, 0, (off_t)off)) == 0)) {
1460 #endif
1461         AFS_GLOCK();
1462         if (!ap->l_len) {
1463             vattr.va_mask = AT_SIZE;
1464             vattr.va_size = ap->l_start;
1465             code = afs_setattr((struct vcache *)vnp, &vattr, 0, credp);
1466         } 
1467         AFS_GUNLOCK();
1468     }
1469     return (code);
1470 }
1471
1472
1473 #endif
1474
1475 int afs_dump(vp, addr, i1, i2)
1476 struct vnode *vp;
1477 caddr_t addr;
1478 int i1, i2;
1479 {
1480     AFS_STATCNT(afs_dump);
1481     afs_warn("AFS_DUMP. MUST IMPLEMENT THIS!!!\n");
1482     return EINVAL;
1483 }
1484
1485
1486 /* Nothing fancy here; just compare if vnodes are identical ones */
1487 afs_cmp(vp1, vp2) 
1488 struct vnode *vp1, *vp2;
1489 {
1490     AFS_STATCNT(afs_cmp);
1491     return(vp1 == vp2);
1492 }
1493
1494
1495 int afs_realvp(struct vnode *vp, struct vnode **vpp) {
1496     AFS_STATCNT(afs_realvp);
1497     return EINVAL;
1498 }
1499
1500
1501 int  afs_pageio(vp, pp, ui1, ui2, i1, credp)
1502 struct vnode *vp;
1503 struct page *pp;
1504 u_int ui1, ui2;
1505 int i1;
1506 struct cred *credp;
1507 {
1508     afs_warn("afs_pageio: Not implemented\n");
1509     return EINVAL;
1510 }
1511
1512 int  afs_dumpctl(vp, i)
1513 struct vnode *vp;
1514 int i;
1515 {
1516     afs_warn("afs_dumpctl: Not implemented\n");
1517     return EINVAL;
1518 }
1519
1520 #ifdef  AFS_SUN54_ENV
1521 extern void afs_dispose(vp, p, fl, dn, cr) 
1522     struct vnode *vp;
1523     struct page *p;
1524     int fl, dn;
1525     struct cred *cr;
1526 {
1527     fs_dispose(vp, p, fl, dn, cr);
1528 }
1529
1530 int  afs_setsecattr(vp, vsecattr, flag, creds)
1531 struct vnode *vp;
1532 vsecattr_t *vsecattr;
1533 int flag;
1534 struct cred *creds;
1535 {
1536     return ENOSYS;
1537 }
1538
1539 int  afs_getsecattr(vp, vsecattr, flag, creds)
1540 struct vnode *vp;
1541 vsecattr_t *vsecattr;
1542 int flag;
1543 struct cred *creds;
1544 {
1545     return fs_fab_acl(vp, vsecattr, flag, creds);
1546 }
1547 #endif
1548
1549 #ifdef  AFS_GLOBAL_SUNLOCK
1550 extern int gafs_open(), gafs_close(), afs_ioctl(), gafs_access();
1551 extern int gafs_getattr(), gafs_setattr(), gafs_lookup(), gafs_create();
1552 extern int gafs_remove(), gafs_link(), gafs_rename(), gafs_mkdir();
1553 extern int gafs_rmdir(), gafs_readdir(), gafs_fsync(), gafs_symlink();
1554 extern int gafs_fid(), gafs_readlink(), fs_setfl(), afs_pathconf();
1555 extern int afs_lockctl();
1556 extern void gafs_inactive();
1557
1558 struct vnodeops Afs_vnodeops = {
1559         gafs_open,
1560         gafs_close,
1561         afs_vmread,
1562         afs_vmwrite,
1563         afs_ioctl,
1564         fs_setfl,
1565         gafs_getattr,
1566         gafs_setattr,
1567         gafs_access,
1568         gafs_lookup,
1569         gafs_create,
1570         gafs_remove,
1571         gafs_link,
1572         gafs_rename,
1573         gafs_mkdir,
1574         gafs_rmdir,
1575         gafs_readdir,
1576         gafs_symlink,
1577         gafs_readlink,
1578         gafs_fsync,
1579         gafs_inactive,
1580         gafs_fid,
1581         afs_rwlock,
1582         afs_rwunlock,
1583         afs_seek,
1584         afs_cmp,
1585         afs_frlock,
1586         afs_space,
1587         afs_realvp,
1588         afs_getpage,    
1589         afs_putpage,
1590         afs_map,
1591         afs_addmap,
1592         afs_delmap,
1593         fs_poll,
1594         afs_dump,
1595         afs_pathconf,
1596         afs_pageio,
1597         afs_dumpctl,
1598 #ifdef  AFS_SUN54_ENV
1599         afs_dispose,
1600         afs_setsecattr,
1601         afs_getsecattr,
1602 #endif
1603 #if     defined(AFS_SUN56_ENV)
1604         fs_shrlock,
1605 #endif
1606 };
1607 struct vnodeops *afs_ops = &Afs_vnodeops;
1608
1609
1610
1611 gafs_open(avcp, aflags, acred)
1612     register struct vcache **avcp;
1613     afs_int32 aflags;
1614     struct AFS_UCRED *acred; 
1615 {
1616     register int code;
1617
1618     AFS_GLOCK();
1619     code = afs_open(avcp, aflags, acred);
1620     AFS_GUNLOCK();
1621     return (code);
1622 }
1623
1624
1625 gafs_close(avc, aflags, count, offset, acred)
1626     offset_t offset;
1627     int count;
1628     register struct vcache *avc;
1629     afs_int32 aflags;
1630     struct AFS_UCRED *acred; 
1631 {
1632     register int code;
1633
1634     AFS_GLOCK();
1635     code = afs_close(avc, aflags, count, offset, acred);
1636     AFS_GUNLOCK();
1637     return (code);
1638 }
1639
1640
1641 gafs_getattr(avc, attrs, flags, acred)
1642     int flags;
1643     register struct vcache *avc;
1644     register struct vattr *attrs;
1645     struct AFS_UCRED *acred; 
1646 {
1647     register int code;
1648
1649     AFS_GLOCK();
1650     code = afs_getattr(avc, attrs, flags, acred);
1651     AFS_GUNLOCK();
1652     return (code);
1653 }
1654
1655
1656 gafs_setattr(avc, attrs, flags, acred)
1657     int flags;
1658     register struct vcache *avc;
1659     register struct vattr *attrs;
1660     struct AFS_UCRED *acred; 
1661 {
1662     register int code;
1663
1664     AFS_GLOCK();
1665     code = afs_setattr(avc, attrs, flags, acred);
1666     AFS_GUNLOCK();
1667     return (code);
1668 }
1669
1670
1671 gafs_access(avc, amode, flags, acred)
1672     int flags;          
1673     register struct vcache *avc;
1674     register afs_int32 amode;
1675     struct AFS_UCRED *acred; 
1676 {
1677     register int code;
1678
1679     AFS_GLOCK();
1680     code = afs_access(avc, amode, flags, acred);
1681     AFS_GUNLOCK();
1682     return (code);
1683 }
1684
1685
1686 gafs_lookup(adp, aname, avcp, pnp, flags, rdir, acred)
1687     struct pathname *pnp;
1688     int flags;
1689     struct vnode *rdir;
1690     register struct vcache *adp, **avcp;
1691     char *aname;
1692     struct AFS_UCRED *acred; 
1693 {
1694     register int code;
1695
1696     AFS_GLOCK();
1697     code = afs_lookup(adp, aname, avcp, pnp, flags, rdir, acred);
1698     AFS_GUNLOCK();
1699     return (code);
1700 }
1701
1702
1703 gafs_create(adp, aname, attrs, aexcl, amode, avcp, acred)
1704     register struct vcache *adp;
1705     char *aname;
1706     struct vattr *attrs;
1707     enum vcexcl aexcl;
1708     int amode;
1709     struct vcache **avcp;
1710     struct AFS_UCRED *acred; 
1711 {
1712     register int code;
1713
1714     AFS_GLOCK();
1715     code = afs_create(adp, aname, attrs, aexcl, amode, avcp, acred);
1716     AFS_GUNLOCK();
1717     return (code);
1718 }
1719
1720 gafs_remove(adp, aname, acred)
1721     register struct vcache *adp;
1722     char *aname;
1723     struct AFS_UCRED *acred; 
1724 {
1725     register int code;
1726
1727     AFS_GLOCK();
1728     code = afs_remove(adp, aname, acred);
1729     AFS_GUNLOCK();
1730     return (code);
1731 }
1732
1733 gafs_link(adp, avc, aname, acred)
1734     register struct vcache *avc;
1735     register struct vcache *adp;
1736     char *aname;
1737     struct AFS_UCRED *acred; 
1738 {
1739     register int code;
1740
1741     AFS_GLOCK();
1742     code = afs_link(adp, avc, aname, acred);
1743     AFS_GUNLOCK();
1744     return (code);
1745 }
1746
1747 gafs_rename(aodp, aname1, andp, aname2, acred)
1748     register struct vcache *aodp, *andp;
1749     char *aname1, *aname2;
1750     struct AFS_UCRED *acred; 
1751 {
1752     register int code;
1753
1754     AFS_GLOCK();
1755     code = afs_rename(aodp, aname1, andp, aname2, acred);
1756     AFS_GUNLOCK();
1757     return (code);
1758 }
1759
1760 gafs_mkdir(adp, aname, attrs, avcp, acred)
1761     register struct vcache *adp;
1762     register struct vcache **avcp;
1763     char *aname;
1764     struct vattr *attrs;
1765     struct AFS_UCRED *acred;
1766 {
1767     register int code;
1768
1769     AFS_GLOCK();
1770     code = afs_mkdir(adp, aname, attrs, avcp, acred);
1771     AFS_GUNLOCK();
1772     return (code);
1773 }
1774
1775
1776 gafs_rmdir(adp, aname, cdirp, acred)
1777     struct vnode *cdirp;
1778     register struct vcache *adp;
1779     char *aname;
1780     struct AFS_UCRED *acred; 
1781 {
1782     register int code;
1783
1784     AFS_GLOCK();
1785     code = afs_rmdir(adp, aname, cdirp, acred);
1786     AFS_GUNLOCK();
1787     return (code);
1788 }
1789
1790
1791 gafs_readdir(avc, auio, acred, eofp)
1792     int *eofp;
1793     register struct vcache *avc;
1794     struct uio *auio;
1795     struct AFS_UCRED *acred; 
1796 {
1797     register int code;
1798
1799     AFS_GLOCK();
1800     code = afs_readdir(avc, auio, acred, eofp);
1801     AFS_GUNLOCK();
1802     return (code); 
1803 }
1804
1805 gafs_symlink(adp, aname, attrs, atargetName, acred)
1806     register struct vcache *adp;
1807     register char *atargetName;
1808     char *aname;
1809     struct vattr *attrs;
1810     struct AFS_UCRED *acred; 
1811 {
1812     register int code;
1813
1814     AFS_GLOCK();
1815     code = afs_symlink(adp, aname, attrs, atargetName, acred);
1816     AFS_GUNLOCK();
1817     return (code);
1818 }
1819
1820
1821 gafs_readlink(avc, auio, acred)
1822     register struct vcache *avc;
1823     struct uio *auio;
1824     struct AFS_UCRED *acred; 
1825 {
1826     register int code;
1827
1828     AFS_GLOCK();
1829     code = afs_readlink(avc, auio, acred);
1830     AFS_GUNLOCK();
1831     return (code);
1832 }
1833
1834 #ifdef  AFS_SUN53_ENV
1835 gafs_fsync(avc, flag, acred)
1836     int flag;
1837 #else
1838 gafs_fsync(avc, acred)
1839 #endif
1840     register struct vcache *avc;
1841     struct AFS_UCRED *acred; 
1842 {
1843     register int code;
1844
1845     AFS_GLOCK();
1846 #ifdef  AFS_SUN53_ENV
1847     code = afs_fsync(avc, flag, acred);
1848 #else
1849     code = afs_fsync(avc, acred);
1850 #endif
1851     AFS_GUNLOCK();
1852     return (code);
1853 }
1854
1855 void afs_inactive(struct vcache *avc, struct AFS_UCRED *acred)
1856 {
1857     struct vnode *vp = (struct vnode *)avc;
1858     if (afs_shuttingdown) return ;
1859
1860     /*
1861      * In Solaris and HPUX s800 and HP-UX10.0 they actually call us with
1862      * v_count 1 on last reference!
1863      */
1864     mutex_enter(&vp->v_lock);
1865     if (avc->vrefCount <= 0) osi_Panic("afs_inactive : v_count <=0\n");
1866
1867     /*
1868      * If more than 1 don't unmap the vnode but do decrement the ref count
1869      */
1870     vp->v_count--;
1871     if (vp->v_count > 0) {
1872         mutex_exit(&vp->v_lock);
1873         return;
1874     }   
1875     mutex_exit(&vp->v_lock);    
1876     /*
1877      * Solaris calls VOP_OPEN on exec, but isn't very diligent about calling
1878      * VOP_CLOSE when executable exits.
1879      */
1880     if (avc->opens > 0 && !(avc->states & CCore))
1881         avc->opens = avc->execsOrWriters = 0;
1882
1883     afs_InactiveVCache(avc, acred);
1884 }
1885
1886 void gafs_inactive(avc, acred)
1887     register struct vcache *avc;
1888     struct AFS_UCRED *acred; 
1889 {
1890     AFS_GLOCK();
1891     afs_inactive(avc, acred);
1892     AFS_GUNLOCK();
1893 }
1894
1895
1896 gafs_fid(avc, fidpp)
1897 struct vcache *avc;
1898 struct fid **fidpp;
1899 {
1900     register int code;
1901
1902     AFS_GLOCK();
1903     code = afs_fid(avc, fidpp);
1904     AFS_GUNLOCK();
1905     return (code);
1906 }
1907
1908 #endif  /* AFS_GLOBAL_SUNLOCK */