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