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