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