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