LINUX.ORG.RU

как лучше всего добавить per-process переменную?

 


0

2

через хак с /procfs/self/myfoo, через новое поле в task_struct или как-то еще?

диспозиция такова: есть 2 модуля ядерных, и оба нуждаются в per-process структуре. один создает такую на первом открытии /dev/apu и удаляет когда все файлы /dev/apu которые он открыл(открыть можно много раз), закрыты.

другой вообще занимается сеткой. его можно было бы сделать как security-модуль, но тогда он будет конфликтовать с каким нибудь app-armor(указатель в task-struct один на все модули).

каждому надо уметь присобачить к текущему процессу свою структуру, если таковой нет, иначе взять имеющуюся. операция может происходить довольно часто - особенно для второго модуля, который связан с сетью, поэтому хотелось бы иметь некривой способ добиться искомого результата.

статическую rb-tree с мутексом хотелось бы избежать.

почему-то запостился ненабраный псто.

☆☆☆

Последнее исправление: ckotinko (всего исправлений: 3)

Зря отредактировал. Такой многообещаюший и философский пост был...

geekless ★★
()
Ответ на: комментарий от geekless

чтоб один процесс не открыл много /dev/apu( а это интерфейс к GPU ) а открыл только один(пусть много раз) и мы могли бы его шедулить. второе - надо все равно как-то создать файл /proc/self/apu - просто для управления и статистики.

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от ckotinko

чтоб один процесс не открыл много /dev/apu

Это можно сделать, поместив в дескриптор открытого устройства PID открывшего процесса.

tailgunner ★★★★★
()
Ответ на: Не распарсил от ttnl

Нельзя так жестко насиловать русский язык

+1

Я постановку задачи так и не осилил понять.

geekless ★★
()
Последнее исправление: geekless (всего исправлений: 1)
Ответ на: комментарий от tailgunner

ок.

int apu_open(struct inode * pNode, struct file * pFile)
{
    //ок, как мне это сделать тут?
}

static struct file_operations apu_file_operations={
	.owner=THIS_MODULE,
	.open=apu_open,
	.release=apu_release,
	.flush=apu_flush,
	.poll=apu_poll,
	.read=apu_read,
	.write=apu_write,
	.mmap=apu_mmap
};

int module_init()
{
   ....blahblahblah....;

   cdev_init(g_apu_cdev, &apu_file_operations);

   ....blahblahblah....;
}
ckotinko ☆☆☆
() автор топика
Ответ на: ок. от ckotinko

Если предполагать, что у тебя struct cdev встроена в дескриптор устройства, я бы начал делать с такого варианта:

#define DEVICE_FROM_INODE(i) container_of((i)->i_cdev, struct apu_device, cdev)

int apu_open(struct inode *inode, struct file *file)
{
    struct apu_device *apu = DEVICE_FROM_INODE(inode);

    if (apu == NULL) {
        /* ОК, первое открытие */
    }
    if (apu->opener == current) {
        /* ОК, это повторное открытие */
    }
    else
        err = -EBUSY;
    return ret;
}

Здесь предполагается, что дескриптор APU имеет примерно такой вид:

struct apu_device {
    /* ... */
    struct cdev cdev; /* встроенный cdev */
    /* ... */
    struct task *opener;
};

cdev_init вызывается на apu_device::cdev

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

вот в том-то и проблема, что inode у всех процессов один. и cdev - статическая переменная. предполагается, что они будут просто открывать /dev/apu «не думая» и получать opengl оттуда.

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от ckotinko

inode у всех процессов один.

Ну да. Решение полагается на это.

и cdev - статическая переменная

Я надеюсь, ты хотел сказать «глобальная», даже если ты не собираешься поддерживать более одного APU.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Ну да. Глобальная

static struct cdev_t   g_apu_cdev 		= { .owner=NULL };
gpu может быть много - это просто интерфейс. процессов может быть много. но /dev/apu - ровно один и поэтому у него и inode будет один на всю систему.

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от ckotinko

gpu может быть много [...] но /dev/apu - ровно один

У тебя должно быть минимум по одному device node на каждый APU: /dev/apu0, /dev/apu1 и т.д.

static struct cdev_t g_apu_cdev = { .owner=NULL };

struct cdev должна быть в каждом дескрипторе устройства.

То есть ты наверняка можешь сделать всё именно так, как хочешь: с одним device node на всех и static g_apu_cdev, но всё в ядре будет стараться тебе помешать.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

мне нужно не 1apu/1device, а 1структура/1процесс. более того, я хочу, чтоб эту структуру нельзя было угнать у процесса.

можно это сделать через procfs(proc_create_entry(«self/apu»...)) но в procfs какое-то стремное API

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от tailgunner

так проблема в том, что процесс может открыть файл много раз. а мне надо чтоб один раз открыл только. чтоб он не спамил.

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от ckotinko

