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