Чтение / запись файлов в модуле ядра Linux

99

Я знаю все дискуссии о том, почему не следует читать / записывать файлы из ядра, вместо этого, как использовать / proc или netlink для этого. Я все равно хочу читать / писать. Я также прочитал Driving Me Nuts - Вещи, которые вы никогда не должны делать в ядре .

Однако проблема в том, что 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()из ядра?
Методы
источник

Ответы:

122

Вы должны знать, что вам следует избегать файлового ввода-вывода из ядра Linux, когда это возможно. Основная идея состоит в том, чтобы пойти «на один уровень глубже» и напрямую вызвать функции уровня VFS вместо обработчика системных вызовов:

Включает:

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

dmeister
источник
2
Спасибо. Я думал сделать что-то подобное, реплицируя функциональность sys_read / sys_open. Но это большая помощь. Любопытно, есть ли способ использовать системные вызовы, объявленные с помощью SYSCALL_DEFINE?
Methos
5
Я пробовал этот код в ядре 2.6.30 (Ubuntu 9.04), и чтение файла приводит к сбою системы. Кто-нибудь испытал такую ​​же проблему?
Энрико Детома,
@ Энрико Детома? Ух ты. Есть ли способ дать мне модуль, который вы использовали? Никогда раньше не видел?
dmeister
2
Это сразу вызывает вопрос «почему вы занимаетесь этим танцем FS, кстати?», На который здесь довольно хорошо дан ответ: linuxjournal.com/node/8110/print в разделе «Исправление адресного пространства».
PypeBros
@dmeister, объект не найден для ur link функций уровня VFS
sree 01
20

Начиная с версии ядра Linux 4.14, функции 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).

Цыварев
источник