LINUX.ORG.RU

Выделение памяти в модуле.


0

0

Заранее прошу прощения за назойливость ;)

Вообщем имеется модуль, в нём создаётся устройство, которое далее создаётся

mknod /dev/netfw c 252 0

В модуле есть такой код:

/*******************************************************************************
********************************/

//................. for IO at dev ....................//
int step, n_par, n_arg, n, par_accept;

char **par, **arg;
char *to_table;
int id, it, num, act;
//..........................................................//

int netfw_add_rule(char *table_name, int id, int it, char **par, char **arg, int num)
{
	int i;
	for(i = 0; i < num; i++){
		if(par[i]) kfree(par[i]);
		if(arg[i]) kfree(arg[i]);
	}

	printk( KERN_DEBUG "NetFW: Rule was add successfull\n");

	return 1;
}

//функция записи
ssize_t netfw_write (struct file *f, const char *ch, size_t size, loff_t *loff)
{
	if(num > 0)if(n < num*2)
	{
		if(par_accept)
		{
			par[n_par] = kmalloc((sizeof(char) * strlen(ch)) + 1,GFP_ATOMIC);
			if(!par[n_par]) return 0;
			par[n_par] = strcpy(par[n_par],ch);
			printk("par[%d] = %s, ch = %s\n",n_par,par[n_par],ch);	//Тестовый вывод тут
			par_accept = 0;
			n_par++;
		}
		else
		{
			arg[n_arg] = kmalloc((sizeof(char) * strlen(ch)) + 1,GFP_ATOMIC);
			if(!arg[n_arg]) return 0;
			arg[n_arg] = strcpy(arg[n_arg],ch);
			printk("arg[%d] = %s, ch = %s\n",n_arg,arg[n_arg],ch);	//И тут тоже вывод
			par_accept = 1;
			n_arg++;
		}
		n++;
	}
	if(!strcmp(ch,"$"))
	{
		step = -1;
		n = n_par = n_arg = 0;
		if(act > 0)
		{
			switch(act)
			{
				case NETFW_ADD_RULE:
					/*if(*/netfw_add_rule(to_table,0,it,par,arg,num)/*)*/;
					       break;
				...
			}
		}
		if(par) kfree(par);
		if(arg) kfree(arg);
		if(to_table) kfree(to_table);
		to_table = 0;
		num = 0;
	}
	step++;
	switch(step)
	{
		//Action
		case 1:
			if(!strcmp(ch,"add"))
			{
				act = NETFW_ADD_RULE;
			}
			if(!strcmp(ch,"del"))
			{
				act = NETFW_DEL_RULE;
			}
			if(!strcmp(ch,"policy"))
			{
				act = NETFW_SET_POL;
			}
			if(!strcmp(ch,"show"))
			{
				act = NETFW_SHOW_RULE;
			}
			break;
		//Table name
		case 2:
			to_table = kmalloc(sizeof(char[strlen(ch)]),GFP_ATOMIC);
			if(!to_table) return 0;
			to_table = strcpy(to_table,ch);
			break;
		//What to do ( aka "it" )
		case 3:
			if(!strcmp(ch,"accept"))
			{
				it = NETFW_ACCEPT;
			}
			if(!strcmp(ch,"drop"))
			{
				it = NETFW_DROP;
			}
			break;
		//Num of elements
		case 4:
			num = netfw_char_to_int((char*)ch);	//эта функция конвертит char* в int
											//работает одназначно и правильно :)
			par = kmalloc((sizeof(char *) * num),GFP_ATOMIC);
			if(!par) return 0;
			arg = kmalloc((sizeof(char *) * num),GFP_ATOMIC);
			if(!arg) return 0;
			par_accept = 1;
			break;
	}

	return 0;
}

/*******************************************************************************
********************************/

Используется это из приложения-интерфейса.

/************************************** user-space-app.c **************************************************/
char *num;

