LINUX.ORG.RU

Избранные сообщения SysMan

Multiqueue tuntap interface

Форум — Development

Узнал вот, что tuntap поддерживает такую фичу, решил попробовать.

Мой юзкейс - создаю очередь из 5 дескрипторов, первый используется ТОЛЬКО для записи пакетов в интерфейс, остальные 4 - ТОЛЬКО для чтения из своего потока.

Отправляю icmp для теста, в tcpdump вижу, что пакеты отправляются И принимаются интерфейсом, однако прикладной софт из дескрипторов, предназначенных для чтения ничего не получает. если же читаю из того же дескриптора, через который отправляю данные - все читается.

М.б я не правильно понял назначение этих очередей?

 , ,

vvviperrr
()

[kernel] generic_make_request - не срабатывает callback

Форум — Development

Привет всем, если следующий код драйвера

void my_end_request(struct bio* child, int error)
{
  my_private_t*    private = child->bi_private;
  complete((struct completion*)private->completion);
}

int my_submit_request
(
    my_handle_t*   handle,
    int             rw,
    int             mode, 
    struct bio*     bio,
    void*           user_private_data,
    bio_end_io_t*   user_callback
)
{
  struct bio*       child     = NULL;
  my_private_t*    private   = NULL;
  my_registry_t*   registry  = NULL;
  int               direction = -1;
  DECLARE_COMPLETION_ONSTACK(completion);

  registry = handle->registry;

  direction = bio_data_dir(bio);

  child = bio_clone(bio, GFP_NOIO);

  private = my_private_get(registry->my_cache_private); // тут получаем структуру, в которой хранятся некоторые наши данные
 
  child->bi_end_io = (bio_end_io_t*)my_end_request; // устанавливаем callback

  child->bi_bdev = handle->bdev; // с этого устройства будем производить чтение
  
  private->completion = &completion;

  private->parent = bio;
  private->user_private_data = user_private_data;
  private->user_callback = user_callback;
  private->mode = mode;
  private->handle = handle;
  child->bi_private = private;
 
  generic_make_request(child);
  wait_for_completion(&completion); // Ждем конца чтения
  
  // еще какой то код
}

Пытаюсь перенаправлять запросы (пока только на чтение) со своего устройства на другое, в функции my_submit_request клонирую bio, вызываю сначала generic_make_request затем wait_for_completion(&completion) для того, что бы дождать окончания чтения, в коллбэке my_submit_request должна сработать функция complete. Проблема в том, никакого вызова коллбэка не происходит и мы вечно висим в wait_for_completion.

Код проверяющий ошибки не стал приводить что бы сократить объем.

 

megabug
()

подводные камни в функции bio_map_kern

Форум — Development

Пишу target драйвер для device mapper. Столкнулся с падением при попытке освобождения bio контекста выделяемого bio_map_kern. В исходниках ядра примеров применения этой функции не обнаружил, в сети с подробной документацией туго. Пример кода:

static void dcrypt_endio(struct bio *clone, int status)
{
	dc_io  *io = clone->bi_private;
	dc_dev *dc = io->target->private;
	struct bio_vec *bv; 
	int             i;
	char           *buff, *data;
	unsigned long   flags;

	if (unlikely(!bio_flagged(clone, BIO_UPTODATE) && !status)) {
		DbgMsg("EIO\n");
		status = -EIO;
	}
	
	if (unlikely(status))
		goto out;
	
	if (bio_data_dir(io->base_io) == READ) 
	{
		buff = io->data;
		
		bio_for_each_segment(bv, io->base_io, i) {
			data = bvec_kmap_irq(bv, &flags);
			memcpy(data, buff, bv->bv_len); buff += bv->bv_len;
			flush_dcache_page(bv->bv_page);
			bvec_kunmap_irq(data, &flags);
		}
	}

out:
	DbgMsg("dcrypt_endio-1 : %d\n", status);
//	bio_put(clone);
	dcrypt_complete_io(io, status);
	
}

