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