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