static void dcrypt_do_io(dc_io *io, char *buff, u32 size)
{
	dc_dev     *dc  = io->target->private;
	struct bio *bio = io->base_io;
	struct bio *clone;
	sector_t    sector = bio->bi_sector + io->target->begin;
	struct request_queue *q = bdev_get_queue(dc->orig_dev->bdev);
	
	clone = bio_map_kern(q, buff, size, GFP_NOIO);		
	if (IS_ERR(clone)) {
		DbgMsg("clone is not mapped\n");
		dcrypt_io_complete(io, -ENOMEM);
		return;
	}
	
	clone->bi_private = io;
	clone->bi_end_io  = dcrypt_endio;
	clone->bi_bdev    = dc->orig_dev->bdev;
	clone->bi_rw      = bio->bi_rw;

	clone->bi_sector = DC_AREA_SIZE + sector;

	DbgMsg("dcrypt_do_io %x\n", clone);
	generic_make_request(clone); 
}
Если раскомментировать bio_put(clone), то система падает. Кто-нибудь с этим сталкивался? Ядро 2.6.27, Ubuntu.

ntldr
()

Block device driver

Форум — Development

Привет всем!

Есть задача изготовления драйвера блочного устройства. В нём нужно делать I/O к другим дископодобным девайсам ... Гуглил, читал LDD, LDD3 ... но видимо что-то всё равно упускаю ...

Есть тут кто имеет предметный опыт написания ? В качестве первого вопроса: после инсталляции модуля в dmesg появляется «cut -here» секция, что это означает ? Что-то пошло не так, или это информационный блок ?

root@sysman:/home/sysman/Works/vCloud/block# insmod dudriver.ko
root@sysman:/home/sysman/Works/vCloud/block# 

[ 4174.458121] DUDRIVER: Initialize the driver ...
[ 4174.458123] [DUDRIVER:458] : Assigned major = 252
[ 4174.458125] [DUDRIVER:367] : [ffff97cb191ebf60] Begin setup device, mode = 0 ...
[ 4174.458238] blk_queue_max_segment_size: set to minimum 4096
[ 4174.458240] [DUDRIVER:388] : [ffff97cb191ebf60] Opening ...
[ 4174.458253] [DUDRIVER:402] : [ffff97cb191ebf60] Opened, iodevfp = ffff97cab93aef00.
[ 4174.458257] [DUDRIVER:425] : [ffff97cb191ebf60] disk_name = dua, iobuf = ffff97cace83cc00


[ 4174.458259] ------------[ cut here ]------------
[ 4174.458265] WARNING: CPU: 2 PID: 5049 at /build/linux-hwe-0vY49E/linux-hwe-4.10.0/block/genhd.c:596 device_add_disk+0x2cf/0x480
[ 4174.458266] Modules linked in: dudriver(OE+) vboxsf(OE) vboxvideo(OE) crct10dif_pclmul crc32_pclmul joydev ghash_clmulni_intel ttm drm_kms_helper drm fb_sys_fops syscopyarea sysfillrect vboxguest(OE) sysimgblt pcbc input_leds mac_hid serio_raw aesni_intel aes_x86_64 crypto_simd glue_helper i2c_piix4 cryptd intel_rapl_perf parport_pc ppdev lp parport autofs4 hid_generic usbhid hid fjes psmouse ahci e1000 libahci video
[ 4174.458283] CPU: 2 PID: 5049 Comm: insmod Tainted: G           OE   4.10.0-42-generic #46~16.04.1-Ubuntu
[ 4174.458284] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
[ 4174.458285] Call Trace:
[ 4174.458290]  dump_stack+0x63/0x90
[ 4174.458293]  __warn+0xcb/0xf0
[ 4174.458294]  warn_slowpath_null+0x1d/0x20
[ 4174.458295]  device_add_disk+0x2cf/0x480
[ 4174.458298]  dua_init+0x2dd/0x1000 [dudriver]
[ 4174.458299]  ? 0xffffffffc033d000
[ 4174.458302]  do_one_initcall+0x53/0x1c0
[ 4174.458306]  ? kmem_cache_alloc_trace+0x152/0x1c0
[ 4174.458308]  do_init_module+0x5f/0x1ff
[ 4174.458311]  load_module+0x1825/0x1bf0
[ 4174.458312]  ? __symbol_put+0x60/0x60
[ 4174.458315]  ? ima_post_read_file+0x7d/0xa0
[ 4174.458319]  ? security_kernel_post_read_file+0x6b/0x80
[ 4174.458320]  SYSC_finit_module+0xdf/0x110
[ 4174.458321]  SyS_finit_module+0xe/0x10
[ 4174.458327]  entry_SYSCALL_64_fastpath+0x1e/0xad
[ 4174.458328] RIP: 0033:0x7fda77b60499
[ 4174.458329] RSP: 002b:00007ffe49df7778 EFLAGS: 00000206 ORIG_RAX: 0000000000000139
[ 4174.458330] RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007fda77b60499
[ 4174.458331] RDX: 0000000000000000 RSI: 0000563ba88dc26b RDI: 0000000000000003
[ 4174.458331] RBP: 00007ffe49df6730 R08: 0000000000000000 R09: 00007fda77e25ea0
[ 4174.458332] R10: 0000000000000003 R11: 0000000000000206 R12: 000000000000006a
[ 4174.458332] R13: 0000563ba92261d0 R14: 0000563ba9226130 R15: 00007ffe49df65fc
[ 4174.458333] ---[ end trace 9676674954dab3b5 ]---
[ 4174.459946] [DUDRIVER:434] : [ffff97cb191ebf60] setup device end (dua)
[ 4174.459947] DUDRIVER: End the driver initialization.
root@sysman:/home/sysman/Works/vCloud/block# 

