Читання / запис файлів у модулі ядра 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 замість обробника 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;
}

[Редагувати] Спочатку я запропонував використовувати file_fsync, який відсутній у нових версіях ядра. Дякую бідному хлопцеві, який запропонував зміни, але чиї зміни було відхилено. Правка була відхилена до того, як я зміг переглянути її.


2
Дякую. Я думав зробити щось подібне, відтворивши функціональність sys_read / sys_open. Але це велика допомога. Цікаво, чи є спосіб використовувати системні дзвінки, заявлені за допомогою SYSCALL_DEFINE?
Methos

5
Я спробував цей код у ядрі 2.6.30 (Ubuntu 9.04) і читання файлу приводить до аварійного завершення роботи системи. Хтось стикався з такою ж проблемою?
Enrico Detoma

@Enrico Detoma? Ух ти. Це будь-яким чином, що ви можете дати мені модуль, який ви використовували? Ніколи раніше цього не бачив?
dmeister

2
Це негайно піднімає питання про те, "чому ти робиш цей танець FS, до речі", на що тут досить приємно відповіли: linuxjournal.com/node/8110/print у розділі "Виправлення адресного простору".
PypeBros

@dmeister, Об'єкт не знайдено для функцій рівня посилання VFS
sree

19

З версії 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).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.