так проблема в том, что процесс может открыть файл много раз. а мне надо чтоб один раз открыл только.

По-моему, ты и сам еще не решил, что тебе нужно:

ckotinko> а открыл только один(пусть много раз)

Впрочем, ЕМНИП, для single-open device в ядре уже и готовая функция есть.

tailgunner ★★★★★
()

А void *private_data у struct file не получится использовать для хранения?

Или ту же private_data у vm_area_struct. Добавлять новую vm_area_struct к процессу при открытии устройства. Или использовать уже имеющуюся, если устройство было открыто.

Не очень хорошо представляю, как оно там работает на самом деле, но наверное struct file будет не per-process, а шариться между несколькими.

А вот vm_area_struct вроде как можно сделать более per-process.

kike
()
Ответ на: комментарий от kike

решил проблему вот так:

int apu_open(struct inode * pNode, struct file * pFile)
{
	struct proc_dir_entry    * pde;
	struct PerProcessContext * pCtx;

	//initialize private_data to zero
	pFile->private_data=NULL;
	
	//try to allocate empty context
	pCtx=(struct PerProcessContext *)vmalloc(sizeof(struct PerProcessContext));
	if(pCtx != NULL)
	{		
		pde = proc_create_data("self/apu", 
							   S_IRUSR|S_IWUSR, 
							   NULL,
							   &apu_monitor_operations,
							   pCtx);
		if(pde != NULL) // we cannot detect 'in-use' situation.. :(
		{
			//initialize context
			....
			
			atomic_set(&pCtx->refcount, /*referenced by pFile and pde*/ 2);
			pFile->private_data=pCtx;
			
			return 0;
		}
		vfree(pCtx);
	}
	return -ENOMEM;	
}
int apu_release(struct inode * pNode, struct file * pFile)
{
	struct PerProcessContext * pCtx=(struct PerProcessContext *)pFile->private_data;
	if(pCtx != NULL)
	{
		remove_proc_entry("self/apu", NULL);
		pFile->private_data=NULL;
		
		if(atomic_dec_and_test(&pCtx->refcount))
		{
			//deinitialize context
			...
			
			vfree(pCtx);
		}
	}
	return 0;
}
ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от kike

может. но тут нам уже пофигу. главное, чтоб она была одна: чтоб нельзя было обмануть планировщик GPU, создав много контекстов и закидав ими GPU.

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от ckotinko

главное, чтоб она была одна

Я ничего не понимаю. Вам per-process структуру, per-file или просто одну структуру на всех?

kike
()
Ответ на: комментарий от kike

per-process. причем жестко привязанную к создателю. чтоб можно было сделать ему xkill и отобрать все ресурсы

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от kike

кстати, код выше - полное решето. если кто надумает делать что-то похожее, пишите я пришлю правильный код. это чтоб никто не скопипастил бездумно.

ckotinko ☆☆☆
() автор топика
Ответ на: комментарий от ckotinko

жестко привязанную к создателю

Создатель это тот, кто открывает файл, я правильно понял? Если теперь создатель форкнется, и помрёт, у child тоже отберутся ресурсы?

kike
()

статическую rb-tree с мутексом хотелось бы избежать.

Кстати, почему?

kike
()

Если всё же решил извратиться с per-process, наверное ничего лучше, чем использовать свою vm_area_struct не придумать.

Её определение: http://lxr.free-electrons.com/source/include/linux/mm_types.h#L227

Как примерно использовать: http://lxr.free-electrons.com/source/mm/mmap.c#L2498

И вообще, посмотреть все места, откуда дёргается insert_vm_struct: http://lxr.free-electrons.com/ident?i=insert_vm_struct

Посмотреть на определение vm_operations_struct: http://lxr.free-electrons.com/source/include/linux/mm.h#L205 и узнать зачем они нужны и когда вызываются. Может пригодятся.

Для того, чтобы искать у процесса нашу VMA можно в private data засунуть указатель на какую-нибудь magic-переменную модуля.

kike
()

Кстати, забей на предыдущее сообщение. Эти функции не экспортируются.

kike
()

Хотя kallsyms_lookup_name ещё никто не отменял...

kike
()
Ответ на: комментарий от kike

у child тоже отберутся ресурсы

child их даже не увидит. т.е. он будет только получать EPERM на все обращения к дескриптору, кроме close(2).

это связано с тем, что современные видяхи поддерживают preemption, и поэтому надо добиться ситуации 1контекст/1процесс полюбому - иначе это решето. при этом сам контекст - не относится к рисованию, только к ресурсам. per-thread контекстов может быть много и строго говоря, для AMD карт в ядре вообще про них ничего знать не надо. NVidia может быть их потребует. Штеуд скорее всего потребует точно.

ckotinko ☆☆☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.