Чтение/запись файлов в модуле ядра 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() изнутри ядра?

Ответ 1

Вы должны знать, что вам следует избегать ввода/вывода файлов, когда это возможно. Основная идея состоит в том, чтобы пойти "на один уровень глубже" и вызвать функции уровня 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;
}

Закройте файл (аналогично закрытию):

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, который ушел в более новые версии ядра. Благодаря бедному парню, предлагающему изменение, но чье изменение было отклонено. Редактирование было отклонено, прежде чем я смог его просмотреть.

Ответ 2

Начиная с версии 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).