webentwicklung-frage-antwort-db.com.de

Lesen / Schreiben von Dateien in einem Linux-Kernelmodul

Ich kenne alle Diskussionen darüber, warum man keine Dateien aus dem Kernel lesen/schreiben sollte, sondern wie man dazu /proc oder netlink verwendet. Ich möchte trotzdem lesen/schreiben. Ich habe auch gelesen Driving Me Nuts - Dinge, die Sie nie im Kernel tun sollten .

Das Problem ist jedoch, dass 2.6.30 sys_read() nicht exportiert. Eher ist es in SYSCALL_DEFINE3 Eingewickelt. Wenn ich es also in meinem Modul verwende, erhalte ich die folgenden Warnungen:

WARNING: "sys_read" [xxx.ko] undefined!
WARNING: "sys_open" [xxx.ko] undefined!

Offensichtlich kann insmod das Modul nicht laden, da die Verknüpfung nicht korrekt erfolgt.

Fragen:

  • Wie kann ich nach 2.6.22 im Kernel lesen/schreiben (wobei sys_read()/sys_open() nicht exportiert werden)?
  • Wie verwende ich im Allgemeinen Systemaufrufe, die in das Makro SYSCALL_DEFINEn() innerhalb des Kernels eingebunden sind?
87
Methos

Sie sollten sich bewusst sein, dass Sie Datei-E/A nach Möglichkeit vermeiden sollten. Die Hauptidee ist, "eine Ebene tiefer" zu gehen und VFS-Ebenenfunktionen anstelle des Syscall-Handlers direkt aufzurufen:

Beinhaltet:

#include <linux/fs.h>
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <linux/buffer_head.h>

Öffnen einer Datei (ähnlich wie beim Öffnen):

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;
}

Schließen Sie eine Datei (ähnlich wie beim Schließen):

void file_close(struct file *file) 
{
    filp_close(file, NULL);
}

Daten aus einer Datei lesen (ähnlich wie bei 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;
}   

Daten in eine Datei schreiben (ähnlich wie bei 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;
}

Durch das Synchronisieren wird eine Datei geändert (ähnlich wie bei fsync):

int file_sync(struct file *file) 
{
    vfs_fsync(file, 0);
    return 0;
}

[Bearbeiten] Ursprünglich habe ich vorgeschlagen, file_fsync zu verwenden, das in neueren Kernelversionen nicht mehr vorhanden ist. Vielen Dank an den armen Kerl, der die Änderung vorschlug, aber dessen Änderung abgelehnt wurde. Die Bearbeitung wurde abgelehnt, bevor ich sie überprüfen konnte.

112
dmeister

Seit Version 4.14 des Linux-Kernels ist vfs_read und vfs_write Funktionen sind nicht mehr exportiert zur Verwendung in Modulen. Stattdessen werden Funktionen exklusiv für den Dateizugriff des Kernels bereitgestellt:

# 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);

Ebenfalls, filp_open akzeptiert keine User-Space-Zeichenfolge mehr, kann also für den Kernel-Zugriff verwendet werden direkt (ohne Tanz mit set_fs).

9
Tsyvarev