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 "../afs/param.h" /* Should be always first */
11 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
13 * SOLARIS/osi_vnodeops.c
17 * Functions: AFS_TRYUP, _init, _info, _fini, afs_addmap, afs_delmap,
18 * afs_vmread, afs_vmwrite, afs_getpage, afs_GetOnePage, afs_putpage,
19 * afs_putapage, afs_nfsrdwr, afs_map, afs_PageLeft, afs_pathconf/afs_cntl,
20 * afs_ioctl, afs_rwlock, afs_rwunlock, afs_seek, afs_space, afs_dump,
21 * afs_cmp, afs_realvp, afs_pageio, afs_dumpctl, afs_dispose, afs_setsecattr,
22 * afs_getsecattr, gafs_open, gafs_close, gafs_getattr, gafs_setattr,
23 * gafs_access, gafs_lookup, gafs_create, gafs_remove, gafs_link,
24 * gafs_rename, gafs_mkdir, gafs_rmdir, gafs_readdir, gafs_symlink,
25 * gafs_readlink, gafs_fsync, afs_inactive, gafs_inactive, gafs_fid
28 * Variables: Afs_vnodeops
31 #include "../afs/sysincludes.h" /* Standard vendor system headers */
32 #include "../afs/afsincludes.h" /* Afs-based standard headers */
33 #include "../afs/afs_stats.h" /* statistics */
34 #include "../afs/nfsclient.h"
43 #include <vm/seg_map.h>
44 #include <vm/seg_vn.h>
46 #if defined(AFS_SUN5_ENV)
47 #include <sys/modctl.h>
48 #include <sys/syscall.h>
52 #include <sys/debug.h>
53 #if defined(AFS_SUN5_ENV)
54 #include <sys/fs_subr.h>
57 #if defined(AFS_SUN5_ENV)
59 * XXX Temporary fix for problems with Solaris rw_tryupgrade() lock.
60 * It isn't very persistent in getting the upgrade when others are
61 * waiting for it and returns 0. So the UpgradeSToW() macro that the
62 * rw_tryupgrade used to map to wasn't good enough and we need to use
63 * the following code instead. Obviously this isn't the proper place
64 * for it but it's only called from here for now
71 if (!rw_tryupgrade(lock)) {
73 rw_enter(lock, RW_WRITER);
80 extern struct as kas; /* kernel addr space */
81 extern unsigned char *afs_indexFlags;
82 extern afs_lock_t afs_xdcache;
84 /* Additional vnodeops for SunOS 4.0.x */
85 int afs_nfsrdwr(), afs_getpage(), afs_putpage(), afs_map();
86 int afs_dump(), afs_cmp(), afs_realvp(), afs_GetOnePage();
92 int afs_addmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
93 register struct vnode *avp;
97 int length, prot, maxprot, flags;
98 struct AFS_UCRED *credp;
100 /* XXX What should we do here?? XXX */
104 int afs_delmap(avp, offset, asp, addr, length, prot, maxprot, flags, credp)
105 register struct vnode *avp;
109 int length, prot, maxprot, flags;
110 struct AFS_UCRED *credp;
112 /* XXX What should we do here?? XXX */
116 int afs_vmread(avp, auio, ioflag, acred)
117 register struct vnode *avp;
120 struct AFS_UCRED *acred;
124 if (!RW_READ_HELD(&((struct vcache *)avp)->rwlock))
125 osi_Panic("afs_vmread: !rwlock");
127 code = afs_nfsrdwr((struct vcache *)avp, auio, UIO_READ, ioflag, acred);
133 int afs_vmwrite(avp, auio, ioflag, acred)
134 register struct vnode *avp;
137 struct AFS_UCRED *acred;
141 if (!RW_WRITE_HELD(&((struct vcache *)avp)->rwlock))
142 osi_Panic("afs_vmwrite: !rwlock");
144 code = afs_nfsrdwr((struct vcache *)avp, auio, UIO_WRITE, ioflag, acred);
149 #endif /* AFS_SUN5_ENV */
151 int afs_getpage(vp, off, len, protp, pl, plsz, seg, addr, rw, acred)
166 struct AFS_UCRED *acred;
168 register afs_int32 code = 0;
169 #if defined(AFS_SUN56_ENV)
170 u_offset_t toff = (u_offset_t)off;
173 AFS_STATCNT(afs_getpage);
175 if (vp->v_flag & VNOMAP) /* File doesn't allow mapping */
181 #if defined(AFS_SUN56_ENV)
183 code = afs_GetOnePage((struct vnode *) vp, toff, len, protp, pl, plsz,
184 seg, addr, rw, acred);
188 code = afs_GetOnePage(vp, (u_int)off, len, protp, pl, plsz,
189 seg, addr, rw, acred);
192 code = afs_GetOnePage(vp, off, protp, pl, plsz,
193 seg, addr, rw, acred);
197 struct vcache *vcp = (struct vcache *)vp;
199 ObtainWriteLock(&vcp->vlock, 548);
201 ReleaseWriteLock(&vcp->vlock);
203 afs_BozonLock(&vcp->pvnLock, vcp);
204 #if defined(AFS_SUN56_ENV)
205 code = pvn_getpages(afs_GetOnePage, (struct vnode *) vp, toff,
206 len, protp, pl, plsz, seg, addr, rw, acred);
208 code = pvn_getpages(afs_GetOnePage, (struct vnode *) vp, (u_int)off,
209 len, protp, pl, plsz, seg, addr, rw, acred);
211 afs_BozonUnlock(&vcp->pvnLock, vcp);
213 ObtainWriteLock(&vcp->vlock, 549);
215 ReleaseWriteLock(&vcp->vlock);
222 /* Return all the pages from [off..off+len) in file */
224 int afs_GetOnePage(vp, off, alen, protp, pl, plsz, seg, addr, rw, acred)
227 int afs_GetOnePage(vp, off, protp, pl, plsz, seg, addr, rw, acred)
230 #if defined(AFS_SUN56_ENV)
245 struct AFS_UCRED *acred;
247 register struct page *page;
248 register afs_int32 code = 0;
252 register struct vcache *avc;
253 register struct dcache *tdc;
255 int slot, offset, nlen;
256 struct vrequest treq;
257 afs_int32 mapForRead = 0, Code=0;
258 #if defined(AFS_SUN56_ENV)
264 if (!pl) return 0; /* punt asynch requests */
267 pl[0] = NULL; /* Make sure it's empty */
270 osi_Panic("GetOnePage: !acred");
272 acred = u.u_cred; /* better than nothing */
275 /* first, obtain the proper lock for the VM system */
276 avc = (struct vcache *) vp; /* cast to afs vnode */
278 /* if this is a read request, map the page in read-only. This will
279 * allow us to swap out the dcache entry if there are only read-only
280 * pages created for the chunk, which helps a *lot* when dealing
281 * with small caches. Otherwise, we have to invalidate the vm
282 * pages for the range covered by a chunk when we swap out the
285 if (rw == S_READ || rw == S_EXEC)
288 if (protp) *protp = PROT_ALL;
290 if (avc->credp /*&& AFS_NFSXLATORREQ(acred)*/ && AFS_NFSXLATORREQ(avc->credp)) {
294 if (code = afs_InitReq(&treq, acred)) return code;
296 if (AFS_NFSXLATORREQ(acred)) {
298 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
299 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
307 if (rw == S_WRITE || rw == S_CREATE)
308 tdc = afs_GetDCache(avc, (afs_int32)off, &treq, &offset, &nlen, 5);
310 tdc = afs_GetDCache(avc, (afs_int32)off, &treq, &offset, &nlen, 1);
311 if (!tdc) return EINVAL;
313 code = afs_VerifyVCache(avc, &treq);
318 return afs_CheckCode(code, &treq, 44); /* failed to get it */
321 afs_BozonLock(&avc->pvnLock, avc);
322 ObtainSharedLock(&avc->lock,566);
324 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, (afs_int32) vp,
325 ICL_TYPE_LONG, (afs_int32) off, ICL_TYPE_LONG, (afs_int32) len,
326 ICL_TYPE_LONG, (int) rw);
332 /* Check to see if we're in the middle of a VM purge, and if we are, release
333 * the locks and try again when the VM purge is done. */
334 ObtainWriteLock(&avc->vlock, 550);
336 ReleaseSharedLock(&avc->lock);
337 ReleaseWriteLock(&avc->vlock);
338 afs_BozonUnlock(&avc->pvnLock, avc);
340 /* Check activeV again, it may have been turned off
341 * while we were waiting for a lock in afs_PutDCache */
342 ObtainWriteLock(&avc->vlock, 574);
344 avc->vstates |= VRevokeWait;
345 ReleaseWriteLock(&avc->vlock);
346 afs_osi_Sleep(&avc->vstates);
348 ReleaseWriteLock(&avc->vlock);
352 ReleaseWriteLock(&avc->vlock);
355 /* Check to see whether the cache entry is still valid */
356 if (!(avc->states & CStatd)
357 || !hsame(avc->m.DataVersion, tdc->f.versionNo)) {
358 ReleaseSharedLock(&avc->lock);
359 afs_BozonUnlock(&avc->pvnLock, avc);
365 while (1) { /* loop over all pages */
366 /* now, try to find the page in memory (it may already be intransit or laying
367 around the free list */
368 page = page_lookup( vp, toffset, (rw == S_CREATE ? SE_EXCL : SE_SHARED) );
372 /* if we make it here, we can't find the page in memory. Do a real disk read
373 from the cache to get the data */
374 Code |= 0x200; /* XXX */
376 #if defined(AFS_SUN54_ENV)
377 /* use PG_EXCL because we know the page does not exist already. If it
378 * actually does exist, we have somehow raced between lookup and create.
379 * As of 4/98, that shouldn't be possible, but we'll be defensive here
380 * in case someone tries to relax all the serialization of read and write
381 * operations with harmless things like stat. */
382 #if defined(AFS_SUN58_ENV)
383 page = page_create_va(vp, toffset, PAGESIZE, PG_WAIT|PG_EXCL, seg, addr);
385 page = page_create_va(vp, toffset, PAGESIZE, PG_WAIT|PG_EXCL, seg->s_as, addr);
388 page = page_create(vp, toffset, PAGESIZE, PG_WAIT);
394 pagezero(page, alen, PAGESIZE-alen);
396 page = rm_allocpage(seg, addr, PAGESIZE, 1); /* can't fail */
397 if (!page) osi_Panic("afs_getpage alloc page");
398 /* we get a circularly-linked list of pages back, but we expect only
399 one, since that's what we asked for */
400 if (page->p_next != page) osi_Panic("afs_getpage list");
401 /* page enter returns a locked page; we'll drop the lock as a side-effect
402 of the pvn_done done by afs_ustrategy. If we decide not to call
403 strategy, we must be sure to call pvn_fail, at least, to release the
404 page locks and otherwise reset the pages. The page, while locked, is
405 not held, for what it is worth */
406 page->p_intrans = 1; /* set appropriate flags */
408 /* next call shouldn't fail, since we have pvnLock set */
409 if (page_enter(page, vp, toffset)) osi_Panic("afs_getpage enter race");
410 #endif /* AFS_SUN5_ENV */
413 if (rw == S_CREATE) {
414 /* XXX Don't read from AFS in write only cases XXX */
415 page_io_unlock(page);
419 /* XXX Don't read from AFS in write only cases XXX */
420 page->p_intrans = page->p_pagein = 0;
421 page_unlock(page); /* XXX */
428 /* now it is time to start I/O operation */
429 buf = pageio_setup(page, PAGESIZE, vp, B_READ); /* allocate a buf structure */
430 #if defined(AFS_SUN5_ENV)
434 buf->b_blkno = btodb(toffset);
435 bp_mapin(buf); /* map it in to our address space */
437 ReleaseSharedLock(&avc->lock);
439 #if defined(AFS_SUN5_ENV)
441 UpgradeSToWLock(&avc->lock, 564);
442 code = afs_ustrategy(buf, acred); /* do the I/O */
443 ConvertWToSLock(&avc->lock);
446 code = afs_ustrategy(buf); /* do the I/O */
449 ObtainSharedLock(&avc->lock,245);
452 /* Before freeing unmap the buffer */
463 page_io_unlock(page);
467 /* come here when we have another page (already held) to enter */
469 /* put page in array and continue */
471 /* The p_selock must be downgraded to a shared lock after the page is read */
472 #if defined(AFS_SUN56_ENV)
473 if ((rw != S_CREATE) && !(PAGE_SHARED(page)))
475 if ((rw != S_CREATE) && !(se_shared_assert(&page->p_selock)))
478 page_downgrade(page);
483 code = page_iolock_assert(page);
489 if (tlen <= 0) break; /* done all the pages */
490 } /* while (1) ... */
493 pl[slot] = (struct page *) 0;
494 avc->states |= CHasPages;
495 ReleaseSharedLock(&avc->lock);
497 ObtainWriteLock(&afs_xdcache,246);
499 /* track that we have dirty (or dirty-able) pages for this chunk. */
500 afs_indexFlags[tdc->index] |= IFDirtyPages;
502 afs_indexFlags[tdc->index] |= IFAnyPages;
503 ReleaseWriteLock(&afs_xdcache);
505 afs_BozonUnlock(&avc->pvnLock, avc);
509 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, (int)page,
510 ICL_TYPE_LONG, Code);
515 afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, (int)page,
516 ICL_TYPE_LONG, Code);
517 /* release all pages, drop locks, return code */
520 pvn_read_done(page, B_ERROR);
522 for(i=0; i<slot; i++)
525 ReleaseSharedLock(&avc->lock);
526 afs_BozonUnlock(&avc->pvnLock, avc);
534 int afs_putpage(vp, off, len, flags, cred)
539 struct AFS_UCRED *cred;
544 #if defined(AFS_SUN58_ENV)
549 afs_int32 endPos, NPages=0;
550 #if defined(AFS_SUN56_ENV)
551 u_offset_t toff = off;
556 AFS_STATCNT(afs_putpage);
557 if (vp->v_flag & VNOMAP) /* file doesn't allow mapping */
561 * Putpage (ASYNC) is called every sec to flush out dirty vm pages
564 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER, (afs_int32) vp,
565 ICL_TYPE_LONG, (afs_int32) off, ICL_TYPE_LONG, (afs_int32) len,
566 ICL_TYPE_LONG, (int) flags);
567 avc = (struct vcache *) vp;
568 afs_BozonLock(&avc->pvnLock, avc);
569 ObtainWriteLock(&avc->lock,247);
571 /* Get a list of modified (or whatever) pages */
573 endPos = (int)off + len; /* position we're supposed to write up to */
574 while ((afs_int32)toff < endPos && (afs_int32)toff < avc->m.Length) {
575 /* If not invalidating pages use page_lookup_nowait to avoid reclaiming
576 * them from the free list
579 if (flags & (B_FREE|B_INVAL))
580 pages = page_lookup(vp, toff, SE_EXCL);
582 pages = page_lookup_nowait(vp, toff, SE_SHARED);
583 if (!pages || !pvn_getdirty(pages, flags))
587 code = afs_putapage(vp, pages, &toff, &tlen, flags, cred);
598 #if defined(AFS_SUN56_ENV)
599 code = pvn_vplist_dirty(vp, toff, afs_putapage, flags, cred);
601 code = pvn_vplist_dirty(vp, (u_int)off, afs_putapage, flags, cred);
606 if (code && !avc->vc_error)
607 avc->vc_error = code;
609 ReleaseWriteLock(&avc->lock);
610 afs_BozonUnlock(&avc->pvnLock, avc);
611 afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_LONG, code, ICL_TYPE_LONG, NPages);
617 int afs_putapage(struct vnode *vp, struct page *pages,
618 #if defined(AFS_SUN56_ENV)
623 #if defined(AFS_SUN58_ENV)
628 int flags, struct AFS_UCRED *credp)
631 struct vcache *avc = (struct vcache *)vp;
633 u_int toff, tlen = PAGESIZE, off = (pages->p_offset/PAGESIZE)*PAGESIZE;
634 u_int poff = pages->p_offset;
637 * Now we've got the modified pages. All pages are locked and held
638 * XXX Find a kluster that fits in one block (or page). We also
639 * adjust the i/o if the file space is less than a while page. XXX
642 if (tlen+toff > avc->m.Length) {
643 tlen = avc->m.Length - toff;
645 /* can't call mapout with 0 length buffers (rmfree panics) */
646 if (((tlen>>24)&0xff) == 0xff) {
651 * Can't call mapout with 0 length buffers since we'll get rmfree panics
653 tbuf = pageio_setup(pages, tlen, vp, B_WRITE | flags);
654 if (!tbuf) return (ENOMEM);
657 tbuf->b_blkno = btodb(pages->p_offset);
660 afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUTONE, ICL_TYPE_LONG, avc, ICL_TYPE_LONG, pages,
661 ICL_TYPE_LONG, tlen, ICL_TYPE_LONG, toff);
662 code = afs_ustrategy(tbuf, credp); /* unlocks page */
666 pvn_write_done(pages, ((code) ? B_ERROR:0) | B_WRITE | flags);
669 if (offp) *offp = toff;
670 if (lenp) *lenp = tlen;
676 int afs_putpage(vp, off, len, flags, cred)
681 struct AFS_UCRED *cred;
683 int wholeEnchilada; /* true if we must get all of the pages */
689 afs_int32 code = 0, rcode;
691 afs_int32 clusterStart, clusterEnd, endPos;
693 /* In the wholeEnchilada case, we must ensure that we get all of the pages
694 from the system, since we're doing this to shutdown the use of a vnode */
696 AFS_STATCNT(afs_putpage);
697 wholeEnchilada = (off == 0 && len == 0 && (flags & (B_INVAL|B_ASYNC)) == B_INVAL);
699 avc = (struct vcache *) vp;
700 afs_BozonLock(&avc->pvnLock, avc);
701 ObtainWriteLock(&avc->lock,248);
704 /* in whole enchilada case, loop until call to pvn_getdirty can't find
705 any more modified pages */
707 /* first we try to get a list of modified (or whatever) pages */
709 pages = pvn_vplist_dirty(vp, off, flags);
712 endPos = off + len; /* position we're supposed to write up to */
713 if (endPos > avc->m.Length) endPos = avc->m.Length; /* bound by this */
714 clusterStart = off & ~(PAGESIZE-1); /* round down to nearest page */
715 clusterEnd = ((endPos-1) | (PAGESIZE-1))+1; /* round up to nearest page */
716 pages = pvn_range_dirty(vp, off, endPos, clusterStart, clusterEnd, flags);
719 /* Now we've got the modified pages. All pages are locked and held */
720 rcode = 0; /* return code */
721 while(pages) { /* look over all pages in the returned set */
722 tpage = pages; /* get first page in the list */
724 /* write out the page */
725 poffset = tpage->p_offset; /* where the page starts in the file */
726 /* tlen will represent the end of the range to write, for a while */
727 tlen = PAGESIZE+poffset; /* basic place to end tpage write */
728 /* but we also don't want to write past end of off..off+len range */
729 if (len != 0 && tlen > off+len) tlen = off+len;
730 /* and we don't want to write past the end of the file */
731 if (tlen > avc->m.Length) tlen = avc->m.Length;
732 /* and we don't want to write at all if page starts after end */
733 if (poffset >= tlen) {
734 pvn_fail(pages, B_WRITE | flags);
737 /* finally change tlen from end position to length */
738 tlen -= poffset; /* compute bytes to write from this page */
739 page_sub(&pages, tpage); /* remove tpage from "pages" list */
740 tbuf = pageio_setup(tpage, tlen, vp, B_WRITE | flags);
742 pvn_fail(tpage, B_WRITE|flags);
743 pvn_fail(pages, B_WRITE|flags);
747 tbuf->b_blkno = btodb(tpage->p_offset);
749 ReleaseWriteLock(&avc->lock); /* can't hold during strategy call */
750 code = afs_ustrategy(tbuf); /* unlocks page */
751 ObtainWriteLock(&avc->lock,249); /* re-obtain */
753 /* unlocking of tpage is done by afs_ustrategy */
755 if (pages) /* may have already removed last page */
756 pvn_fail(pages, B_WRITE|flags);
759 } /* for (tpage=pages....) */
761 /* see if we've gotten all of the pages in the whole enchilada case */
762 if (!wholeEnchilada || !vp->v_pages) break;
763 } /* while(1) obtaining all pages */
766 * If low on chunks, and if writing the last byte of a chunk, try to
767 * free some. Note that afs_DoPartialWrite calls osi_SyncVM which now
768 * calls afs_putpage, so this is recursion. It stops there because we
769 * insist on len being non-zero.
771 if (afs_stats_cmperf.cacheCurrDirtyChunks > afs_stats_cmperf.cacheMaxDirtyChunks
772 && len != 0 && AFS_CHUNKOFFSET((off + len)) == 0) {
773 struct vrequest treq;
774 if (!afs_InitReq(&treq, cred ? cred : u.u_cred)) {
775 rcode = afs_DoPartialWrite(avc, &treq); /* XXX */
781 if (rcode && !avc->vc_error)
782 avc->vc_error = rcode;
784 /* when we're here, we just return code. */
785 ReleaseWriteLock(&avc->lock);
786 afs_BozonUnlock(&avc->pvnLock, avc);
790 #endif /* AFS_SUN5_ENV */
792 int afs_nfsrdwr(avc, auio, arw, ioflag, acred)
793 register struct vcache *avc;
797 struct AFS_UCRED *acred;
799 register afs_int32 code;
802 afs_int32 mode, sflags;
804 struct dcache *dcp, *dcp_newpage;
805 afs_int32 fileBase, size;
807 register afs_int32 tsize;
808 register afs_int32 pageOffset, extraResid=0;
809 register long origLength; /* length when reading/writing started */
810 register long appendLength; /* length when this call will finish */
811 int created; /* created pages instead of faulting them */
813 int didFakeOpen, eof;
814 struct vrequest treq;
818 AFS_STATCNT(afs_nfsrdwr);
820 /* can't read or write other things */
821 if (vType(avc) != VREG) return EISDIR;
823 if (auio->uio_resid == 0)
826 afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, (afs_int32)avc,
827 ICL_TYPE_LONG, (arw==UIO_WRITE? 1 : 0),
828 ICL_TYPE_LONG, auio->uio_offset,
829 ICL_TYPE_LONG, auio->uio_resid);
831 if ( AfsLargeFileUio(auio) ) /* file is larger than 2 GB */
835 if (!acred) osi_Panic("rdwr: !acred");
837 if (!acred) acred = u.u_cred;
839 if (code = afs_InitReq(&treq, acred)) return code;
841 /* It's not really possible to know if a write cause a growth in the
842 * cache size, we we wait for a cache drain for any write.
844 afs_MaybeWakeupTruncateDaemon();
845 while ((arw == UIO_WRITE) &&
846 (afs_blocksUsed > (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100)) {
847 if (afs_blocksUsed - afs_blocksDiscarded >
848 (CM_WAITFORDRAINPCT*afs_cacheBlocks)/100) {
849 afs_WaitForCacheDrain = 1;
850 afs_osi_Sleep(&afs_WaitForCacheDrain);
852 afs_MaybeFreeDiscardedDCache();
853 afs_MaybeWakeupTruncateDaemon();
855 code = afs_VerifyVCache(avc, &treq);
856 if (code) return afs_CheckCode(code, &treq, 45);
858 afs_BozonLock(&avc->pvnLock, avc);
859 osi_FlushPages(avc, acred); /* hold bozon lock, but not basic vnode lock */
861 ObtainWriteLock(&avc->lock,250);
863 /* adjust parameters when appending files */
864 if ((ioflag & IO_APPEND) && arw == UIO_WRITE)
866 #if defined(AFS_SUN56_ENV)
867 auio->uio_loffset = 0;
869 auio->uio_offset = avc->m.Length; /* write at EOF position */
871 if (auio->uio_offset < 0 || (auio->uio_offset + auio->uio_resid) < 0) {
872 ReleaseWriteLock(&avc->lock);
873 afs_BozonUnlock(&avc->pvnLock, avc);
877 /* file is larger than 2GB */
878 if ( AfsLargeFileSize(auio->uio_offset, auio->uio_resid) ) {
879 ReleaseWriteLock(&avc->lock);
880 afs_BozonUnlock(&avc->pvnLock, avc);
884 didFakeOpen=0; /* keep track of open so we can do close */
885 if (arw == UIO_WRITE) {
886 /* do ulimit processing; shrink resid or fail */
887 #if defined(AFS_SUN56_ENV)
888 if (auio->uio_loffset + auio->afsio_resid > auio->uio_llimit) {
889 if (auio->uio_llimit >= auio->uio_llimit) {
890 ReleaseWriteLock(&avc->lock);
891 afs_BozonUnlock(&avc->pvnLock, avc);
894 /* track # of bytes we should write, but won't because of
895 * ulimit; we must add this into the final resid value
896 * so caller knows we punted some data.
898 extraResid = auio->uio_resid;
899 auio->uio_resid = auio->uio_llimit - auio->uio_loffset;
900 extraResid -= auio->uio_resid;
905 if (auio->afsio_offset + auio->afsio_resid > auio->uio_limit) {
906 if (auio->afsio_offset >= auio->uio_limit) {
907 ReleaseWriteLock(&avc->lock);
908 afs_BozonUnlock(&avc->pvnLock, avc);
911 /* track # of bytes we should write, but won't because of
912 * ulimit; we must add this into the final resid value
913 * so caller knows we punted some data.
915 extraResid = auio->uio_resid;
916 auio->uio_resid = auio->uio_limit - auio->afsio_offset;
917 extraResid -= auio->uio_resid;
922 mode = S_WRITE; /* segment map-in mode */
923 afs_FakeOpen(avc); /* do this for writes, so data gets put back
924 when we want it to be put back */
925 didFakeOpen = 1; /* we'll be doing a fake open */
926 /* before starting any I/O, we must ensure that the file is big enough
927 to hold the results (since afs_putpage will be called to force the I/O */
928 size = auio->afsio_resid + auio->afsio_offset; /* new file size */
930 origLength = avc->m.Length;
931 if (size > avc->m.Length)
932 avc->m.Length = size; /* file grew */
933 avc->states |= CDirty; /* Set the dirty bit */
934 avc->m.Date = osi_Time(); /* Set file date (for ranlib) */
936 mode = S_READ; /* map-in read-only */
937 origLength = avc->m.Length;
940 if (acred && AFS_NFSXLATORREQ(acred)) {
941 if (arw == UIO_READ) {
942 if (!afs_AccessOK(avc, PRSFS_READ, &treq,
943 CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) {
944 ReleaseWriteLock(&avc->lock);
945 afs_BozonUnlock(&avc->pvnLock, avc);
957 counter = 0; /* don't call afs_DoPartialWrite first time through. */
959 /* compute the amount of data to move into this block,
960 based on auio->afsio_resid. Note that we copy data in units of
961 MAXBSIZE, not PAGESIZE. This is because segmap_getmap panics if you
962 call it with an offset based on blocks smaller than MAXBSIZE
963 (implying that it should be named BSIZE, since it is clearly both a
965 size = auio->afsio_resid; /* transfer size */
966 fileBase = auio->afsio_offset; /* start file position for xfr */
967 pageBase = fileBase & ~(MAXBSIZE-1); /* file position of the page */
968 pageOffset = fileBase & (MAXBSIZE-1); /* xfr start's offset within page */
969 tsize = MAXBSIZE-pageOffset; /* how much more fits in this page */
970 /* we'll read tsize bytes, but first must make sure tsize isn't too big */
971 if (tsize > size) tsize = size; /* don't read past end of request */
972 eof = 0; /* flag telling us if we hit the EOF on the read */
973 if (arw == UIO_READ) { /* we're doing a read operation */
974 /* don't read past EOF */
975 if (tsize + fileBase > origLength) {
976 tsize = origLength - fileBase;
977 eof = 1; /* we did hit the EOF */
978 if (tsize < 0) tsize = 0; /* better safe than sorry */
984 /* Purge dirty chunks of file if there are too many dirty
985 * chunks. Inside the write loop, we only do this at a chunk
986 * boundary. Clean up partial chunk if necessary at end of loop.
988 if (counter > 0 && code == 0 && AFS_CHUNKOFFSET(fileBase) == 0)
990 code = afs_DoPartialWrite(avc, &treq);
994 #endif /* AFS_SUN5_ENV */
995 /* write case, we ask segmap_release to call putpage. Really, we
996 don't have to do this on every page mapin, but for now we're
997 lazy, and don't modify the rest of AFS to scan for modified
998 pages on a close or other "synchronize with file server"
999 operation. This makes things a little cleaner, but probably
1000 hurts performance. */
1005 break; /* nothing to transfer, we're done */
1008 if (arw == UIO_WRITE)
1009 avc->states |= CDirty; /* may have been cleared by DoPartialWrite*/
1011 /* Before dropping lock, hold the chunk (create it if necessary). This
1012 * serves two purposes: (1) Ensure Cache Truncate Daemon doesn't try
1013 * to purge the chunk's pages while we have them locked. This would
1014 * cause deadlock because we might be waiting for the CTD to free up
1015 * a chunk. (2) If we're writing past the original EOF, and we're
1016 * at the base of the chunk, then make sure it exists online
1017 * before we do the uiomove, since the segmap_release will
1018 * write out to the chunk, causing it to get fetched if it hasn't
1019 * been created yet. The code that would otherwise notice that
1020 * we're fetching a chunk past EOF won't work, since we've
1021 * already adjusted the file size above.
1023 ObtainWriteLock(&avc->vlock, 551);
1024 while (avc->vstates & VPageCleaning) {
1025 ReleaseWriteLock(&avc->vlock);
1026 ReleaseWriteLock(&avc->lock);
1027 afs_osi_Sleep(&avc->vstates);
1028 ObtainWriteLock(&avc->lock, 334);
1029 ObtainWriteLock(&avc->vlock, 552);
1031 ReleaseWriteLock(&avc->vlock);
1034 dcp = afs_GetDCache(avc, fileBase, &treq, &toff, &tlen, 2);
1041 ReleaseWriteLock(&avc->lock); /* uiomove may page fault */
1043 #if defined(AFS_SUN56_ENV)
1044 data = segmap_getmap(segkmap,(struct vnode *)avc,(u_offset_t)pageBase);
1046 data = segmap_getmap(segkmap, (struct vnode *) avc, pageBase);
1048 #ifndef AFS_SUN5_ENV
1049 code = as_fault(&kas, data+pageOffset, tsize, F_SOFTLOCK, mode);
1051 AFS_UIOMOVE(data+pageOffset, tsize, arw, auio, code);
1052 as_fault(&kas, data+pageOffset, tsize, F_SOFTUNLOCK, mode);
1053 code2 = segmap_release(segkmap, data, sflags);
1058 (void) segmap_release(segkmap, data, 0);
1061 #if defined(AFS_SUN56_ENV)
1062 raddr = (caddr_t) (((uintptr_t)data +pageOffset) & PAGEMASK);
1064 raddr = (caddr_t) (((u_int)data +pageOffset) & PAGEMASK);
1066 rsize = (((u_int)data+pageOffset+tsize+PAGEOFFSET) & PAGEMASK)-(u_int)raddr;
1068 /* if we're doing a write, and we're starting at the rounded
1069 * down page base, and we're writing enough data to cover all
1070 * created pages, then we must be writing all of the pages
1071 * in this MAXBSIZE window that we're creating.
1074 if (arw == UIO_WRITE
1075 && ((long)raddr == (long)data+pageOffset)
1076 && tsize >= rsize) {
1077 /* probably the dcache backing this guy is around, but if
1078 * not, we can't do this optimization, since we're creating
1079 * writable pages, which must be backed by a chunk.
1082 dcp_newpage = afs_FindDCache(avc, pageBase);
1084 && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)) {
1085 ObtainWriteLock(&avc->lock,251);
1086 ObtainWriteLock(&avc->vlock,576);
1087 if ((avc->activeV == 0)
1088 && hsame(avc->m.DataVersion, dcp_newpage->f.versionNo)
1089 && !(dcp_newpage->flags & (DFFetching))) {
1091 segmap_pagecreate(segkmap, raddr, rsize, 1);
1093 ObtainWriteLock(&afs_xdcache,252);
1094 /* Mark the pages as created and dirty */
1095 afs_indexFlags[dcp_newpage->index]
1096 |= (IFAnyPages | IFDirtyPages);
1097 ReleaseWriteLock(&afs_xdcache);
1098 avc->states |= CHasPages;
1101 afs_PutDCache(dcp_newpage);
1102 ReleaseWriteLock(&avc->vlock);
1103 ReleaseWriteLock(&avc->lock);
1105 else if ( dcp_newpage )
1106 afs_PutDCache(dcp_newpage);
1110 code = segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTLOCK, mode);
1113 AFS_UIOMOVE(data+pageOffset, tsize, arw, auio, code);
1114 segmap_fault(kas.a_hat, segkmap, raddr, rsize, F_SOFTUNLOCK, mode);
1117 code = segmap_release(segkmap, data, sflags);
1119 (void) segmap_release(segkmap, data, 0);
1121 #endif /* AFS_SUN5_ENV */
1123 ObtainWriteLock(&avc->lock,253);
1126 * If at a chunk boundary, start prefetch of next chunk.
1128 if (counter == 0 || AFS_CHUNKOFFSET(fileBase) == 0) {
1129 if (!(dcp->flags & DFNextStarted))
1130 afs_PrefetchChunk(avc, dcp, acred, &treq);
1135 #endif /* AFS_SUN5_ENV */
1139 afs_FakeClose(avc, acred);
1143 if (arw == UIO_WRITE && (avc->states & CDirty)) {
1144 code2 = afs_DoPartialWrite(avc, &treq);
1148 #endif /* AFS_SUN5_ENV */
1150 if (!code && avc->vc_error) {
1151 code = avc->vc_error;
1153 ReleaseWriteLock(&avc->lock);
1154 afs_BozonUnlock(&avc->pvnLock, avc);
1156 #ifdef AFS_SUN53_ENV
1157 if ((ioflag & FSYNC) && (arw == UIO_WRITE) && !AFS_NFSXLATORREQ(acred))
1158 code = afs_fsync(avc, 0, acred);
1160 if ((ioflag & IO_SYNC) && (arw == UIO_WRITE)
1161 && !AFS_NFSXLATORREQ(acred))
1162 code = afs_fsync(avc, acred);
1165 #ifdef AFS_SUN52_ENV
1167 * If things worked, add in as remaining in request any bytes
1168 * we didn't write due to file size ulimit.
1170 if (code == 0 && extraResid > 0)
1171 auio->uio_resid += extraResid;
1173 return afs_CheckCode(code, &treq, 46);
1176 afs_map(vp, off, as, addr, len, prot, maxprot, flags, cred)
1188 u_char prot, maxprot;
1190 u_int prot, maxprot;
1193 struct AFS_UCRED *cred;
1195 struct segvn_crargs crargs;
1196 register afs_int32 code;
1197 struct vrequest treq;
1198 register struct vcache *avc = (struct vcache *) vp;
1200 AFS_STATCNT(afs_map);
1203 /* check for reasonableness on segment bounds; apparently len can be < 0 */
1204 if ((int)off < 0 || (int)(off + len) < 0) {
1207 if ( AfsLargeFileSize(off, len) ) /* file is larger than 2 GB */
1213 #if defined(AFS_SUN5_ENV)
1214 if (vp->v_flag & VNOMAP) /* File isn't allowed to be mapped */
1217 if (vp->v_filocks) /* if locked, disallow mapping */
1221 if (code = afs_InitReq(&treq, cred)) goto out;
1223 if (vp->v_type != VREG) {
1228 code = afs_VerifyVCache(avc, &treq);
1232 afs_BozonLock(&avc->pvnLock, avc);
1233 osi_FlushPages(avc, cred); /* ensure old pages are gone */
1234 avc->states |= CMAPPED; /* flag cleared at afs_inactive */
1235 afs_BozonUnlock(&avc->pvnLock, avc);
1241 if ((flags & MAP_FIXED) == 0) {
1242 #if defined(AFS_SUN57_ENV)
1243 map_addr(addr, len, off, 1, flags);
1244 #elif defined(AFS_SUN56_ENV)
1245 map_addr(addr, len, off, 1);
1247 map_addr(addr, len, (off_t)off, 1);
1249 if (*addr == NULL) {
1257 (void) as_unmap(as, *addr, len); /* unmap old address space use */
1258 /* setup the create parameter block for the call */
1259 crargs.vp = (struct vnode *) avc;
1260 crargs.offset = (u_int)off;
1262 crargs.type = flags&MAP_TYPE;
1264 crargs.maxprot = maxprot;
1265 crargs.amp = (struct anon_map *) 0;
1266 #if defined(AFS_SUN5_ENV)
1267 crargs.flags = flags & ~MAP_TYPE;
1270 code = as_map(as, *addr, len, segvn_create, (char *) &crargs);
1276 code = afs_CheckCode(code, &treq, 47);
1280 code = afs_CheckCode(code, &treq, 48);
1285 /* Sun 4.0.X-specific code. It computes the number of bytes that need
1286 to be zeroed at the end of a page by pvn_vptrunc, given that you're
1287 trying to get vptrunc to truncate a file to alen bytes. The result
1288 will be passed to pvn_vptrunc by the truncate code */
1289 #ifndef AFS_SUN5_ENV /* Not good for Solaris */
1291 register afs_int32 alen; {
1292 register afs_int32 nbytes;
1294 AFS_STATCNT(afs_PageLeft);
1295 nbytes = PAGESIZE - (alen & PAGEOFFSET); /* amount to zap in last page */
1296 /* now check if we'd zero the entire last page. Don't need to do this
1297 since pvn_vptrunc will handle this case properly (it will invalidate
1299 if (nbytes == PAGESIZE) nbytes = 0;
1300 if (nbytes < 0) nbytes = 0; /* just in case */
1307 * For Now We use standard local kernel params for AFS system values. Change this
1310 #if defined(AFS_SUN5_ENV)
1311 afs_pathconf(vp, cmd, outdatap, credp)
1312 register struct AFS_UCRED *credp;
1314 afs_cntl(vp, cmd, indatap, outdatap, inflag, outflag)
1315 int inflag, outflag;
1322 AFS_STATCNT(afs_cntl);
1325 *outdatap = MAXLINK;
1328 *outdatap = MAXNAMLEN;
1331 *outdatap = MAXPATHLEN;
1333 case _PC_CHOWN_RESTRICTED:
1339 #if !defined(AFS_SUN5_ENV)
1341 *outdatap = CANBSIZ;
1344 *outdatap = VDISABLE;
1356 #endif /* AFS_SUN_ENV */
1358 #if defined(AFS_SUN5_ENV)
1360 afs_ioctl(vnp, com, arg, flag, credp, rvalp)
1369 void afs_rwlock(vnp, wlock)
1373 rw_enter(&((struct vcache *)vnp)->rwlock, (wlock ? RW_WRITER : RW_READER));
1377 void afs_rwunlock(vnp, wlock)
1381 rw_exit(&((struct vcache *)vnp)->rwlock);
1386 afs_seek(vnp, ooff, noffp)
1391 register int code = 0;
1393 if ((*noffp < 0 || *noffp > MAXOFF_T))
1398 int afs_frlock(vnp, cmd, ap, flag, off, credp)
1401 #if defined(AFS_SUN56_ENV)
1408 struct AFS_UCRED *credp;
1410 register afs_int32 code = 0;
1412 * Implement based on afs_lockctl
1415 if ((cmd == F_GETLK) || (cmd == F_O_GETLK) || (cmd == F_SETLK) || (cmd == F_SETLKW)) {
1416 #ifdef AFS_SUN53_ENV
1417 ap->l_pid = ttoproc(curthread)->p_pid;
1420 ap->l_pid = ttoproc(curthread)->p_epid;
1421 ap->l_sysid = ttoproc(curthread)->p_sysid;
1425 #ifdef AFS_SUN56_ENV
1426 code = convoff(vnp, ap, 0, off);
1428 code = convoff(vnp, ap, 0, (off_t)off);
1430 if (code) return code;
1434 code = afs_lockctl((struct vcache *)vnp, ap, cmd, credp);
1440 int afs_space(vnp, cmd, ap, flag, off, credp)
1443 #if defined(AFS_SUN56_ENV)
1450 struct AFS_UCRED *credp;
1452 register afs_int32 code = EINVAL;
1455 if ((cmd == F_FREESP)
1456 #ifdef AFS_SUN56_ENV
1457 && ((code = convoff(vnp, ap, 0, off)) == 0)) {
1459 && ((code = convoff(vnp, ap, 0, (off_t)off)) == 0)) {
1463 vattr.va_mask = AT_SIZE;
1464 vattr.va_size = ap->l_start;
1465 code = afs_setattr((struct vcache *)vnp, &vattr, 0, credp);
1475 int afs_dump(vp, addr, i1, i2)
1480 AFS_STATCNT(afs_dump);
1481 afs_warn("AFS_DUMP. MUST IMPLEMENT THIS!!!\n");
1486 /* Nothing fancy here; just compare if vnodes are identical ones */
1488 struct vnode *vp1, *vp2;
1490 AFS_STATCNT(afs_cmp);
1495 int afs_realvp(struct vnode *vp, struct vnode **vpp) {
1496 AFS_STATCNT(afs_realvp);
1501 int afs_pageio(vp, pp, ui1, ui2, i1, credp)
1508 afs_warn("afs_pageio: Not implemented\n");
1512 int afs_dumpctl(vp, i)
1516 afs_warn("afs_dumpctl: Not implemented\n");
1520 #ifdef AFS_SUN54_ENV
1521 extern void afs_dispose(vp, p, fl, dn, cr)
1527 fs_dispose(vp, p, fl, dn, cr);
1530 int afs_setsecattr(vp, vsecattr, flag, creds)
1532 vsecattr_t *vsecattr;
1539 int afs_getsecattr(vp, vsecattr, flag, creds)
1541 vsecattr_t *vsecattr;
1545 return fs_fab_acl(vp, vsecattr, flag, creds);
1549 #ifdef AFS_GLOBAL_SUNLOCK
1550 extern int gafs_open(), gafs_close(), afs_ioctl(), gafs_access();
1551 extern int gafs_getattr(), gafs_setattr(), gafs_lookup(), gafs_create();
1552 extern int gafs_remove(), gafs_link(), gafs_rename(), gafs_mkdir();
1553 extern int gafs_rmdir(), gafs_readdir(), gafs_fsync(), gafs_symlink();
1554 extern int gafs_fid(), gafs_readlink(), fs_setfl(), afs_pathconf();
1555 extern int afs_lockctl();
1556 extern void gafs_inactive();
1558 struct vnodeops Afs_vnodeops = {
1598 #ifdef AFS_SUN54_ENV
1603 #if defined(AFS_SUN56_ENV)
1607 struct vnodeops *afs_ops = &Afs_vnodeops;
1611 gafs_open(avcp, aflags, acred)
1612 register struct vcache **avcp;
1614 struct AFS_UCRED *acred;
1619 code = afs_open(avcp, aflags, acred);
1625 gafs_close(avc, aflags, count, offset, acred)
1628 register struct vcache *avc;
1630 struct AFS_UCRED *acred;
1635 code = afs_close(avc, aflags, count, offset, acred);
1641 gafs_getattr(avc, attrs, flags, acred)
1643 register struct vcache *avc;
1644 register struct vattr *attrs;
1645 struct AFS_UCRED *acred;
1650 code = afs_getattr(avc, attrs, flags, acred);
1656 gafs_setattr(avc, attrs, flags, acred)
1658 register struct vcache *avc;
1659 register struct vattr *attrs;
1660 struct AFS_UCRED *acred;
1665 code = afs_setattr(avc, attrs, flags, acred);
1671 gafs_access(avc, amode, flags, acred)
1673 register struct vcache *avc;
1674 register afs_int32 amode;
1675 struct AFS_UCRED *acred;
1680 code = afs_access(avc, amode, flags, acred);
1686 gafs_lookup(adp, aname, avcp, pnp, flags, rdir, acred)
1687 struct pathname *pnp;
1690 register struct vcache *adp, **avcp;
1692 struct AFS_UCRED *acred;
1697 code = afs_lookup(adp, aname, avcp, pnp, flags, rdir, acred);
1703 gafs_create(adp, aname, attrs, aexcl, amode, avcp, acred)
1704 register struct vcache *adp;
1706 struct vattr *attrs;
1709 struct vcache **avcp;
1710 struct AFS_UCRED *acred;
1715 code = afs_create(adp, aname, attrs, aexcl, amode, avcp, acred);
1720 gafs_remove(adp, aname, acred)
1721 register struct vcache *adp;
1723 struct AFS_UCRED *acred;
1728 code = afs_remove(adp, aname, acred);
1733 gafs_link(adp, avc, aname, acred)
1734 register struct vcache *avc;
1735 register struct vcache *adp;
1737 struct AFS_UCRED *acred;
1742 code = afs_link(adp, avc, aname, acred);
1747 gafs_rename(aodp, aname1, andp, aname2, acred)
1748 register struct vcache *aodp, *andp;
1749 char *aname1, *aname2;
1750 struct AFS_UCRED *acred;
1755 code = afs_rename(aodp, aname1, andp, aname2, acred);
1760 gafs_mkdir(adp, aname, attrs, avcp, acred)
1761 register struct vcache *adp;
1762 register struct vcache **avcp;
1764 struct vattr *attrs;
1765 struct AFS_UCRED *acred;
1770 code = afs_mkdir(adp, aname, attrs, avcp, acred);
1776 gafs_rmdir(adp, aname, cdirp, acred)
1777 struct vnode *cdirp;
1778 register struct vcache *adp;
1780 struct AFS_UCRED *acred;
1785 code = afs_rmdir(adp, aname, cdirp, acred);
1791 gafs_readdir(avc, auio, acred, eofp)
1793 register struct vcache *avc;
1795 struct AFS_UCRED *acred;
1800 code = afs_readdir(avc, auio, acred, eofp);
1805 gafs_symlink(adp, aname, attrs, atargetName, acred)
1806 register struct vcache *adp;
1807 register char *atargetName;
1809 struct vattr *attrs;
1810 struct AFS_UCRED *acred;
1815 code = afs_symlink(adp, aname, attrs, atargetName, acred);
1821 gafs_readlink(avc, auio, acred)
1822 register struct vcache *avc;
1824 struct AFS_UCRED *acred;
1829 code = afs_readlink(avc, auio, acred);
1834 #ifdef AFS_SUN53_ENV
1835 gafs_fsync(avc, flag, acred)
1838 gafs_fsync(avc, acred)
1840 register struct vcache *avc;
1841 struct AFS_UCRED *acred;
1846 #ifdef AFS_SUN53_ENV
1847 code = afs_fsync(avc, flag, acred);
1849 code = afs_fsync(avc, acred);
1855 void afs_inactive(struct vcache *avc, struct AFS_UCRED *acred)
1857 struct vnode *vp = (struct vnode *)avc;
1858 if (afs_shuttingdown) return ;
1861 * In Solaris and HPUX s800 and HP-UX10.0 they actually call us with
1862 * v_count 1 on last reference!
1864 mutex_enter(&vp->v_lock);
1865 if (avc->vrefCount <= 0) osi_Panic("afs_inactive : v_count <=0\n");
1868 * If more than 1 don't unmap the vnode but do decrement the ref count
1871 if (vp->v_count > 0) {
1872 mutex_exit(&vp->v_lock);
1875 mutex_exit(&vp->v_lock);
1877 * Solaris calls VOP_OPEN on exec, but isn't very diligent about calling
1878 * VOP_CLOSE when executable exits.
1880 if (avc->opens > 0 && !(avc->states & CCore))
1881 avc->opens = avc->execsOrWriters = 0;
1883 afs_InactiveVCache(avc, acred);
1886 void gafs_inactive(avc, acred)
1887 register struct vcache *avc;
1888 struct AFS_UCRED *acred;
1891 afs_inactive(avc, acred);
1896 gafs_fid(avc, fidpp)
1903 code = afs_fid(avc, fidpp);
1908 #endif /* AFS_GLOBAL_SUNLOCK */