a005ec193b551ee9014cc364f531021d7370ec77
[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,
1423 #ifdef AFS_SUN59_ENV
1424                flkcb,
1425 #endif
1426                credp)
1427     struct vnode *vnp;
1428     int cmd;
1429 #if     defined(AFS_SUN56_ENV)
1430     struct flock64 *ap;
1431 #else
1432     struct flock *ap;
1433 #endif
1434     int flag;
1435     offset_t off;
1436 #ifdef AFS_SUN59_ENV
1437     struct flk_callback *flkcb;
1438 #endif
1439     struct AFS_UCRED *credp;
1440 {
1441     register afs_int32 code = 0;
1442     /*
1443      * Implement based on afs_lockctl
1444      */
1445     AFS_GLOCK();
1446 #ifdef AFS_SUN59_ENV
1447     if (flkcb)
1448         afs_warn("Don't know how to deal with flk_callback's!\n");
1449 #endif
1450     if ((cmd == F_GETLK) || (cmd == F_O_GETLK) || (cmd == F_SETLK) || (cmd ==  F_SETLKW)) {
1451 #ifdef  AFS_SUN53_ENV
1452         ap->l_pid = ttoproc(curthread)->p_pid;
1453         ap->l_sysid = 0;
1454 #else
1455         ap->l_pid = ttoproc(curthread)->p_epid;
1456         ap->l_sysid = ttoproc(curthread)->p_sysid;
1457 #endif
1458
1459         AFS_GUNLOCK();
1460 #ifdef  AFS_SUN56_ENV
1461         code = convoff(vnp, ap, 0, off);
1462 #else
1463         code = convoff(vnp, ap, 0, (off_t)off);
1464 #endif
1465         if (code) return code;
1466         AFS_GLOCK();
1467     }
1468
1469     code = afs_lockctl((struct vcache *)vnp, ap, cmd, credp);
1470     AFS_GUNLOCK();
1471     return code;
1472 }
1473
1474
1475 int afs_space(vnp, cmd, ap, flag, off, credp)
1476     struct vnode *vnp;
1477     int cmd;
1478 #if     defined(AFS_SUN56_ENV)
1479     struct flock64 *ap;
1480 #else
1481     struct flock *ap;
1482 #endif
1483     int flag;
1484     offset_t off;
1485     struct AFS_UCRED *credp;
1486 {
1487     register afs_int32 code = EINVAL;
1488     struct vattr vattr;
1489
1490     if ((cmd == F_FREESP)
1491 #ifdef  AFS_SUN56_ENV
1492         && ((code = convoff(vnp, ap, 0, off)) == 0)) {
1493 #else
1494         && ((code = convoff(vnp, ap, 0, (off_t)off)) == 0)) {
1495 #endif
1496         AFS_GLOCK();
1497         if (!ap->l_len) {
1498             vattr.va_mask = AT_SIZE;
1499             vattr.va_size = ap->l_start;
1500             code = afs_setattr((struct vcache *)vnp, &vattr, 0, credp);
1501         } 
1502         AFS_GUNLOCK();
1503     }
1504     return (code);
1505 }
1506
1507
1508 #endif
1509
1510 int afs_dump(vp, addr, i1, i2)
1511 struct vnode *vp;
1512 caddr_t addr;
1513 int i1, i2;
1514 {
1515     AFS_STATCNT(afs_dump);
1516     afs_warn("AFS_DUMP. MUST IMPLEMENT THIS!!!\n");
1517     return EINVAL;
1518 }
1519
1520
1521 /* Nothing fancy here; just compare if vnodes are identical ones */
1522 afs_cmp(vp1, vp2) 
1523 struct vnode *vp1, *vp2;
1524 {
1525     AFS_STATCNT(afs_cmp);
1526     return(vp1 == vp2);
1527 }
1528
1529
1530 int afs_realvp(struct vnode *vp, struct vnode **vpp) {
1531     AFS_STATCNT(afs_realvp);
1532     return EINVAL;
1533 }
1534
1535
1536 int  afs_pageio(vp, pp, ui1, ui2, i1, credp)
1537 struct vnode *vp;
1538 struct page *pp;
1539 u_int ui1, ui2;
1540 int i1;
1541 struct cred *credp;
1542 {
1543     afs_warn("afs_pageio: Not implemented\n");
1544     return EINVAL;
1545 }
1546
1547 int  afs_dumpctl(vp, i
1548 #ifdef AFS_SUN59_ENV
1549                  , blkp
1550 #endif
1551                  )
1552 struct vnode *vp;
1553 int i;
1554 #ifdef AFS_SUN59_ENV
1555 int *blkp;
1556 #endif
1557 {
1558     afs_warn("afs_dumpctl: Not implemented\n");
1559     return EINVAL;
1560 }
1561
1562 #ifdef  AFS_SUN54_ENV
1563 extern void afs_dispose(vp, p, fl, dn, cr) 
1564     struct vnode *vp;
1565     struct page *p;
1566     int fl, dn;
1567     struct cred *cr;
1568 {
1569     fs_dispose(vp, p, fl, dn, cr);
1570 }
1571
1572 int  afs_setsecattr(vp, vsecattr, flag, creds)
1573 struct vnode *vp;
1574 vsecattr_t *vsecattr;
1575 int flag;
1576 struct cred *creds;
1577 {
1578     return ENOSYS;
1579 }
1580
1581 int  afs_getsecattr(vp, vsecattr, flag, creds)
1582 struct vnode *vp;
1583 vsecattr_t *vsecattr;
1584 int flag;
1585 struct cred *creds;
1586 {
1587     return fs_fab_acl(vp, vsecattr, flag, creds);
1588 }
1589 #endif
1590
1591 #ifdef  AFS_GLOBAL_SUNLOCK
1592 extern int gafs_open(), gafs_close(), afs_ioctl(), gafs_access();
1593 extern int gafs_getattr(), gafs_setattr(), gafs_lookup(), gafs_create();
1594 extern int gafs_remove(), gafs_link(), gafs_rename(), gafs_mkdir();
1595 extern int gafs_rmdir(), gafs_readdir(), gafs_fsync(), gafs_symlink();
1596 extern int gafs_fid(), gafs_readlink(), fs_setfl(), afs_pathconf();
1597 extern int afs_lockctl();
1598 extern void gafs_inactive();
1599
1600 struct vnodeops Afs_vnodeops = {
1601         gafs_open,
1602         gafs_close,
1603         afs_vmread,
1604         afs_vmwrite,
1605         afs_ioctl,
1606         fs_setfl,
1607         gafs_getattr,
1608         gafs_setattr,
1609         gafs_access,
1610         gafs_lookup,
1611         gafs_create,
1612         gafs_remove,
1613         gafs_link,
1614         gafs_rename,
1615         gafs_mkdir,
1616         gafs_rmdir,
1617         gafs_readdir,
1618         gafs_symlink,
1619         gafs_readlink,
1620         gafs_fsync,
1621         gafs_inactive,
1622         gafs_fid,
1623         afs_rwlock,
1624         afs_rwunlock,
1625         afs_seek,
1626         afs_cmp,
1627         afs_frlock,
1628         afs_space,
1629         afs_realvp,
1630         afs_getpage,    
1631         afs_putpage,
1632         afs_map,
1633         afs_addmap,
1634         afs_delmap,
1635         fs_poll,
1636         afs_dump,
1637         afs_pathconf,
1638         afs_pageio,
1639         afs_dumpctl,
1640 #ifdef  AFS_SUN54_ENV
1641         afs_dispose,
1642         afs_setsecattr,
1643         afs_getsecattr,
1644 #endif
1645 #if     defined(AFS_SUN56_ENV)
1646         fs_shrlock,
1647 #endif
1648 };
1649 struct vnodeops *afs_ops = &Afs_vnodeops;
1650
1651
1652
1653 gafs_open(avcp, aflags, acred)
1654     register struct vcache **avcp;
1655     afs_int32 aflags;
1656     struct AFS_UCRED *acred; 
1657 {
1658     register int code;
1659
1660     AFS_GLOCK();
1661     code = afs_open(avcp, aflags, acred);
1662     AFS_GUNLOCK();
1663     return (code);
1664 }
1665
1666
1667 gafs_close(avc, aflags, count, offset, acred)
1668     offset_t offset;
1669     int count;
1670     register struct vcache *avc;
1671     afs_int32 aflags;
1672     struct AFS_UCRED *acred; 
1673 {
1674     register int code;
1675
1676     AFS_GLOCK();
1677     code = afs_close(avc, aflags, count, offset, acred);
1678     AFS_GUNLOCK();
1679     return (code);
1680 }
1681
1682
1683 gafs_getattr(avc, attrs, flags, acred)
1684     int flags;
1685     register struct vcache *avc;
1686     register struct vattr *attrs;
1687     struct AFS_UCRED *acred; 
1688 {
1689     register int code;
1690
1691     AFS_GLOCK();
1692     code = afs_getattr(avc, attrs, flags, acred);
1693     AFS_GUNLOCK();
1694     return (code);
1695 }
1696
1697
1698 gafs_setattr(avc, attrs, flags, acred)
1699     int flags;
1700     register struct vcache *avc;
1701     register struct vattr *attrs;
1702     struct AFS_UCRED *acred; 
1703 {
1704     register int code;
1705
1706     AFS_GLOCK();
1707     code = afs_setattr(avc, attrs, flags, acred);
1708     AFS_GUNLOCK();
1709     return (code);
1710 }
1711
1712
1713 gafs_access(avc, amode, flags, acred)
1714     int flags;          
1715     register struct vcache *avc;
1716     register afs_int32 amode;
1717     struct AFS_UCRED *acred; 
1718 {
1719     register int code;
1720
1721     AFS_GLOCK();
1722     code = afs_access(avc, amode, flags, acred);
1723     AFS_GUNLOCK();
1724     return (code);
1725 }
1726
1727
1728 gafs_lookup(adp, aname, avcp, pnp, flags, rdir, acred)
1729     struct pathname *pnp;
1730     int flags;
1731     struct vnode *rdir;
1732     register struct vcache *adp, **avcp;
1733     char *aname;
1734     struct AFS_UCRED *acred; 
1735 {
1736     register int code;
1737
1738     AFS_GLOCK();
1739     code = afs_lookup(adp, aname, avcp, pnp, flags, rdir, acred);
1740     AFS_GUNLOCK();
1741     return (code);
1742 }
1743
1744
1745 gafs_create(adp, aname, attrs, aexcl, amode, avcp, acred)
1746     register struct vcache *adp;
1747     char *aname;
1748     struct vattr *attrs;
1749     enum vcexcl aexcl;
1750     int amode;
1751     struct vcache **avcp;
1752     struct AFS_UCRED *acred; 
1753 {
1754     register int code;
1755
1756     AFS_GLOCK();
1757     code = afs_create(adp, aname, attrs, aexcl, amode, avcp, acred);
1758     AFS_GUNLOCK();
1759     return (code);
1760 }
1761
1762 gafs_remove(adp, aname, acred)
1763     register struct vcache *adp;
1764     char *aname;
1765     struct AFS_UCRED *acred; 
1766 {
1767     register int code;
1768
1769     AFS_GLOCK();
1770     code = afs_remove(adp, aname, acred);
1771     AFS_GUNLOCK();
1772     return (code);
1773 }
1774
1775 gafs_link(adp, avc, aname, acred)
1776     register struct vcache *avc;
1777     register struct vcache *adp;
1778     char *aname;
1779     struct AFS_UCRED *acred; 
1780 {
1781     register int code;
1782
1783     AFS_GLOCK();
1784     code = afs_link(adp, avc, aname, acred);
1785     AFS_GUNLOCK();
1786     return (code);
1787 }
1788
1789 gafs_rename(aodp, aname1, andp, aname2, acred)
1790     register struct vcache *aodp, *andp;
1791     char *aname1, *aname2;
1792     struct AFS_UCRED *acred; 
1793 {
1794     register int code;
1795
1796     AFS_GLOCK();
1797     code = afs_rename(aodp, aname1, andp, aname2, acred);
1798     AFS_GUNLOCK();
1799     return (code);
1800 }
1801
1802 gafs_mkdir(adp, aname, attrs, avcp, acred)
1803     register struct vcache *adp;
1804     register struct vcache **avcp;
1805     char *aname;
1806     struct vattr *attrs;
1807     struct AFS_UCRED *acred;
1808 {
1809     register int code;
1810
1811     AFS_GLOCK();
1812     code = afs_mkdir(adp, aname, attrs, avcp, acred);
1813     AFS_GUNLOCK();
1814     return (code);
1815 }
1816
1817
1818 gafs_rmdir(adp, aname, cdirp, acred)
1819     struct vnode *cdirp;
1820     register struct vcache *adp;
1821     char *aname;
1822     struct AFS_UCRED *acred; 
1823 {
1824     register int code;
1825
1826     AFS_GLOCK();
1827     code = afs_rmdir(adp, aname, cdirp, acred);
1828     AFS_GUNLOCK();
1829     return (code);
1830 }
1831
1832
1833 gafs_readdir(avc, auio, acred, eofp)
1834     int *eofp;
1835     register struct vcache *avc;
1836     struct uio *auio;
1837     struct AFS_UCRED *acred; 
1838 {
1839     register int code;
1840
1841     AFS_GLOCK();
1842     code = afs_readdir(avc, auio, acred, eofp);
1843     AFS_GUNLOCK();
1844     return (code); 
1845 }
1846
1847 gafs_symlink(adp, aname, attrs, atargetName, acred)
1848     register struct vcache *adp;
1849     register char *atargetName;
1850     char *aname;
1851     struct vattr *attrs;
1852     struct AFS_UCRED *acred; 
1853 {
1854     register int code;
1855
1856     AFS_GLOCK();
1857     code = afs_symlink(adp, aname, attrs, atargetName, acred);
1858     AFS_GUNLOCK();
1859     return (code);
1860 }
1861
1862
1863 gafs_readlink(avc, auio, acred)
1864     register struct vcache *avc;
1865     struct uio *auio;
1866     struct AFS_UCRED *acred; 
1867 {
1868     register int code;
1869
1870     AFS_GLOCK();
1871     code = afs_readlink(avc, auio, acred);
1872     AFS_GUNLOCK();
1873     return (code);
1874 }
1875
1876 #ifdef  AFS_SUN53_ENV
1877 gafs_fsync(avc, flag, acred)
1878     int flag;
1879 #else
1880 gafs_fsync(avc, acred)
1881 #endif
1882     register struct vcache *avc;
1883     struct AFS_UCRED *acred; 
1884 {
1885     register int code;
1886
1887     AFS_GLOCK();
1888 #ifdef  AFS_SUN53_ENV
1889     code = afs_fsync(avc, flag, acred);
1890 #else
1891     code = afs_fsync(avc, acred);
1892 #endif
1893     AFS_GUNLOCK();
1894     return (code);
1895 }
1896
1897 void afs_inactive(struct vcache *avc, struct AFS_UCRED *acred)
1898 {
1899     struct vnode *vp = (struct vnode *)avc;
1900     if (afs_shuttingdown) return ;
1901
1902     /*
1903      * In Solaris and HPUX s800 and HP-UX10.0 they actually call us with
1904      * v_count 1 on last reference!
1905      */
1906     mutex_enter(&vp->v_lock);
1907     if (avc->vrefCount <= 0) osi_Panic("afs_inactive : v_count <=0\n");
1908
1909     /*
1910      * If more than 1 don't unmap the vnode but do decrement the ref count
1911      */
1912     vp->v_count--;
1913     if (vp->v_count > 0) {
1914         mutex_exit(&vp->v_lock);
1915         return;
1916     }   
1917     mutex_exit(&vp->v_lock);    
1918     /*
1919      * Solaris calls VOP_OPEN on exec, but isn't very diligent about calling
1920      * VOP_CLOSE when executable exits.
1921      */
1922     if (avc->opens > 0 && !(avc->states & CCore))
1923         avc->opens = avc->execsOrWriters = 0;
1924
1925     afs_InactiveVCache(avc, acred);
1926 }
1927
1928 void gafs_inactive(avc, acred)
1929     register struct vcache *avc;
1930     struct AFS_UCRED *acred; 
1931 {
1932     AFS_GLOCK();
1933     afs_inactive(avc, acred);
1934     AFS_GUNLOCK();
1935 }
1936
1937
1938 gafs_fid(avc, fidpp)
1939 struct vcache *avc;
1940 struct fid **fidpp;
1941 {
1942     register int code;
1943
1944     AFS_GLOCK();
1945     code = afs_fid(avc, fidpp);
1946     AFS_GUNLOCK();
1947     return (code);
1948 }
1949
1950 #endif  /* AFS_GLOBAL_SUNLOCK */