Чтение / запись файлов в модуле ядра Linux
Я знаю все дискуссии о том, почему нельзя читать / писать файлы из ядра, а как использовать / proc или netlink для этого. Я все равно хочу читать / писать. Я также прочитал " Сводить меня с ума" - то, что вы никогда не должны делать в ядре.
Однако проблема в том, что 2.6.30 не экспортирует sys_read()
, Скорее это завернуто в SYSCALL_DEFINE3
, Поэтому, если я использую его в своем модуле, я получаю следующие предупреждения:
WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!
очевидно insmod
не могу загрузить модуль, потому что связывание не происходит правильно.
Вопросы:
- Как читать / писать в ядре после 2.6.22 (где
sys_read()
/sys_open()
не экспортируются)? - В общем, как использовать системные вызовы, завернутые в макрос
SYSCALL_DEFINEn()
изнутри ядра?
2 ответа
Вы должны знать, что вам следует избегать файлового ввода-вывода, когда это возможно. Основная идея состоит в том, чтобы пойти "на один уровень глубже" и напрямую вызывать функции уровня VFS вместо обработчика syscall:
Включает в себя:
#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>
Открытие файла (аналогично открытию):
struct file *file_open(const char *path, int flags, int rights)
{
struct file *filp = NULL;
mm_segment_t oldfs;
int err = 0;
oldfs = get_fs();
set_fs(get_ds());
filp = filp_open(path, flags, rights);
set_fs(oldfs);
if (IS_ERR(filp)) {
err = PTR_ERR(filp);
return NULL;
}
return filp;
}
Закрыть файл (аналогично close):
void file_close(struct file *file)
{
filp_close(file, NULL);
}
Чтение данных из файла (аналогично pread):
int file_read(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_read(file, data, size, &offset);
set_fs(oldfs);
return ret;
}
Запись данных в файл (аналог pwrite):
int file_write(struct file *file, unsigned long long offset, unsigned char *data, unsigned int size)
{
mm_segment_t oldfs;
int ret;
oldfs = get_fs();
set_fs(get_ds());
ret = vfs_write(file, data, size, &offset);
set_fs(oldfs);
return ret;
}
Синхронизация изменений файла (аналогично fsync):
int file_sync(struct file *file)
{
vfs_fsync(file, 0);
return 0;
}
[Edit] Первоначально я предложил использовать file_fsync, который отсутствует в более новых версиях ядра. Спасибо бедному парню, предложившему изменение, но чье изменение было отклонено. Редактирование было отклонено, прежде чем я смог его просмотреть.
Начиная с версии 4.14 ядра Linux, vfs_read
а также vfs_write
функции больше не экспортируются для использования в модулях. Вместо этого предоставляются функции исключительно для доступа к файлам ядра:
# Read the file from the kernel space.
ssize_t kernel_read(struct file *file, void *buf, size_t count, loff_t *pos);
# Write the file from the kernel space.
ssize_t kernel_write(struct file *file, const void *buf, size_t count,
loff_t *pos);
Также, filp_open
больше не принимает строку пользовательского пространства, поэтому ее можно использовать для доступа к ядру напрямую (без set_fs
).