web-dev-qa-db-fra.com

Lecture / écriture de fichiers dans un module de noyau Linux

Je connais toutes les discussions sur les raisons pour lesquelles on ne devrait pas lire/écrire des fichiers du noyau, mais comment utiliser /proc ou ) netlink pour le faire. Je veux lire/écrire quand même. J'ai aussi lu Driving Me Nuts - Ce que vous ne devriez jamais faire dans le noya .

Cependant, le problème est que 2.6.30 n'exporte pas sys_read(). Plutôt c'est enveloppé dans SYSCALL_DEFINE3. Donc, si je l'utilise dans mon module, j'obtiens les avertissements suivants:

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

De toute évidence, insmod ne peut pas charger le module car la liaison n’est pas établie correctement.

Des questions:

  • Comment lire/écrire dans le noyau après la version 2.6.22 (où sys_read()/sys_open() ne sont pas exportés)?
  • En général, comment utiliser les appels système intégrés dans la macro SYSCALL_DEFINEn() à partir du noyau?
87
Methos

Vous devez savoir que vous devez éviter les E/S sur fichier lorsque cela est possible. L’idée principale est d’aller "un niveau plus profond" et d’appeler directement fonctions de niveau VFS au lieu du gestionnaire syscall:

Comprend:

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

Ouvrir un fichier (similaire à ouvrir):

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

Fermer un fichier (similaire à fermer):

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

Lecture de données depuis un fichier (similaire à 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;
}   

Écrire des données dans un fichier (similaire à 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;
}

La synchronisation modifie un fichier (similaire à fsync):

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

[Edit] À l'origine, j'avais proposé d'utiliser file_fsync, qui a disparu dans les versions plus récentes du noyau. Merci au pauvre gars qui suggère le changement, mais dont le changement a été rejeté. Le montage a été rejeté avant que je puisse le relire.

112
dmeister

Depuis la version 4.14 du noyau Linux, vfs_read et vfs_write Les fonctions sont ne sont plus exportées à utiliser dans les modules. Au lieu de cela, des fonctions exclusivement pour l'accès aux fichiers du noyau sont fournies:

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

Également, filp_open n'accepte plus la chaîne d'espace utilisateur, elle peut donc être utilisée pour l'accès au noyau directement (sans dance avec set_fs).

9
Tsyvarev