2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include "../afs/param.h"
15 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
17 * SOLARIS/osi_vnodeops.c
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
32 * Variables: Afs_vnodeops
35 #include "../afs/sysincludes.h" /* Standard vendor system headers */
36 #include "../afs/afsincludes.h" /* Afs-based standard headers */
37 #include "../afs/afs_stats.h" /* statistics */
38 #include "../afs/nfsclient.h"
47 #include <vm/seg_map.h>
48 #include <vm/seg_vn.h>
50 #if defined(AFS_SUN5_ENV)
51 #include <sys/modctl.h>
52 #include <sys/syscall.h>
56 #include <sys/debug.h>
57 #if defined(AFS_SUN5_ENV)
58 #include <sys/fs_subr.h>
61 #if defined(AFS_SUN5_ENV)
63 * XXX Temporary fix for problems with Solaris rw_tryupgrade() lock.
64 * It isn't very persistent in getting the upgrade when others are
65 * waiting for it and returns 0. So the UpgradeSToW() macro that the
66 * rw_tryupgrade used to map to wasn't good enough and we need to use
67 * the following code instead. Obviously this isn't the proper place
68 * for it but it's only called from here for now
75 if (!rw_tryupgrade(lock)) {
77 rw_enter(lock, RW_WRITER);
84 extern struct as kas; /* kernel addr space */
85 extern unsigned char *afs_indexFlags;
86 extern afs_lock_t afs_xdcache;
88 /* Additional vnodeops for SunOS 4.0.x */
89 int afs_nfsrdwr(), afs_getpage(), afs_putpage(), afs_map();
90 int afs_dump(), afs_cmp(), afs_realvp(), afs_GetOnePage();
96 int afs_addmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
97 register struct vnode *avp;
101 int length, prot, maxprot, flags;
102 struct AFS_UCRED *credp;
104 /* XXX What should we do here?? XXX */
108 int afs_delmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
109 register struct vnode *avp;
113 int length, prot, maxprot, flags;
114 struct AFS_UCRED *credp;
116 /* XXX What should we do here?? XXX */
120 int afs_vmread(avp, auio, ioflag, acred)
121 register struct vnode *avp;
124 struct AFS_UCRED *acred;
128 if (!RW_READ_HELD(&((struct vcache *)avp)->rwlock))
129 osi_Panic("afs_vmread: !rwlock");
131 code = afs_nfsrdwr((struct vcache *)avp, auio, UIO_READ, ioflag, acred);
137 int afs_vmwrite(avp, auio, ioflag, acred)
138 register struct vnode *avp;
141 struct AFS_UCRED *acred;
145 if (!RW_WRITE_HELD(&((struct vcache *)avp)->rwlock))
146 osi_Panic("afs_vmwrite: !rwlock");
148 code = afs_nfsrdwr((struct vcache *)avp, auio, UIO_WRITE, ioflag, acred);
153 #endif /* AFS_SUN5_ENV */
155 int afs_getpage(vp, off, len, protp, pl, plsz, seg, addr, rw, acred)
170 struct AFS_UCRED *acred;
172 register afs_int32 code = 0;
173 #if defined(AFS_SUN56_ENV)
174 u_offset_t toff = (u_offset_t)off;
177 AFS_STATCNT(afs_getpage);
179 if (vp->v_flag & VNOMAP) /* File doesn't allow mapping */
185 #if defined(AFS_SUN56_ENV)
187 code = afs_GetOnePage((struct vnode *) vp, toff, len, protp, pl, plsz,
188 seg, addr, rw, acred);
192 code = afs_GetOnePage(vp, (u_int)off, len, protp, pl, plsz,
193 seg, addr, rw, acred);
196 code = afs_GetOnePage(vp, off, protp, pl, plsz,
197 seg, addr, rw, acred);
201 struct vcache *vcp = (struct vcache *)vp;
203 ObtainWriteLock(&vcp->vlock, 548);
205 ReleaseWriteLock(&vcp->vlock);
207 afs_BozonLock(&vcp->pvnLock, vcp);
208 #if defined(AFS_SUN56_ENV)
209 code = pvn_getpages(afs_GetOnePage, (struct vnode *) vp, toff,
210 len, protp, pl, plsz, seg, addr, rw, acred);
212 code = pvn_getpages(afs_GetOnePage, (struct vnode *) vp, (u_int)off,
213 len, protp, pl, plsz, seg, addr, rw, acred);
215 afs_BozonUnlock(&vcp->pvnLock, vcp);
217 ObtainWriteLock(&vcp->vlock, 549);
219 ReleaseWriteLock(&vcp->vlock);
226 /* Return all the pages from [off..off+len) in file */
228 int afs_GetOnePage(vp, off, alen, protp, pl, plsz, seg, addr, rw, acred)
231 int afs_GetOnePage(vp, off, protp, pl, plsz, seg, addr, rw, acred)
234 #if defined(AFS_SUN56_ENV)
249 struct AFS_UCRED *acred;
251 register struct page *page;
252 register afs_int32 code = 0;
256 register struct vcache *avc;
257 register struct dcache *tdc;
259 int slot, offset, nlen;
260 struct vrequest treq;
261 afs_int32 mapForRead = 0, Code=0;
262 #if defined(AFS_SUN56_ENV)
268 if (!pl) return 0; /* punt asynch requests */
271 pl[0] = NULL; /* Make sure it's empty */
274 osi_Panic("GetOnePage: !acred");
276 acred = u.u_cred; /* better than nothing */
279 /* first, obtain the proper lock for the VM system */
280 avc = (struct vcache *) vp; /* cast to afs vnode */
282 /* if this is a read request, map the page in read-only. This will
283 * allow us to swap out the dcache entry if there are only read-only
284 * pages created for the chunk, which helps a *lot* when dealing
285 * with small caches. Otherwise, we have to invalidate the vm
286 * pages for the range covered by a chunk when we swap out the
289 if (rw == S_READ || rw == S_EXEC)
292 if (protp) *protp = PROT_ALL;
294 if (avc->credp /*&& AFS_NFSXLATORREQ(acred)*/ && AFS_NFSXLATORREQ(avc->credp)) {
298 if (code = afs_InitReq(&treq, acred)) return code;
300 if (AFS_NFSXLATORREQ(acred)) {
302 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
303 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
311 if (rw == S_WRITE || rw == S_CREATE)
312 tdc = afs_GetDCache(avc, (afs_int32)off, &treq, &offset, &nlen, 5);
314 tdc = afs_GetDCache(avc, (afs_int32)off, &treq, &offset, &nlen, 1);
315 if (!tdc) return EINVAL;
317 code = afs_VerifyVCache(avc, &treq);
322 return afs_CheckCode(code, &treq, 44); /* failed to get it */
325 afs_BozonLock(&avc->pvnLock, avc);
326 ObtainSharedLock(&avc->lock,566);
328 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, (afs_int32) vp,
329 ICL_TYPE_LONG, (afs_int32) off, ICL_TYPE_LONG, (afs_int32) len,
330 ICL_TYPE_LONG, (int) rw);
336 /* Check to see if we're in the middle of a VM purge, and if we are, release
337 * the locks and try again when the VM purge is done. */
338 ObtainWriteLock(&avc->vlock, 550);
340 ReleaseSharedLock(&avc->lock);
341 ReleaseWriteLock(&avc->vlock);
342 afs_BozonUnlock(&avc->pvnLock, avc);
344 /* Check activeV again, it may have been turned off
345 * while we were waiting for a lock in afs_PutDCache */
346 ObtainWriteLock(&avc->vlock, 574);
348 avc->vstates |= VRevokeWait;
349 ReleaseWriteLock(&avc->vlock);
350 afs_osi_Sleep(&avc->vstates);
352 ReleaseWriteLock(&avc->vlock);
356 ReleaseWriteLock(&avc->vlock);
359 /* Check to see whether the cache entry is still valid */
360 if (!(avc->states & CStatd)
361 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
362 ReleaseSharedLock(&avc->lock);
363 afs_BozonUnlock(&avc->pvnLock, avc);
369 while (1) { /* loop over all pages */
370 /* now, try to find the page in memory (it may already be intransit or laying
371 around the free list */
372 page = page_lookup( vp, toffset, (rw == S_CREATE ? SE_EXCL : SE_SHARED) );
376 /* if we make it here, we can't find the page in memory. Do a real disk read
377 from the cache to get the data */
378 Code |= 0x200; /* XXX */
380 #if defined(AFS_SUN54_ENV)
381 /* use PG_EXCL because we know the page does not exist already. If it
382 * actually does exist, we have somehow raced between lookup and create.
383 * As of 4/98, that shouldn't be possible, but we'll be defensive here
384 * in case someone tries to relax all the serialization of read and write
385 * operations with harmless things like stat. */
386 #if defined(AFS_SUN58_ENV)
387 page = page_create_va(vp, toffset, PAGESIZE, PG_WAIT|PG_EXCL, seg, addr);
389 page = page_create_va(vp, toffset, PAGESIZE, PG_WAIT|PG_EXCL, seg->s_as, addr);
392 page = page_create(vp, toffset, PAGESIZE, PG_WAIT);
398 pagezero(page, alen, PAGESIZE-alen);
400 page = rm_allocpage(seg, addr, PAGESIZE, 1); /* can't fail */
401 if (!page) osi_Panic("afs_getpage alloc page");
402 /* we get a circularly-linked list of pages back, but we expect only
403 one, since that's what we asked for */
404 if (page->p_next != page) osi_Panic("afs_getpage list");
405 /* page enter returns a locked page; we'll drop the lock as a side-effect
406 of the pvn_done done by afs_ustrategy. If we decide not to call
407 strategy, we must be sure to call pvn_fail, at least, to release the
408 page locks and otherwise reset the pages. The page, while locked, is
409 not held, for what it is worth */
410 page->p_intrans = 1; /* set appropriate flags */
412 /* next call shouldn't fail, since we have pvnLock set */
413 if (page_enter(page, vp, toffset)) osi_Panic("afs_getpage enter race");
414 #endif /* AFS_SUN5_ENV */
417 if (rw == S_CREATE) {
418 /* XXX Don't read from AFS in write only cases XXX */
419 page_io_unlock(page);
423 /* XXX Don't read from AFS in write only cases XXX */
424 page->p_intrans = page->p_pagein = 0;
425 page_unlock(page); /* XXX */
432 /* now it is time to start I/O operation */
433 buf = pageio_setup(page, PAGESIZE, vp, B_READ); /* allocate a buf structure */
434 #if defined(AFS_SUN5_ENV)
438 buf->b_blkno = btodb(toffset);
439 bp_mapin(buf); /* map it in to our address space */
441 ReleaseSharedLock(&avc->lock);
443 #if defined(AFS_SUN5_ENV)
445 UpgradeSToWLock(&avc->lock, 564);
446 code = afs_ustrategy(buf, acred); /* do the I/O */
447 ConvertWToSLock(&avc->lock);
450 code = afs_ustrategy(buf); /* do the I/O */
453 ObtainSharedLock(&avc->lock,245);
456 /* Before freeing unmap the buffer */
467 page_io_unlock(page);
471 /* come here when we have another page (already held) to enter */
473 /* put page in array and continue */
475 /* The p_selock must be downgraded to a shared lock after the page is read */
476 #if defined(AFS_SUN56_ENV)
477 if ((rw != S_CREATE) && !(PAGE_SHARED(page)))
479 if ((rw != S_CREATE) && !(se_shared_assert(&page->p_selock)))
482 page_downgrade(page);
487 code = page_iolock_assert(page);
493 if (tlen <= 0) break; /* done all the pages */
494 } /* while (1) ... */
497 pl[slot] = (struct page *) 0;
498 avc->states |= CHasPages;
499 ReleaseSharedLock(&avc->lock);
501 ObtainWriteLock(&afs_xdcache,246);
503 /* track that we have dirty (or dirty-able) pages for this chunk. */
504 afs_indexFlags[tdc->index] |= IFDirtyPages;
506 afs_indexFlags[tdc->index] |= IFAnyPages;
507 ReleaseWriteLock(&afs_xdcache);
509 afs_BozonUnlock(&avc->pvnLock, avc);
513 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, (int)page,
514 ICL_TYPE_LONG, Code);
519 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, (int)page,
520 ICL_TYPE_LONG, Code);
521 /* release all pages, drop locks, return code */
524 pvn_read_done(page, B_ERROR);
526 for(i=0; i<slot; i++)
529 ReleaseSharedLock(&avc->lock);
530 afs_BozonUnlock(&avc->pvnLock, avc);
538 int afs_putpage(vp, off, len, flags, cred)
543 struct AFS_UCRED *cred;
548 #if defined(AFS_SUN58_ENV)
553 afs_int32 endPos, NPages=0;
554 #if defined(AFS_SUN56_ENV)
555 u_offset_t toff = off;
560 AFS_STATCNT(afs_putpage);
561 if (vp->v_flag & VNOMAP) /* file doesn't allow mapping */
565 * Putpage (ASYNC) is called every sec to flush out dirty vm pages
568 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER, (afs_int32) vp,
569 ICL_TYPE_LONG, (afs_int32) off, ICL_TYPE_LONG, (afs_int32) len,
570 ICL_TYPE_LONG, (int) flags);
571 avc = (struct vcache *) vp;
572 afs_BozonLock(&avc->pvnLock, avc);
573 ObtainWriteLock(&avc->lock,247);
575 /* Get a list of modified (or whatever) pages */
577 endPos = (int)off + len; /* position we're supposed to write up to */
578 while ((afs_int32)toff < endPos && (afs_int32)toff < avc->m.Length) {
579 /* If not invalidating pages use page_lookup_nowait to avoid reclaiming
580 * them from the free list
583 if (flags & (B_FREE|B_INVAL))
584 pages = page_lookup(vp, toff, SE_EXCL);
586 pages = page_lookup_nowait(vp, toff, SE_SHARED);
587 if (!pages || !pvn_getdirty(pages, flags))
591 code = afs_putapage(vp, pages, &toff, &tlen, flags, cred);
602 #if defined(AFS_SUN56_ENV)
603 code = pvn_vplist_dirty(vp, toff, afs_putapage, flags, cred);
605 code = pvn_vplist_dirty(vp, (u_int)off, afs_putapage, flags, cred);
610 if (code && !avc->vc_error)
611 avc->vc_error = code;
613 ReleaseWriteLock(&avc->lock);
614 afs_BozonUnlock(&avc->pvnLock, avc);
615 afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, NPages);
621 int afs_putapage(struct vnode *vp, struct page *pages,
622 #if defined(AFS_SUN56_ENV)
627 #if defined(AFS_SUN58_ENV)
632 int flags, struct AFS_UCRED *credp)
635 struct vcache *avc = (struct vcache *)vp;
637 u_int toff, tlen = PAGESIZE, off = (pages->p_offset/PAGESIZE)*PAGESIZE;
638 u_int poff = pages->p_offset;
641 * Now we've got the modified pages. All pages are locked and held
642 * XXX Find a kluster that fits in one block (or page). We also
643 * adjust the i/o if the file space is less than a while page. XXX
646 if (tlen+toff > avc->m.Length) {
647 tlen = avc->m.Length - toff;
649 /* can't call mapout with 0 length buffers (rmfree panics) */
650 if (((tlen>>24)&0xff) == 0xff) {
655 * Can't call mapout with 0 length buffers since we'll get rmfree panics
657 tbuf = pageio_setup(pages, tlen, vp, B_WRITE | flags);
658 if (!tbuf) return (ENOMEM);
661 tbuf->b_blkno = btodb(pages->p_offset);
664 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUTONE, ICL_TYPE_LONG, avc, ICL_TYPE_LONG, pages,
665 ICL_TYPE_LONG, tlen, ICL_TYPE_LONG, toff);
666 code = afs_ustrategy(tbuf, credp); /* unlocks page */
670 pvn_write_done(pages, ((code) ? B_ERROR:0) | B_WRITE | flags);
673 if (offp) *offp = toff;
674 if (lenp) *lenp = tlen;
680 int afs_putpage(vp, off, len, flags, cred)
685 struct AFS_UCRED *cred;
687 int wholeEnchilada; /* true if we must get all of the pages */
693 afs_int32 code = 0, rcode;
695 afs_int32 clusterStart, clusterEnd, endPos;
697 /* In the wholeEnchilada case, we must ensure that we get all of the pages
698 from the system, since we're doing this to shutdown the use of a vnode */
700 AFS_STATCNT(afs_putpage);
701 wholeEnchilada = (off == 0 && len == 0 && (flags & (B_INVAL|B_ASYNC)) == B_INVAL);
703 avc = (struct vcache *) vp;
704 afs_BozonLock(&avc->pvnLock, avc);
705 ObtainWriteLock(&avc->lock,248);
708 /* in whole enchilada case, loop until call to pvn_getdirty can't find
709 any more modified pages */
711 /* first we try to get a list of modified (or whatever) pages */
713 pages = pvn_vplist_dirty(vp, off, flags);
716 endPos = off + len; /* position we're supposed to write up to */
717 if (endPos > avc->m.Length) endPos = avc->m.Length; /* bound by this */
718 clusterStart = off & ~(PAGESIZE-1); /* round down to nearest page */
719 clusterEnd = ((endPos-1) | (PAGESIZE-1))+1; /* round up to nearest page */
720 pages = pvn_range_dirty(vp, off, endPos, clusterStart, clusterEnd, flags);
723 /* Now we've got the modified pages. All pages are locked and held */
724 rcode = 0; /* return code */
725 while(pages) { /* look over all pages in the returned set */
726 tpage = pages; /* get first page in the list */
728 /* write out the page */
729 poffset = tpage->p_offset; /* where the page starts in the file */
730 /* tlen will represent the end of the range to write, for a while */
731 tlen = PAGESIZE+poffset; /* basic place to end tpage write */
732 /* but we also don't want to write past end of off..off+len range */
733 if (len != 0 && tlen > off+len) tlen = off+len;
734 /* and we don't want to write past the end of the file */
735 if (tlen > avc->m.Length) tlen = avc->m.Length;
736 /* and we don't want to write at all if page starts after end */
737 if (poffset >= tlen) {
738 pvn_fail(pages, B_WRITE | flags);
741 /* finally change tlen from end position to length */
742 tlen -= poffset; /* compute bytes to write from this page */
743 page_sub(&pages, tpage); /* remove tpage from "pages" list */
744 tbuf = pageio_setup(tpage, tlen, vp, B_WRITE | flags);
746 pvn_fail(tpage, B_WRITE|flags);
747 pvn_fail(pages, B_WRITE|flags);
751 tbuf->b_blkno = btodb(tpage->p_offset);
753 ReleaseWriteLock(&avc->lock); /* can't hold during strategy call */
754 code = afs_ustrategy(tbuf); /* unlocks page */
755 ObtainWriteLock(&avc->lock,249); /* re-obtain */
757 /* unlocking of tpage is done by afs_ustrategy */
759 if (pages) /* may have already removed last page */
760 pvn_fail(pages, B_WRITE|flags);
763 } /* for (tpage=pages....) */
765 /* see if we've gotten all of the pages in the whole enchilada case */
766 if (!wholeEnchilada || !vp->v_pages) break;
767 } /* while(1) obtaining all pages */
770 * If low on chunks, and if writing the last byte of a chunk, try to
771 * free some. Note that afs_DoPartialWrite calls osi_SyncVM which now
772 * calls afs_putpage, so this is recursion. It stops there because we
773 * insist on len being non-zero.
775 if (afs_stats_cmperf.cacheCurrDirtyChunks > afs_stats_cmperf.cacheMaxDirtyChunks
776 && len != 0 && AFS_CHUNKOFFSET((off + len)) == 0) {
777 struct vrequest treq;
778 if (!afs_InitReq(&treq, cred ? cred : u.u_cred)) {
779 rcode = afs_DoPartialWrite(avc, &treq); /* XXX */
785 if (rcode && !avc->vc_error)
786 avc->vc_error = rcode;
788 /* when we're here, we just return code. */
789 ReleaseWriteLock(&avc->lock);
790 afs_BozonUnlock(&avc->pvnLock, avc);
794 #endif /* AFS_SUN5_ENV */
796 int afs_nfsrdwr(avc, auio, arw, ioflag, acred)
797 register struct vcache *avc;
801 struct AFS_UCRED *acred;
803 register afs_int32 code;
806 afs_int32 mode, sflags;
808 struct dcache *dcp, *dcp_newpage;
809 afs_int32 fileBase, size;
811 register afs_int32 tsize;
812 register afs_int32 pageOffset, extraResid=0;
813 register long origLength; /* length when reading/writing started */
814 register long appendLength; /* length when this call will finish */
815 int created; /* created pages instead of faulting them */
817 int didFakeOpen, eof;
818 struct vrequest treq;
822 AFS_STATCNT(afs_nfsrdwr);
824 /* can't read or write other things */
825 if (vType(avc) != VREG) return EISDIR;
827 if (auio->uio_resid == 0)
830 afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, (afs_int32)avc,
831 ICL_TYPE_LONG, (arw==UIO_WRITE? 1 : 0),
832 ICL_TYPE_LONG, auio->uio_offset,
833 ICL_TYPE_LONG, auio->uio_resid);
835 if ( AfsLargeFileUio(auio) ) /* file is larger than 2 GB */
839 if (!acred) osi_Panic("rdwr: !acred");
841 if (!acred) acred = u.u_cred;
843 if (code = afs_InitReq(&treq, acred)) return code;
845 /* It's not really possible to know if a write cause a growth in the
846 * cache size, we we wait for a cache drain for any write.
848 afs_MaybeWakeupTruncateDaemon();
849 while ((arw == UIO_WRITE) &&
850 (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100)) {
851 if (afs_blocksUsed - afs_blocksDiscarded >
852 (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
853 afs_WaitForCacheDrain = 1;
854 afs_osi_Sleep(&afs_WaitForCacheDrain);
856 afs_MaybeFreeDiscardedDCache();
857 afs_MaybeWakeupTruncateDaemon();
859 code = afs_VerifyVCache(avc, &treq);
860 if (code) return afs_CheckCode(code, &treq, 45);
862 afs_BozonLock(&avc->pvnLock, avc);
863 osi_FlushPages(avc, acred); /* hold bozon lock, but not basic vnode lock */
865 ObtainWriteLock(&avc->lock,250);
867 /* adjust parameters when appending files */
868 if ((ioflag & IO_APPEND) && arw == UIO_WRITE)
870 #if defined(AFS_SUN56_ENV)
871 auio->uio_loffset = 0;
873 auio->uio_offset = avc->m.Length; /* write at EOF position */
875 if (auio->uio_offset < 0 || (auio->uio_offset + auio->uio_resid) < 0) {
876 ReleaseWriteLock(&avc->lock);
877 afs_BozonUnlock(&avc->pvnLock, avc);
881 /* file is larger than 2GB */
882 if ( AfsLargeFileSize(auio->uio_offset, auio->uio_resid) ) {
883 ReleaseWriteLock(&avc->lock);
884 afs_BozonUnlock(&avc->pvnLock, avc);
888 didFakeOpen=0; /* keep track of open so we can do close */
889 if (arw == UIO_WRITE) {
890 /* do ulimit processing; shrink resid or fail */
891 #if defined(AFS_SUN56_ENV)
892 if (auio->uio_loffset + auio->afsio_resid > auio->uio_llimit) {
893 if (auio->uio_llimit >= auio->uio_llimit) {
894 ReleaseWriteLock(&avc->lock);
895 afs_BozonUnlock(&avc->pvnLock, avc);
898 /* track # of bytes we should write, but won't because of
899 * ulimit; we must add this into the final resid value
900 * so caller knows we punted some data.
902 extraResid = auio->uio_resid;
903 auio->uio_resid = auio->uio_llimit - auio->uio_loffset;
904 extraResid -= auio->uio_resid;
909 if (auio->afsio_offset + auio->afsio_resid > auio->uio_limit) {
910 if (auio->afsio_offset >= auio->uio_limit) {
911 ReleaseWriteLock(&avc->lock);
912 afs_BozonUnlock(&avc->pvnLock, avc);
915 /* track # of bytes we should write, but won't because of
916 * ulimit; we must add this into the final resid value
917 * so caller knows we punted some data.
919 extraResid = auio->uio_resid;
920 auio->uio_resid = auio->uio_limit - auio->afsio_offset;
921 extraResid -= auio->uio_resid;
926 mode = S_WRITE; /* segment map-in mode */
927 afs_FakeOpen(avc); /* do this for writes, so data gets put back
928 when we want it to be put back */
929 didFakeOpen = 1; /* we'll be doing a fake open */
930 /* before starting any I/O, we must ensure that the file is big enough
931 to hold the results (since afs_putpage will be called to force the I/O */
932 size = auio->afsio_resid + auio->afsio_offset; /* new file size */
934 origLength = avc->m.Length;
935 if (size > avc->m.Length)
936 avc->m.Length = size; /* file grew */
937 avc->states |= CDirty; /* Set the dirty bit */
938 avc->m.Date = osi_Time(); /* Set file date (for ranlib) */
940 mode = S_READ; /* map-in read-only */
941 origLength = avc->m.Length;
944 if (acred && AFS_NFSXLATORREQ(acred)) {
945 if (arw == UIO_READ) {
946 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
947 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
948 ReleaseWriteLock(&avc->lock);
949 afs_BozonUnlock(&avc->pvnLock, avc);
961 counter = 0; /* don't call afs_DoPartialWrite first time through. */
963 /* compute the amount of data to move into this block,
964 based on auio->afsio_resid. Note that we copy data in units of
965 MAXBSIZE, not PAGESIZE. This is because segmap_getmap panics if you
966 call it with an offset based on blocks smaller than MAXBSIZE
967 (implying that it should be named BSIZE, since it is clearly both a
969 size = auio->afsio_resid; /* transfer size */
970 fileBase = auio->afsio_offset; /* start file position for xfr */
971 pageBase = fileBase & ~(MAXBSIZE-1); /* file position of the page */
972 pageOffset = fileBase & (MAXBSIZE-1); /* xfr start's offset within page */
973 tsize = MAXBSIZE-pageOffset; /* how much more fits in this page */
974 /* we'll read tsize bytes, but first must make sure tsize isn't too big */
975 if (tsize > size) tsize = size; /* don't read past end of request */
976 eof = 0; /* flag telling us if we hit the EOF on the read */
977 if (arw == UIO_READ) { /* we're doing a read operation */
978 /* don't read past EOF */
979 if (tsize + fileBase > origLength) {
980 tsize = origLength - fileBase;
981 eof = 1; /* we did hit the EOF */
982 if (tsize < 0) tsize = 0; /* better safe than sorry */
988 /* Purge dirty chunks of file if there are too many dirty
989 * chunks. Inside the write loop, we only do this at a chunk
990 * boundary. Clean up partial chunk if necessary at end of loop.
992 if (counter > 0 && code == 0 && AFS_CHUNKOFFSET(fileBase) == 0)
994 code = afs_DoPartialWrite(avc, &treq);
998 #endif /* AFS_SUN5_ENV */
999 /* write case, we ask segmap_release to call putpage. Really, we
1000 don't have to do this on every page mapin, but for now we're
1001 lazy, and don't modify the rest of AFS to scan for modified
1002 pages on a close or other "synchronize with file server"
1003 operation. This makes things a little cleaner, but probably
1004 hurts performance. */
1009 break; /* nothing to transfer, we're done */
1012 if (arw == UIO_WRITE)
1013 avc->states |= CDirty; /* may have been cleared by DoPartialWrite*/
1015 /* Before dropping lock, hold the chunk (create it if necessary). This
1016 * serves two purposes: (1) Ensure Cache Truncate Daemon doesn't try
1017 * to purge the chunk's pages while we have them locked. This would
1018 * cause deadlock because we might be waiting for the CTD to free up
1019 * a chunk. (2) If we're writing past the original EOF, and we're
1020 * at the base of the chunk, then make sure it exists online
1021 * before we do the uiomove, since the segmap_release will
1022 * write out to the chunk, causing it to get fetched if it hasn't
1023 * been created yet. The code that would otherwise notice that
1024 * we're fetching a chunk past EOF won't work, since we've
1025 * already adjusted the file size above.
1027 ObtainWriteLock(&avc->vlock, 551);
1028 while (avc->vstates & VPageCleaning) {
1029 ReleaseWriteLock(&avc->vlock);
1030 ReleaseWriteLock(&avc->lock);
1031 afs_osi_Sleep(&avc->vstates);
1032 ObtainWriteLock(&avc->lock, 334);
1033 ObtainWriteLock(&avc->vlock, 552);
1035 ReleaseWriteLock(&avc->vlock);
1038 dcp = afs_GetDCache(avc, fileBase, &treq, &toff, &tlen, 2);
1045 ReleaseWriteLock(&avc->lock); /* uiomove may page fault */
1047 #if defined(AFS_SUN56_ENV)
1048 data = segmap_getmap(segkmap,(struct vnode *)avc,(u_offset_t)pageBase);
1050 data = segmap_getmap(segkmap, (struct vnode *) avc, pageBase);
1052 #ifndef AFS_SUN5_ENV
1053 code = as_fault(&kas, data+pageOffset, tsize, F_SOFTLOCK, mode);
1055 AFS_UIOMOVE(data+pageOffset, tsize, arw, auio, code);
1056 as_fault(&kas, data+pageOffset, tsize, F_SOFTUNLOCK, mode);
1057 code2 = segmap_release(segkmap, data, sflags);
1062 (void) segmap_release(segkmap, data, 0);
1065 #if defined(AFS_SUN56_ENV)
1066 raddr = (caddr_t) (((uintptr_t)data +pageOffset) & PAGEMASK);
1068 raddr = (caddr_t) (((u_int)data +pageOffset) & PAGEMASK);
1070 rsize = (((u_int)data+pageOffset+tsize+PAGEOFFSET) & PAGEMASK)-(u_int)raddr;
1072 /* if we're doing a write, and we're starting at the rounded
1073 * down page base, and we're writing enough data to cover all
1074 * created pages, then we must be writing all of the pages
1075 * in this MAXBSIZE window that we're creating.
1078 if (arw == UIO_WRITE
1079 && ((long)raddr == (long)data+pageOffset)
1080 && tsize >= rsize) {
1081 /* probably the dcache backing this guy is around, but if
1082 * not, we can't do this optimization, since we're creating
1083 * writable pages, which must be backed by a chunk.
1086 dcp_newpage = afs_FindDCache(avc, pageBase);
1088 && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)) {
1089 ObtainWriteLock(&avc->lock,251);
1090 ObtainWriteLock(&avc->vlock,576);
1091 if ((avc->activeV == 0)
1092 && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)
1093 && !(dcp_newpage->flags & (DFFetching))) {
1095 segmap_pagecreate(segkmap, raddr, rsize, 1);
1097 ObtainWriteLock(&afs_xdcache,252);
1098 /* Mark the pages as created and dirty */
1099 afs_indexFlags[dcp_newpage->index]
1100 |= (IFAnyPages | IFDirtyPages);
1101 ReleaseWriteLock(&afs_xdcache);
1102 avc->states |= CHasPages;
1105 afs_PutDCache(dcp_newpage);
1106 ReleaseWriteLock(&avc->vlock);
1107 ReleaseWriteLock(&avc->lock);
1109 else if ( dcp_newpage )
1110 afs_PutDCache(dcp_newpage);
1114 code = segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTLOCK, mode);
1117 AFS_UIOMOVE(data+pageOffset, tsize, arw, auio, code);
1118 segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTUNLOCK, mode);
1121 code = segmap_release(segkmap, data, sflags);
1123 (void) segmap_release(segkmap, data, 0);
1125 #endif /* AFS_SUN5_ENV */
1127 ObtainWriteLock(&avc->lock,253);
1130 * If at a chunk boundary, start prefetch of next chunk.
1132 if (counter == 0 || AFS_CHUNKOFFSET(fileBase) == 0) {
1133 if (!(dcp->flags & DFNextStarted))
1134 afs_PrefetchChunk(avc, dcp, acred, &treq);
1139 #endif /* AFS_SUN5_ENV */
1143 afs_FakeClose(avc, acred);
1147 if (arw == UIO_WRITE && (avc->states & CDirty)) {
1148 code2 = afs_DoPartialWrite(avc, &treq);
1152 #endif /* AFS_SUN5_ENV */
1154 if (!code && avc->vc_error) {
1155 code = avc->vc_error;
1157 ReleaseWriteLock(&avc->lock);
1158 afs_BozonUnlock(&avc->pvnLock, avc);
1160 #ifdef AFS_SUN53_ENV
1161 if ((ioflag & FSYNC) && (arw == UIO_WRITE) && !AFS_NFSXLATORREQ(acred))
1162 code = afs_fsync(avc, 0, acred);
1164 if ((ioflag & IO_SYNC) && (arw == UIO_WRITE)
1165 && !AFS_NFSXLATORREQ(acred))
1166 code = afs_fsync(avc, acred);
1169 #ifdef AFS_SUN52_ENV
1171 * If things worked, add in as remaining in request any bytes
1172 * we didn't write due to file size ulimit.
1174 if (code == 0 && extraResid > 0)
1175 auio->uio_resid += extraResid;
1177 return afs_CheckCode(code, &treq, 46);
1180 afs_map(vp, off, as, addr, len, prot, maxprot, flags, cred)
1192 u_char prot, maxprot;
1194 u_int prot, maxprot;
1197 struct AFS_UCRED *cred;
1199 struct segvn_crargs crargs;
1200 register afs_int32 code;
1201 struct vrequest treq;
1202 register struct vcache *avc = (struct vcache *) vp;
1204 AFS_STATCNT(afs_map);
1207 /* check for reasonableness on segment bounds; apparently len can be < 0 */
1208 if ((int)off < 0 || (int)(off + len) < 0) {
1211 if ( AfsLargeFileSize(off, len) ) /* file is larger than 2 GB */
1217 #if defined(AFS_SUN5_ENV)
1218 if (vp->v_flag & VNOMAP) /* File isn't allowed to be mapped */
1221 if (vp->v_filocks) /* if locked, disallow mapping */
1225 if (code = afs_InitReq(&treq, cred)) goto out;
1227 if (vp->v_type != VREG) {
1232 code = afs_VerifyVCache(avc, &treq);
1236 afs_BozonLock(&avc->pvnLock, avc);
1237 osi_FlushPages(avc, cred); /* ensure old pages are gone */
1238 avc->states |= CMAPPED; /* flag cleared at afs_inactive */
1239 afs_BozonUnlock(&avc->pvnLock, avc);
1245 if ((flags & MAP_FIXED) == 0) {
1246 #if defined(AFS_SUN57_ENV)
1247 map_addr(addr, len, off, 1, flags);
1248 #elif defined(AFS_SUN56_ENV)
1249 map_addr(addr, len, off, 1);
1251 map_addr(addr, len, (off_t)off, 1);
1253 if (*addr == NULL) {
1261 (void) as_unmap(as, *addr, len); /* unmap old address space use */
1262 /* setup the create parameter block for the call */
1263 crargs.vp = (struct vnode *) avc;
1264 crargs.offset = (u_int)off;
1266 crargs.type = flags&MAP_TYPE;
1268 crargs.maxprot = maxprot;
1269 crargs.amp = (struct anon_map *) 0;
1270 #if defined(AFS_SUN5_ENV)
1271 crargs.flags = flags & ~MAP_TYPE;
1274 code = as_map(as, *addr, len, segvn_create, (char *) &crargs);
1280 code = afs_CheckCode(code, &treq, 47);
1284 code = afs_CheckCode(code, &treq, 48);
1289 /* Sun 4.0.X-specific code. It computes the number of bytes that need
1290 to be zeroed at the end of a page by pvn_vptrunc, given that you're
1291 trying to get vptrunc to truncate a file to alen bytes. The result
1292 will be passed to pvn_vptrunc by the truncate code */
1293 #ifndef AFS_SUN5_ENV /* Not good for Solaris */
1295 register afs_int32 alen; {
1296 register afs_int32 nbytes;
1298 AFS_STATCNT(afs_PageLeft);
1299 nbytes = PAGESIZE - (alen & PAGEOFFSET); /* amount to zap in last page */
1300 /* now check if we'd zero the entire last page. Don't need to do this
1301 since pvn_vptrunc will handle this case properly (it will invalidate
1303 if (nbytes == PAGESIZE) nbytes = 0;
1304 if (nbytes < 0) nbytes = 0; /* just in case */
1311 * For Now We use standard local kernel params for AFS system values. Change this
1314 #if defined(AFS_SUN5_ENV)
1315 afs_pathconf(vp, cmd, outdatap, credp)
1316 register struct AFS_UCRED *credp;
1318 afs_cntl(vp, cmd, indatap, outdatap, inflag, outflag)
1319 int inflag, outflag;
1326 AFS_STATCNT(afs_cntl);
1329 *outdatap = MAXLINK;
1332 *outdatap = MAXNAMLEN;
1335 *outdatap = MAXPATHLEN;
1337 case _PC_CHOWN_RESTRICTED:
1343 #if !defined(AFS_SUN5_ENV)
1345 *outdatap = CANBSIZ;
1348 *outdatap = VDISABLE;
1360 #endif /* AFS_SUN_ENV */
1362 #if defined(AFS_SUN5_ENV)
1364 afs_ioctl(vnp, com, arg, flag, credp, rvalp)
1373 void afs_rwlock(vnp, wlock)
1377 rw_enter(&((struct vcache *)vnp)->rwlock, (wlock ? RW_WRITER : RW_READER));
1381 void afs_rwunlock(vnp, wlock)
1385 rw_exit(&((struct vcache *)vnp)->rwlock);
1390 afs_seek(vnp, ooff, noffp)
1395 register int code = 0;
1397 if ((*noffp < 0 || *noffp > MAXOFF_T))
1402 int afs_frlock(vnp, cmd, ap, flag, off, credp)
1405 #if defined(AFS_SUN56_ENV)
1412 struct AFS_UCRED *credp;
1414 register afs_int32 code = 0;
1416 * Implement based on afs_lockctl
1419 if ((cmd == F_GETLK) || (cmd == F_O_GETLK) || (cmd == F_SETLK) || (cmd == F_SETLKW)) {
1420 #ifdef AFS_SUN53_ENV
1421 ap->l_pid = ttoproc(curthread)->p_pid;
1424 ap->l_pid = ttoproc(curthread)->p_epid;
1425 ap->l_sysid = ttoproc(curthread)->p_sysid;
1429 #ifdef AFS_SUN56_ENV
1430 code = convoff(vnp, ap, 0, off);
1432 code = convoff(vnp, ap, 0, (off_t)off);
1434 if (code) return code;
1438 code = afs_lockctl((struct vcache *)vnp, ap, cmd, credp);
1444 int afs_space(vnp, cmd, ap, flag, off, credp)
1447 #if defined(AFS_SUN56_ENV)
1454 struct AFS_UCRED *credp;
1456 register afs_int32 code = EINVAL;
1459 if ((cmd == F_FREESP)
1460 #ifdef AFS_SUN56_ENV
1461 && ((code = convoff(vnp, ap, 0, off)) == 0)) {
1463 && ((code = convoff(vnp, ap, 0, (off_t)off)) == 0)) {
1467 vattr.va_mask = AT_SIZE;
1468 vattr.va_size = ap->l_start;
1469 code = afs_setattr((struct vcache *)vnp, &vattr, 0, credp);
1479 int afs_dump(vp, addr, i1, i2)
1484 AFS_STATCNT(afs_dump);
1485 afs_warn("AFS_DUMP. MUST IMPLEMENT THIS!!!\n");
1490 /* Nothing fancy here; just compare if vnodes are identical ones */
1492 struct vnode *vp1, *vp2;
1494 AFS_STATCNT(afs_cmp);
1499 int afs_realvp(struct vnode *vp, struct vnode **vpp) {
1500 AFS_STATCNT(afs_realvp);
1505 int afs_pageio(vp, pp, ui1, ui2, i1, credp)
1512 afs_warn("afs_pageio: Not implemented\n");
1516 int afs_dumpctl(vp, i)
1520 afs_warn("afs_dumpctl: Not implemented\n");
1524 #ifdef AFS_SUN54_ENV
1525 extern void afs_dispose(vp, p, fl, dn, cr)
1531 fs_dispose(vp, p, fl, dn, cr);
1534 int afs_setsecattr(vp, vsecattr, flag, creds)
1536 vsecattr_t *vsecattr;
1543 int afs_getsecattr(vp, vsecattr, flag, creds)
1545 vsecattr_t *vsecattr;
1549 return fs_fab_acl(vp, vsecattr, flag, creds);
1553 #ifdef AFS_GLOBAL_SUNLOCK
1554 extern int gafs_open(), gafs_close(), afs_ioctl(), gafs_access();
1555 extern int gafs_getattr(), gafs_setattr(), gafs_lookup(), gafs_create();
1556 extern int gafs_remove(), gafs_link(), gafs_rename(), gafs_mkdir();
1557 extern int gafs_rmdir(), gafs_readdir(), gafs_fsync(), gafs_symlink();
1558 extern int gafs_fid(), gafs_readlink(), fs_setfl(), afs_pathconf();
1559 extern int afs_lockctl();
1560 extern void gafs_inactive();
1562 struct vnodeops Afs_vnodeops = {
1602 #ifdef AFS_SUN54_ENV
1607 #if defined(AFS_SUN56_ENV)
1611 struct vnodeops *afs_ops = &Afs_vnodeops;
1615 gafs_open(avcp, aflags, acred)
1616 register struct vcache **avcp;
1618 struct AFS_UCRED *acred;
1623 code = afs_open(avcp, aflags, acred);
1629 gafs_close(avc, aflags, count, offset, acred)
1632 register struct vcache *avc;
1634 struct AFS_UCRED *acred;
1639 code = afs_close(avc, aflags, count, offset, acred);
1645 gafs_getattr(avc, attrs, flags, acred)
1647 register struct vcache *avc;
1648 register struct vattr *attrs;
1649 struct AFS_UCRED *acred;
1654 code = afs_getattr(avc, attrs, flags, acred);
1660 gafs_setattr(avc, attrs, flags, acred)
1662 register struct vcache *avc;
1663 register struct vattr *attrs;
1664 struct AFS_UCRED *acred;
1669 code = afs_setattr(avc, attrs, flags, acred);
1675 gafs_access(avc, amode, flags, acred)
1677 register struct vcache *avc;
1678 register afs_int32 amode;
1679 struct AFS_UCRED *acred;
1684 code = afs_access(avc, amode, flags, acred);
1690 gafs_lookup(adp, aname, avcp, pnp, flags, rdir, acred)
1691 struct pathname *pnp;
1694 register struct vcache *adp, **avcp;
1696 struct AFS_UCRED *acred;
1701 code = afs_lookup(adp, aname, avcp, pnp, flags, rdir, acred);
1707 gafs_create(adp, aname, attrs, aexcl, amode, avcp, acred)
1708 register struct vcache *adp;
1710 struct vattr *attrs;
1713 struct vcache **avcp;
1714 struct AFS_UCRED *acred;
1719 code = afs_create(adp, aname, attrs, aexcl, amode, avcp, acred);
1724 gafs_remove(adp, aname, acred)
1725 register struct vcache *adp;
1727 struct AFS_UCRED *acred;
1732 code = afs_remove(adp, aname, acred);
1737 gafs_link(adp, avc, aname, acred)
1738 register struct vcache *avc;
1739 register struct vcache *adp;
1741 struct AFS_UCRED *acred;
1746 code = afs_link(adp, avc, aname, acred);
1751 gafs_rename(aodp, aname1, andp, aname2, acred)
1752 register struct vcache *aodp, *andp;
1753 char *aname1, *aname2;
1754 struct AFS_UCRED *acred;
1759 code = afs_rename(aodp, aname1, andp, aname2, acred);
1764 gafs_mkdir(adp, aname, attrs, avcp, acred)
1765 register struct vcache *adp;
1766 register struct vcache **avcp;
1768 struct vattr *attrs;
1769 struct AFS_UCRED *acred;
1774 code = afs_mkdir(adp, aname, attrs, avcp, acred);
1780 gafs_rmdir(adp, aname, cdirp, acred)
1781 struct vnode *cdirp;
1782 register struct vcache *adp;
1784 struct AFS_UCRED *acred;
1789 code = afs_rmdir(adp, aname, cdirp, acred);
1795 gafs_readdir(avc, auio, acred, eofp)
1797 register struct vcache *avc;
1799 struct AFS_UCRED *acred;
1804 code = afs_readdir(avc, auio, acred, eofp);
1809 gafs_symlink(adp, aname, attrs, atargetName, acred)
1810 register struct vcache *adp;
1811 register char *atargetName;
1813 struct vattr *attrs;
1814 struct AFS_UCRED *acred;
1819 code = afs_symlink(adp, aname, attrs, atargetName, acred);
1825 gafs_readlink(avc, auio, acred)
1826 register struct vcache *avc;
1828 struct AFS_UCRED *acred;
1833 code = afs_readlink(avc, auio, acred);
1838 #ifdef AFS_SUN53_ENV
1839 gafs_fsync(avc, flag, acred)
1842 gafs_fsync(avc, acred)
1844 register struct vcache *avc;
1845 struct AFS_UCRED *acred;
1850 #ifdef AFS_SUN53_ENV
1851 code = afs_fsync(avc, flag, acred);
1853 code = afs_fsync(avc, acred);
1859 void afs_inactive(struct vcache *avc, struct AFS_UCRED *acred)
1861 struct vnode *vp = (struct vnode *)avc;
1862 if (afs_shuttingdown) return ;
1865 * In Solaris and HPUX s800 and HP-UX10.0 they actually call us with
1866 * v_count 1 on last reference!
1868 mutex_enter(&vp->v_lock);
1869 if (avc->vrefCount <= 0) osi_Panic("afs_inactive : v_count <=0\n");
1872 * If more than 1 don't unmap the vnode but do decrement the ref count
1875 if (vp->v_count > 0) {
1876 mutex_exit(&vp->v_lock);
1879 mutex_exit(&vp->v_lock);
1881 * Solaris calls VOP_OPEN on exec, but isn't very diligent about calling
1882 * VOP_CLOSE when executable exits.
1884 if (avc->opens > 0 && !(avc->states & CCore))
1885 avc->opens = avc->execsOrWriters = 0;
1887 afs_InactiveVCache(avc, acred);
1890 void gafs_inactive(avc, acred)
1891 register struct vcache *avc;
1892 struct AFS_UCRED *acred;
1895 afs_inactive(avc, acred);
1900 gafs_fid(avc, fidpp)
1907 code = afs_fid(avc, fidpp);
1912 #endif /* AFS_GLOBAL_SUNLOCK */