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"
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 "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 #include <sys/modctl.h>
51 #include <sys/syscall.h>
52 #include <sys/debug.h>
53 #include <sys/fs_subr.h>
56 * XXX Temporary fix for problems with Solaris rw_tryupgrade() lock.
57 * It isn't very persistent in getting the upgrade when others are
58 * waiting for it and returns 0. So the UpgradeSToW() macro that the
59 * rw_tryupgrade used to map to wasn't good enough and we need to use
60 * the following code instead. Obviously this isn't the proper place
61 * for it but it's only called from here for now
68 if (!rw_tryupgrade(lock)) {
70 rw_enter(lock, RW_WRITER);
76 /* Translate a faultcode_t as returned by some of the vm routines
77 * into a suitable errno value.
80 afs_fc2errno(faultcode_t fc)
82 switch (FC_CODE(fc)) {
95 extern struct as kas; /* kernel addr space */
96 extern unsigned char *afs_indexFlags;
97 extern afs_lock_t afs_xdcache;
99 /* Additional vnodeops for SunOS 4.0.x */
100 int afs_nfsrdwr(), afs_getpage(), afs_putpage(), afs_map();
101 int afs_dump(), afs_cmp(), afs_realvp(), afs_GetOnePage();
106 afs_addmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
107 register struct vnode *avp;
111 int length, prot, maxprot, flags;
112 struct AFS_UCRED *credp;
114 /* XXX What should we do here?? XXX */
119 afs_delmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
120 register struct vnode *avp;
124 int length, prot, maxprot, flags;
125 struct AFS_UCRED *credp;
127 /* XXX What should we do here?? XXX */
131 #ifdef AFS_SUN510_ENV
133 afs_vmread(avp, auio, ioflag, acred, ct)
134 register struct vnode *avp;
137 struct AFS_UCRED *acred;
138 caller_context_t *ct;
141 afs_vmread(avp, auio, ioflag, acred)
142 register struct vnode *avp;
145 struct AFS_UCRED *acred;
150 if (!RW_READ_HELD(&(VTOAFS(avp))->rwlock))
151 osi_Panic("afs_vmread: !rwlock");
153 code = afs_nfsrdwr(VTOAFS(avp), auio, UIO_READ, ioflag, acred);
159 #ifdef AFS_SUN510_ENV
161 afs_vmwrite(avp, auio, ioflag, acred, ct)
162 register struct vnode *avp;
165 struct AFS_UCRED *acred;
166 caller_context_t *ct;
169 afs_vmwrite(avp, auio, ioflag, acred)
170 register struct vnode *avp;
173 struct AFS_UCRED *acred;
178 if (!RW_WRITE_HELD(&(VTOAFS(avp))->rwlock))
179 osi_Panic("afs_vmwrite: !rwlock");
181 code = afs_nfsrdwr(VTOAFS(avp), auio, UIO_WRITE, ioflag, acred);
187 afs_getpage(vp, off, len, protp, pl, plsz, seg, addr, rw, acred)
197 struct AFS_UCRED *acred;
199 register afs_int32 code = 0;
200 AFS_STATCNT(afs_getpage);
202 if (vp->v_flag & VNOMAP) /* File doesn't allow mapping */
207 #if defined(AFS_SUN56_ENV)
210 afs_GetOnePage(vp, off, len, protp, pl, plsz, seg, addr, rw,
215 afs_GetOnePage(vp, (u_int) off, len, protp, pl, plsz, seg, addr,
219 struct vcache *vcp = VTOAFS(vp);
220 ObtainWriteLock(&vcp->vlock, 548);
222 ReleaseWriteLock(&vcp->vlock);
223 afs_BozonLock(&vcp->pvnLock, vcp);
224 #if defined(AFS_SUN56_ENV)
226 pvn_getpages(afs_GetOnePage, vp, off, len, protp, pl, plsz, seg,
230 pvn_getpages(afs_GetOnePage, vp, (u_int) off, len, protp, pl,
231 plsz, seg, addr, rw, acred);
233 afs_BozonUnlock(&vcp->pvnLock, vcp);
234 ObtainWriteLock(&vcp->vlock, 549);
236 ReleaseWriteLock(&vcp->vlock);
242 /* Return all the pages from [off..off+len) in file */
244 afs_GetOnePage(vp, off, alen, protp, pl, plsz, seg, addr, rw, acred)
247 #if defined(AFS_SUN56_ENV)
258 struct AFS_UCRED *acred;
260 register struct page *page;
261 register afs_int32 code = 0;
265 register struct vcache *avc;
266 register struct dcache *tdc;
269 afs_size_t offset, nlen = 0;
270 struct vrequest treq;
271 afs_int32 mapForRead = 0, Code = 0;
275 osi_Panic("GetOnePage: !acred");
277 avc = VTOAFS(vp); /* cast to afs vnode */
279 if (avc->credp /*&& AFS_NFSXLATORREQ(acred) */
280 && AFS_NFSXLATORREQ(avc->credp)) {
283 if (code = afs_InitReq(&treq, acred))
287 /* This is a read-ahead request, e.g. due to madvise. */
289 ObtainReadLock(&avc->lock);
291 while (plen > 0 && !afs_BBusy()) {
292 /* Obtain a dcache entry at off. 2 means don't fetch data. */
294 afs_GetDCache(avc, (afs_offs_t) off, &treq, &offset, &nlen,
299 /* Write-lock the dcache entry, if we don't succeed, just go on */
300 if (0 != NBObtainWriteLock(&tdc->lock, 642)) {
305 /* If we aren't already fetching this dcache entry, queue it */
306 if (!(tdc->mflags & DFFetchReq)) {
309 tdc->mflags |= DFFetchReq;
310 bp = afs_BQueue(BOP_FETCH, avc, B_DONTWAIT, 0, acred,
311 (afs_size_t) off, (afs_size_t) 1, tdc);
313 /* Unable to start background fetch; might as well stop */
314 tdc->mflags &= ~DFFetchReq;
315 ReleaseWriteLock(&tdc->lock);
319 ReleaseWriteLock(&tdc->lock);
321 ReleaseWriteLock(&tdc->lock);
326 /* Adjust our offset and remaining length values */
330 /* If we aren't making progress for some reason, bail out */
335 ReleaseReadLock(&avc->lock);
340 pl[0] = NULL; /* Make sure it's empty */
342 /* first, obtain the proper lock for the VM system */
344 /* if this is a read request, map the page in read-only. This will
345 * allow us to swap out the dcache entry if there are only read-only
346 * pages created for the chunk, which helps a *lot* when dealing
347 * with small caches. Otherwise, we have to invalidate the vm
348 * pages for the range covered by a chunk when we swap out the
351 if (rw == S_READ || rw == S_EXEC)
358 if (rw == S_WRITE || rw == S_CREATE)
359 tdc = afs_GetDCache(avc, (afs_offs_t) off, &treq, &offset, &nlen, 5);
361 tdc = afs_GetDCache(avc, (afs_offs_t) off, &treq, &offset, &nlen, 1);
364 code = afs_VerifyVCache(avc, &treq);
367 return afs_CheckCode(code, &treq, 44); /* failed to get it */
370 afs_BozonLock(&avc->pvnLock, avc);
371 ObtainReadLock(&avc->lock);
373 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, (afs_int32) vp,
374 ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(off), ICL_TYPE_LONG, len,
375 ICL_TYPE_LONG, (int)rw);
380 /* Check to see if we're in the middle of a VM purge, and if we are, release
381 * the locks and try again when the VM purge is done. */
382 ObtainWriteLock(&avc->vlock, 550);
384 ReleaseReadLock(&avc->lock);
385 ReleaseWriteLock(&avc->vlock);
386 afs_BozonUnlock(&avc->pvnLock, avc);
388 /* Check activeV again, it may have been turned off
389 * while we were waiting for a lock in afs_PutDCache */
390 ObtainWriteLock(&avc->vlock, 574);
392 avc->vstates |= VRevokeWait;
393 ReleaseWriteLock(&avc->vlock);
394 afs_osi_Sleep(&avc->vstates);
396 ReleaseWriteLock(&avc->vlock);
400 ReleaseWriteLock(&avc->vlock);
402 /* We're about to do stuff with our dcache entry.. Lock it. */
403 ObtainReadLock(&tdc->lock);
405 /* Check to see whether the cache entry is still valid */
406 if (!(avc->states & CStatd)
407 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
408 ReleaseReadLock(&tdc->lock);
409 ReleaseReadLock(&avc->lock);
410 afs_BozonUnlock(&avc->pvnLock, avc);
416 while (1) { /* loop over all pages */
417 /* now, try to find the page in memory (it may already be intransit or laying
418 * around the free list */
420 page_lookup(vp, toffset, (rw == S_CREATE ? SE_EXCL : SE_SHARED));
424 /* if we make it here, we can't find the page in memory. Do a real disk read
425 * from the cache to get the data */
426 Code |= 0x200; /* XXX */
427 #if defined(AFS_SUN54_ENV)
428 /* use PG_EXCL because we know the page does not exist already. If it
429 * actually does exist, we have somehow raced between lookup and create.
430 * As of 4/98, that shouldn't be possible, but we'll be defensive here
431 * in case someone tries to relax all the serialization of read and write
432 * operations with harmless things like stat. */
433 #if defined(AFS_SUN58_ENV)
435 page_create_va(vp, toffset, PAGESIZE, PG_WAIT | PG_EXCL, seg,
439 page_create_va(vp, toffset, PAGESIZE, PG_WAIT | PG_EXCL,
443 page = page_create(vp, toffset, PAGESIZE, PG_WAIT);
449 pagezero(page, alen, PAGESIZE - alen);
451 if (rw == S_CREATE) {
452 /* XXX Don't read from AFS in write only cases XXX */
453 page_io_unlock(page);
456 /* now it is time to start I/O operation */
457 buf = pageio_setup(page, PAGESIZE, vp, B_READ); /* allocate a buf structure */
460 #if defined(AFS_SUN56_ENV)
461 buf->b_lblkno = lbtodb(toffset);
463 buf->b_blkno = btodb(toffset);
465 bp_mapin(buf); /* map it in to our address space */
468 /* afs_ustrategy will want to lock the dcache entry */
469 ReleaseReadLock(&tdc->lock);
470 code = afs_ustrategy(buf, acred); /* do the I/O */
471 ObtainReadLock(&tdc->lock);
474 /* Before freeing unmap the buffer */
480 page_io_unlock(page);
483 /* come here when we have another page (already held) to enter */
485 /* put page in array and continue */
486 /* The p_selock must be downgraded to a shared lock after the page is read */
487 #if defined(AFS_SUN56_ENV)
488 if ((rw != S_CREATE) && !(PAGE_SHARED(page)))
490 if ((rw != S_CREATE) && !(se_shared_assert(&page->p_selock)))
493 page_downgrade(page);
496 code = page_iolock_assert(page);
502 break; /* done all the pages */
503 } /* while (1) ... */
507 ReleaseReadLock(&tdc->lock);
509 /* Prefetch next chunk if we're at a chunk boundary */
510 if (AFS_CHUNKOFFSET(off) == 0) {
511 if (!(tdc->mflags & DFNextStarted))
512 afs_PrefetchChunk(avc, tdc, acred, &treq);
515 ReleaseReadLock(&avc->lock);
516 ObtainWriteLock(&afs_xdcache, 246);
518 /* track that we have dirty (or dirty-able) pages for this chunk. */
519 afs_indexFlags[tdc->index] |= IFDirtyPages;
521 afs_indexFlags[tdc->index] |= IFAnyPages;
522 ReleaseWriteLock(&afs_xdcache);
523 afs_BozonUnlock(&avc->pvnLock, avc);
525 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code,
526 ICL_TYPE_LONG, (int)page, ICL_TYPE_LONG, Code);
531 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code,
532 ICL_TYPE_LONG, (int)page, ICL_TYPE_LONG, Code);
533 /* release all pages, drop locks, return code */
535 pvn_read_done(page, B_ERROR);
536 ReleaseReadLock(&avc->lock);
537 afs_BozonUnlock(&avc->pvnLock, avc);
538 ReleaseReadLock(&tdc->lock);
544 afs_putpage(vp, off, len, flags, cred)
549 struct AFS_UCRED *cred;
554 #if defined(AFS_SUN58_ENV)
560 afs_int32 NPages = 0;
561 #if defined(AFS_SUN56_ENV)
562 u_offset_t toff = off;
568 AFS_STATCNT(afs_putpage);
569 if (vp->v_flag & VNOMAP) /* file doesn't allow mapping */
573 * Putpage (ASYNC) is called every sec to flush out dirty vm pages
576 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER,
577 (afs_int32) vp, ICL_TYPE_OFFSET, ICL_HANDLE_OFFSET(off),
578 ICL_TYPE_INT32, (afs_int32) len, ICL_TYPE_LONG, (int)flags);
580 afs_BozonLock(&avc->pvnLock, avc);
581 ObtainSharedLock(&avc->lock, 247);
584 /* Get a list of modified (or whatever) pages */
586 endPos = (afs_offs_t) off + len; /* position we're supposed to write up to */
587 while ((afs_offs_t) toff < endPos
588 && (afs_offs_t) toff < avc->m.Length) {
589 /* If not invalidating pages use page_lookup_nowait to avoid reclaiming
590 * them from the free list
593 if (flags & (B_FREE | B_INVAL))
594 pages = page_lookup(vp, toff, SE_EXCL);
596 pages = page_lookup_nowait(vp, toff, SE_SHARED);
597 if (!pages || !pvn_getdirty(pages, flags))
603 UpgradeSToWLock(&avc->lock, 671);
607 code = afs_putapage(vp, pages, &toff, &tlen, flags, cred);
618 UpgradeSToWLock(&avc->lock, 670);
623 #if defined(AFS_SUN56_ENV)
624 code = pvn_vplist_dirty(vp, toff, afs_putapage, flags, cred);
626 code = pvn_vplist_dirty(vp, (u_int) off, afs_putapage, flags, cred);
631 if (code && !avc->vc_error) {
633 UpgradeSToWLock(&avc->lock, 669);
636 avc->vc_error = code;
640 ReleaseWriteLock(&avc->lock);
642 ReleaseSharedLock(&avc->lock);
643 afs_BozonUnlock(&avc->pvnLock, avc);
644 afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_LONG, code,
645 ICL_TYPE_LONG, NPages);
652 afs_putapage(struct vnode *vp, struct page *pages,
653 #if defined(AFS_SUN56_ENV)
658 #if defined(AFS_SUN58_ENV)
663 int flags, struct AFS_UCRED *credp)
666 struct vcache *avc = VTOAFS(vp);
668 u_int tlen = PAGESIZE;
669 afs_offs_t off = (pages->p_offset / PAGESIZE) * PAGESIZE;
672 * Now we've got the modified pages. All pages are locked and held
673 * XXX Find a kluster that fits in one block (or page). We also
674 * adjust the i/o if the file space is less than a while page. XXX
676 if (off + tlen > avc->m.Length) {
677 tlen = avc->m.Length - off;
679 /* can't call mapout with 0 length buffers (rmfree panics) */
680 if (((tlen >> 24) & 0xff) == 0xff) {
685 * Can't call mapout with 0 length buffers since we'll get rmfree panics
687 tbuf = pageio_setup(pages, tlen, vp, B_WRITE | flags);
692 #if defined(AFS_SUN56_ENV)
693 tbuf->b_lblkno = lbtodb(pages->p_offset);
695 tbuf->b_blkno = btodb(pages->p_offset);
699 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUTONE, ICL_TYPE_LONG, avc,
700 ICL_TYPE_LONG, pages, ICL_TYPE_LONG, tlen, ICL_TYPE_OFFSET,
701 ICL_HANDLE_OFFSET(off));
702 code = afs_ustrategy(tbuf, credp); /* unlocks page */
706 pvn_write_done(pages, ((code) ? B_ERROR : 0) | B_WRITE | flags);
717 afs_nfsrdwr(avc, auio, arw, ioflag, acred)
718 register struct vcache *avc;
722 struct AFS_UCRED *acred;
724 register afs_int32 code;
727 afs_int32 mode, sflags;
729 struct dcache *dcp, *dcp_newpage;
730 afs_size_t fileBase, size;
732 register afs_int32 tsize;
733 register afs_int32 pageOffset, extraResid = 0;
734 register afs_size_t origLength; /* length when reading/writing started */
735 register long appendLength; /* length when this call will finish */
736 int created; /* created pages instead of faulting them */
738 int didFakeOpen, eof;
739 struct vrequest treq;
743 AFS_STATCNT(afs_nfsrdwr);
745 /* can't read or write other things */
746 if (vType(avc) != VREG)
749 if (auio->uio_resid == 0)
752 afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, (afs_int32) avc,
753 ICL_TYPE_LONG, (arw == UIO_WRITE ? 1 : 0), ICL_TYPE_OFFSET,
754 ICL_HANDLE_OFFSET(auio->uio_loffset), ICL_TYPE_OFFSET,
755 ICL_HANDLE_OFFSET(auio->uio_resid));
757 #ifndef AFS_64BIT_CLIENT
758 if (AfsLargeFileUio(auio)) /* file is larger than 2 GB */
763 osi_Panic("rdwr: !acred");
765 if (code = afs_InitReq(&treq, acred))
768 /* It's not really possible to know if a write cause a growth in the
769 * cache size, we we wait for a cache drain for any write.
771 afs_MaybeWakeupTruncateDaemon();
772 while ((arw == UIO_WRITE)
773 && (afs_blocksUsed > PERCENT(CM_WAITFORDRAINPCT, afs_cacheBlocks))) {
774 if (afs_blocksUsed - afs_blocksDiscarded >
775 PERCENT(CM_WAITFORDRAINPCT, afs_cacheBlocks)) {
776 afs_WaitForCacheDrain = 1;
777 afs_osi_Sleep(&afs_WaitForCacheDrain);
779 afs_MaybeFreeDiscardedDCache();
780 afs_MaybeWakeupTruncateDaemon();
782 code = afs_VerifyVCache(avc, &treq);
784 return afs_CheckCode(code, &treq, 45);
786 afs_BozonLock(&avc->pvnLock, avc);
787 osi_FlushPages(avc, acred); /* hold bozon lock, but not basic vnode lock */
789 ObtainWriteLock(&avc->lock, 250);
791 /* adjust parameters when appending files */
792 if ((ioflag & IO_APPEND) && arw == UIO_WRITE) {
793 #if defined(AFS_SUN56_ENV)
794 auio->uio_loffset = avc->m.Length; /* write at EOF position */
796 auio->uio_offset = avc->m.Length; /* write at EOF position */
799 if (auio->afsio_offset < 0 || (auio->afsio_offset + auio->uio_resid) < 0) {
800 ReleaseWriteLock(&avc->lock);
801 afs_BozonUnlock(&avc->pvnLock, avc);
804 #ifndef AFS_64BIT_CLIENT
805 /* file is larger than 2GB */
806 if (AfsLargeFileSize(auio->uio_offset, auio->uio_resid)) {
807 ReleaseWriteLock(&avc->lock);
808 afs_BozonUnlock(&avc->pvnLock, avc);
813 didFakeOpen = 0; /* keep track of open so we can do close */
814 if (arw == UIO_WRITE) {
815 /* do ulimit processing; shrink resid or fail */
816 #if defined(AFS_SUN56_ENV)
817 if (auio->uio_loffset + auio->afsio_resid > auio->uio_llimit) {
818 if (auio->uio_loffset >= auio->uio_llimit) {
819 ReleaseWriteLock(&avc->lock);
820 afs_BozonUnlock(&avc->pvnLock, avc);
823 /* track # of bytes we should write, but won't because of
824 * ulimit; we must add this into the final resid value
825 * so caller knows we punted some data.
827 extraResid = auio->uio_resid;
828 auio->uio_resid = auio->uio_llimit - auio->uio_loffset;
829 extraResid -= auio->uio_resid;
834 if (auio->afsio_offset + auio->afsio_resid > auio->uio_limit) {
835 if (auio->afsio_offset >= auio->uio_limit) {
836 ReleaseWriteLock(&avc->lock);
837 afs_BozonUnlock(&avc->pvnLock, avc);
840 /* track # of bytes we should write, but won't because of
841 * ulimit; we must add this into the final resid value
842 * so caller knows we punted some data.
844 extraResid = auio->uio_resid;
845 auio->uio_resid = auio->uio_limit - auio->afsio_offset;
846 extraResid -= auio->uio_resid;
851 mode = S_WRITE; /* segment map-in mode */
852 afs_FakeOpen(avc); /* do this for writes, so data gets put back
853 * when we want it to be put back */
854 didFakeOpen = 1; /* we'll be doing a fake open */
855 /* before starting any I/O, we must ensure that the file is big enough
856 * to hold the results (since afs_putpage will be called to force the I/O */
857 size = auio->afsio_resid + auio->afsio_offset; /* new file size */
859 origLength = avc->m.Length;
860 if (size > avc->m.Length) {
861 afs_Trace4(afs_iclSetp, CM_TRACE_SETLENGTH, ICL_TYPE_STRING,
862 __FILE__, ICL_TYPE_LONG, __LINE__, ICL_TYPE_OFFSET,
863 ICL_HANDLE_OFFSET(avc->m.Length), ICL_TYPE_OFFSET,
864 ICL_HANDLE_OFFSET(size));
865 avc->m.Length = size; /* file grew */
867 avc->states |= CDirty; /* Set the dirty bit */
868 avc->m.Date = osi_Time(); /* Set file date (for ranlib) */
870 mode = S_READ; /* map-in read-only */
871 origLength = avc->m.Length;
874 if (acred && AFS_NFSXLATORREQ(acred)) {
875 if (arw == UIO_READ) {
877 (avc, PRSFS_READ, &treq,
878 CHECK_MODE_BITS | CMB_ALLOW_EXEC_AS_READ)) {
879 ReleaseWriteLock(&avc->lock);
880 afs_BozonUnlock(&avc->pvnLock, avc);
890 counter = 0; /* don't call afs_DoPartialWrite first time through. */
892 /* compute the amount of data to move into this block,
893 * based on auio->afsio_resid. Note that we copy data in units of
894 * MAXBSIZE, not PAGESIZE. This is because segmap_getmap panics if you
895 * call it with an offset based on blocks smaller than MAXBSIZE
896 * (implying that it should be named BSIZE, since it is clearly both a
898 size = auio->afsio_resid; /* transfer size */
899 fileBase = ((arw == UIO_READ) && (origLength < auio->uio_offset)) ?
900 origLength : auio->afsio_offset; /* start file position for xfr */
901 pageBase = fileBase & ~(MAXBSIZE - 1); /* file position of the page */
902 pageOffset = fileBase & (MAXBSIZE - 1); /* xfr start's offset within page */
903 tsize = MAXBSIZE - pageOffset; /* how much more fits in this page */
904 /* we'll read tsize bytes, but first must make sure tsize isn't too big */
906 tsize = size; /* don't read past end of request */
907 eof = 0; /* flag telling us if we hit the EOF on the read */
908 if (arw == UIO_READ) { /* we're doing a read operation */
909 /* don't read past EOF */
910 if (fileBase + tsize > origLength) {
911 tsize = origLength - fileBase;
912 eof = 1; /* we did hit the EOF */
914 tsize = 0; /* better safe than sorry */
918 /* Purge dirty chunks of file if there are too many dirty
919 * chunks. Inside the write loop, we only do this at a chunk
920 * boundary. Clean up partial chunk if necessary at end of loop.
922 if (counter > 0 && code == 0 && AFS_CHUNKOFFSET(fileBase) == 0) {
923 code = afs_DoPartialWrite(avc, &treq);
927 /* write case, we ask segmap_release to call putpage. Really, we
928 * don't have to do this on every page mapin, but for now we're
929 * lazy, and don't modify the rest of AFS to scan for modified
930 * pages on a close or other "synchronize with file server"
931 * operation. This makes things a little cleaner, but probably
932 * hurts performance. */
937 break; /* nothing to transfer, we're done */
939 if (arw == UIO_WRITE)
940 avc->states |= CDirty; /* may have been cleared by DoPartialWrite */
942 /* Before dropping lock, hold the chunk (create it if necessary). This
943 * serves two purposes: (1) Ensure Cache Truncate Daemon doesn't try
944 * to purge the chunk's pages while we have them locked. This would
945 * cause deadlock because we might be waiting for the CTD to free up
946 * a chunk. (2) If we're writing past the original EOF, and we're
947 * at the base of the chunk, then make sure it exists online
948 * before we do the uiomove, since the segmap_release will
949 * write out to the chunk, causing it to get fetched if it hasn't
950 * been created yet. The code that would otherwise notice that
951 * we're fetching a chunk past EOF won't work, since we've
952 * already adjusted the file size above.
954 ObtainWriteLock(&avc->vlock, 551);
955 while (avc->vstates & VPageCleaning) {
956 ReleaseWriteLock(&avc->vlock);
957 ReleaseWriteLock(&avc->lock);
958 afs_osi_Sleep(&avc->vstates);
959 ObtainWriteLock(&avc->lock, 334);
960 ObtainWriteLock(&avc->vlock, 552);
962 ReleaseWriteLock(&avc->vlock);
964 afs_size_t toff, tlen;
965 dcp = afs_GetDCache(avc, fileBase, &treq, &toff, &tlen, 2);
971 ReleaseWriteLock(&avc->lock); /* uiomove may page fault */
973 #if defined(AFS_SUN56_ENV)
974 data = segmap_getmap(segkmap, AFSTOV(avc), (u_offset_t) pageBase);
975 raddr = (caddr_t) (((uintptr_t) data + pageOffset) & PAGEMASK);
977 data = segmap_getmap(segkmap, AFSTOV(avc), pageBase);
978 raddr = (caddr_t) (((u_int) data + pageOffset) & PAGEMASK);
981 (((u_int) data + pageOffset + tsize + PAGEOFFSET) & PAGEMASK) -
984 /* if we're doing a write, and we're starting at the rounded
985 * down page base, and we're writing enough data to cover all
986 * created pages, then we must be writing all of the pages
987 * in this MAXBSIZE window that we're creating.
990 if (arw == UIO_WRITE && ((long)raddr == (long)data + pageOffset)
992 /* probably the dcache backing this guy is around, but if
993 * not, we can't do this optimization, since we're creating
994 * writable pages, which must be backed by a chunk.
997 dcp_newpage = afs_FindDCache(avc, pageBase);
999 && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)) {
1000 ObtainWriteLock(&avc->lock, 251);
1001 ObtainWriteLock(&avc->vlock, 576);
1002 ObtainReadLock(&dcp_newpage->lock);
1003 if ((avc->activeV == 0)
1004 && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)
1005 && !(dcp_newpage->dflags & (DFFetching))) {
1007 segmap_pagecreate(segkmap, raddr, rsize, 1);
1009 ObtainWriteLock(&afs_xdcache, 252);
1010 /* Mark the pages as created and dirty */
1011 afs_indexFlags[dcp_newpage->index]
1012 |= (IFAnyPages | IFDirtyPages);
1013 ReleaseWriteLock(&afs_xdcache);
1016 ReleaseReadLock(&dcp_newpage->lock);
1017 afs_PutDCache(dcp_newpage);
1018 ReleaseWriteLock(&avc->vlock);
1019 ReleaseWriteLock(&avc->lock);
1020 } else if (dcp_newpage)
1021 afs_PutDCache(dcp_newpage);
1026 afs_fc2errno(segmap_fault
1027 (kas.a_hat, segkmap, raddr, rsize,
1031 AFS_UIOMOVE(data + pageOffset, tsize, arw, auio, code);
1032 segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTUNLOCK,
1036 code = segmap_release(segkmap, data, sflags);
1038 (void)segmap_release(segkmap, data, 0);
1041 ObtainWriteLock(&avc->lock, 253);
1049 afs_FakeClose(avc, acred);
1051 if (arw == UIO_WRITE && (avc->states & CDirty)) {
1052 code2 = afs_DoPartialWrite(avc, &treq);
1057 if (!code && avc->vc_error) {
1058 code = avc->vc_error;
1060 ReleaseWriteLock(&avc->lock);
1061 afs_BozonUnlock(&avc->pvnLock, avc);
1063 #ifdef AFS_SUN53_ENV
1064 if ((ioflag & FSYNC) && (arw == UIO_WRITE)
1065 && !AFS_NFSXLATORREQ(acred))
1066 code = afs_fsync(avc, 0, acred);
1068 if ((ioflag & IO_SYNC) && (arw == UIO_WRITE)
1069 && !AFS_NFSXLATORREQ(acred))
1070 code = afs_fsync(avc, acred);
1073 #ifdef AFS_SUN52_ENV
1075 * If things worked, add in as remaining in request any bytes
1076 * we didn't write due to file size ulimit.
1078 if (code == 0 && extraResid > 0)
1079 auio->uio_resid += extraResid;
1081 return afs_CheckCode(code, &treq, 46);
1084 afs_map(vp, off, as, addr, len, prot, maxprot, flags, cred)
1090 u_char prot, maxprot;
1092 struct AFS_UCRED *cred;
1094 struct segvn_crargs crargs;
1095 register afs_int32 code;
1096 struct vrequest treq;
1097 register struct vcache *avc = VTOAFS(vp);
1099 AFS_STATCNT(afs_map);
1102 /* check for reasonableness on segment bounds; apparently len can be < 0 */
1103 if (off < 0 || off + len < 0) {
1106 #ifndef AFS_64BIT_CLIENT
1107 if (AfsLargeFileSize(off, len)) { /* file is larger than 2 GB */
1113 if (vp->v_flag & VNOMAP) /* File isn't allowed to be mapped */
1116 if (vp->v_filocks) /* if locked, disallow mapping */
1120 if (code = afs_InitReq(&treq, cred))
1123 if (vp->v_type != VREG) {
1128 code = afs_VerifyVCache(avc, &treq);
1132 afs_BozonLock(&avc->pvnLock, avc);
1133 osi_FlushPages(avc, cred); /* ensure old pages are gone */
1134 avc->states |= CMAPPED; /* flag cleared at afs_inactive */
1135 afs_BozonUnlock(&avc->pvnLock, avc);
1139 if ((flags & MAP_FIXED) == 0) {
1140 #if defined(AFS_SUN57_ENV)
1141 map_addr(addr, len, off, 1, flags);
1142 #elif defined(AFS_SUN56_ENV)
1143 map_addr(addr, len, off, 1);
1145 map_addr(addr, len, (off_t) off, 1);
1147 if (*addr == NULL) {
1153 (void)as_unmap(as, *addr, len); /* unmap old address space use */
1154 /* setup the create parameter block for the call */
1155 crargs.vp = AFSTOV(avc);
1156 crargs.offset = (u_int) off;
1158 crargs.type = flags & MAP_TYPE;
1160 crargs.maxprot = maxprot;
1161 crargs.amp = (struct anon_map *)0;
1162 crargs.flags = flags & ~MAP_TYPE;
1164 code = as_map(as, *addr, len, segvn_create, (char *)&crargs);
1168 code = afs_CheckCode(code, &treq, 47);
1172 code = afs_CheckCode(code, &treq, 48);
1179 * For Now We use standard local kernel params for AFS system values. Change this
1182 afs_pathconf(vp, cmd, outdatap, credp)
1183 register struct AFS_UCRED *credp;
1188 AFS_STATCNT(afs_cntl);
1191 *outdatap = MAXLINK;
1194 *outdatap = MAXNAMLEN;
1197 *outdatap = MAXPATHLEN;
1199 case _PC_CHOWN_RESTRICTED:
1211 afs_ioctl(vnp, com, arg, flag, credp, rvalp)
1221 afs_rwlock(vnp, wlock)
1225 rw_enter(&(VTOAFS(vnp))->rwlock, (wlock ? RW_WRITER : RW_READER));
1230 afs_rwunlock(vnp, wlock)
1234 rw_exit(&(VTOAFS(vnp))->rwlock);
1239 afs_seek(vnp, ooff, noffp)
1244 register int code = 0;
1246 #ifndef AFS_64BIT_CLIENT
1247 # define __MAXOFF_T MAXOFF_T
1249 # define __MAXOFF_T MAXOFFSET_T
1252 if ((*noffp < 0 || *noffp > __MAXOFF_T))
1258 afs_frlock(vnp, cmd, ap, flag, off,
1259 #ifdef AFS_SUN59_ENV
1265 #if defined(AFS_SUN56_ENV)
1272 #ifdef AFS_SUN59_ENV
1273 struct flk_callback *flkcb;
1275 struct AFS_UCRED *credp;
1277 register afs_int32 code = 0;
1279 * Implement based on afs_lockctl
1282 #ifdef AFS_SUN59_ENV
1284 afs_warn("Don't know how to deal with flk_callback's!\n");
1286 if ((cmd == F_GETLK) || (cmd == F_O_GETLK) || (cmd == F_SETLK)
1287 || (cmd == F_SETLKW)) {
1288 #ifdef AFS_SUN53_ENV
1289 ap->l_pid = ttoproc(curthread)->p_pid;
1292 ap->l_pid = ttoproc(curthread)->p_epid;
1293 ap->l_sysid = ttoproc(curthread)->p_sysid;
1297 #ifdef AFS_SUN56_ENV
1298 code = convoff(vnp, ap, 0, off);
1300 code = convoff(vnp, ap, 0, (off_t) off);
1307 code = afs_lockctl(VTOAFS(vnp), ap, cmd, credp);
1314 afs_space(vnp, cmd, ap, flag, off, credp)
1317 #if defined(AFS_SUN56_ENV)
1324 struct AFS_UCRED *credp;
1326 register afs_int32 code = EINVAL;
1329 if ((cmd == F_FREESP)
1330 #ifdef AFS_SUN56_ENV
1331 && ((code = convoff(vnp, ap, 0, off)) == 0)) {
1333 && ((code = convoff(vnp, ap, 0, (off_t) off)) == 0)) {
1337 vattr.va_mask = AT_SIZE;
1338 vattr.va_size = ap->l_start;
1339 code = afs_setattr(VTOAFS(vnp), &vattr, 0, credp);
1347 afs_dump(vp, addr, i1, i2)
1352 AFS_STATCNT(afs_dump);
1353 afs_warn("AFS_DUMP. MUST IMPLEMENT THIS!!!\n");
1358 /* Nothing fancy here; just compare if vnodes are identical ones */
1360 struct vnode *vp1, *vp2;
1362 AFS_STATCNT(afs_cmp);
1363 return (vp1 == vp2);
1368 afs_realvp(struct vnode *vp, struct vnode **vpp)
1370 AFS_STATCNT(afs_realvp);
1376 afs_pageio(vp, pp, ui1, ui2, i1, credp)
1383 afs_warn("afs_pageio: Not implemented\n");
1389 #ifdef AFS_SUN59_ENV
1395 #ifdef AFS_SUN59_ENV
1399 afs_warn("afs_dumpctl: Not implemented\n");
1403 #ifdef AFS_SUN54_ENV
1405 afs_dispose(vp, p, fl, dn, cr)
1411 fs_dispose(vp, p, fl, dn, cr);
1415 afs_setsecattr(vp, vsecattr, flag, creds)
1417 vsecattr_t *vsecattr;
1425 afs_getsecattr(vp, vsecattr, flag, creds)
1427 vsecattr_t *vsecattr;
1431 return fs_fab_acl(vp, vsecattr, flag, creds);
1435 #ifdef AFS_GLOBAL_SUNLOCK
1436 extern int gafs_open(), gafs_close(), afs_ioctl(), gafs_access();
1437 extern int gafs_getattr(), gafs_setattr(), gafs_lookup(), gafs_create();
1438 extern int gafs_remove(), gafs_link(), gafs_rename(), gafs_mkdir();
1439 extern int gafs_rmdir(), gafs_readdir(), gafs_fsync(), gafs_symlink();
1440 extern int gafs_fid(), gafs_readlink(), fs_setfl(), afs_pathconf();
1441 extern int afs_lockctl();
1442 extern void gafs_inactive();
1444 #ifdef AFS_SUN510_ENV
1445 struct fs_operation_def afs_vnodeops_template[] = {
1446 { VOPNAME_OPEN, gafs_open },
1447 { VOPNAME_CLOSE, gafs_close },
1448 { VOPNAME_READ, afs_vmread },
1449 { VOPNAME_WRITE, afs_vmwrite },
1450 { VOPNAME_IOCTL, afs_ioctl },
1451 { VOPNAME_SETFL, fs_setfl },
1452 { VOPNAME_GETATTR, gafs_getattr },
1453 { VOPNAME_SETATTR, gafs_setattr },
1454 { VOPNAME_ACCESS, gafs_access },
1455 { VOPNAME_LOOKUP, gafs_lookup },
1456 { VOPNAME_CREATE, gafs_create },
1457 { VOPNAME_REMOVE, gafs_remove },
1458 { VOPNAME_LINK, gafs_link },
1459 { VOPNAME_RENAME, gafs_rename },
1460 { VOPNAME_MKDIR, gafs_mkdir },
1461 { VOPNAME_RMDIR, gafs_rmdir },
1462 { VOPNAME_READDIR, gafs_readdir },
1463 { VOPNAME_SYMLINK, gafs_symlink },
1464 { VOPNAME_READLINK, gafs_readlink },
1465 { VOPNAME_FSYNC, gafs_fsync },
1466 { VOPNAME_INACTIVE, gafs_inactive },
1467 { VOPNAME_FID, gafs_fid },
1468 { VOPNAME_RWLOCK, afs_rwlock },
1469 { VOPNAME_RWUNLOCK, afs_rwunlock },
1470 { VOPNAME_SEEK, afs_seek },
1471 { VOPNAME_CMP, afs_cmp },
1472 { VOPNAME_FRLOCK, afs_frlock },
1473 { VOPNAME_SPACE, afs_space },
1474 { VOPNAME_REALVP, afs_realvp },
1475 { VOPNAME_GETPAGE, afs_getpage },
1476 { VOPNAME_PUTPAGE, afs_putpage },
1477 { VOPNAME_MAP, afs_map },
1478 { VOPNAME_ADDMAP, afs_addmap },
1479 { VOPNAME_DELMAP, afs_delmap },
1480 { VOPNAME_POLL, fs_poll },
1481 { VOPNAME_DUMP, afs_dump },
1482 { VOPNAME_PATHCONF, afs_pathconf },
1483 { VOPNAME_PAGEIO, afs_pageio },
1484 { VOPNAME_DUMPCTL, afs_dumpctl },
1485 { VOPNAME_DISPOSE, afs_dispose },
1486 { VOPNAME_GETSECATTR, afs_getsecattr },
1487 { VOPNAME_SETSECATTR, afs_setsecattr },
1488 { VOPNAME_SHRLOCK, fs_shrlock },
1491 struct vnodeops *afs_ops;
1493 struct vnodeops Afs_vnodeops = {
1533 #ifdef AFS_SUN54_ENV
1538 #if defined(AFS_SUN56_ENV)
1542 struct vnodeops *afs_ops = &Afs_vnodeops;
1547 gafs_open(avcp, aflags, acred)
1548 register struct vcache **avcp;
1550 struct AFS_UCRED *acred;
1555 code = afs_open(avcp, aflags, acred);
1561 gafs_close(avc, aflags, count, offset, acred)
1564 register struct vcache *avc;
1566 struct AFS_UCRED *acred;
1571 code = afs_close(avc, aflags, count, offset, acred);
1577 gafs_getattr(avc, attrs, flags, acred)
1579 register struct vcache *avc;
1580 register struct vattr *attrs;
1581 struct AFS_UCRED *acred;
1586 code = afs_getattr(avc, attrs, flags, acred);
1592 gafs_setattr(avc, attrs, flags, acred)
1594 register struct vcache *avc;
1595 register struct vattr *attrs;
1596 struct AFS_UCRED *acred;
1601 code = afs_setattr(avc, attrs, flags, acred);
1607 gafs_access(avc, amode, flags, acred)
1609 register struct vcache *avc;
1610 register afs_int32 amode;
1611 struct AFS_UCRED *acred;
1616 code = afs_access(avc, amode, flags, acred);
1622 gafs_lookup(adp, aname, avcp, pnp, flags, rdir, acred)
1623 struct pathname *pnp;
1626 register struct vcache *adp, **avcp;
1628 struct AFS_UCRED *acred;
1633 code = afs_lookup(adp, aname, avcp, pnp, flags, rdir, acred);
1639 gafs_create(adp, aname, attrs, aexcl, amode, avcp, acred)
1640 register struct vcache *adp;
1642 struct vattr *attrs;
1645 struct vcache **avcp;
1646 struct AFS_UCRED *acred;
1651 code = afs_create(adp, aname, attrs, aexcl, amode, avcp, acred);
1656 gafs_remove(adp, aname, acred)
1657 register struct vcache *adp;
1659 struct AFS_UCRED *acred;
1664 code = afs_remove(adp, aname, acred);
1669 gafs_link(adp, avc, aname, acred)
1670 register struct vcache *avc;
1671 register struct vcache *adp;
1673 struct AFS_UCRED *acred;
1678 code = afs_link(adp, avc, aname, acred);
1683 gafs_rename(aodp, aname1, andp, aname2, acred)
1684 register struct vcache *aodp, *andp;
1685 char *aname1, *aname2;
1686 struct AFS_UCRED *acred;
1691 code = afs_rename(aodp, aname1, andp, aname2, acred);
1692 #ifdef AFS_SUN510_ENV
1694 struct vcache *avcp = NULL;
1696 (void) afs_lookup(andp, aname2, &avcp, NULL, 0, NULL, acred);
1698 struct vnode *vp = AFSTOV(avcp), *pvp = AFSTOV(andp);
1700 mutex_enter(&vp->v_lock);
1701 kmem_free(vp->v_path, strlen(vp->v_path) + 1);
1703 mutex_exit(&vp->v_lock);
1704 VN_SETPATH(afs_globalVp, pvp, vp, aname2, strlen(aname2));
1714 gafs_mkdir(adp, aname, attrs, avcp, acred)
1715 register struct vcache *adp;
1716 register struct vcache **avcp;
1718 struct vattr *attrs;
1719 struct AFS_UCRED *acred;
1724 code = afs_mkdir(adp, aname, attrs, avcp, acred);
1730 gafs_rmdir(adp, aname, cdirp, acred)
1731 struct vnode *cdirp;
1732 register struct vcache *adp;
1734 struct AFS_UCRED *acred;
1739 code = afs_rmdir(adp, aname, cdirp, acred);
1745 gafs_readdir(avc, auio, acred, eofp)
1747 register struct vcache *avc;
1749 struct AFS_UCRED *acred;
1754 code = afs_readdir(avc, auio, acred, eofp);
1759 gafs_symlink(adp, aname, attrs, atargetName, acred)
1760 register struct vcache *adp;
1761 register char *atargetName;
1763 struct vattr *attrs;
1764 struct AFS_UCRED *acred;
1769 code = afs_symlink(adp, aname, attrs, atargetName, acred);
1775 gafs_readlink(avc, auio, acred)
1776 register struct vcache *avc;
1778 struct AFS_UCRED *acred;
1783 code = afs_readlink(avc, auio, acred);
1788 #ifdef AFS_SUN53_ENV
1789 gafs_fsync(avc, flag, acred)
1792 gafs_fsync(avc, acred)
1794 register struct vcache *avc;
1795 struct AFS_UCRED *acred;
1800 #ifdef AFS_SUN53_ENV
1801 code = afs_fsync(avc, flag, acred);
1803 code = afs_fsync(avc, acred);
1810 afs_inactive(struct vcache *avc, struct AFS_UCRED *acred)
1812 struct vnode *vp = AFSTOV(avc);
1813 if (afs_shuttingdown)
1817 * In Solaris and HPUX s800 and HP-UX10.0 they actually call us with
1818 * v_count 1 on last reference!
1820 mutex_enter(&vp->v_lock);
1821 if (avc->vrefCount <= 0)
1822 osi_Panic("afs_inactive : v_count <=0\n");
1825 * If more than 1 don't unmap the vnode but do decrement the ref count
1828 if (vp->v_count > 0) {
1829 mutex_exit(&vp->v_lock);
1832 mutex_exit(&vp->v_lock);
1835 * Solaris calls VOP_OPEN on exec, but doesn't call VOP_CLOSE when
1836 * the executable exits. So we clean up the open count here.
1838 * Only do this for mvstat 0 vnodes: when using fakestat, we can't
1839 * lose the open count for volume roots (mvstat 2), even though they
1840 * will get VOP_INACTIVE'd when released by afs_PutFakeStat().
1842 if (avc->opens > 0 && avc->mvstat == 0 && !(avc->states & CCore))
1843 avc->opens = avc->execsOrWriters = 0;
1845 afs_InactiveVCache(avc, acred);
1849 gafs_inactive(avc, acred)
1850 register struct vcache *avc;
1851 struct AFS_UCRED *acred;
1854 afs_inactive(avc, acred);
1859 gafs_fid(avc, fidpp)
1866 code = afs_fid(avc, fidpp);
1871 #endif /* AFS_GLOBAL_SUNLOCK */