LINUX.ORG.RU

Разработка модуля очереди сообщений с помощью procfs

 ,


0

1

Доброго времени суток, ЛОР. Пишу модуль для очереди сообщений, используя procfs. Сначала при попытке записи в память у меня одуль зависал, потом я исправил чуть чуть код и когда делал pop (cat), то у меня выводился весь файл, потом я понял свою ошибку, что функция pop возвращала у меня неверное значение, исправил, и теперь у меня на cat не выводится ничего, зато, очередь, вроде как, правильно отрабатывает, то есть я сделал push (echo) 4 раза и 5 раз pop (cat) и в dmesg один раз написано, что очередь пуста. Прошу помощи, так как занимаюсь таким впервые. Прошу прощения за возможный тупняк. Заранее благодарю.

Ссылка на код: Тык.


Ну, во-первых, насколько я помню, операции над procfs сами по себе не защищены блокировками, поэтому весь твой код это один большой race condition.

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

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

tgwt ()

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

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

если я возвращаю длину сообщения, то cat выводит весь файл, а мне нужно, чтобы cat выводил только одно сообщение

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

Файл это поток байт. Там нет разделения на сообщения. Если ты начинаешь мухлевать с реализацией это концепции, всё начинает разъезжаться, и ни о какой надёжности работы речи быть не может. Если тебе нужны сообщения, упакованные именно в поток, изобрети свой вариант tag-length-value.

Возможно, тебе стоит использовать netlink, а не файл в /proc.

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

да это, скорее-всего, стандартная домашка (например, от Auriga)

2 tgwt: read будет долбиться до тех пока не получит код ошибки или конца файла. вот пример решения: https://pastebin.com/gqY5z2mN

metawishmaster ★★★★ ()
Последнее исправление: metawishmaster (всего исправлений: 2)

Я, конечно, давно в ядро не залезал, но мне кажется, что тут лучше создать девайс в /dev, либо работать с netlink.

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

А можно пример какого нибудь решения? Что то не могу найти в гугле пример с девайсом в /dev, с netlink сижу разбираюсь, но еще не понимаю до конца ничего.

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

Ну тогда иди читай про то, как устроено ядро, как работают сисколы, как procfs натягивается на абстракцию файла. И заодно почитай про <kernel/list.h>, потому что то, что ты тут делаешь, это оно. Заодно почитай про RCU, скорее всего, оно тебе здесь пригодится. Есть хорошая (хоть и старая) книжка Linux Kernel Development. И вот это https://www.kernel.org/doc/html/latest/process/howto.html.

P.S. И почитай уже про linux kernel coding style, и следуй ему, позязя.

P.P.S. В современных трендах лялекса вынести из procfs все, что там быть не должно.

kirk_johnson ★☆ ()
Последнее исправление: kirk_johnson (всего исправлений: 2)
Ответ на: комментарий от tgwt

да не за что, еще нужно за собой память-таки подчищать в случае когда не все считал из своего lkm_queue

static void __exit lkm_example_exit(void)
{
	message_item *tmp;

	while (queue.front) {
		tmp = queue.front;
		queue.front = queue.front->next;
		kfree(tmp);
	}
	printk(KERN_INFO "End of message queue linux kernel module...\n");
	remove_proc_entry(PROC_ENTRY_FILENAME, NULL);
}


ну и соблюдать «культуру кода» ядра :)

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

Обычно такие вещи, как «подчищать память» забываю, и делаю в конце. А про кодинг стайл посмотрел уже, я просто не переношу открывающие скобки на той же строке, но буду следовать, раз надо :)

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

с _этим_ во всем юзерспейсе полегче, а вот в ядре вроде нет механизма сбора «потерянной» памяти, хотя, может я отстал от жихни, но пять лет назад такого не было %)

а вот практика оставления мусора ведет к более частым перезагрузкам девелоперской машины

поэтому если на каждый alloc будет соответствующий free, жизнь станет легче, а волосы шелковистее %)

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

Нет, лол. Рефкаунтинг в C выглядит так:


struct some_stuff *st = make_new_stuff(...);

...

kref_get(&st->ref); /* ref == 2 */

...

kref_put(&st->ref, st_remove_this_shit); /* ref == 1 */

...

kref_put(&st->ref, st_remove_this_shit); /* st_remove_this_shit called */ 

Это тот же malloc/free, просто на стероидах.

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

мне шо-то подумалось, что malloc => mmap => sys_mmap => get_page => kref*... но вроде как эта проблема по-другому решается

// а вот чтобы kmalloc дергал kref* я не увидел... соответственно, и память не возвращается, что подтверждается экпериметом - уже часа два +/- одно и то же

              total        used        free      shared  buff/cache   available
Mem:        8044464     7581256      329168       46484      134040      134784
Swap:             0           0           0

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

Я не понимаю, что ты несешь, если быть совсем уж честным. Плюсы имеют концепцию скоупа и перегрузок операторов, за счет чего на умных указателях можно нафигачить что-то похожее на то, что было в перле. В C такого нет, поэтому все всегда сводится к ручному указанию 'выдели/освободи' или 'выдели, а потом инкрементируй/декрементируй рефы, чтобы в конце концов освободить'.

P.S. Однако для тех, кому плюсы не милы, раст слишком коряв, а go слишком медленный, придумали gcc расширение для автоматической деиницилизации. Насколько дико это ввглядит можно найти в сырцах systemd.

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

да мы о разном говорим, когда я сказал «с _этим_ во всем юзерспейсе полегче» - я имел в виду ту проблему, которая возникала у ТС (не чистил память при выходе). Если не чистить память после malloc'ов при выходе в юзерспейсе, то ее все-равно подчистит система. В ядре после kmalloc такого нет.

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

Если не чистить память после malloc'ов

То твоя программа рано или поздно сожрет всю память или свалится с oom. Глобальные структуры, которые чистить не нужно, потому что ядро само справится, есть и в ядре. Потому что когда ядро завершает работу, то тебе уже пофиг на содержимое виртуальных таблиц :)

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


copy_to_user возвращает код ошибки


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

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