FreeBSD/sys/dev/xen/blkback/blkback.c
/**
 * Backend handler for file access.
 *
 * \param xbb        Per-instance xbb configuration structure.
 * \param reqlist    Allocated internal request list.
 * \param operation  BIO_* I/O operation code.
 * \param flags      Additional bio_flag data to pass to any generated bios
 *                   (e.g. BIO_ORDERED)..
 *
 * \return  0 for success, errno codes for failure.
 */
Backend handler for file access.
\param xbb        Per-instance xbb configuration structure.
\param reqlist    Allocated internal request list.
\param operation  BIO_* I/O operation code.
\param flags      Additional bio_flag data to pass to any generated bios

\return  0 for success, errno codes for failure.
Backend handler for file access . \ param xbb Per - instance xbb configuration structure . \ param reqlist Allocated internal request list . \ param operation BIO_ * I / O operation code . \ param flags Additional bio_flag data to pass to any generated bios \ return 0 for success errno codes for failure .
static int
xbb_dispatch_file(struct xbb_softc *xbb, struct xbb_xen_reqlist *reqlist,
		  int operation, int flags)
{
	struct xbb_file_data *file_data;
	u_int                 seg_idx;
	u_int		      nseg;
	struct uio            xuio;
	struct xbb_sg        *xbb_sg;
	struct iovec         *xiovec;
#ifdef XBB_USE_BOUNCE_BUFFERS
	void                **p_vaddr;
	int                   saved_uio_iovcnt;
#endif 
	int                   error;
	file_data = &xbb->backend.file;
	error = 0;
	bzero(&xuio, sizeof(xuio));
	switch (operation) {
	case BIO_READ:
		xuio.uio_rw = UIO_READ;
		break;
	case BIO_WRITE:
		xuio.uio_rw = UIO_WRITE;
		break;
	case BIO_FLUSH: {
		struct mount *mountpoint;
		SDT_PROBE1(xbb, kernel, xbb_dispatch_file, flush,
			   device_get_unit(xbb->dev));
		(void) vn_start_write(xbb->vn, &mountpoint, V_WAIT);
		vn_lock(xbb->vn, LK_EXCLUSIVE | LK_RETRY);
		error = VOP_FSYNC(xbb->vn, MNT_WAIT, curthread);
		VOP_UNLOCK(xbb->vn, 0);
		vn_finished_write(mountpoint);
		goto bailout_send_response;
	}
	default:
		panic("invalid operation %d", operation);
	}
	xuio.uio_offset = (vm_offset_t)reqlist->starting_sector_number
			<< xbb->sector_size_shift;
	xuio.uio_segflg = UIO_SYSSPACE;
	xuio.uio_iov = file_data->xiovecs;
	xuio.uio_iovcnt = 0;
	xbb_sg = xbb->xbb_sgs;
	nseg = reqlist->nr_segments;
	for (xiovec = NULL, seg_idx = 0; seg_idx < nseg; seg_idx++, xbb_sg++) {
		if (xbb_sg->first_sect != 0)
			xiovec = NULL;
		if (xiovec == NULL) {
			xiovec = &file_data->xiovecs[xuio.uio_iovcnt];
			xiovec->iov_base = xbb_reqlist_ioaddr(reqlist,
			    seg_idx, xbb_sg->first_sect);
#ifdef XBB_USE_BOUNCE_BUFFERS
			p_vaddr = &file_data->xiovecs_vaddr[xuio.uio_iovcnt];
			*p_vaddr = xbb_reqlist_vaddr(reqlist, seg_idx,
			    xbb_sg->first_sect);
#endif 
			xiovec->iov_len = 0;
			xuio.uio_iovcnt++;
		}
		xiovec->iov_len += xbb_sg->nsect << 9;
		xuio.uio_resid += xbb_sg->nsect << 9;
		if (xbb_sg->last_sect != (PAGE_SIZE - 512) >> 9)
			xiovec = NULL;
	}
	xuio.uio_td = curthread;
#ifdef XBB_USE_BOUNCE_BUFFERS
	saved_uio_iovcnt = xuio.uio_iovcnt;
	if (operation == BIO_WRITE) {
		for (seg_idx = 0, p_vaddr = file_data->xiovecs_vaddr,
		     xiovec = xuio.uio_iov; seg_idx < xuio.uio_iovcnt;
		     seg_idx++, xiovec++, p_vaddr++) {
			memcpy(xiovec->iov_base, *p_vaddr, xiovec->iov_len);
		}
	} else {
		memcpy(file_data->saved_xiovecs, xuio.uio_iov,
		       xuio.uio_iovcnt * sizeof(xuio.uio_iov[0]));
	}
#endif 
	switch (operation) {
	case BIO_READ:
		SDT_PROBE3(xbb, kernel, xbb_dispatch_file, read,
			   device_get_unit(xbb->dev), xuio.uio_offset,
			   xuio.uio_resid);
		vn_lock(xbb->vn, LK_EXCLUSIVE | LK_RETRY);
		error = VOP_READ(xbb->vn, &xuio, (flags & BIO_ORDERED) ? 
				 (IO_DIRECT|IO_SYNC) : 0, file_data->cred);
		VOP_UNLOCK(xbb->vn, 0);
		break;
	case BIO_WRITE: {
		struct mount *mountpoint;
		SDT_PROBE3(xbb, kernel, xbb_dispatch_file, write,
			   device_get_unit(xbb->dev), xuio.uio_offset,
			   xuio.uio_resid);
		(void)vn_start_write(xbb->vn, &mountpoint, V_WAIT);
		vn_lock(xbb->vn, LK_EXCLUSIVE | LK_RETRY);
		error = VOP_WRITE(xbb->vn, &xuio, (flags & BIO_ORDERED) ?
				  IO_SYNC : 0, file_data->cred);
		VOP_UNLOCK(xbb->vn, 0);
		vn_finished_write(mountpoint);
		break;
	}
	default:
		panic("invalid operation %d", operation);
	}
#ifdef XBB_USE_BOUNCE_BUFFERS
	if (operation == BIO_READ) {
		for (seg_idx = 0, p_vaddr = file_data->xiovecs_vaddr,
		     xiovec = file_data->saved_xiovecs;
		     seg_idx < saved_uio_iovcnt; seg_idx++,
		     xiovec++, p_vaddr++) {
			memcpy(*p_vaddr, xiovec->iov_base, xiovec->iov_len);
		}
	}
#endif 
bailout_send_response:
	if (error != 0)
		reqlist->status = BLKIF_RSP_ERROR;
	xbb_complete_reqlist(xbb, reqlist);
	return (0);
}
static int xbb_dispatch_file ( struct xbb_softc * xbb , struct xbb_xen_reqlist * reqlist , int operation , int flags ) { struct xbb_file_data * file_data ; u_int seg_idx ; u_int nseg ; struct uio xuio ; struct xbb_sg * xbb_sg ; struct iovec * xiovec ; #ifdef XBB_USE_BOUNCE_BUFFERS void * * p_vaddr ; int saved_uio_iovcnt ; #endif int error ; file_data = & xbb -> backend . file ; error = 0 ; bzero ( & xuio , sizeof ( xuio ) ) ; switch ( operation ) { case BIO_READ : xuio . uio_rw = UIO_READ ; break ; case BIO_WRITE : xuio . uio_rw = UIO_WRITE ; break ; case BIO_FLUSH : { struct mount * mountpoint ; SDT_PROBE1 ( xbb , kernel , xbb_dispatch_file , flush , device_get_unit ( xbb -> dev ) ) ; ( void ) vn_start_write ( xbb -> vn , & mountpoint , V_WAIT ) ; vn_lock ( xbb -> vn , LK_EXCLUSIVE | LK_RETRY ) ; error = VOP_FSYNC ( xbb -> vn , MNT_WAIT , curthread ) ; VOP_UNLOCK ( xbb -> vn , 0 ) ; vn_finished_write ( mountpoint ) ; goto bailout_send_response ; } default : panic ( " " , operation ) ; } xuio . uio_offset = ( vm_offset_t ) reqlist -> starting_sector_number << xbb -> sector_size_shift ; xuio . uio_segflg = UIO_SYSSPACE ; xuio . uio_iov = file_data -> xiovecs ; xuio . uio_iovcnt = 0 ; xbb_sg = xbb -> xbb_sgs ; nseg = reqlist -> nr_segments ; for ( xiovec = NULL , seg_idx = 0 ; seg_idx < nseg ; seg_idx ++ , xbb_sg ++ ) { if ( xbb_sg -> first_sect != 0 ) xiovec = NULL ; if ( xiovec == NULL ) { xiovec = & file_data -> xiovecs [ xuio . uio_iovcnt ] ; xiovec -> iov_base = xbb_reqlist_ioaddr ( reqlist , seg_idx , xbb_sg -> first_sect ) ; #ifdef XBB_USE_BOUNCE_BUFFERS p_vaddr = & file_data -> xiovecs_vaddr [ xuio . uio_iovcnt ] ; * p_vaddr = xbb_reqlist_vaddr ( reqlist , seg_idx , xbb_sg -> first_sect ) ; #endif xiovec -> iov_len = 0 ; xuio . uio_iovcnt ++ ; } xiovec -> iov_len += xbb_sg -> nsect << 9 ; xuio . uio_resid += xbb_sg -> nsect << 9 ; if ( xbb_sg -> last_sect != ( PAGE_SIZE - 512 ) >> 9 ) xiovec = NULL ; } xuio . uio_td = curthread ; #ifdef XBB_USE_BOUNCE_BUFFERS saved_uio_iovcnt = xuio . uio_iovcnt ; if ( operation == BIO_WRITE ) { for ( seg_idx = 0 , p_vaddr = file_data -> xiovecs_vaddr , xiovec = xuio . uio_iov ; seg_idx < xuio . uio_iovcnt ; seg_idx ++ , xiovec ++ , p_vaddr ++ ) { memcpy ( xiovec -> iov_base , * p_vaddr , xiovec -> iov_len ) ; } } else { memcpy ( file_data -> saved_xiovecs , xuio . uio_iov , xuio . uio_iovcnt * sizeof ( xuio . uio_iov [ 0 ] ) ) ; } #endif switch ( operation ) { case BIO_READ : SDT_PROBE3 ( xbb , kernel , xbb_dispatch_file , read , device_get_unit ( xbb -> dev ) , xuio . uio_offset , xuio . uio_resid ) ; vn_lock ( xbb -> vn , LK_EXCLUSIVE | LK_RETRY ) ; error = VOP_READ ( xbb -> vn , & xuio , ( flags & BIO_ORDERED ) ? ( IO_DIRECT | IO_SYNC ) : 0 , file_data -> cred ) ; VOP_UNLOCK ( xbb -> vn , 0 ) ; break ; case BIO_WRITE : { struct mount * mountpoint ; SDT_PROBE3 ( xbb , kernel , xbb_dispatch_file , write , device_get_unit ( xbb -> dev ) , xuio . uio_offset , xuio . uio_resid ) ; ( void ) vn_start_write ( xbb -> vn , & mountpoint , V_WAIT ) ; vn_lock ( xbb -> vn , LK_EXCLUSIVE | LK_RETRY ) ; error = VOP_WRITE ( xbb -> vn , & xuio , ( flags & BIO_ORDERED ) ? IO_SYNC : 0 , file_data -> cred ) ; VOP_UNLOCK ( xbb -> vn , 0 ) ; vn_finished_write ( mountpoint ) ; break ; } default : panic ( " " , operation ) ; } #ifdef XBB_USE_BOUNCE_BUFFERS if ( operation == BIO_READ ) { for ( seg_idx = 0 , p_vaddr = file_data -> xiovecs_vaddr , xiovec = file_data -> saved_xiovecs ; seg_idx < saved_uio_iovcnt ; seg_idx ++ , xiovec ++ , p_vaddr ++ ) { memcpy ( * p_vaddr , xiovec -> iov_base , xiovec -> iov_len ) ; } } #endif bailout_send_response : if ( error != 0 ) reqlist -> status = BLKIF_RSP_ERROR ; xbb_complete_reqlist ( xbb , reqlist ) ; return ( 0 ) ; }
Backend handler for file access.
Backend handler for file access .
/* XBB_USE_BOUNCE_BUFFERS */ /* NOTREACHED */ /* NOTREACHED */ /*
		 * If the first sector is not 0, the KVA will
		 * not be contiguous and we'll need to go on
		 * to another segment.
		 */ /*
			 * Store the address of the incoming
			 * buffer at this particular offset
			 * as well, so we can do the copy
			 * later without having to do more
			 * work to recalculate this address.
		 	 */ /* XBB_USE_BOUNCE_BUFFERS */ /*
		 * If the last sector is not the full page
		 * size count, the next segment will not be
		 * contiguous in KVA and we need a new iovec.
		 */ /* Copy the write data to the local buffer. */ /*
		 * We only need to save off the iovecs in the case of a
		 * read, because the copy for the read happens after the
		 * VOP_READ().  (The uio will get modified in that call
		 * sequence.)
		 */ /* XBB_USE_BOUNCE_BUFFERS */ /*
		 * UFS pays attention to IO_DIRECT for reads.  If the
		 * DIRECTIO option is configured into the kernel, it calls
		 * ffs_rawread().  But that only works for single-segment
		 * uios with user space addresses.  In our case, with a
		 * kernel uio, it still reads into the buffer cache, but it
		 * will just try to release the buffer from the cache later
		 * on in ffs_read().
		 *
		 * ZFS does not pay attention to IO_DIRECT for reads.
		 *
		 * UFS does not pay attention to IO_SYNC for reads.
		 *
		 * ZFS pays attention to IO_SYNC (which translates into the
		 * Solaris define FRSYNC for zfs_read()) for reads.  It
		 * attempts to sync the file before reading.
		 *
		 * So, to attempt to provide some barrier semantics in the
		 * BIO_ORDERED case, set both IO_DIRECT and IO_SYNC.  
		 */ /*
		 * UFS pays attention to IO_DIRECT for writes.  The write
		 * is done asynchronously.  (Normally the write would just
		 * get put into cache.
		 *
		 * UFS pays attention to IO_SYNC for writes.  It will
		 * attempt to write the buffer out synchronously if that
		 * flag is set.
		 *
		 * ZFS does not pay attention to IO_DIRECT for writes.
		 *
		 * ZFS pays attention to IO_SYNC (a.k.a. FSYNC or FRSYNC)
		 * for writes.  It will flush the transaction from the
		 * cache before returning.
		 *
		 * So if we've got the BIO_ORDERED flag set, we want
		 * IO_SYNC in either the UFS or ZFS case.
		 */ /* NOTREACHED */ /* We only need to copy here for read operations */ /*
			 * Note that we have to use the copy of the 
			 * io vector we made above.  uiomove() modifies
			 * the uio and its referenced vector as uiomove
			 * performs the copy, so we can't rely on any
			 * state from the original uio.
			 */ /* XBB_USE_BOUNCE_BUFFERS */