int main(int argc, char *argv[])
{
	int fd;
	char *end = "$";

	//this is dev for netfw control
	fd = open("/dev/netfw", O_RDWR);
	if(fd == -1){
		printf("open failed\n");
		return -1;
	}
	printf("Device netfw open\nTry to write\n");

	//calc num of parametrs like: from, to, fport, tport
	int ap = argc - 1 - 3;
	printf("ap = %d\n",ap);	//check it
	int i;
	//write control element like: add/del, pass/drop and name of table
	printf("argc = %d\n",argc);	//check it
	if(!argv[1]){
		printf("write 1$\n");
		write(fd,end,sizeof(end));
		return 0;
	}
	else write(fd, argv[1], sizeof(argv[1]));
	if(!argv[2]){
		printf("wrte 2$\n");
		write(fd,end,sizeof(end));
		return 0;
	}
	else write(fd, argv[2], sizeof(argv[2]));
	if(!argv[3]){
		printf("write 3$\n");
		write(fd,end,sizeof(end));
		return 0;
	}
	else write(fd, argv[3], sizeof(argv[3]));
	if(ap > 0){
		//write num of parametrs
		int_to_char(ap/2);	//эта функция конвертит int в char*
						//так же работает одназначно и без ошибок
						//устанавливает глобальную переменную char *num
		write(fd, num, sizeof(num));
	
		//write parametrs
		for(i = argc - ap; i < argc; i++)
		{
			printf(argv[i]);
			printf("\n");
			write(fd, argv[i], sizeof(argv[i]));
		}
	}
	//write symbol to finish transacton, in this case it's "$"
	printf("write 4$\n");
	write(fd,end,sizeof(end));
	
	//close file
	close(fd);
	printf("Device netfw close\n");

	return 0;
}

/*******************************************************************************
*********************************/

Вообщем запись работает по принципу конвеера и заканчивается с записью символа "$".

А суть проблеммы такая, при попытке в третий раз записать блок данных, в массивах
char **par и char **arg начинает появлятся мусор

(выглядит примерно так)
//первая запись
par[0] = from, ch = from
arg[0] = 127.0.0.1, ch = 127.0.0.1
NetFW: Rule was add successfull
//вторая запись
//Дальше идёт мусор
par[0] = , ch = from
arg[0] = -0.0.1, ch = 127.0.0.1
NetFW: Rule was add successfull
//третья запись
par[0] = J=, ch = from
arg[0] = .50.0.1, ch = 127.0.0.1
NetFW: Rule was add successfull

и при последующих действиях,
таких как выгрузка модуля или если попытаться что то cat'нуть /var/log/messages, а
иногда и просто так.. вообщем всё виснет. Как я понимаю проблемма в том что
где то не очищается память или что то похожее.

Может помочь опознать ошибку в функции записи ssize_t netfw_write () в модуле, 
как полагаю это именно там.

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

как оно у тебя вообще работает не понятно...
write(fd, num, sizeof(num));
это ты поинтер пытаешся туда записать или sizeof c strlen перепутал?

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

То где sizeof, так это там вааще ноль можно поставить, поскольку не пользую третий аргумент.

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

ого, а как его можно не использовать?
вот обявление (see write(3)):
ssize_t
write(int d, const void *buf, size_t nbytes);
т.е. ты из своего буфера, num, argv[i] и т.д.,
записываешь ровно 4 байта - sizeof(char*).

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

Да неее.. ты не понял :) Если ты посмотриш функцию write которая определена в моём модуле то увидешь что переменная nbytes там не учитывается! (просто пока проблемма не в этом вот и не исправил)

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

когда ты зовешь write зовется не тот самый SYS_write, а ф-я из libc, в которой параметр nbytes проверяется. К тому же в ядре пока дело дойдет до вызова твоей ф-ии на этот параметр еще несколько раз посмотрят...
И еще если ты все-таки передаешь в ядро строку, то почему не вызываешь copy_from_user, а используешь просто strcpy перед использованием данных из буфера?

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

> И еще если ты все-таки передаешь в ядро строку, то почему не вызываешь copy_from_user, а используешь просто strcpy перед использованием данных из

т.е. ты хочешь сказать что просто strcpy не прокатывает и надо юзать именно copy_from_user?

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

Вообщем заюзал вместо strcpy функцию copy_from_user, мусор вроде перестал набираться, но как и прежде, после трёх вызовов моей апликухи (та что приведена выше) вылетает сегфолт. А по логу видно что строка выводящая par[n_par] выводит пустой элемент, т.е. как будто там нет данных, но при этом копируется пустота. Хочу заметить что именно после трёх вызовов.

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

> Вообщем заюзал вместо strcpy функцию copy_from_user, мусор вроде перестал набираться, но как и прежде, после трёх вызовов моей апликухи (та что приведена выше) вылетает сегфолт. А по логу видно что строка выводящая par[n_par] выводит пустой элемент, т.е. как будто там нет данных, но при этом копируется пустота. Хочу заметить что именно после трёх вызовов.

Бох троицу любит :>

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

Ну то что он любит троицу это понятно, но всё же не понятно, почему случается такая дрянь.

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