Динамический массив в модуле ядра Linux - PullRequest
0 голосов
/ 17 мая 2011

Я работаю над модификацией PKTGEN для отправки пакетов, содержащих последовательности серии Фибоначчи.Это мой первый раз в разработке ядра, поэтому я не очень хорошо знаком с доступными функциями для распределения памяти.Я также не гуру C:)

Я храню итерационные шаги алгоритма в массиве, который я хотел бы быть динамическим, если кто-то запрашивает отличный параметр Фибоначчи n.Realloc не доступен.Вы знаете способ динамического увеличения размера массива?

Спасибо

Ответы [ 2 ]

3 голосов
/ 02 мая 2013

См. Гибкие массивы Дэйва Хансена, добавленные к 2.6.31-rc5

https://lwn.net/Articles/345273/

Создание гибкого массива выполняется с помощью:

#include <linux/flex_array.h>

struct flex_array *flex_array_alloc(int element_size, int total, gfp_t flags);

Размер отдельного объекта предоставляется element_size, а total - это максимальное количество объектов, которое может храниться в массиве. Аргумент flags передается непосредственно вызовам выделения внутренней памяти. В текущем коде использование флагов для запроса большого объема памяти может привести к особенно неприятным побочным эффектам.

Сохранение данных в гибкий массив выполняется с помощью вызова:

int flex_array_put(struct flex_array *array, int element_nr, void *src, gfp_t flags);

Этот вызов скопирует данные из src в массив в позиции, указанной element_nr (которая должна быть меньше максимальной, указанной при создании массива). Если какие-либо выделения памяти должны быть выполнены, будут использоваться флаги. Возвращаемое значение равно нулю в случае успеха, в противном случае - отрицательный код ошибки.

Возможно, может потребоваться сохранение данных в гибком массиве при работе в некотором атомарном контексте; в этой ситуации спать в распределителе памяти было бы плохо. Этого можно избежать, используя GFP_ATOMIC для значения флагов, но часто есть лучший способ. Хитрость заключается в том, чтобы убедиться, что все необходимые выделения памяти сделаны перед входом в атомарный контекст, используя:

int flex_array_prealloc(struct flex_array *array, int start, int end, gfp_t flags);

Эта функция обеспечит выделение памяти для элементов, проиндексированных в диапазоне, определенном параметрами start и end. После этого вызов flex_array_put () для элемента в этом диапазоне гарантированно не блокируется.

Получение данных из массива выполняется с помощью:

void *flex_array_get(struct flex_array *fa, int element_nr);

Возвращаемое значение - указатель на элемент данных или NULL, если этот конкретный элемент никогда не был выделен.

Обратите внимание, что можно получить верный указатель на элемент, который никогда не сохранялся в массиве. Память для элементов массива выделяется по одной странице за раз; одиночное распределение может обеспечить память для нескольких смежных элементов. Код гибкого массива не знает, был ли записан конкретный элемент; он только знает, присутствует ли связанная память. Таким образом, вызов flex_array_get () для элемента, который никогда не был сохранен в массиве, может вернуть указатель на случайные данные. Если у вызывающей стороны нет отдельного способа узнать, какие элементы на самом деле были сохранены, было бы целесообразно, по крайней мере, добавить GFP_ZERO в аргумент flags, чтобы гарантировать, что все элементы обнуляются.

Нет способа удалить отдельный элемент из массива. Однако можно удалить все элементы с помощью вызова:

void flex_array_free_parts(struct flex_array *array);

Этот вызов освобождает все элементы, но оставляет сам массив на месте. Освобождение всего массива выполняется с помощью:

void flex_array_free(struct flex_array *array);

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

1 голос
/ 18 мая 2011

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

Однако способ сделать это - реализовать собственный массив динамической длины . Отследите, насколько большой массив. Если необходимо увеличить, вызовите kmalloc() (обычно с параметром GFP_KERNEL) с новым размером, скопируйте старые данные в новый и утилизируйте старый (kfree()). Смотрите заголовочный файл ядра

Если массив будет больше, чем примерно 4K или 8K, рассмотрите возможность использования __get_free_pages() или vmalloc().

kmalloc () и kfree () находятся в linux-2.X.XX.XX/include/linux/slob_def.h
__get_free_pages () находится в linux-2.X.XX.XX/include/linux/gfp.h
vmalloc () находится в linux-2.X.XX.XX/include/linux/vmalloc.h

...