Click here to Skip to main content
15,886,799 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello !

I writting the Linux Device Driver is supposed to work on top of existen device drivers, so I try to use bi_end_io() complition I/O routine to access a data buffers has been read from disk device, see piece of code follows:


C++
static	void	dua_bio_end_io	(
			struct bio *	iob
				)
{
IOB_ARGS * iob_args;

	$TRACE("Entering to %s completion I/O, bio=%p ...", bio_data_dir(iob) == WRITE ? "WRITE" : "READ", iob);

	$SHOW_UNSIGNED(iob->bi_flags);
	$SHOW_INT(iob->bi_vcnt);

	$SHOW_BOOL(bio_has_data(iob));

	iob_args = iob->bi_private;

	iob->bi_end_io = iob_args->bi_end_io;
	iob->bi_private = iob_args->bi_private;

	bio_put(iob);

	__ret_iob_args (iob_args);

	/* In case of READ request - we should  decrypt data buffer right now */
	if ( bio_data_dir(iob) == READ )
		__iob_enc_dec(iob);

	bio_endio (iob);

}

static blk_qc_t dua_make_request_fn	(
		struct request_queue *	ioq,
			struct bio *	iob
				)
{
int	status = 0;

	$TRACE("Starting (%s), bio=%p, op=%d ...", bio_data_dir(iob) == WRITE ? "WRITE" : "READ", iob, bio_op(iob));


	$SHOW_UNSIGNED(iob->bi_flags);
	$SHOW_INT(iob->bi_vcnt);

	$SHOW_BOOL(bio_has_data(iob));

	/* In case of WRITE request - we can encrypt data buffer right now */
	if ( bio_data_dir(iob) == WRITE )
		__iob_enc_dec(iob);

	/*
	 * A handling of the READ request is require 'enqueue read request' & 'wait for read completion' paradigm,
	 * so we need to allocate IOB_ARGS block to carry data to the "Read Completion I/O" routine.
	 */
	else if ( bio_data_dir(iob) == READ )
		{
		IOB_ARGS *iob_args = NULL;

		if ( __get_iob_args (&iob_args) )
			{
			printk(KERN_ERR  __MODULE__ ": Buffered I/O quota limit has been exhausted\n");

			iob->bi_error = -EBUSY;
			bio_endio(iob);
			}

		iob_args->bi_end_io = iob->bi_end_io;
		iob_args->bi_private = iob->bi_private;

		/*
		 * Replace an address of the Completion I/O routine for 'read' operation,
		 * save original address.
		 */
		iob->bi_private = iob_args;
		iob->bi_end_io = dua_bio_end_io;

		bio_get(iob);
		}

	/* Just for sanity check ... */
	else	{
		printk(KERN_WARNING  __MODULE__ ": Unhandled I/O request %d\n", bio_data_dir(iob) );
		}


	/* Call original make_reques_fn() to performs a main work ... */
	status = backend_make_request_fn(ioq, iob);

	return	status;
}


...
6463.418222] [DUDRIVER\dua_make_request_fn:479] Starting (READ), bio=ffff95c5f9552100, op=0 ...
[ 6463.418222] [DUDRIVER\dua_make_request_fn:482] : iob->bi_flags = 0x00000000
[ 6463.418223] [DUDRIVER\dua_make_request_fn:483] : iob->bi_vcnt = 1
[ 6463.418223] [DUDRIVER\dua_make_request_fn:485] : bio_has_data(iob) = ENABLED(TRUE)

[ 6463.418266] [DUDRIVER\dua_bio_end_io:445] Entering to READ completion I/O, bio=ffff95c5f9552100 ...
[ 6463.418266] [DUDRIVER\dua_bio_end_io:447] : iob->bi_flags = 0x00000102
[ 6463.418267] [DUDRIVER\dua_bio_end_io:448] : iob->bi_vcnt = 1
[ 6463.418267] [DUDRIVER\dua_bio_end_io:450] : bio_has_data(iob) = DISABLED(FALSE)


So, is there a way to access has been read data in the cloned BIO ?
Or, may be I'm need to use some other tactic to keep access to original biovecs ?

What I have tried:

I read LDD3, and check the a lot of examples.
I working with the Linux kernel 4.10.y


Thanks in advance!
Posted
Updated 4-Jan-18 21:56pm
v2

1 solution

C++
static	void	__iob_enc_dec	(
		struct bio *	iob,
		sector_t	lbn
			)
{
struct bio_vec	*bvl;
sector_t	nlbn;
int	i;

	$TRACE("Start %scrypting ...", bio_data_dir(iob) == WRITE ? "En" : "De");

#if	0
{
	for (i = 0, bvl = iob->bi_io_vec; i < iob->bi_vcnt; i++, bvl++)
		{
		$SHOW_PTR(bvl->bv_page);
		$SHOW_INT(bvl->bv_len);
		$SHOW_INT(bvl->bv_offset);
		}
	}

	/* Do each segment independently. */
	bio_for_each_segment(bvec, iob, iter)
		{
		char *	iobuf;

		iobuf = __bio_kmap_atomic(iob, iter);

		$TRACE("#%02d: page=%p, off=%u, len=%u, iobuf=%p, lbn=%lu",
			iter.bi_idx, bvec.bv_page, bvec.bv_offset, bvec.bv_len, iobuf, iter.bi_sector);

		iobuf += bvec.bv_offset;

		lbn	= iter.bi_sector;
		nlbn	= iter.bi_size/DUDRV$K_BLKSZ;

		for ( ;nlbn; nlbn--, lbn++ , iobuf += DUDRV$K_BLKSZ)
			{
			bio_data_dir(iob) == WRITE
					? __encrypt (&gost89_ctx, lbn, iobuf, iobuf)
					: __decrypt (&gost89_ctx, lbn, iobuf, iobuf);
			}

		__bio_kunmap_atomic(iob);
	}

#endif

	/* Do each segment independently. */
	for (i = 0, bvl = iob->bi_io_vec; i < iob->bi_vcnt; i++, bvl++)
		{
		void	 *kaddr = kmap_atomic(bvl->bv_page), *iobuf;

		iobuf	= kaddr + bvl->bv_offset;

		nlbn	= bvl->bv_len/DUDRV$K_BLKSZ;

		$TRACE("#%02d: page=%p, off=%u, len=%u, iobuf=%p, lbn=%lu, nlbn=%lu",
			i, bvl->bv_page, bvl->bv_offset, bvl->bv_len, iobuf, lbn, nlbn);

		for ( ;nlbn; nlbn--, lbn++ , iobuf += DUDRV$K_BLKSZ)
			{
			if ( bio_data_dir(iob) == WRITE )
				__encrypt (&gost89_ctx, lbn, iobuf, iobuf);
			else	__decrypt (&gost89_ctx, lbn, iobuf, iobuf);
			}

		kunmap_atomic(kaddr);
	}
}
 
Share this answer
 
v4

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900