/* Copyright (C) 1998 Transarc Corporation - All rights reserved. */ /* * vnodeops structure and Digital Unix specific ops and support routines. */ #include "../afs/param.h" /* Should be always first */ #include "../afs/sysincludes.h" /* Standard vendor system headers */ #include "../afs/afsincludes.h" /* Afs-based standard headers */ #include "../afs/afs_stats.h" /* statistics */ #include #include #include "../afs/afs_cbqueue.h" #include "../afs/nfsclient.h" #include "../afs/afs_osidnlc.h" extern int afs_lookup(), afs_create(), afs_noop(), afs_open(), afs_close(); extern int afs_access(), afs_getattr(), afs_setattr(), afs_badop(); extern int afs_fsync(), afs_seek(), afs_remove(), afs_link(), afs_rename(); extern int afs_mkdir(), afs_rmdir(), afs_symlink(), afs_readdir(); extern int afs_readlink(), afs_lockctl(); extern int vn_pathconf_default(), seltrue(); int mp_afs_lookup(), mp_afs_create(), mp_afs_open(); int mp_afs_access(), mp_afs_getattr(), mp_afs_setattr(), mp_afs_ubcrdwr(); int mp_afs_ubcrdwr(), mp_afs_mmap(); int mp_afs_fsync(), mp_afs_seek(), mp_afs_remove(), mp_afs_link(); int mp_afs_rename(), mp_afs_mkdir(), mp_afs_rmdir(), mp_afs_symlink(); int mp_afs_readdir(), mp_afs_readlink(), mp_afs_abortop(), mp_afs_inactive(); int mp_afs_reclaim(), mp_afs_bmap(), mp_afs_strategy(), mp_afs_print(); int mp_afs_page_read(), mp_afs_page_write(), mp_afs_swap(), mp_afs_bread(); int mp_afs_brelse(), mp_afs_lockctl(), mp_afs_syncdata(), mp_afs_close(); int mp_afs_closex(); /* AFS vnodeops */ struct vnodeops Afs_vnodeops = { mp_afs_lookup, mp_afs_create, afs_noop, /* vn_mknod */ mp_afs_open, mp_afs_close, mp_afs_access, mp_afs_getattr, mp_afs_setattr, mp_afs_ubcrdwr, mp_afs_ubcrdwr, afs_badop, /* vn_ioctl */ seltrue, /* vn_select */ mp_afs_mmap, mp_afs_fsync, mp_afs_seek, mp_afs_remove, mp_afs_link, mp_afs_rename, mp_afs_mkdir, mp_afs_rmdir, mp_afs_symlink, mp_afs_readdir, mp_afs_readlink, mp_afs_abortop, mp_afs_inactive, mp_afs_reclaim, mp_afs_bmap, mp_afs_strategy, mp_afs_print, mp_afs_page_read, mp_afs_page_write, mp_afs_swap, mp_afs_bread, mp_afs_brelse, mp_afs_lockctl, mp_afs_syncdata, afs_noop, /* Lock */ afs_noop, /* unLock */ afs_noop, /* get ext attrs */ afs_noop, /* set ext attrs */ afs_noop, /* del ext attrs */ vn_pathconf_default, }; struct vnodeops *afs_ops = &Afs_vnodeops; /* vnode file operations, and our own */ extern int vn_read(); extern int vn_write(); extern int vn_ioctl(); extern int vn_select(); extern int afs_closex(); struct fileops afs_fileops = { vn_read, vn_write, vn_ioctl, vn_select, mp_afs_closex, }; mp_afs_lookup(adp, ndp) struct vcache *adp; struct nameidata *ndp; { int code; AFS_GLOCK(); code = afs_lookup(adp, ndp); AFS_GUNLOCK(); return code; } mp_afs_create(ndp, attrs) struct nameidata *ndp; struct vattr *attrs; { int code; AFS_GLOCK(); code = afs_create(ndp, attrs); AFS_GUNLOCK(); return code; } mp_afs_open(avcp, aflags, acred) struct vcache **avcp; afs_int32 aflags; struct AFS_UCRED *acred; { int code; AFS_GLOCK(); code = afs_open(avcp, aflags, acred); AFS_GUNLOCK(); return code; } mp_afs_access(avc, amode, acred) struct vcache *avc; afs_int32 amode; struct AFS_UCRED *acred; { int code; AFS_GLOCK(); code = afs_access(avc, amode, acred); AFS_GUNLOCK(); return code; } mp_afs_close(avc, flags, cred) struct vnode *avc; int flags; struct ucred *cred; { int code; AFS_GLOCK(); code = afs_close(avc, flags, cred); AFS_GUNLOCK(); return code; } mp_afs_getattr(avc, attrs, acred) struct vcache *avc; struct vattr *attrs; struct AFS_UCRED *acred; { int code; AFS_GLOCK(); code = afs_getattr(avc, attrs, acred); AFS_GUNLOCK(); return code; } mp_afs_setattr(avc, attrs, acred) struct vcache *avc; struct vattr *attrs; struct AFS_UCRED *acred; { int code; AFS_GLOCK(); code = afs_setattr(avc, attrs, acred); AFS_GUNLOCK(); return code; } mp_afs_fsync(avc, fflags, acred, waitfor) struct vcache *avc; int fflags; struct AFS_UCRED *acred; int waitfor; { int code; AFS_GLOCK(); code = afs_fsync(avc, fflags, acred, waitfor); AFS_GUNLOCK(); return code; } mp_afs_remove(ndp) struct nameidata *ndp; { int code; AFS_GLOCK(); code = afs_remove(ndp); AFS_GUNLOCK(); return code; } mp_afs_link(avc, ndp) struct vcache *avc; struct nameidata *ndp; { int code; AFS_GLOCK(); code = afs_link(avc, ndp); AFS_GUNLOCK(); return code; } mp_afs_rename(fndp, tndp) struct nameidata *fndp, *tndp; { int code; AFS_GLOCK(); code = afs_rename(fndp, tndp); AFS_GUNLOCK(); return code; } mp_afs_mkdir(ndp, attrs) struct nameidata *ndp; struct vattr *attrs; { int code; AFS_GLOCK(); code = afs_mkdir(ndp, attrs); AFS_GUNLOCK(); return code; } mp_afs_rmdir(ndp) struct nameidata *ndp; { int code; AFS_GLOCK(); code = afs_rmdir(ndp); AFS_GUNLOCK(); return code; } mp_afs_symlink(ndp, attrs, atargetName) struct nameidata *ndp; struct vattr *attrs; register char *atargetName; { int code; AFS_GLOCK(); code = afs_symlink(ndp, attrs, atargetName); AFS_GUNLOCK(); return code; } mp_afs_readdir(avc, auio, acred, eofp) struct vcache *avc; struct uio *auio; struct AFS_UCRED *acred; int *eofp; { int code; AFS_GLOCK(); code = afs_readdir(avc, auio, acred, eofp); AFS_GUNLOCK(); return code; } mp_afs_readlink(avc, auio, acred) struct vcache *avc; struct uio *auio; struct AFS_UCRED *acred; { int code; AFS_GLOCK(); code = afs_readlink(avc, auio, acred); AFS_GUNLOCK(); return code; } mp_afs_lockctl(avc, af, flag, acred, clid, offset) struct vcache *avc; struct eflock *af; struct AFS_UCRED *acred; int flag; pid_t clid; off_t offset; { int code; AFS_GLOCK(); code = afs_lockctl(avc, af, flag, acred, clid, offset); AFS_GUNLOCK(); return code; } mp_afs_closex(afd) struct file *afd; { int code; AFS_GLOCK(); code = afs_closex(afd); AFS_GUNLOCK(); return code; } mp_afs_seek(avc, oldoff, newoff, cred) struct vcache *avc; off_t oldoff, newoff; struct ucred *cred; { if ((int) newoff < 0) return(EINVAL); else return(0); } mp_afs_abortop(ndp) struct nameidata *ndp; { return(0); } mp_afs_inactive(avc, acred) register struct vcache *avc; struct AFS_UCRED *acred; { AFS_GLOCK(); afs_InactiveVCache(avc, acred); AFS_GUNLOCK(); } mp_afs_reclaim(avc) struct vcache *avc; { return(0); } mp_afs_print(avc) struct vcache *avc; { return(0); } mp_afs_page_read(avc, uio, acred) struct vcache *avc; struct uio *uio; struct ucred *acred; { int error; struct vrequest treq; AFS_GLOCK(); error = afs_rdwr(avc, uio, UIO_READ, 0, acred); afs_Trace3(afs_iclSetp, CM_TRACE_PAGE_READ, ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, error, ICL_TYPE_INT32, avc->states); if (error) { error = EIO; } else if ((avc->states & CWired) == 0) { afs_InitReq(&treq, acred); ObtainWriteLock(&avc->lock,161); afs_Wire(avc, &treq); ReleaseWriteLock(&avc->lock); } AFS_GUNLOCK(); return(error); } mp_afs_page_write(avc, uio, acred, pager, offset) struct vcache *avc; struct uio *uio; struct ucred *acred; memory_object_t pager; vm_offset_t offset; { int error; AFS_GLOCK(); error = afs_rdwr(avc, uio, UIO_WRITE, 0, acred); afs_Trace3(afs_iclSetp, CM_TRACE_PAGE_WRITE, ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, error, ICL_TYPE_INT32, avc->states); if (error) { error = EIO; } AFS_GUNLOCK(); return(error); } int DO_FLUSH=1; mp_afs_ubcrdwr(avc, uio, ioflag, cred) struct vcache *avc; struct uio *uio; int ioflag; struct ucred *cred; { register afs_int32 code; register char *data; afs_int32 fileBase, size, cnt=0; afs_int32 pageBase; register afs_int32 tsize; register afs_int32 pageOffset; int eof; struct vrequest treq; int rw = uio->uio_rw; int rv, flags; int newpage=0; vm_page_t page; afs_int32 save_resid; struct dcache *tdc; int didFakeOpen=0; int counter=0; AFS_GLOCK(); afs_InitReq(&treq, cred); if (AFS_NFSXLATORREQ(cred) && rw == UIO_READ) { if (!afs_AccessOK(avc, PRSFS_READ, &treq, CHECK_MODE_BITS|CMB_ALLOW_EXEC_AS_READ)) { AFS_GUNLOCK(); return EACCES; } } afs_Trace4(afs_iclSetp, CM_TRACE_VMRW, ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, (rw==UIO_WRITE? 1 : 0), ICL_TYPE_LONG, uio->uio_offset, ICL_TYPE_LONG, uio->uio_resid); code = afs_VerifyVCache(avc, &treq); if (code) { code = afs_CheckCode(code, &treq, 35); AFS_GUNLOCK(); return code; } if (vType(avc) != VREG) { AFS_GUNLOCK(); return EISDIR; /* can't read or write other things */ } afs_BozonLock(&avc->pvnLock, avc); osi_FlushPages(avc); /* hold bozon lock, but not basic vnode lock */ ObtainWriteLock(&avc->lock,162); /* adjust parameters when appending files */ if ((ioflag & IO_APPEND) && uio->uio_rw == UIO_WRITE) uio->uio_offset = avc->m.Length; /* write at EOF position */ if (uio->uio_rw == UIO_WRITE) { avc->states |= CDirty; afs_FakeOpen(avc); didFakeOpen=1; /* * before starting any I/O, we must ensure that the file is big enough * to hold the results (since afs_putpage will be called to force * the I/O. */ size = uio->afsio_resid + uio->afsio_offset; /* new file size */ if (size > avc->m.Length) avc->m.Length = size; /* file grew */ avc->m.Date = osi_Time(); /* Set file date (for ranlib) */ if (uio->afsio_resid > PAGE_SIZE) cnt = uio->afsio_resid / PAGE_SIZE; save_resid = uio->afsio_resid; } while (1) { /* * compute the amount of data to move into this block, * based on uio->afsio_resid. */ size = uio->afsio_resid; /* transfer size */ fileBase = uio->afsio_offset; /* start file position */ pageBase = fileBase & ~(PAGE_SIZE-1); /* file position of the page */ pageOffset = fileBase & (PAGE_SIZE-1); /* start offset within page */ tsize = PAGE_SIZE-pageOffset; /* amount left in this page */ /* * we'll read tsize bytes, * but first must make sure tsize isn't too big */ if (tsize > size) tsize = size; /* don't read past end of request */ eof = 0; /* flag telling us if we hit the EOF on the read */ if (uio->uio_rw == UIO_READ) { /* we're doing a read operation */ /* don't read past EOF */ if (tsize + fileBase > avc->m.Length) { tsize = avc->m.Length - fileBase; eof = 1; /* we did hit the EOF */ if (tsize < 0) tsize = 0; /* better safe than sorry */ } } if (tsize <= 0) break; /* nothing to transfer, we're done */ /* Purge dirty chunks of file if there are too many dirty chunks. * Inside the write loop, we only do this at a chunk boundary. * Clean up partial chunk if necessary at end of loop. */ if (uio->uio_rw == UIO_WRITE && counter > 0 && AFS_CHUNKOFFSET(fileBase) == 0) { code = afs_DoPartialWrite(avc, &treq); avc->states |= CDirty; } if (code) { break; } flags = 0; ReleaseWriteLock(&avc->lock); AFS_GUNLOCK(); code = ubc_lookup(((struct vnode *)avc)->v_object, pageBase, PAGE_SIZE, PAGE_SIZE, &page, &flags); AFS_GLOCK(); ObtainWriteLock(&avc->lock,163); if (code) { break; } if (flags & B_NOCACHE) { /* No page found. We should not read the page in if 1. the write starts on a page edge (ie, pageoffset == 0) and either 1. we will fill the page (ie, size == PAGESIZE), or 2. we are writing past eof */ if ((uio->uio_rw == UIO_WRITE) && ((pageOffset == 0 && (size == PAGE_SIZE || fileBase >= avc->m.Length)))) { struct vnode *vp = (struct vnode *)avc; /* we're doing a write operation past eof; no need to read it */ newpage = 1; AFS_GUNLOCK(); ubc_page_zero(page, 0, PAGE_SIZE); ubc_page_release(page, B_DONE); AFS_GLOCK(); } else { /* page wasn't cached, read it in. */ struct buf *bp; AFS_GUNLOCK(); bp = ubc_bufalloc(page, 1, PAGE_SIZE, 1, B_READ); AFS_GLOCK(); bp->b_dev = 0; bp->b_vp = (struct vnode *)avc; bp->b_blkno = btodb(pageBase); ReleaseWriteLock(&avc->lock); code = afs_ustrategy(bp, cred); /* do the I/O */ ObtainWriteLock(&avc->lock,164); AFS_GUNLOCK(); ubc_sync_iodone(bp); AFS_GLOCK(); if (code) { AFS_GUNLOCK(); ubc_page_release(page, 0); AFS_GLOCK(); break; } } } AFS_GUNLOCK(); ubc_page_wait(page); data = (char *)page->pg_addr; /* DUX 4.0D */ if (data == 0) data = (char *)PHYS_TO_KSEG(page->pg_phys_addr); /* DUX 4.0E */ AFS_GLOCK(); ReleaseWriteLock(&avc->lock); /* uiomove may page fault */ AFS_GUNLOCK(); code = uiomove(data+pageOffset, tsize, uio); ubc_unload(page, pageOffset, page_size); if (uio->uio_rw == UIO_WRITE) { vm_offset_t toffset; /* Mark the page dirty and release it to avoid a deadlock * in ubc_dirty_kluster when more than one process writes * this page at the same time. */ toffset = page->pg_offset; flags |= B_DIRTY; ubc_page_release(page, flags); if (cnt > 10) { vm_page_t pl; int kpcnt; struct buf *bp; /* We released the page, so we can get a null page * list if another thread calls the strategy routine. */ pl = ubc_dirty_kluster(((struct vnode *)avc)->v_object, NULL, toffset, 0, B_WANTED, FALSE, &kpcnt); if (pl) { bp = ubc_bufalloc(pl, 1, PAGE_SIZE, 1, B_WRITE); bp->b_dev = 0; bp->b_vp = (struct vnode *)avc; bp->b_blkno = btodb(pageBase); AFS_GLOCK(); code = afs_ustrategy(bp, cred); /* do the I/O */ AFS_GUNLOCK(); ubc_sync_iodone(bp); if (code) { AFS_GLOCK(); ObtainWriteLock(&avc->lock,415); break; } } } } else { ubc_page_release(page, flags); } AFS_GLOCK(); ObtainWriteLock(&avc->lock,165); /* * If reading at a chunk boundary, start prefetch of next chunk. */ if (uio->uio_rw == UIO_READ && (counter == 0 || AFS_CHUNKOFFSET(fileBase) == 0)) { tdc = afs_FindDCache(avc, fileBase); if (tdc) { if (!(tdc->flags & DFNextStarted)) afs_PrefetchChunk(avc, tdc, cred, &treq); afs_PutDCache(tdc); } } counter++; if (code) break; } if (didFakeOpen) afs_FakeClose(avc, cred); if (uio->uio_rw == UIO_WRITE && code == 0 && (avc->states & CDirty)) { code = afs_DoPartialWrite(avc, &treq); } ReleaseWriteLock(&avc->lock); afs_BozonUnlock(&avc->pvnLock, avc); if (DO_FLUSH || (!newpage && (cnt < 10))) { AFS_GUNLOCK(); ubc_flush_dirty(((struct vnode *)avc)->v_object, flags); AFS_GLOCK(); } ObtainSharedLock(&avc->lock, 409); if (!code) { if (avc->vc_error) { code = avc->vc_error; } } /* This is required since we may still have dirty pages after the write. * I could just let close do the right thing, but stat's before the close * return the wrong length. */ if (code == EDQUOT || code == ENOSPC) { uio->uio_resid = save_resid; UpgradeSToWLock(&avc->lock, 410); osi_ReleaseVM(avc, cred); ConvertWToSLock(&avc->lock); } ReleaseSharedLock(&avc->lock); if (!code && (ioflag & IO_SYNC) && (uio->uio_rw == UIO_WRITE) && !AFS_NFSXLATORREQ(cred)) { code = afs_fsync(avc, 0, cred, 0); } out: code = afs_CheckCode(code, &treq, 36); AFS_GUNLOCK(); return code; } /* * Now for some bad news. Since we artificially hold on to vnodes by doing * and extra VNHOLD in afs_NewVCache(), there is no way for us to know * when we need to flush the pages when a program exits. Particularly * if it closes the file after mapping it R/W. * */ mp_afs_mmap(avc, offset, map, addrp, len, prot, maxprot, flags, cred) register struct vcache *avc; vm_offset_t offset; vm_map_t map; vm_offset_t *addrp; vm_size_t len; vm_prot_t prot; vm_prot_t maxprot; int flags; struct ucred *cred; { struct vp_mmap_args args; register struct vp_mmap_args *ap = &args; struct vnode *vp = (struct vnode *)avc; int code; struct vrequest treq; #if !defined(DYNEL) extern kern_return_t u_vp_create(); #endif AFS_GLOCK(); afs_InitReq(&treq, cred); code = afs_VerifyVCache(avc, &treq); if (code) { code = afs_CheckCode(code, &treq, 37); AFS_GUNLOCK(); return code; } afs_BozonLock(&avc->pvnLock, avc); osi_FlushPages(avc); /* ensure old pages are gone */ afs_BozonUnlock(&avc->pvnLock, avc); ObtainWriteLock(&avc->lock,166); avc->states |= CMAPPED; ReleaseWriteLock(&avc->lock); ap->a_offset = offset; ap->a_vaddr = addrp; ap->a_size = len; ap->a_prot = prot, ap->a_maxprot = maxprot; ap->a_flags = flags; AFS_GUNLOCK(); code = u_vp_create(map, vp->v_object, (vm_offset_t) ap); AFS_GLOCK(); code = afs_CheckCode(code, &treq, 38); AFS_GUNLOCK(); return code; } int mp_afs_getpage(vop, offset, len, protp, pl, plsz, mape, addr, rw, cred) vm_ubc_object_t vop; vm_offset_t offset; vm_size_t len; vm_prot_t *protp; vm_page_t *pl; int plsz; vm_map_entry_t mape; vm_offset_t addr; int rw; struct ucred *cred; { register afs_int32 code; struct vrequest treq; int flags = 0; int i, pages = (len + PAGE_SIZE - 1) >> page_shift; vm_page_t *pagep; vm_offset_t off; struct vcache *avc = (struct vcache *)vop->vu_vp; /* first, obtain the proper lock for the VM system */ AFS_GLOCK(); afs_InitReq(&treq, cred); code = afs_VerifyVCache(avc, &treq); if (code) { *pl = VM_PAGE_NULL; code = afs_CheckCode(code, &treq, 39); /* failed to get it */ AFS_GUNLOCK(); return code; } /* clean all dirty pages for this vnode */ AFS_GUNLOCK(); ubc_flush_dirty(vop,0); AFS_GLOCK(); afs_BozonLock(&avc->pvnLock, avc); ObtainWriteLock(&avc->lock,167); afs_Trace4(afs_iclSetp, CM_TRACE_PAGEIN, ICL_TYPE_POINTER, avc, ICL_TYPE_LONG, offset, ICL_TYPE_LONG, len, ICL_TYPE_INT32, (int) rw); for (i = 0; i < pages; i++) { pagep = &pl[i]; off = offset + PAGE_SIZE * i; if (protp) protp[i] = 0; flags = 0; ReleaseWriteLock(&avc->lock); AFS_GUNLOCK(); code = ubc_lookup(((struct vnode *)avc)->v_object, off, PAGE_SIZE, PAGE_SIZE, pagep, &flags); AFS_GLOCK(); ObtainWriteLock(&avc->lock,168); if (code) { goto out; } if(flags & B_NOCACHE) { /* if (page) */ if ((rw & B_WRITE) && (offset+len >= avc->m.Length)) { struct vnode *vp = (struct vnode *)avc; /* we're doing a write operation past eof; no need to read it */ AFS_GUNLOCK(); ubc_page_zero(*pagep, 0, PAGE_SIZE); ubc_page_release(*pagep, B_DONE); AFS_GLOCK(); } else { /* page wasn't cached, read it in. */ struct buf *bp; AFS_GUNLOCK(); bp = ubc_bufalloc(*pagep, 1, PAGE_SIZE, 1, B_READ); AFS_GLOCK(); bp->b_dev = 0; bp->b_vp = (struct vnode *)avc; bp->b_blkno = btodb(off); ReleaseWriteLock(&avc->lock); code = afs_ustrategy(bp, cred); /* do the I/O */ ObtainWriteLock(&avc->lock,169); AFS_GUNLOCK(); ubc_sync_iodone(bp); AFS_GLOCK(); if (code) { AFS_GUNLOCK(); ubc_page_release(pl[i], 0); AFS_GLOCK(); goto out; } } } if ((rw & B_READ) == 0) { AFS_GUNLOCK(); ubc_page_dirty(pl[i]); AFS_GLOCK(); } else { if (protp && (flags & B_DIRTY) == 0) { protp[i] = VM_PROT_WRITE; } } } out: pl[i] = VM_PAGE_NULL; ReleaseWriteLock(&avc->lock); afs_BozonUnlock(&avc->pvnLock, avc); afs_Trace3(afs_iclSetp, CM_TRACE_PAGEINDONE, ICL_TYPE_INT32, code, ICL_TYPE_POINTER, *pagep, ICL_TYPE_INT32, flags); code = afs_CheckCode(code, &treq, 40); AFS_GUNLOCK(); return code; } int mp_afs_putpage(vop, pl, pcnt, flags, cred) vm_ubc_object_t vop; vm_page_t *pl; int pcnt; int flags; struct ucred *cred; { register afs_int32 code=0; struct vcache *avc = (struct vcache *)vop->vu_vp; struct vnode *vp = (struct vnode *)avc; int i; AFS_GLOCK(); afs_Trace4(afs_iclSetp, CM_TRACE_PAGEOUT, ICL_TYPE_POINTER, avc, ICL_TYPE_INT32, pcnt, ICL_TYPE_INT32, vp->v_flag, ICL_TYPE_INT32, flags); if (flags & B_UBC) { AFS_GUNLOCK(); VN_LOCK(vp); if (vp->v_flag & VXLOCK) { VN_UNLOCK(vp); for (i = 0; i < pcnt; i++) { ubc_page_release(pl[i], B_DONE|B_DIRTY); pl[i] = VM_PAGE_NULL; } return(0); } else { VN_UNLOCK(vp); } AFS_GLOCK(); } /* first, obtain the proper lock for the VM system */ afs_BozonLock(&avc->pvnLock, avc); ObtainWriteLock(&avc->lock,170); for (i = 0; i < pcnt; i++) { vm_page_t page = pl[i]; struct buf *bp; /* write it out */ AFS_GUNLOCK(); bp = ubc_bufalloc(page, 1, PAGE_SIZE, 1, B_WRITE); AFS_GLOCK(); bp->b_dev = 0; bp->b_vp = (struct vnode *)avc; bp->b_blkno = btodb(page->pg_offset); ReleaseWriteLock(&avc->lock); code = afs_ustrategy(bp, cred); /* do the I/O */ ObtainWriteLock(&avc->lock,171); AFS_GUNLOCK(); ubc_sync_iodone(bp); AFS_GLOCK(); if (code) { goto done; } else { pl[i] = VM_PAGE_NULL; } } done: ReleaseWriteLock(&avc->lock); afs_BozonUnlock(&avc->pvnLock, avc); afs_Trace2(afs_iclSetp, CM_TRACE_PAGEOUTDONE, ICL_TYPE_INT32, code, ICL_TYPE_INT32, avc->m.Length); AFS_GUNLOCK(); return code; } int mp_afs_swap(avc, swapop, argp) struct vcache *avc; vp_swap_op_t swapop; vm_offset_t argp; { return EIO; } int mp_afs_syncdata(avc, flag, offset, length, cred) struct vcache *avc; int flag; vm_offset_t offset; vm_size_t length; struct ucred *cred; { /* NFS V3 makes this call, ignore it. We'll sync the data in afs_fsync. */ if (AFS_NFSXLATORREQ(cred)) return 0; else return EINVAL; } /* a freelist of one */ struct buf *afs_bread_freebp = 0; /* * Only rfs_read calls this, and it only looks at bp->b_un.b_addr. * Thus we can use fake bufs (ie not from the real buffer pool). */ mp_afs_bread(vp, lbn, bpp, cred) struct ucred *cred; struct vnode *vp; daddr_t lbn; struct buf **bpp; { int offset, fsbsize, error; struct buf *bp; struct iovec iov; struct uio uio; AFS_GLOCK(); AFS_STATCNT(afs_bread); fsbsize = vp->v_vfsp->vfs_bsize; offset = lbn * fsbsize; if (afs_bread_freebp) { bp = afs_bread_freebp; afs_bread_freebp = 0; } else { bp = (struct buf *) AFS_KALLOC(sizeof(*bp)); bp->b_un.b_addr = (caddr_t) AFS_KALLOC(fsbsize); } iov.iov_base = bp->b_un.b_addr; iov.iov_len = fsbsize; uio.afsio_iov = &iov; uio.afsio_iovcnt = 1; uio.afsio_seg = AFS_UIOSYS; uio.afsio_offset = offset; uio.afsio_resid = fsbsize; *bpp = 0; error = afs_read((struct vcache *)vp, &uio, cred, lbn, bpp, 0); if (error) { afs_bread_freebp = bp; AFS_GUNLOCK(); return error; } if (*bpp) { afs_bread_freebp = bp; } else { *(struct buf **)&bp->b_vp = bp; /* mark as fake */ *bpp = bp; } AFS_GUNLOCK(); return 0; } mp_afs_brelse(vp, bp) struct vnode *vp; struct buf *bp; { AFS_GLOCK(); AFS_STATCNT(afs_brelse); if ((struct buf *)bp->b_vp != bp) { /* not fake */ brelse(bp); } else if (afs_bread_freebp) { AFS_KFREE(bp->b_un.b_addr, vp->v_vfsp->vfs_bsize); AFS_KFREE(bp, sizeof(*bp)); } else { afs_bread_freebp = bp; } AFS_GUNLOCK(); } mp_afs_bmap(avc, abn, anvp, anbn) register struct vcache *avc; afs_int32 abn, *anbn; struct vcache **anvp; { AFS_GLOCK(); AFS_STATCNT(afs_bmap); if (anvp) *anvp = avc; if (anbn) *anbn = abn * (8192 / DEV_BSIZE); /* in 512 byte units */ AFS_GUNLOCK(); return 0; } /* real strategy */ mp_afs_strategy (abp) register struct buf *abp; { register afs_int32 code; AFS_GLOCK(); AFS_STATCNT(afs_strategy); code = afs_osi_MapStrategy(afs_ustrategy, abp); AFS_GUNLOCK(); return code; } mp_afs_refer(vm_ubc_object_t vop) { VREF(vop->vu_vp); } mp_afs_release(vm_ubc_object_t vop) { vrele(vop->vu_vp); } mp_afs_write_check(vm_ubc_object_t vop, vm_page_t pp) { return TRUE; } struct vfs_ubcops afs_ubcops = { mp_afs_refer, /* refer vnode */ mp_afs_release, /* release vnode */ mp_afs_getpage, /* get page */ mp_afs_putpage, /* put page */ mp_afs_write_check, /* check writablity */ }; /* * Cover function for lookup name using OSF equivalent, namei() * * Note, the result vnode (ni_vp) in the namei data structure is remains * locked after return. */ lookupname(namep, seg, follow, dvpp, cvpp) char *namep; /* path name */ int seg; /* address space containing name */ int follow; /* follow symbolic links */ struct vnode **dvpp; /* result, containing parent vnode */ struct vnode **cvpp; /* result, containing final component vnode */ { /* Should I use free-bee in u-area? */ struct nameidata *ndp = &u.u_nd; int error; ndp->ni_nameiop = ((follow) ? (LOOKUP|FOLLOW) : (LOOKUP)); ndp->ni_segflg = seg; ndp->ni_dirp = namep; error = namei(ndp); if (dvpp != (struct vnode **)0) *dvpp = ndp->ni_dvp; if (cvpp != (struct vnode **)0) *cvpp = ndp->ni_vp; return(error); }