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