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

\param xbb        Per-instance xbb configuration structure.
\param reqlist    Allocated internal request list structure.
\param operation  BIO_* I/O operation code.
\param bio_flags  Additional bio_flag data to pass to any generated
bios

\return  0 for success, errno codes for failure.
Backend Handlers Backend handler for character device access . \ param xbb Per - instance xbb configuration structure . \ param reqlist Allocated internal request list structure . \ param operation BIO_ * I / O operation code . \ param bio_flags Additional bio_flag data to pass to any generated bios \ return 0 for success errno codes for failure .
static int
xbb_dispatch_dev(struct xbb_softc *xbb, struct xbb_xen_reqlist *reqlist,
		 int operation, int bio_flags)
{
	struct xbb_dev_data *dev_data;
	struct bio          *bios[XBB_MAX_SEGMENTS_PER_REQLIST];
	off_t                bio_offset;
	struct bio          *bio;
	struct xbb_sg       *xbb_sg;
	u_int	             nbio;
	u_int                bio_idx;
	u_int		     nseg;
	u_int                seg_idx;
	int                  error;
	dev_data   = &xbb->backend.dev;
	bio_offset = (off_t)reqlist->starting_sector_number
		   << xbb->sector_size_shift;
	error      = 0;
	nbio       = 0;
	bio_idx    = 0;
	if (operation == BIO_FLUSH) {
		bio = g_new_bio();
		if (__predict_false(bio == NULL)) {
			DPRINTF("Unable to allocate bio for BIO_FLUSH\n");
			error = ENOMEM;
			return (error);
		}
		bio->bio_cmd	 = BIO_FLUSH;
		bio->bio_flags	|= BIO_ORDERED;
		bio->bio_dev	 = dev_data->cdev;
		bio->bio_offset	 = 0;
		bio->bio_data	 = 0;
		bio->bio_done	 = xbb_bio_done;
		bio->bio_caller1 = reqlist;
		bio->bio_pblkno	 = 0;
		reqlist->pendcnt = 1;
		SDT_PROBE1(xbb, kernel, xbb_dispatch_dev, flush,
			   device_get_unit(xbb->dev));
		(*dev_data->csw->d_strategy)(bio);
		return (0);
	}
	xbb_sg = xbb->xbb_sgs;
	bio    = NULL;
	nseg = reqlist->nr_segments;
	for (seg_idx = 0; seg_idx < nseg; seg_idx++, xbb_sg++) {
		if ((bio != NULL)
		 && (xbb_sg->first_sect != 0)) {
			if ((bio->bio_length & (xbb->sector_size - 1)) != 0) {
				printf("%s: Discontiguous I/O request "
				       "from domain %d ends on "
				       "non-sector boundary\n",
				       __func__, xbb->otherend_id);
				error = EINVAL;
				goto fail_free_bios;
			}
			bio = NULL;
		}
		if (bio == NULL) {
			if ((bio_offset & (xbb->sector_size - 1)) != 0){
				printf("%s: Misaligned I/O request "
				       "from domain %d\n", __func__,
				       xbb->otherend_id);
				error = EINVAL;
				goto fail_free_bios;
			}
			bio = bios[nbio++] = g_new_bio();
			if (__predict_false(bio == NULL)) {
				error = ENOMEM;
				goto fail_free_bios;
			}
			bio->bio_cmd     = operation;
			bio->bio_flags  |= bio_flags;
			bio->bio_dev     = dev_data->cdev;
			bio->bio_offset  = bio_offset;
			bio->bio_data    = xbb_reqlist_ioaddr(reqlist, seg_idx,
						xbb_sg->first_sect);
			bio->bio_done    = xbb_bio_done;
			bio->bio_caller1 = reqlist;
			bio->bio_pblkno  = bio_offset >> xbb->sector_size_shift;
		}
		bio->bio_length += xbb_sg->nsect << 9;
		bio->bio_bcount  = bio->bio_length;
		bio_offset      += xbb_sg->nsect << 9;
		if (xbb_sg->last_sect != (PAGE_SIZE - 512) >> 9) {
			if ((bio->bio_length & (xbb->sector_size - 1)) != 0) {
				printf("%s: Discontiguous I/O request "
				       "from domain %d ends on "
				       "non-sector boundary\n",
				       __func__, xbb->otherend_id);
				error = EINVAL;
				goto fail_free_bios;
			}
			bio = NULL;
		}
	}
	reqlist->pendcnt = nbio;
	for (bio_idx = 0; bio_idx < nbio; bio_idx++)
	{
#ifdef XBB_USE_BOUNCE_BUFFERS
		vm_offset_t kva_offset;
		kva_offset = (vm_offset_t)bios[bio_idx]->bio_data
			   - (vm_offset_t)reqlist->bounce;
		if (operation == BIO_WRITE) {
			memcpy(bios[bio_idx]->bio_data,
			       (uint8_t *)reqlist->kva + kva_offset,
			       bios[bio_idx]->bio_bcount);
		}
#endif
		if (operation == BIO_READ) {
			SDT_PROBE3(xbb, kernel, xbb_dispatch_dev, read,
				   device_get_unit(xbb->dev),
				   bios[bio_idx]->bio_offset,
				   bios[bio_idx]->bio_length);
		} else if (operation == BIO_WRITE) {
			SDT_PROBE3(xbb, kernel, xbb_dispatch_dev, write,
				   device_get_unit(xbb->dev),
				   bios[bio_idx]->bio_offset,
				   bios[bio_idx]->bio_length);
		}
		(*dev_data->csw->d_strategy)(bios[bio_idx]);
	}
	return (error);
fail_free_bios:
	for (bio_idx = 0; bio_idx < (nbio-1); bio_idx++)
		g_destroy_bio(bios[bio_idx]);
	return (error);
}
static int xbb_dispatch_dev ( struct xbb_softc * xbb , struct xbb_xen_reqlist * reqlist , int operation , int bio_flags ) { struct xbb_dev_data * dev_data ; struct bio * bios [ XBB_MAX_SEGMENTS_PER_REQLIST ] ; off_t bio_offset ; struct bio * bio ; struct xbb_sg * xbb_sg ; u_int nbio ; u_int bio_idx ; u_int nseg ; u_int seg_idx ; int error ; dev_data = & xbb -> backend . dev ; bio_offset = ( off_t ) reqlist -> starting_sector_number << xbb -> sector_size_shift ; error = 0 ; nbio = 0 ; bio_idx = 0 ; if ( operation == BIO_FLUSH ) { bio = g_new_bio ( ) ; if ( __predict_false ( bio == NULL ) ) { DPRINTF ( " \n " ) ; error = ENOMEM ; return ( error ) ; } bio -> bio_cmd = BIO_FLUSH ; bio -> bio_flags |= BIO_ORDERED ; bio -> bio_dev = dev_data -> cdev ; bio -> bio_offset = 0 ; bio -> bio_data = 0 ; bio -> bio_done = xbb_bio_done ; bio -> bio_caller1 = reqlist ; bio -> bio_pblkno = 0 ; reqlist -> pendcnt = 1 ; SDT_PROBE1 ( xbb , kernel , xbb_dispatch_dev , flush , device_get_unit ( xbb -> dev ) ) ; ( * dev_data -> csw -> d_strategy ) ( bio ) ; return ( 0 ) ; } xbb_sg = xbb -> xbb_sgs ; bio = NULL ; nseg = reqlist -> nr_segments ; for ( seg_idx = 0 ; seg_idx < nseg ; seg_idx ++ , xbb_sg ++ ) { if ( ( bio != NULL ) && ( xbb_sg -> first_sect != 0 ) ) { if ( ( bio -> bio_length & ( xbb -> sector_size - 1 ) ) != 0 ) { printf ( " " " " " \n " , __func__ , xbb -> otherend_id ) ; error = EINVAL ; goto fail_free_bios ; } bio = NULL ; } if ( bio == NULL ) { if ( ( bio_offset & ( xbb -> sector_size - 1 ) ) != 0 ) { printf ( " " " \n " , __func__ , xbb -> otherend_id ) ; error = EINVAL ; goto fail_free_bios ; } bio = bios [ nbio ++ ] = g_new_bio ( ) ; if ( __predict_false ( bio == NULL ) ) { error = ENOMEM ; goto fail_free_bios ; } bio -> bio_cmd = operation ; bio -> bio_flags |= bio_flags ; bio -> bio_dev = dev_data -> cdev ; bio -> bio_offset = bio_offset ; bio -> bio_data = xbb_reqlist_ioaddr ( reqlist , seg_idx , xbb_sg -> first_sect ) ; bio -> bio_done = xbb_bio_done ; bio -> bio_caller1 = reqlist ; bio -> bio_pblkno = bio_offset >> xbb -> sector_size_shift ; } bio -> bio_length += xbb_sg -> nsect << 9 ; bio -> bio_bcount = bio -> bio_length ; bio_offset += xbb_sg -> nsect << 9 ; if ( xbb_sg -> last_sect != ( PAGE_SIZE - 512 ) >> 9 ) { if ( ( bio -> bio_length & ( xbb -> sector_size - 1 ) ) != 0 ) { printf ( " " " " " \n " , __func__ , xbb -> otherend_id ) ; error = EINVAL ; goto fail_free_bios ; } bio = NULL ; } } reqlist -> pendcnt = nbio ; for ( bio_idx = 0 ; bio_idx < nbio ; bio_idx ++ ) { #ifdef XBB_USE_BOUNCE_BUFFERS vm_offset_t kva_offset ; kva_offset = ( vm_offset_t ) bios [ bio_idx ] -> bio_data - ( vm_offset_t ) reqlist -> bounce ; if ( operation == BIO_WRITE ) { memcpy ( bios [ bio_idx ] -> bio_data , ( uint8_t * ) reqlist -> kva + kva_offset , bios [ bio_idx ] -> bio_bcount ) ; } #endif if ( operation == BIO_READ ) { SDT_PROBE3 ( xbb , kernel , xbb_dispatch_dev , read , device_get_unit ( xbb -> dev ) , bios [ bio_idx ] -> bio_offset , bios [ bio_idx ] -> bio_length ) ; } else if ( operation == BIO_WRITE ) { SDT_PROBE3 ( xbb , kernel , xbb_dispatch_dev , write , device_get_unit ( xbb -> dev ) , bios [ bio_idx ] -> bio_offset , bios [ bio_idx ] -> bio_length ) ; } ( * dev_data -> csw -> d_strategy ) ( bios [ bio_idx ] ) ; } return ( error ) ; fail_free_bios : for ( bio_idx = 0 ; bio_idx < ( nbio - 1 ) ; bio_idx ++ ) g_destroy_bio ( bios [ bio_idx ] ) ; return ( error ) ; }
Backend Handlers
 Backend handler for character device access.
Backend Handlers Backend handler for character device access .
/*
		 * KVA will not be contiguous, so any additional
		 * I/O will need to be represented in a new bio.
		 */ /*
			 * Make sure that the start of this bio is
			 * aligned to a device sector.
			 */ /*
			 * KVA will not be contiguous, so any additional
			 * I/O will need to be represented in a new bio.
			 */