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