Ruslan R. Laishev Ответов: 1

Как получить доступ к данным, если био было клонировано ?


- Привет !

Я пишу драйвер устройства Linux, который должен работать поверх драйверов устройств existen, поэтому я пытаюсь использовать процедуру ввода-вывода bi_end_io() complition для доступа к буферам данных, считанным с дискового устройства, смотрите следующий фрагмент кода:


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)


Итак, есть ли способ получить доступ к уже прочитанным данным в клонированной биографии ?
Или, может быть, мне нужно использовать какую-то другую тактику, чтобы сохранить доступ к оригинальным биовекам ?

Что я уже пробовал:

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


Заранее спасибо!

1 Ответов

Рейтинг:
12

Ruslan R. Laishev

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);
	}
}