Следующая проблема связана с I/O из модуля, похоже что нет возврата из vfs_read/vfs_write , сужу по dmesg, не выходим на «Checking read/write status».

/**
 * @brief xfer	- Handle an I/O request.
 *
 * @param dcb	- device context block
 *
 * @param lbn	- Logical Block Number
 * @param bcnt	- a length of the data in the I/O buffer
 * @param buff	- I/O buffer
 * @param iodir	- I/O direction: 0 - READ, 1 - WRITE
 *
 * @return	- 0 > : bytes count has beed read/wrote
 *		- 0 <= errno
 */
static int xfer		(
		DRIVER_CTX *	dctx,
		sector_t	lbn,
		size_t	 	bcnt,
		char *		iobuf,
		int		iodir
				)
{
loff_t	pos = lbn * DUDRV$K_BLKSZ;
size_t	status64 = bcnt;
mm_segment_t	old_fs;

	$TRACE( ": [%p] Start I/O : iodevfp=%p lbn=%lu bcnt=%lu iobuf=%p iodir=%d", dctx, dctx->iodevfp, lbn, bcnt, iobuf, iodir);

	if ( !dctx || !dctx->iodevfp )
		{
		printk(KERN_ERR  __MODULE__ ": [%p] %s(%p) -> EIO\n", dctx,
			iodir == WRITE ? "write" : "read", dctx->iodevfp);
		return	-EIO;
		}

	if ( iodir == WRITE )
		copy_to_user (dctx->iobuf, iobuf, DUDRV$K_BLKSZ);

	old_fs = get_fs();
	set_fs(get_ds());

	if ( iodir == WRITE )
		status64 = vfs_write(dctx->iodevfp, dctx->iobuf, bcnt, &pos);
	else	status64 = vfs_read(dctx->iodevfp, dctx->iobuf, bcnt, &pos);

	set_fs( old_fs );

	$TRACE("Checking read/write status = %ld ...", status64);

	if ( bcnt != status64 )
		printk(KERN_ERR  __MODULE__ ": [%p] %s(%p, %lu octets, pos = %llu) -> %lu\n", dctx,
		       iodir == WRITE ? "write" : "read", dctx->iodevfp, bcnt, pos, status64);

	if ( iodir == READ )
		copy_from_user (iobuf, dctx->iobuf, DUDRV$K_BLKSZ);

	$TRACE( ": [%p] End I/O : pos=%llu bcnt=%lu iobuf=%p iodir=%d, status = %ld", dctx, pos, bcnt, iobuf, iodir, status64);

	return	status64;
}

Буду благодарен за любую помощь.

 , , , ,

SysMan
()