Доступ к данным из файла proc в модуле ядра
Мне нужно получить доступ к некоторым файлам proc в модуле на ядре Android. В основном мне нужна информация, показанная в команде cat, например cat /proc/uptime
, Однако мне нужно сделать это программно.
Я пробовал работать с proc_fs
функций, но для меня это было немного нечетко, обычно примеры - создать файл proc, затем прочитать его и все. Мне действительно нужно использовать данные из файлов proc.
Я тоже тред хороший fopen
, но, похоже, не работает на модулях.
Как я могу это сделать? Я действительно новичок в этом. Я работаю над ядром Android в виде золотой рыбки.
Благодарю.
3 ответа
Procfs - это файловая система в памяти. Это интерфейс для пользовательского пространства для извлечения информации и помещения (конфигурации) информации в структуры данных ядра. Другими словами, procfs позволяет пользователям взаимодействовать и просматривать структуры данных ядра так, как они существуют во время выполнения.
Следовательно, любой файл внутри / proc не предназначен для чтения изнутри ядра или модуля ядра. И зачем это делать? В монолитном ядре, таком как Linux, вы можете получить доступ к структурам данных одной подсистемы в ядре через другую напрямую или через предопределенную функцию.
Следующий вызов функции может помочь:
struct timespec uptime;
do_posix_clock_monotonic_gettime(&uptime);
Вы можете обратиться к реализации / proc / uptime по ссылке ниже, это по сути seq_file
,
Я отвечаю на исходный вопрос: как модуль ядра может получить доступ к файлам в формате.
Как модуль ядра получает доступ к файлам в специальных файловых системах
Я нашел следующее полезным справочником:https://elixir.bootlin.com/linux/latest/source/fs/proc/proc_sysctl.c#L1790
Я думаю, это настройка
sysctl
значения из командной строки ядра. Последовательность выглядит следующим образом:
A. Смонтируйте файловую систему
-
proc_fs_type = get_fs_type("proc");
-
*proc_mnt = kern_mount(proc_fs_type);
Б. Откройте файл по пути относительно корня procfs.
-
file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);
C. Чтение / запись файла
-
int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id)
-
wret = kernel_write(file, val, len, &pos);
D. Закройте файл
-
err = filp_close(file, NULL);
D. Очистка монтирования файловой системы
-
kern_unmount(proc_mnt);
-
put_filesystem(proc_fs_type);
Должен ли модуль ядра обращаться к файлам в специальных файловых системах
Да, в основном предоставляет пользовательскому пространству доступ для чтения / записи к данным уровня ядра. Поскольку модуль ядра работает в ядре, если существует более прямая последовательность вызовов API, которая позволяет модулю получать доступ к таким данным, использование такого API было бы предпочтительным, поскольку он, вероятно, намного чище, меньше кода и более эффективен.
Однако динамически загружаемый модуль ядра не имеет (чистого) прямого доступа ко всем символам (или структурам данных) в ядре.
Модуль ядра может обращаться только к функциям и переменным, которые
полностью определяется в файле заголовка, который может быть включен в исходный код модуля ядра
или явно доступны модулям ядра через один из макросов в
/include/asm-generic/export.h
:-
EXPORT_SYMBOL
-
EXPORT_SYMBOL_GPL
-
EXPORT_DATA_SYMBOL
-
EXPORT_DATA_SYMBOL_GPL
-
Случаи, когда модулю ядра требуется доступ к данным, которые не отображаются через такие
EXPORTED
API, но доступный через файлы в
procfs
или любая другая специальная файловая система кажется законным случаем для доступа к таким файлам из модулей ядра.
Насколько я понимаю, в качестве общего принципа проектирования ядро нацелено на реализацию механизмов без навязывания определенной политики. Любая функция, реализованная таким образом, чтобы принудительно использовать политику, при которой пространство пользователя имеет доступ к данным, а модуль ядра - нет, плохо спроектирован.
Код модуля ядра, по замыслу, выполняется с тем же уровнем привилегий, что и остальная часть ядра. Не существует надежного способа запретить модулю ядра доступ к любым данным, к которым может получить доступ любая другая часть ядра. Любые такие попытки можно обойти с помощью красивых уродливых хаков.
В качестве крайнего примера, на машинах x86 модуль ядра может использовать встроенную сборку для прямого доступа к регистрам управления, обхода таблиц страниц и работать с любой желаемой областью памяти. То же самое и с обработчиками прерываний и исключений.
Для этого я использовал top, потому что он на самом деле дает CPU %. Код, который я использовал, выглядит следующим образом
Process process = Runtime.getRuntime().exec("top -n 1");
//Get the output of top so that it can be read
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
String line;
//Read every line of the output of top that contains data
while (((line = bufferedReader.readLine()) != null)) {
//Break the line into parts. Any number of spaces greater than 0 defines a new element
numbersC = line.split("[ ]+");
if (i > 6) {
//Some lines start with a space, so their indices are different than others
if (numbersC[0].equals("")){
//If name contains the string com.android, then it is a process that we want to take values for
if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android".toLowerCase())){
//Add the name of the process to the Name arraylist, excluding the com.android. part
Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
//Add the CPU value of the process to the CPU arraylist, without the % at the end
CPU.add(Long.parseLong(numbersC[3].replace("%", "")));
}
}
else {
//This is basically the same as above, except with different index values, as there is no leading space in the numbers array
if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android.".toLowerCase())){
Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
CPU.add(Long.parseLong(numbersC[2].replace("%", "")));
}
}
}
i++;
}