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