FreeBSD/sys/fs/nfsclient/nfs_clbio.c
/*
 * Vnode op for VM getpages.
 */
Vnode op for VM getpages.
Vnode op for VM getpages .
int
ncl_getpages(struct vop_getpages_args *ap)
{
	int i, error, nextoff, size, toff, count, npages;
	struct uio uio;
	struct iovec iov;
	vm_offset_t kva;
	struct buf *bp;
	struct vnode *vp;
	struct thread *td;
	struct ucred *cred;
	struct nfsmount *nmp;
	vm_object_t object;
	vm_page_t *pages;
	struct nfsnode *np;
	vp = ap->a_vp;
	np = VTONFS(vp);
	td = curthread;				
	cred = curthread->td_ucred;		
	nmp = VFSTONFS(vp->v_mount);
	pages = ap->a_m;
	npages = ap->a_count;
	if ((object = vp->v_object) == NULL) {
		printf("ncl_getpages: called with non-merged cache vnode\n");
		return (VM_PAGER_ERROR);
	}
	if (newnfs_directio_enable && !newnfs_directio_allow_mmap) {
		mtx_lock(&np->n_mtx);
		if ((np->n_flag & NNONCACHE) && (vp->v_type == VREG)) {
			mtx_unlock(&np->n_mtx);
			printf("ncl_getpages: called on non-cacheable vnode\n");
			return (VM_PAGER_ERROR);
		} else
			mtx_unlock(&np->n_mtx);
	}
	mtx_lock(&nmp->nm_mtx);
	if ((nmp->nm_flag & NFSMNT_NFSV3) != 0 &&
	    (nmp->nm_state & NFSSTA_GOTFSINFO) == 0) {
		mtx_unlock(&nmp->nm_mtx);
		(void)ncl_fsinfo(nmp, vp, cred, td);
	} else
		mtx_unlock(&nmp->nm_mtx);
	VM_OBJECT_WLOCK(object);
	if (pages[npages - 1]->valid != 0 && --npages == 0)
		goto out;
	VM_OBJECT_WUNLOCK(object);
	bp = getpbuf(&ncl_pbuf_freecnt);
	kva = (vm_offset_t) bp->b_data;
	pmap_qenter(kva, pages, npages);
	PCPU_INC(cnt.v_vnodein);
	PCPU_ADD(cnt.v_vnodepgsin, npages);
	count = npages << PAGE_SHIFT;
	iov.iov_base = (caddr_t) kva;
	iov.iov_len = count;
	uio.uio_iov = &iov;
	uio.uio_iovcnt = 1;
	uio.uio_offset = IDX_TO_OFF(pages[0]->pindex);
	uio.uio_resid = count;
	uio.uio_segflg = UIO_SYSSPACE;
	uio.uio_rw = UIO_READ;
	uio.uio_td = td;
	error = ncl_readrpc(vp, &uio, cred);
	pmap_qremove(kva, npages);
	relpbuf(bp, &ncl_pbuf_freecnt);
	if (error && (uio.uio_resid == count)) {
		printf("ncl_getpages: error %d\n", error);
		return (VM_PAGER_ERROR);
	}
	size = count - uio.uio_resid;
	VM_OBJECT_WLOCK(object);
	for (i = 0, toff = 0; i < npages; i++, toff = nextoff) {
		vm_page_t m;
		nextoff = toff + PAGE_SIZE;
		m = pages[i];
		if (nextoff <= size) {
			m->valid = VM_PAGE_BITS_ALL;
			KASSERT(m->dirty == 0,
			    ("nfs_getpages: page %p is dirty", m));
		} else if (size > toff) {
			m->valid = 0;
			vm_page_set_valid_range(m, 0, size - toff);
			KASSERT(m->dirty == 0,
			    ("nfs_getpages: page %p is dirty", m));
		} else {
			;
		}
	}
out:
	VM_OBJECT_WUNLOCK(object);
	if (ap->a_rbehind)
		*ap->a_rbehind = 0;
	if (ap->a_rahead)
		*ap->a_rahead = 0;
	return (VM_PAGER_OK);
}
int ncl_getpages ( struct vop_getpages_args * ap ) { int i , error , nextoff , size , toff , count , npages ; struct uio uio ; struct iovec iov ; vm_offset_t kva ; struct buf * bp ; struct vnode * vp ; struct thread * td ; struct ucred * cred ; struct nfsmount * nmp ; vm_object_t object ; vm_page_t * pages ; struct nfsnode * np ; vp = ap -> a_vp ; np = VTONFS ( vp ) ; td = curthread ; cred = curthread -> td_ucred ; nmp = VFSTONFS ( vp -> v_mount ) ; pages = ap -> a_m ; npages = ap -> a_count ; if ( ( object = vp -> v_object ) == NULL ) { printf ( " \n " ) ; return ( VM_PAGER_ERROR ) ; } if ( newnfs_directio_enable && ! newnfs_directio_allow_mmap ) { mtx_lock ( & np -> n_mtx ) ; if ( ( np -> n_flag & NNONCACHE ) && ( vp -> v_type == VREG ) ) { mtx_unlock ( & np -> n_mtx ) ; printf ( " \n " ) ; return ( VM_PAGER_ERROR ) ; } else mtx_unlock ( & np -> n_mtx ) ; } mtx_lock ( & nmp -> nm_mtx ) ; if ( ( nmp -> nm_flag & NFSMNT_NFSV3 ) != 0 && ( nmp -> nm_state & NFSSTA_GOTFSINFO ) == 0 ) { mtx_unlock ( & nmp -> nm_mtx ) ; ( void ) ncl_fsinfo ( nmp , vp , cred , td ) ; } else mtx_unlock ( & nmp -> nm_mtx ) ; VM_OBJECT_WLOCK ( object ) ; if ( pages [ npages - 1 ] -> valid != 0 && -- npages == 0 ) goto out ; VM_OBJECT_WUNLOCK ( object ) ; bp = getpbuf ( & ncl_pbuf_freecnt ) ; kva = ( vm_offset_t ) bp -> b_data ; pmap_qenter ( kva , pages , npages ) ; PCPU_INC ( cnt . v_vnodein ) ; PCPU_ADD ( cnt . v_vnodepgsin , npages ) ; count = npages << PAGE_SHIFT ; iov . iov_base = ( caddr_t ) kva ; iov . iov_len = count ; uio . uio_iov = & iov ; uio . uio_iovcnt = 1 ; uio . uio_offset = IDX_TO_OFF ( pages [ 0 ] -> pindex ) ; uio . uio_resid = count ; uio . uio_segflg = UIO_SYSSPACE ; uio . uio_rw = UIO_READ ; uio . uio_td = td ; error = ncl_readrpc ( vp , & uio , cred ) ; pmap_qremove ( kva , npages ) ; relpbuf ( bp , & ncl_pbuf_freecnt ) ; if ( error && ( uio . uio_resid == count ) ) { printf ( " \n " , error ) ; return ( VM_PAGER_ERROR ) ; } size = count - uio . uio_resid ; VM_OBJECT_WLOCK ( object ) ; for ( i = 0 , toff = 0 ; i < npages ; i ++ , toff = nextoff ) { vm_page_t m ; nextoff = toff + PAGE_SIZE ; m = pages [ i ] ; if ( nextoff <= size ) { m -> valid = VM_PAGE_BITS_ALL ; KASSERT ( m -> dirty == 0 , ( " " , m ) ) ; } else if ( size > toff ) { m -> valid = 0 ; vm_page_set_valid_range ( m , 0 , size - toff ) ; KASSERT ( m -> dirty == 0 , ( " " , m ) ) ; } else { ; } } out : VM_OBJECT_WUNLOCK ( object ) ; if ( ap -> a_rbehind ) * ap -> a_rbehind = 0 ; if ( ap -> a_rahead ) * ap -> a_rahead = 0 ; return ( VM_PAGER_OK ) ; }
Vnode op for VM getpages.
Vnode op for VM getpages .
/* XXX */ /* XXX */ /* We'll never get here for v4, because we always have fsinfo */ /*
	 * If the requested page is partially valid, just return it and
	 * allow the pager to zero-out the blanks.  Partially valid pages
	 * can only occur at the file EOF.
	 *
	 * XXXGL: is that true for NFS, where short read can occur???
	 */ /*
	 * We use only the kva address for the buffer, but this is extremely
	 * convenient and fast.
	 */ /*
	 * Calculate the number of bytes read and validate only that number
	 * of bytes.  Note that due to pending writes, size may be 0.  This
	 * does not mean that the remaining data is invalid!
	 */ /*
			 * Read operation filled an entire page
			 */ /*
			 * Read operation filled a partial page.
			 */ /*
			 * Read operation was short.  If no error
			 * occurred we may have hit a zero-fill
			 * section.  We leave valid set to 0, and page
			 * is freed by vm_page_readahead_finish() if
			 * its index is not equal to requested, or
			 * page is zeroed and set valid by
			 * vm_pager_get_pages() for requested page.
			 */